php设计模式(八)原型模式

原型模式主要用于创建重复的对象;
目的是使用 clone 对象来减少 new 对象的开销;
如果某个场景需要多次实例化一个类;
那就可以尝试用原型模式优化;
在 php 中使用原型模式是很简单的;
毕竟 php 是世界上最好的语言;
我们只需要 clone 就行了;
但是 clone 有一些问题;
我们下面在代码中讲;

结构

抽象的 __clone() 方法;

示例

我们先来个 clone 节省资源的直观示例;

造个车;
Car.php

<?php

namespace Baijunyao\DesignPatterns\Prototype;

/**
 * Class Car
 * @package Baijunyao\DesignPatterns\Prototype
 */
class Car
{
    /**
     * 车名
     *
     * @var
     */
    public $name;

    /**
     * 设置车名
     *
     * @param $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }
}

驾驶汽车;
ShallowDrive.php

<?php

namespace Baijunyao\DesignPatterns\Prototype;

/**
 * Class ShallowDrive
 * @package Baijunyao\DesignPatterns\Prototype
 */
class ShallowDrive
{

    private $car;

    /**
     * Drive constructor.
     */
    public function __construct()
    {
        echo '准备完成';
    }

    /**
     * 选择要开的车
     *
     * @param $car
     */
    public function setCar($car)
    {
        $this->car = $car;
    }

    public function show()
    {
        echo '开始驾驶'.$this->car->name;
        echo '<br>';
    }
}

运行;
index.php

<?php

namespace Baijunyao\DesignPatterns\Prototype;

require __DIR__.'/../vendor/autoload.php';

/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\Prototype
 */
class Client
{
    /**
     * 浅复制
     */
    public function shallowCopy()
    {
        $car = new Car();
        $car->name = '特斯拉';
        $shallowDrive = new ShallowDrive();
        $shallowDrive->setCar($car);
        $shallowDrive->show();

        $cloneDrive = clone $shallowDrive;
        $cloneDrive->show();
    }

}

$client = new Client();
$client->shallowCopy();


从运行结果可以看出;
原本的流程需要先 new Car();
然后new Drive();
得到的 $shallowDrive 先执行__contract() 然后执行 show();

而克隆出来的$cloneDrive 不要 new Car();
不要 __contract() ;
直接 show() 带回家 ;

相当于 $cloneDrive 不用做准备工作直接就能驾驶起来跑了;
但是问题也显而易见;
我们不要在 __contract() 中做具体的工作;
而且需要注意的是 clone 是浅复制;
也就是说 $cloneDrive 的 car 和 $shallowDrive 的 car 是一个引用;
如果我们改变了 $car ;
$cloneDrive 也会被改变;

index.php

<?php

namespace Baijunyao\DesignPatterns\Prototype;

require __DIR__.'/../vendor/autoload.php';

/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\Prototype
 */
class Client
{
    /**
     * 浅复制
     */
    public function shallowCopy()
    {
        $car = new Car();
        $car->name = '特斯拉';
        $shallowDrive = new ShallowDrive();
        $shallowDrive->setCar($car);
        $shallowDrive->show();

        $cloneDrive = clone $shallowDrive;
        $cloneDrive->show();

        echo '<hr>';
        $car->name = '凯迪拉克';
        $shallowDrive->show();
        $cloneDrive->show();
    }

}

$client = new Client();
$client->shallowCopy();

如果我们想要一个深复制;
$shallowDrive 和 $cloneDrive 之间不再有引用一个 car;
再建个 DeepDrive.php ;
核心是 __clone 方法;

<?php

namespace Baijunyao\DesignPatterns\Prototype;

/**
 * Class DeepDrive
 * @package Baijunyao\DesignPatterns\Prototype
 */
class DeepDrive
{

    private $car;

    /**
     * Drive constructor.
     */
    public function __construct()
    {
        echo '准备完成';
    }

    /**
     * 选择要开的车
     *
     * @param $car
     */
    public function setCar($car)
    {
        $this->car = $car;
    }

    public function show()
    {
        echo '开始驾驶'.$this->car->name;
        echo '<br>';
    }

    public function __clone()
    {
        $this->car = clone $this->car;
    }
}

运行;
index.php

<?php

namespace Baijunyao\DesignPatterns\Prototype;

require __DIR__.'/../vendor/autoload.php';

/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\Prototype
 */
class Client
{
    /**
     * 浅复制
     */
    public function shallowCopy()
    {
        $car = new Car();
        $car->name = '特斯拉';

        $shallowDrive = new ShallowDrive();
        $shallowDrive->setCar($car);
        $shallowDrive->show();

        $cloneDrive = clone $shallowDrive;
        $cloneDrive->show();

        echo '<hr>';

        $car->name = '凯迪拉克';
        $shallowDrive->show();
        $cloneDrive->show();
    }

    /**
     *
     */
    public function deepCopy()
    {
        $car = new Car();
        $car->name = '特斯拉';

        $deepDrive = new DeepDrive();
        $deepDrive->setCar($car);
        $deepDrive->show();

        $cloneDrive = clone $deepDrive;
        $cloneDrive->show();

        echo '<hr>';

        $car->name = '凯迪拉克';
        $deepDrive->show();
        $cloneDrive->show();
    }
}

$client = new Client();
$client->shallowCopy();
echo '<br>-----------------------------<br>';
$client->deepCopy();

如我们所愿;
$cloneDrive 并没有随 $deepDrive 的 car 变化;
创建型的设计模式就算讲完了;
下篇文章我们将开始结构型的设计模式;

github示例:https://github.com/baijunyao/design-patterns/tree/master/Prototype

白俊遥博客
请先登录后发表评论
  • latest comments
  • 总共2条评论
白俊遥博客

龍族十三 :那假如说这个 car 创建的时候需要一把钥匙,clone 的时候钥匙也是引用了,深拷贝就得一层一层 clone 下去,直到没有属性为止

2019-08-20 20:02:57 回复

白俊遥博客

至死方休 :好久没来白大神这里了,新增了好多内容啊,这几天得花时间来此学习一下白俊遥博客

2018-08-20 15:39:55 回复