Php 设计模式学习(单例,工厂,抽象工厂)

设计模式简介

在软件开发过程中,经常出现的典型场景的典型解决方案,称为设计模式

面型对象 三大特性:多态 继承 封装

设计模式按目的分为三种类型:创建型,结构型,行为型
创建型

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  1. 单例模式【Singleton】
  2. 工厂模式【Factory】
  3. 抽象工厂模式【Abstract Factory】
  4. 建造者模式【Builder】
  5. 原型模式【Prototype】

结构型

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

  1. 适配器模式【Adapter】
  2. 桥接模式【Bridge】
  3. 合成模式【Composite】
  4. 装饰器模式【Decorator】
  5. 门面模式【Facade】
  6. 代理模式【Proxy】
  7. 享元模式【Flyweight】

行为型

这些设计模式特别关注对象之间的通信。

  1. 策略模式【Strategy】
  2. 模板方法模式【TemplateMethod】
  3. 观察者模式【Observer】
  4. 迭代器模式【Iterator】
  5. 责任链模式【ResponsibilityChain】
  6. 命令模式【Command】
  7. 备忘录模式【Memento】
  8. 状态模式【State】
  9. 访问者模式【Visitor】
  10. 中介者模式【Mediator】
  11. 解释器模式【Interpreter】

因为php是一门弱类型语言 所以以上的一些设计模式在php中是自动实现的 不需要通过代码实现 但是设计模式实现的思想都是一样的

设计模式优点:

	1.降低代码的冗余量,写出优雅的代码
	2.可以快速的帮助你读懂源码
	3.提高代码的可扩展性
	4.模块化代码,解决问题更加容易

设计模式原则

1. 开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
2. 里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.
3. 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
4. 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
5. 接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
6. 迪米特法则:一个对象应该对其他对象保持最少的了解。

单例模式[Singleton]

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。
//单例模式,一个类只能实例化一次
class Single
{
    //私有化静态属性,保存类的实例对象
    private static $single = [];

    //私有化构造方法
    private function __contruct()
    {
    }
    //私有化克隆方法
    private function __clone()
    {
    }
    //入口
    public static function getInstance( $classname  , $arg = null)
    {
        //判断该类是否存在
        if (!class_exists($classname))
        {
           return "class '{$classname}' is not found!";
        }
        //判断对象是否存在,不存在进行实例化
        if( !isset(self::$single[$classname]) )
        {
            self::$single[$classname] = new $classname($arg);
        }
        return self::$single[$classname];

    }
}

class test1
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
}
class test2
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
}
$obj1 = Single::getInstance('test1','test1');
$obj2 = Single::getInstance('test1','test2');
$obj3 = Single::getInstance('test2','test11111');
$obj4 = Single::getInstance('test2','test22222');
$obj5 = Single::getInstance('test3','test333');
var_dump($obj1,$obj2,$obj3,$obj4,$obj5);
/*输出:
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test1)[1]
  public 'name' => string 'test1' (length=5)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test1)[1]
  public 'name' => string 'test1' (length=5)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test2)[2]
  public 'name' => string 'test11111' (length=9)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test2)[2]
  public 'name' => string 'test11111' (length=9)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:string 'class 'test3' is not found!' (length=27)
*/

工厂模式[Factory]

工厂模式要解决的问题:

  • 在代码运行时候才知道要生成的对象类型
  • 对象类型可能要扩充新产品类型
  • 每个产品类型都可以定制特定的功能

采用简单工厂的优点是可以使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性;

缺点是可实例化的类型在编译期间已经被确定,如果增加新类型,则需要修改工厂,不符合OCP(开闭原则)的原则。

简单模拟一个超人
一个超人 具备超人的能力(就是超人技能:如飞行 射击 扔炸弹 暴力攻击等能力)
从面向对象设计:首先分析应该分为超人类(Superman) 和超人技能类(Flight Shot UltraBomb等)
为了规范编程写一个技能接口类(Ability) 用来规范超人技能类(同上) 当然超人也可以写一个超人接口来规范超人,这里就不写了
我要实现的是使用超人来拥有超人技能,我到底怎么实现的

<?php

