2013-05-13 26 views
4

我想知道如果this tutorial在PHP中正確實現工廠設計模式。以下是實際的源代碼。PHP工廠設計模式方法說明

<?php 
class Automobile 
{ 
    private $vehicle_make; 
    private $vehicle_model; 

    public function __construct($make, $model) 
    { 
     $this->vehicle_make = $make; 
     $this->vehicle_model = $model; 
    } 

    public function get_make_and_model() 
    { 
     return $this->vehicle_make . ' ' . $this->vehicle_model; 
    } 
} 

class AutomobileFactory 
{ 
    public static function create($make, $model) 
    { 
     return new Automobile($make, $model); 
    } 
} 

// have the factory create the Automobile object 
$veyron = AutomobileFactory::create('Bugatti', 'Veyron'); 

print_r($veyron->get_make_and_model()); // outputs "Bugatti Veyron" 

根據一本書「設計模式」,由四人幫,工廠模式的適用性

  • 一個類不能預見的類的對象,必須創建
  • 一類希望其子類指定它創建的對象
  • 類將責任委託給幾個輔助子類之一,並且您想本地化哪些輔助子類是委託的知識

第一點,這個例子實際上知道要創建什麼類的對象,即Automobile,不是嗎?

第二點,沒有子類。 Automobile類不會從AutomobileFactory繼承。我認爲AutomobileFactory應該至少有一個由Automobile實現的功能,它處理對象創建。

有人可以澄清這一點嗎?我剛開始學習設計模式,每次遇到與別人不同的教程時,都會讓我困惑不已。

回答

1

我不太喜歡這個教程。正如您在WikiPedia頁面中看到的關於工廠(https://en.wikipedia.org/wiki/Factory_pattern)的那樣 - 通常以不同的方式進行。 WikiPedia的例子確實符合你提到的規則。看看那裏的PHP部分。

+0

這幾乎是相同的例子:) – 2013-05-13 14:33:49

+0

我不同意 - 除了他們都生產汽車的事實。我們來看看你的清單,然後看Wiki的例子。 1.一個類無法預測它必須創建的對象類 - 對於CarFactory來說是真的 - 不知道它會產生什麼。 2.一個類想要它的子類指定它創建的對象 - 真,檢查出SedanFactory – 2013-05-13 14:37:34

+0

但它知道它是'Sedan'。還有另一個例子(封裝),這確實是不同的 – 2013-05-13 14:40:36

1

我和你在一起kidonchu,我不是真的把這個例子看作是傳統的工廠方法模式。

我會寫你的例子是這樣的(僞代碼)

<?php 

abstract class CarAbstract 
{ 
    protected $_vehicleMake; 
    protected $_vehicleModel; 

    public function __construct($model) 
    { 
     $this->_vehicleModel = $model; 
    } 

    public function getMakeAndModel() 
    { 
     return $this->_vehicleMake . ' ' . $this->_vehicleModel; 
    } 
} 

class Bugatti extends CarAbstract 
{ 
    public function __construct($model) 
    { 
     parent::__construct($model); 

     $this->_vehicleMake = get_class($this); 
    } 
} 

class AutomobileFactory 
{ 
    public static function getInstance($make, $model) 
    { 
     if (is_file('Model/Car/' . $make . '.php')){ 
      require_once 'Model/Car/' . $make . '.php'; 
      $car = new $make($model); 
     }else{ 
      throw new Exception('Car not found'); 
     } 
    } 
} 

$veyron = AutomobileFactory::getInstance('Bugatti', 'Veyron'); 

print_r($veyron->getMakeAndModel()); // outputs "Bugatti Veyron" 
+0

感謝您修改代碼。嚴格地說,這種修改仍然不是「工廠方法」,是嗎?據我所知,至少有三種工廠方法 - 抽象工廠方法,工廠方法和簡單工廠方法。而修改過的代碼看起來更像Simple Factory方法,因爲CarAbstract類根本不處理任何對象的創建。如果我錯了,請糾正我。 – kidonchu 2013-05-16 20:04:50

3

我非常同意什麼是維基百科說

  • 對象的創建排除其再利用而無需顯著代碼重複。
  • 創建對象需要訪問不應包含在構成類中的信息或資源。
  • 生成對象的生命週期管理必須集中以確保應用程序內的一致行爲。

