深入PHP面向对象、模式与实践——生成对象(3)

    xiaoxiao2021-03-25  93

    原型模式

    平行继承层次的出现是工厂方法模式带来的一个问题。一个避免这种依赖的方法是使用PHP的clone关键词复制已存在的具体产品。然后,具体产品类本身便成为它们自己生成的基础。这便是原型模式。使用该模式我们可以用组合代替继承。这样的转变促使了代码运行时的灵活性,并减少了必须创建的类。

    以下展示一个抽象工厂和工厂方法模式的类图:

    你可以看到,我们依赖继承来组合工厂生成terrain家族产品,但这需要一个大型的继承体系,并且相对来说不那么灵活。当你不想平行的继承体系而需要最大化运行时的灵活性时,可以使用抽象工厂模式的强大变形——原型模式。

    实现

    简单地创建一个保存具体产品的工厂类,并在初始化时就加入这种做法。

    class Sea { } class EarthSea extends Sea { } class MarsSea extends Sea { } class Plains { } class EarthPlains extends Plains { } class MarsPlains extends Plains { } class Forest { } class EarthForest extends Forest { } class MarsForest extends Forest { } class TerrainFactory { private $sea; private $forest; private $plains; public function __construct(Sea $sea, Plains $plains, Forest $forest) { $this->sea = $sea; $this->forest = $forest; $this->plains = $plains; } public function getSea() { return clone $this->sea; } public function getForest() { return clone $this->forest; } public function getPlains() { return clone $this->plains; } } $factory = new TerrainFactory(new EarthSea(), new EarthPlains(), new EarthForest()); print_r($factory->getSea());

    可以看到,我们加载了一个带有产品对象实例的具体的TerrainFactory对象。当客户端代码调用getSea()时返回在初始化时缓存的Sea对象的一个副本。我们不仅仅省掉了一些类,还增加额外的灵活性。如创建一个有类似地球海洋和森林以及火星平原的星球:

    $factory = new TerrainFactory(new EarthSea(), new MarsPlains(), new EarthForest());

    因此原型模式使我们可利用组合所提供的灵活性,不过我们得到的可不止这个。因为在运行时保存和克隆对象,所以当生成新产品时,可以重新设定对象状态。

    class Sea { private $navigability = 0; function __construct($navigability) { $this->navigability = $navigability; } }

    要记住但是如果产品对象引用了其他对象,那你应该实现__clone()方法来保证你得到的是深复制。

    转载请注明原文地址: https://ju.6miu.com/read-34822.html

    最新回复(0)