“工廠”促進(jìn)多態(tài)
控制被送回對象的內(nèi)在狀態(tài)固然重要, 但是如果促進(jìn)多態(tài)即返回相同的接口多種類的對象,可以使得工廠模式的功能更為強(qiáng)大。
讓我們再次看一下Monopoly的例子,然后執(zhí)行購買游戲中的道具的行為。在游戲中,你的任務(wù)就是買道具,包括一些基本動作。更進(jìn)一步說, 有三種不同的道具: Street,RailRoad和Utility。所有三個類型的道具有一些共同點(diǎn): 每個道具都被一個玩家擁有; 每個都有價格;而且每個都能為它的擁有者產(chǎn)生租金只要其他的玩家在它上面登陸。但道具之間還是存在差異的,舉例來說, 計算租金的多少就取決于道具的類型。
下列的代碼展示了一個Property的基本類:
// PHP5 abstract class Property { protected $name; protected $price; protected $game; function __construct($game, $name, $price) { $this->game = $game; $this->name = $name; $this->price = new Dollar($price); } abstract protected function calcRent(); public function purchase($player) { $player->pay($this->price); $this->owner = $player; } public function rent($player) { if ($this->owner && $this->owner != $player $player($this->calcRent()) ); } } }
這里, Property類和CalcRent() 方法都被聲明為基類。
注:術(shù)語 – 基類 一個基類就是不能被直接實(shí)例化的類。 一個基礎(chǔ)的類包含一個或更多的基礎(chǔ)方法,這些方法必須在子類被覆蓋。一旦所有的抽象方法被覆蓋了, 子類也就產(chǎn)生了。 基類為許多相似的類創(chuàng)造了好的原型。 CalcRent() 方法必須在子類被覆蓋,從而形成一個具體的類。因此, 每個子類包括:Street,RailRoad和Utility,和必須定義的calcRent() 方法。
為實(shí)現(xiàn)以上的情況,這三個類可以定義為:
class Street extends Property { protected $base_rent; public $color; public function setRent($rent) { $this->base_rent = new Dollar($rent); } protected function calcRent() { if ($this->game->hasMonopoly($this->owner, $this->color)) { return $this->base_rent->add($this->base_rent); } return $this->base_rent; } } class RailRoad extends Property { protected function calcRent() { switch($this->game->railRoadCount($this->owner)) { case 1: return new Dollar(25); case 2: return new Dollar(50); case 3: return new Dollar(100); case 4: return new Dollar(200); default: return new Dollar; } } } class Utility extends Property { protected function calcRent() { switch ($this->game->utilityCount($this->owner)) { case 1: return new Dollar(4*$this->game->lastRoll()); case 2: return new Dollar(10*$this->game->lastRoll()); default: return new Dollar; } } }
每個子類都繼承了Property類,而且包括它自己的protected ClacRent() 方法。隨著所有的基礎(chǔ)方法都被定義, 每個子類都被實(shí)例化了。
為了開始游戲, 所有的Monopoly道具必須被創(chuàng)建起來。因?yàn)檫@章是介紹工廠模式的,所有Property的類型存在很多共性,你應(yīng)該想到多態(tài)性,從而建立所有需要的對象。
我們還是以道具工廠類開始。 在我住的地方,政府的Assessor(定稅人)掌握了稅務(wù)和契約, 因此我命名它為的道具定稅工廠。下一步,這個工廠將制造全部的專有道具。在真正應(yīng)用時,所有的Monopoly道具的數(shù)值可能都取自于一個數(shù)據(jù)庫或者一個文本, 但是對于這一個例子來說, 可以僅僅用一個數(shù)組來代替:
class Assessor { protected $prop_info = array( // streets ‘Mediterranean Ave.’ => array(‘Street’, 60, ‘Purple’, 2) ,’Baltic Ave.’ => array(‘Street’, 60, ‘Purple’, 2) //more of the streets... ,’Boardwalk’ => array(‘Street’, 400, ‘Blue’, 50) // railroads ,’Short Line R.R.’ => array(‘RailRoad’, 200) //the rest of the railroads... // utilities ,’Electric Company’ => array(‘Utility’, 150) ,’Water Works’ => array(‘Utility’, 150) ); }
Property子類需要實(shí)例化Monopoly道具,F(xiàn)在,我們只是簡單的用一個函數(shù)定義實(shí)例化變量$game,那么再把它加入Assessor類好了。
class Assessor { protected $game; public function setGame($game) { $this->game = $game; } protected $prop_info = array(/* ... */); }
也許你會偏向于選擇使用數(shù)據(jù)庫記錄數(shù)據(jù),不會用數(shù)組, 因?yàn)橛幸淮蠖训膮?shù)不可避免地要被羅列。如果是這樣的話,可以考慮使用" 引入叁數(shù)對象 " 進(jìn)行重構(gòu)。
注:重構(gòu)-引入叁數(shù)對象 方法中如果有很多參數(shù),常常變得很復(fù)雜,而且容易導(dǎo)致錯誤。你可以引入一個封裝參數(shù)的對象來替代一大堆的參數(shù)。舉例來說,“start date” and “end date” 叁數(shù)可以用一個 DateRange 對象一起代替。
在Monopoly這個例子中,這個參數(shù)對象應(yīng)該是什么呢?PropertyInfo,怎樣?它的目的是使每個道具參數(shù)數(shù)組引入 PropertyInfo 類的構(gòu)造器中,然后返回一個新對象。目的就意味著設(shè)計, 依照 TDD, 那意味著一個測試情形。
出處:
責(zé)任編輯:bluehearts
上一頁 php設(shè)計模式介紹之工廠模式 [5] 下一頁 php設(shè)計模式介紹之工廠模式 [7]
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|