我創建工廠的主要原因是我強調的。

例如,讓我們想象一個在全國各地擁有許多工廠的真實世界工廠。這個工廠生產。門需要旋鈕。由於物流方面的原因,工廠的每個工廠都有自己的旋鈕供應商,這是另一個完全不同的工廠。

該工廠的生產經理軟件會根據一些標準來選擇哪個工廠生產很多門,但是它不需要知道旋鈕將從哪裏來。選定的工廠將要求自己的供應商爲生產的門提供旋鈕。

然而,對於客戶來說,哪家工廠製造門並不重要,他只關心他的門。

讓我們把這個代碼:

class Knob { 
    // something... 
} 

interface KnobSupplier { 
    public function makeKnob(); 
} 

class SaoPauloKnobSupplier { 
    public function makeKnob() { 
     return new Knob('Knob made in São Paulo'); 
    } 
} 

class NewYorkKnobSupplier { 
    public function makeKnob() { 
     return new Knob('Knob made in New York'); 
    } 
} 

class Door { 
    public function __construct(Knob $knob) { 
     // something... 
    } 
} 

interface DoorFactory { 
    public function makeDoor(); 
} 

class SaoPauloDoorFactory { 
    private $knobSupplier; 

    public function __construct() { 
     $this->knobSupplier = new SaoPauloKnobSupplier(); 
    } 

    public function makeDoor() { 
     return new Door($this->knobSupplier->makeKnob(), "Door made in São Paulo"); 
    } 
} 

class NewYorkDoorFactory { 
    private $knobSupplier; 

    public function __construct() { 
     $this->knobSupplier = new NewYorkKnobSupplier(); 
    } 

    public function makeDoor() { 
     return new Door($this->knobSupplier->makeKnob(), "Door made in New York"); 
    } 
} 

class ProductionManager { 
    private $plants = array(); 
    // methods for adding plants, etc... 
    public function getDoor() { 
     // Somehow decides which plant will create the door. 
     return $plant->makeDoor(); 
    } 
} 

class Client { 
    public function getMyDoor(ProductionManager $manager) { 
     return $manager->getDoor(); 
    } 
} 

使用此代碼,如:

$manager = new ProductManager(); 
$manager->addPlant(new SaoPauloDoorFactory()); 
$manager->addPlant(new NewYorkDoorFactory()); 

$client = new Client(); 

var_dump($client->getMyDoor($manager)); 

ProductManager不知道旋鈕什麼,Client不知道廠裏有一個以上的廠什麼。

+1

現在想象一下,工廠不僅可以做門,還可以做窗戶,需要**玻璃**。每家工廠都有自己的玻璃供應商,但同樣,客戶或經理都不需要知道這一點。 – 2013-05-16 13:03:38

+0

非常感謝您的詳細解答。我理解你的代碼中關注的明確分離,我與你同在。但是,我有點困惑。哪一類嚴格使用傳統的工廠方法模式? 'DoorFactory'類似乎在使用工廠模式,因爲它將'Door'對象的創建推遲到它的子類('SaoPauloDoorFactory'和'NYDoorFactory')。但是在設計模式方面,我看不到'DoorFactory'和'KnobSupplier'之間的任何關係。 – kidonchu 2013-05-16 20:19:46

+0

他們之間沒有任何關係。想象一下,還有另一家工廠也在門旁製造旋鈕。它不需要供應商。 在這個例子中,所有工廠都返回相同類型的門。要看到嚴格的傳統工廠方法,您應該只看到一對工廠/產品。在這種情況下,所有工廠都會創建相同類型的對象,但它不需要像這樣。 – 2013-05-16 20:24:57

1

實際上有一個工廠方法設計模式,跟隨着四個目錄的原始團伙。抽象工廠完全不同,它基於不同的結構假設。簡單工廠不是一種設計模式,而是Freemans所謂的「編程習慣用法」。工廠方法包括抽象的創作者和產品,客戶通常通過創作者提出請求。具體工廠在ConcreteCreator中找到,具體產品是Product類的子類,並由具體的創建者實例化。有關完整且簡單的PHP示例,請參閱http://www.php5dp.com/a-simple-php-design-pattern-the-factory-method/