平行的繼承層次使用工廠模式在:大型設計中,必須去維護大量的產品類。(上文中,稱之爲「特殊的耦合」)數據庫
在這裏咱們介紹一種其抽象工廠模式的變體:原型模式。它使用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等)——包含大量的標記/硬編碼;
我的推薦:單例類 + 配置文件,優勢:方便修改、全局訪問。