#### PHP 設計模式系列 —— 工廠方法模式(Factory Method)
Posted on 2015年12月11日 by 學院君
* * * * *
1、模式定義
定義一個創建對象的接口,但是讓子類去實例化具體類。工廠方法模式讓類的實例化延遲到子類中。
2、問題引出
框架需要為多個應用提供標準化的架構模型,同時也要允許獨立應用定義自己的域對象并對其進行實例化。
3、解決辦法
工廠方法以模板方法的方式創建對象來解決上述問題。父類定義所有標準通用行為,然后將創建細節放到子類中實現并輸出給客戶端。
人們通常使用工廠模式作為創建對象的標準方式,但是在這些情況下不必使用工廠方法:實例化的類永遠不會改變;或者實例化發生在子類可以輕易覆蓋的操作中(比如初始化)。
4、UML類圖

5、示例代碼
FactoryMethod.php
~~~
<?php
namespace DesignPatterns\Creational\FactoryMethod;
/**
* 工廠方法抽象類
*/
abstract class FactoryMethod
{
const CHEAP = 1;
const FAST = 2;
/**
* 子類必須實現該方法
*
* @param string $type a generic type
*
* @return VehicleInterface a new vehicle
*/
abstract protected function createVehicle($type);
/**
* 創建新的車輛
*
* @param int $type
*
* @return VehicleInterface a new vehicle
*/
public function create($type)
{
$obj = $this->createVehicle($type);
$obj->setColor("#f00");
return $obj;
}
}
~~~
VehicleInterface.php
~~~
<?php
namespace DesignPatterns\Creational\FactoryMethod;
/**
* VehicleInterface是車輛接口
*/
interface VehicleInterface
{
/**
* 設置車的顏色
*
* @param string $rgb
*/
public function setColor($rgb);
}
~~~
Porsche.php
~~~
<?php
namespace DesignPatterns\Creational\FactoryMethod;
/**
* Porsche(保時捷)
*/
class Porsche implements VehicleInterface
{
/**
* @var string
*/
protected $color;
/**
* @param string $rgb
*/
public function setColor($rgb)
{
$this->color = $rgb;
}
/**
* 盡管只有奔馳汽車掛有AMG品牌,這里我們提供一個空方法僅作代碼示例
*/
public function addTuningAMG()
{
}
}
~~~
Bicycle.php
~~~
<?php
namespace DesignPatterns\Creational\FactoryMethod;
/**
* Bicycle(自行車)
*/
class Bicycle implements VehicleInterface
{
/**
* @var string
*/
protected $color;
/**
* 設置自行車的顏色
*
* @param string $rgb
*/
public function setColor($rgb)
{
$this->color = $rgb;
}
}
~~~
Ferrari.php
~~~
<?php
namespace DesignPatterns\Creational\FactoryMethod;
/**
* Ferrari(法拉利)
*/
class Ferrari implements VehicleInterface
{
/**
* @var string
*/
protected $color;
/**
* @param string $rgb
*/
public function setColor($rgb)
{
$this->color = $rgb;
}
}
~~~
6、測試代碼
Tests/FactoryMethodTest.php
~~~
<?php
namespace DesignPatterns\Creational\FactoryMethod\Tests;
use DesignPatterns\Creational\FactoryMethod\FactoryMethod;
use DesignPatterns\Creational\FactoryMethod\GermanFactory;
use DesignPatterns\Creational\FactoryMethod\ItalianFactory;
/**
* FactoryMethodTest用于測試工廠方法模式
*/
class FactoryMethodTest extends \PHPUnit_Framework_TestCase
{
protected $type = array(
FactoryMethod::CHEAP,
FactoryMethod::FAST
);
public function getShop()
{
return array(
array(new GermanFactory()),
array(new ItalianFactory())
);
}
/**
* @dataProvider getShop
*/
public function testCreation(FactoryMethod $shop)
{
// 該方法扮演客戶端角色,我們不關心什么工廠,我們只知道可以可以用它來造車
foreach ($this->type as $oneType) {
$vehicle = $shop->create($oneType);
$this->assertInstanceOf('DesignPatterns\Creational\FactoryMethod\VehicleInterface', $vehicle);
}
}
/**
* @dataProvider getShop
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage spaceship is not a valid vehicle
*/
public function testUnknownType(FactoryMethod $shop)
{
$shop->create('spaceship');
}
}
~~~
7、總結
工廠方法模式和抽象工廠模式有點類似,但也有不同。
工廠方法針對每一種產品提供一個工廠類,通過不同的工廠實例來創建不同的產品實例,在同一等級結構中,支持增加任意產品。
抽象工廠是應對產品族概念的,比如說,每個汽車公司可能要同時生產轎車,貨車,客車,那么每一個工廠都要有創建轎車,貨車和客車的方法。應對產品族概念而生,增加新的產品線很容易,但是無法增加新的產品。