//工厂类的使用
//超能力接口   作用:规范每个超人能力类
interface Ability
{
    /**
     * @Author   shyn
     * @DateTime 2017-12-20
      * @param    array      $target [针对目标,可以使一个或多个,自己或他人]
      * @return   [type]             [description]
      * [超能力激活方法]
      */
      public function activate(array $target);
  }

  //飞翔能力
  class Flight implements Ability{
     protected $speed;//速度
      protected $holdtime;//飞行时间
      protected $skill = '飞翔技能=';//技能描述
      public function __construct($speed = 0, $holdtime = 0)
      {
          $this->speed = $speed;
          $this->holdtime = $holdtime;
      }
      //激活该技能
      public function activate(array $target = [])//参数可以忽略 保留待用
      {
          echo '超人飞行开始';
      }

      //输出该类实例(就是对象实例 如:new Flight;) 显示信息
      public function __toString()
      {
          return $this->skill.'速度:'.$this->speed.' 飞翔时间:'.$this->holdtime;
      }
  }


  //射击能力
  class Shot implements Ability
  {
    protected $attack;//伤害
    protected $range;//伤害范围
    protected $skill = '射击技能=';//技能解说
    public function __construct($attack = 0, $range = 0)
      {
          $this->attack = $attack;
          $this->range = $range;
      }

      //激活技能
      public function activate(array $target = [])
      {
          echo '超人射击开始';
      }
      public function __toString()
      {
          return $this->skill.'伤害:'.$this->attack.' 射击距离:'.$this->range;
      }

  }

  //暴击能力
  class Force implements Ability
  {
      protected $attack;//伤害
      protected $strength;//力量
      protected $range;//范围
      protected $skill;//技能标签
      public function __construct($attack = 0, $range = 0, $strength = 0)
      {
          $this->attack = $attack;
          $this->range = $range;
          $this->strength = $strength;
      }

      //激活暴击技能
      public function activate(array $target = [])
      {
          echo '超人暴力攻击';
      }

      public function __toString()
      {
          $this->skill = '暴力能力=';
          return $this->skill.'伤害:'.$this->attack.' 力量:'.$this->strength.' 范围'.$this->range;
      }
  }

  //终极炸弹能力(扔炸弹)
  class UltraBomb implements ability
  {
      protected $skill = '炸弹技能=';
      protected $range;
      protected $attack;

     public function __construct($range = 0 , $attack = 0)
     {
         $this->range = $range;
         $this->attack = $attack;

     }
     /*
      *  @Author   shy
      *  @DateTime 2017-12-2109
      *  @param    integer    $bombRange [炸弹伤害范围 ]
      *  @param    integer    $attack    [炸弹伤害程度 ]
      *  @return   [type]                [description ]
      *  [使用炸弹]
      */
     public function throwBomb($range = 5, $attack = 10)
     {
         echo '炸弹范围'.$range.'米 伤害为:'.$attack;
     }

     public function activate(array $target = [])
     {
         echo '超人炸弹发射';
         return $this;
     }

     public function __toString()
     {
         return $this->skill.'伤害:'.$this->attack.' 爆炸范围:'.$this->range;
     }

 }

 //超人技能工厂类
 class abilityFactory{

     public function makeSkill($moduleName , $optoin)
     {
         switch($moduleName){
             case 'Flight':
                 return new Flight($optoin[0], $optoin[1]);
             case 'Force':
                 return new Force($optoin[0], $optoin[1], $optoin[2]);
             case 'Shot':
                 return new Shot($optoin[0], $optoin[1]);
             default :
                 throw new AbilityException("此 {$moduleName} 技能暂未开发");
         }

     }
 }


 //超人类
 class Superman
 {
     public $power = [];//用来保存超人技能 超人会有多个技能所以用数组

     //初始化时传入传入技能类的名称
     public function __construct(array $ability)
     {
         //这里使用超人能力工厂类
         //优点:
         //1.方便对技能的管理 直接在工厂里添加我们扩展的其他超人技能
         //2.我们的超人类不用直接依赖我们的超人技能类
         //缺点:
         //1.不用直接依赖我们的超人技能类但是依赖了工厂类
         //2.工厂类改变的话我们的超人技能必将受到影响
         //3.有没有更好的方法来 当然有 我们的神器:容器(可称为超级工厂)
         //4.容器是什么 不是什么 a.你可以理解一个更厉害的类 b.解决了超人类对工厂类的依赖
         $af = new abilityFactory();//实例化工厂类
         foreach ($ability as $abilityName => $abilityOptions)
         {
             $this->power[] = $af->makeSkill($abilityName, $abilityOptions);
         }
     }

     // 查看超人能力
     public function __toString()
     {
         if(count($this->power)<1){
               return '超人无能纳,还没任何技能';
         }
         foreach ($this->power as $key => $value)
         {
             echo $key.'=>'.$value.'<br/>';
         }
         return '超人共有'.count($this->power).'个技能<br />';
     }
 }
 class AbilityException extends Exception
{

}

 $ability = ['Flight'=>[1,4]];//填写超人技能类名不区分大小写对应 能力工厂类中case
 $superman = new Superman($ability);

 echo '<pre>';
 echo $superman;//此时可以看到超人类中power 属性已经拥有该超人技能对象
 $superman->power[0]->activate([]);//使用技能 看到这里完美 activate([]) 传递了一个空数组完全可以不需要 这里为了你可以传递技能参数故意添加的 可以自己试试搞一下 有些东西得练一下才好记得才明白

