平行的继承层次使用工厂模式在:大型设计中,必须去维护大量的产品类。(上文中,称之为“特殊的耦合”)数据库
在这里咱们介绍一种其抽象工厂模式的变体:原型模式。它使用clone
关键词,来复制具体产品类,使得具体产品类能完成自我复制。segmentfault
(通俗介绍:工场只负责生产产品,选择生产何等产品,再也不由工场本身决定,而是经过传参,来确认——对比抽象工厂,你能够发现,咱们再也找不到一大群具体产品的建立者,而只有一个高度灵活的建立者)设计模式
假设咱们在作一款相似文明(Cicilization)的网页游戏——这么经典的游戏都没玩过?成何体统[滑稽]。(屠龙宝刀,点击就送!)this
里面有个 战斗用途的地理系统——三种地形:海洋 Sea/平原 Forest/森林 Plains,按照抽象工厂 + 工厂模式,咱们确定能够获得这样的结果:编码
(为什么个人眼里常含泪水,由于StartUML2.5难用的深沉)spa
但咱们要避免“大型的继承体系”——开头说了,这会形成另类耦合,因而,来看看原型模式的解决方法吧!设计
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 $plains; private $forest; 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(), new EarthPlains(), new EarthForest() ); print_r( $factory->getSea() ); print_r( $factory->getPlains() ); print_r( $factory->getForest() );
读完代码,你就能看懂原型模式,创造者能够无脑的生产出一片“具有三种地形的战斗区域”,你在地球风格的海洋和森林。火星风格的平原上战斗?那么只须要传递三个对应参数便可,换而言之——创造者再也不负责:我要造什么。rest
咱们还能够增长一些灵活性,譬如:海洋地形中的航行难度——营造出一种“索马里海域 / 渤海海域”的差别(在古代,索马里海域的航船条件至关凶恶)。code
class Sea { private $navigability = 0; function __construct( $navigability ) { $this->navigability = $navigability; } } ...省略部分代码... $factory = new TerrainFactory( new EarthSea( -1 ), new EarthPlains(), new EarthForest() );
能够预见,这是多么具有灵活性的模式。额外说起:若是产品类包含了其余外部类,记得采用__clone()
方法,这样能够保证你获得的是深度复制(deep copy)面向对象设计模式
本节没有结论(或者,这个模式很好理解),这里说起一个模式的诱导和骗术:它们并无帮你决定Create Who?
不管是工厂模式、抽象工厂模式,亦或是原型模式,它们都只是在技术层面简化了类的数量、维护复杂度。
你仍是须要本身决定:生产特定的产品——你会将这些决定留在整个代码系统,在你须要修改一处时,形成瘫痪。
解决方案:操控单例类 / 存储于数据库 / 甚至直接写到配置文件(.htaccess等)——包含大量的标记/硬编码;
我的推荐:单例类 + 配置文件,优势:方便修改、全局访问。