《PHP設計模式介紹》第三章 工廠模式(6)_PHP教程

      編輯Tag賺U幣
      教程Tag:暫無Tag,歡迎添加,賺取U幣!

      推薦:《PHP設計模式介紹》第二章 值對象模式
      在所有的最簡單的程序中,大多數對象都有一個標識,一個重要的商業應用對象,例如一個Customer或者一個SKU,有一個或者更多的屬性---id,name,email地址,這樣可以把它從同一個類的其他實例區分開

      “工廠”促進多態

      控制被送回對象的內在狀態固然重要, 但是如果促進多態即返回相同的接口多種類的對象,可以使得工廠模式的功能更為強大。

      讓我們再次看一下Monopoly的例子,然后執行購買游戲中的道具的行為。在游戲中,你的任務就是買道具,包括一些基本動作。更進一步說, 有三種不同的道具: Street,RailRoad和Utility。所有三個類型的道具有一些共同點: 每個道具都被一個玩家擁有; 每個都有價格;而且每個都能為它的擁有者產生租金只要其他的玩家在它上面登陸。但道具之間還是存在差異的,舉例來說, 計算租金的多少就取決于道具的類型。

      下列的代碼展示了一個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() 方法都被聲明為基類。

      注:術語 – 基類
      一個基類就是不能被直接實例化的類。 一個基礎的類包含一個或更多的基礎方法,這些方法必須在子類被覆蓋。一旦所有的抽象方法被覆蓋了, 子類也就產生了。
      基類為許多相似的類創造了好的原型。
      CalcRent() 方法必須在子類被覆蓋,從而形成一個具體的類。因此, 每個子類包括:Street,RailRoad和Utility,和必須定義的calcRent() 方法。

      為實現以上的情況,這三個類可以定義為:

      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() 方法。隨著所有的基礎方法都被定義, 每個子類都被實例化了。

      為了開始游戲, 所有的Monopoly道具必須被創建起來。因為這章是介紹工廠模式的,所有Property的類型存在很多共性,你應該想到多態性,從而建立所有需要的對象。

      我們還是以道具工廠類開始。 在我住的地方,政府的Assessor(定稅人)掌握了稅務和契約, 因此我命名它為的道具定稅工廠。下一步,這個工廠將制造全部的專有道具。在真正應用時,所有的Monopoly道具的數值可能都取自于一個數據庫或者一個文本, 但是對于這一個例子來說, 可以僅僅用一個數組來代替:

      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子類需要實例化Monopoly道具。現在,我們只是簡單的用一個函數定義實例化變量$game,那么再把它加入Assessor類好了。

      class Assessor {
      protected $game;
      public function setGame($game) { $this->game = $game; }
      protected $prop_info = array(/* ... */);
      }

      也許你會偏向于選擇使用數據庫記錄數據,不會用數組, 因為有一大堆的參數不可避免地要被羅列。如果是這樣的話,可以考慮使用" 引入叁數對象 " 進行重構。

      注:重構-引入叁數對象
      方法中如果有很多參數,常常變得很復雜,而且容易導致錯誤。你可以引入一個封裝參數的對象來替代一大堆的參數。舉例來說,“start date” and “end date” 叁數可以用一個 DateRange 對象一起代替。

      在Monopoly這個例子中,這個參數對象應該是什么呢?PropertyInfo,怎樣?它的目的是使每個道具參數數組引入 PropertyInfo 類的構造器中,然后返回一個新對象。目的就意味著設計, 依照 TDD, 那意味著一個測試情形。

      分享:《PHP設計模式介紹》第一章 編程慣用法
      學習一門新的語言意味著要采用新的慣用法。這章將介紹或者可能重新強調一些慣用法。你會發現這些慣用法在你要在代碼中實現設計模式時候是非常有用的。 在這里總結的許多編程慣用法都是很值得

      來源:模板無憂//所屬分類:PHP教程/更新時間:2008-08-22
      相關PHP教程