抽象工厂模式【Abstract Factory】

抽象工厂模式是对工厂模式的抽象,通俗来说,就是把工厂模式的结构分离出来成为能独立运行的个体。

拿工厂模式中的例子来说明:
现在有一个汽车工厂,它生产小汽车和巴士车,小汽车和巴士车都是由引擎、车身和轮子组成的。
在工厂模式中,我们把小汽车和巴士车作为汽车族群中的两个类别,生产引擎、车身和轮子为生产汽车的固定结构
在这里插入图片描述

再继续对工厂进行抽象,抽象出汽车工厂和巴士车工厂,并且让各工厂与各组件相关联,如图:
在这里插入图片描述

//生产引擎的标准
interface engineNorms{
	function engine();
}
 
class carEngine implements engineNorms{
 
	public function engine(){
		return '汽车引擎';
	}
 
}
 
class busEngine implements engineNorms{
	
	public function engine(){
		return '巴士车引擎';
	}
	
}
 
//生产车身的标准
interface bodyNorms{
	function body();
}
 
class carBody implements bodyNorms{
 
	public function body(){
		return '汽车车身';
	}
 
}
 
class busBody implements bodyNorms{
	
	public function body(){
		return '巴士车车身';
	}
	
}
 
//生产车轮的标准
interface whellNorms{
	function whell();
}
 
class carWhell implements whellNorms{
 
	public function whell(){
		return '汽车轮子';
	}
 
}
 
class busWhell implements whellNorms{
	
	public function whell(){
		return '巴士车轮子';
	}
	
}
 
//工厂标准
interface factory{
	static public function getInstance($type);
}
 
//汽车工厂
class carFactory implements factory{
	
	static public function getInstance($type){
		$instance='';
		switch($type){
			case 'engine':
				$instance=new carEngine();
				break;
			case 'body':
				$instance=new carBody();
				break;
			case 'whell':
				$instance=new carWhell();
				break;	
			default:
				throw new Exception('汽车工厂无法生产这种产品');
		}
		return $instance;
	}
	
}
 
//巴士车工厂
class busFactory implements factory{
	
	static public function getInstance($type){
		$instance='';
		switch($type){
			case 'engine':
				$instance=new busEngine();
				break;
			case 'body':
				$instance=new busBody();
				break;
			case 'whell':
				$instance=new busWhell();
				break;
			default:
				throw new Exception('巴士车工厂无法生产这种产品');
		}
		return $instance;
	}
	
}
 
$car['engine']=carFactory::getInstance('engine')->engine();
$car['body']=carFactory::getInstance('body')->body();
$car['whell']=carFactory::getInstance('whell')->whell();
print_r($car);
 
$bus['engine']=busFactory::getInstance('engine')->engine();
$bus['body']=busFactory::getInstance('body')->body();
$bus['whell']=busFactory::getInstance('whell')->whell();
print_r($bus);

抽象工厂模式将工厂模式进行抽象,可以使得抽象出来的新结构更加的灵活。例如,若生产车身需要一个喷漆的动作,在工厂模式中,我们需要对整体结构进行更改,而抽象工厂中,只需要对生产车身进行更改就ok了。
抽象工厂模式同样具有工厂模式对结构要求高的缺点,整体结构的扩展或精简将变得更加的烦杂,所以使用抽象工厂模式时,对等级结构的划分是非常重要的。

以上部分内容转自
https://www.cnblogs.com/shynshyn/p/8075299.html
https://my.oschina.net/botkenni/blog/1603660
https://blog.csdn.net/phenixsoul/article/details/8493764

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值