原型模式

未匹配的标注

意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

在创建型模式中,原型模式是相对简单的一个模式,我们主要从两点来理解原型模式:

  1. 原型模式如何实现的?
  2. 为什么要使用原型模式。

原型模式如何实现

当你想要复制一个对象时,你可以选择遍历该对象的成员并将其复制到新对象中,但是这样做你可能会获取不到一些私有成员,或者说你可能不清楚这个对象成员的相关依赖。所以,可以采用原型模式来实现复制对象的操作,原型模式将复制对象的任务委托给了对象本身。

为什么要使用原型模式

当你需要复制一些对象,但是你又希望复制的对象是单独的副本,你就可以使用原型模型。例如,当你收到第三方接口传递过来的对象时,在不了解对象信息也不想直接修改对象时,就可以使用原型模式来复制对象并进行操作。

此外,当你创建的实例差别很小时,那么你就可以使用原型模式来减少子类的数量。例如,页面模板可使用原型模式来复制生成。

实现

对于 PHP 而言,对复制对象的支持使得原型模式在 PHP 的使用变得非常简单。对于简单的类而言,直接使用 clone 关键字即可,但是如果类成员包括了引用类型,那就需要在 __clone 方法中实现对成员的复制。

<?php

class Component { }

class Prototype
{
    public $component;

      public $id;

    public function __construct($component, $id)
    {
        $this->component = $component;
          $this->id = $id;
    }

    public function __clone()
    {        
        // 不希望 id 复制到新副本中
          $this->id = 0;

       // component 应当复制一个新的副本,否则将指向同一个 component 实例
        $this->component = clone $this->component;
    }
}

$object = new Prototype(new Component(), 1);
$clone = clone $object;

$clone->component === $object->component; // false;
$clone->id; // 0

应用

我们举一个常见的例子,将页面当成模板保存下来后反复使用,每次相当于复制一份副本。

image.png

实现

<?php

class Author
{
    private $name;

    private $pages = [];

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function addToPage(Page $page): void
    {
        $this->pages[] = $page;
    }
}

class Page
{
    private $title;
    private $body;
    private $author;
    private $comments = [];
    private $date;

    public function __construct(string $title, string $body, Author $author)
    {
        $this->title = $title;
        $this->body = $body;
        $this->author = $author;
        $this->author->addToPage($this);
        $this->date = new \DateTime;
    }

    public function addComment(string $comment): void
    {
        $this->comments[] = $comment;
    }

    public function __clone()
    {
        $this->title = "标题副本" . $this->title;
        $this->author->addToPage($this);
        $this->comments = []; // 不需要拷贝评论
        $this->date = new \DateTime;
    }
}

测试

<?php

$author = new Author("心智极客");
$page = new Page("设计模式之原型模式", "内容", $author);
$page->addComment("这是一条评论");

$newPage = clone $page;

总结

PHP 对原型模式提供了良好的支持。通过原型模式,可以很方便的对对象进行克隆,而无须考虑具体的类。同时,通过原型模式,可以避免反复运行初始化代码。需要注意的是,如果对象非常复杂时,使用原型模式会变得非常的棘手。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~