设计模式--创建型模式--原型模式

欢迎大家关注我的公众号,以后发布的文章会同步在csdn与公众号上!

上一篇文章我们介绍了设计模式的创建型模式中单例与多例模式,本篇文章我们将介绍设计模式中创建型模式的原型模式。

原型模式

原型模式的定义及特点

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

原型模式的优点

  1. 性能优良  原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

  2. 逃避构造函数的约束  这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。

原型模式的缺点

  1. 需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。

  2. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

  3. 由于使用原型模式复制对象时不会调用类的构造方法,所以原型模式无法和单例模式组合使用。

浅克隆和深克隆

  1. 浅克隆:当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。

  2. 深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制。

  3. 深克隆与浅克隆的区别就是,浅克隆不会克隆原对象中的引用类型,仅仅拷贝了引用类型的指向。深克隆则拷贝了所有。也就是说深克隆能够做到原对象和新对象之间完全没有影响。

浅克隆和深克隆

利用序列化来做深拷贝,把对象写到流里的过程是序列化的过程,这一过程称为“冷冻”或“腌咸菜”,反序列化对象的过程叫做“解冻”或“回鲜”。

原型模式的使用场景

  1. 资源优化场景。 

  2. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 

  3. 性能和安全要求的场景(通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式)。 

  4. 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

  5. 一个对象多个修改者的场景。

  6. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 

  7. 对对象状态进行记录。

  8. 创建对象成本j较大。

  9. 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。

原型模式的注意事项

  1. 构造函数不会被执行
    注意浅拷贝

  2. 深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。

  3. 深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下

  4. 使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。

简单实现

<?php 

abstract class ProductPrototype
{
    /**
     * @var string
     */
     protected $title;
  
        
    /**
     * @var string
     */
      protected $category;

      abstract public function __clone();

      public function getTitle(): string {
          return $this->title;
      }
  
      public function setTitle($title) {
          $this->title = $title;
      }
}
  
class BarProductPrototype extends ProductPrototype
{
      /**
       * @var string
       */
      protected $category = 'Bar';
  
      public function __clone() {
  
      }
}
  
class FooProductPrototype extends ProductPrototype
{
      /**
       * @var string
       */
      protected $category = 'Foo';
  
      public function __clone() {
  
      }
}

$fooPrototype = new FooProductPrototype();
$barPrototype = new BarProductPrototype();

for ($i = 0; $i < 10; $i++) {
    $foo = clone $fooPrototype;
    $foo->setTitle('Foo Book No ' . $i);
    if ($foo instanceof FooProductPrototype) {
        echo "ok" . $foo->getTitle();;
    }
}

for ($i = 0; $i < 5; $i++) {
    $bar = clone $barPrototype;
    $bar->setTitle('Bar Book No ' . $i);
    if ($foo instanceof BarProductPrototype) {
        echo "ok" . $bar->getTitle();;
    }
}

以上我们介绍了创建型模式中的原型模式,下一篇将会介绍创建型模式中的工厂方法模式。

 

感谢阅读!

 

                                                                        喜欢本文的朋友,欢迎关注“isevena

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值