2013-05-13 60 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/