原型模式

       虽然抽象工厂把创建者与产品实现分离,但是也造成了每次添加产品家族时,都要创建一个相关的具体创建者,在一个快速增长的系统中,随着包含的产品越来越多,维护这种关系将会变得越来越复杂。为了避免这种情况,我们可以利用PHP中的clone关键字,生成产品对象自身的克隆,具体的产品类本身便成为了它们生成自己的基础。这样做不仅可以促进代码的灵活性,还能够减少创建的对象数目。使用组合代替了继承。

适用:
  一、当要实例化的类是在运行时刻指定时。
  二、为了避免创建一个与产品类层次平行的工厂类层次时。
  三、当一个类的实例只能有几个不同状态组合中的一种时。

Prototype模式优点:
  1、可以在运行时刻增加和删除产品
  2、可以改变值或结构以指定新对象
  3、减少子类的构造
  4、用类动态配置应用

Prototype模式的缺点:
  Prototype是的最主要的缺点就是每一个类必须包含一个克隆方法;
  而且这个克隆方法需要对类的功能进行检测,这对于全新的类来说较容易,但对已有的类进行改造时将不是件容易的事情;


结构图:



Prototype:声明一个克隆自身的接口。
ConcretePrototype:实现一个克隆自身的操作。
Client:让一个原型克隆自身从而创建一个新的对象。

执行方式:客户请求原型克隆自身。

示例代码一:
class Sea{
    protected $navigability=0;
    function __construct($navigability){
        $this->navigability = $navigability;
    }
}
class EarthSea extends Sea{}
class MarsSea extends Sea{}


class Plains{
    protected $navigability=0;
    function __construct($navigability){
        $this->navigability = $navigability;
    }
}
class EarthPlains extends Plains{}
class MarsPlains extends Plains{}


class Forest{
    protected $navigability=0;
    function __construct($navigability){
        $this->navigability = $navigability;
    }
}
class EarthForest extends Forest{
    function getnavigability(){
        return $this->navigability;
    }
}
class MarsForest extends Forest{}


class TerrainFactory{
    private $sea;
    private $forest;
    private $Palins;
    function __construct(Sea $sea,Plains $plains,Forest $forest){
        $this->sea = $sea;
        $this->plains = $plains;
        $this->forest = $forest;
    }


    function getSea(){
        return clone $this->sea;
    }
    function getPlains(){
        return clone $this->plains;
    }
    function getForest(){
        return clone $this->forest;
    }
}


$factory = new TerrainFactory(new EarthSea(-4),new EarthPlains(2),new EarthForest(3));
print_r($factory->getSea());
print_r($factory->getPlains());
print_r($factory->getForest()->getnavigability());
 
  这个例子的结构图:

  

这里的clone方法是浅复制,即如果被克隆的对象引用了其他的对象,那么克隆出来的对象也是引用了以前的对象,这样当被克隆的对象改变了引用的对象时,克隆出来的对象所引用的对象也会被改变了。这种情况就是值对象模式出现的问题原理是相同的。我们可以使用拦截器__clone()方法实现深复制。

如果是浅复制的情况下改变值:
 
class Contained {
    public $now = 5;
}

class Container {
    public $contained;
    function __construct() {
        $this->contained = new Contained();
    }

//    function __clone() {
//        $this->contained = clone $this->contained;
//    }
}

$original = new Container();
$copy = clone $original;
$original->contained->now = -1;//改变引用的值对象
print_r( $original );
print_r( $copy );
 
结果:

Result:Container Object ( [contained] => Contained Object ( [now] => -1 ) )
 Container Object ( [contained] => Contained Object ( [now] => -1 ) )


    在上面的程序中一共创建了两个对象,其中有一个对象是通过clone关键字克隆出来的副本。两个对象完全能独立,但他们中的成员及属性的值完全一样。如果需要对克隆后的副本对象在克隆时重新为成员属性赋初值,则可以在类中声明一个魔术方法“__clone()”。该方法是在对象克隆时自动调用的,所以就可以通过此方法对克隆后的副本重新初始化。__clone()方法不需要任何参数。将上例中的代码改写一下,在类中添加魔术方法__clone(),为副本对象中的成员属性重新初始化
class Contained { //被引用的对象

    public $now = 5;
}
class Container {
    public $contained;
    function __construct() {
        $this->contained = new Contained();
    }
    function __clone() {
        $this->contained = clone $this->contained;
    }
}

$original = new Container();
$copy = clone $original;
$original->contained->now = -1;
print_r( $original );
print_r( $copy );
 
结果:


Result:Container Object ( [contained] => Contained Object ( [now] => -1 ) ) Container Object ( [contained] => Contained Object ( [now] => 5 ) ) 

 序列化与反序列化实现深拷贝:
  
 

示例代码二:
//用原型实例指定创建对象的种类.并且通过拷贝这个原型来创建新的对象

//声明一个克隆自身的接口,即抽象原型角色

interface Prototype{
    public function copy();
}
//实现克隆自身的操作,具体原型角色
class ConcretePrototype implements Prototype{
    private $name;
    function __construct($name){
        $this->name = $name;
    }
    function getName(){
          return $this->name;
      }
      function setName($name){
          $this->name = $name;
      }
      //克隆
      function copy(){
    //浅拷贝
      //return clone $this;
    //深拷贝
      $serialize_obj = serialize($this);  //序列化
      $clone_obj = unserialize($serialize_obj);   //反序列化
      return $clone_obj;
      }
}

//测试深拷贝的类
class Test{
    public $array;
}

class Client{
    //实现原型模式
    public static function main(){
        $test = new Test();
        $test->array = array('1','2','3');
        $pro1 = new ConcretePrototype($test);
        print_r($pro1->getName());
        $test->array = array('2','3','4');
        $pro2 = $pro1->copy();
        echo '<br />';
        print_r($pro2->getName());
    }
}
Client::main();
 
结果:
Test Object ( [array] => Array ( [0] => 1 [1] => 2 [2] => 3 ) ) 
Test Object ( [array] => Array ( [0] => 2 [1] => 3 [2] => 4 ) ) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值