Pattern: 抽象工廠模式
Class Diagram: 運輸系統
前情提要:鐵路運輸系統,參考範例:運輸系統(工廠方法模式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\ModelFactory; use ReflectionClass;
class Program {
public function getModel($modelName) { $modelFactory = $this->createModelFactory($modelName); $model = $modelFactory->createModel(); return $model->getName(); }
private function createModelFactory($modelName) { $namespace = 'App\FactoryPattern\Transport\AbstractFactoryPattern\ModelFactories'; $className = $modelName . 'Factory';
$reflector = new ReflectionClass($namespace . '\\' . $className); return $reflector->newInstance(); } }
|
需求一:各交通工具準備就緒,要開始處理內裝問題。
由於不同的機型會有不同的內裝,讓我們從定義椅子介面開始。
1 2 3 4 5 6 7 8 9
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts;
interface Chair { public function getName(); }
|
- 接著改寫機型工廠介面,
除了製作機型外,要新增製作椅子的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair;
interface ModelFactory { public function createModel(): Model;
public function createChair(): Chair; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\Chair;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair;
class LongChair implements Chair { public function getName() { return '長型座椅'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\Chair;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair;
class ReservedSeatChair implements Chair { public function getName() { return '對號座椅'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\Chair;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair;
class PlaneChair implements Chair { public function getName() { return '飛機座椅'; } }
|
接著改寫各個機型工廠,選擇適合的座椅。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\ModelFactories;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\ModelFactory; use App\FactoryPattern\Transport\AbstractFactoryPattern\Model\LocalTrain; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair; use App\FactoryPattern\Transport\AbstractFactoryPattern\Chair\LongChair;
class LocalTrainFactory implements ModelFactory { public function createModel(): Model { return new LocalTrain(); }
public function createChair(): Chair { return new LongChair(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\ModelFactories;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\ModelFactory; use App\FactoryPattern\Transport\AbstractFactoryPattern\Model\SemiExpress; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair; use App\FactoryPattern\Transport\AbstractFactoryPattern\Chair\ReservedSeatChair;
class SemiExpressFactory implements ModelFactory { public function createModel(): Model { return new SemiExpress(); }
public function createChair(): Chair { return new ReservedSeatChair(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\ModelFactories;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\AbstractFactoryPattern\Model\LimitedExpress; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\ModelFactory; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair; use App\FactoryPattern\Transport\AbstractFactoryPattern\Chair\ReservedSeatChair;
class LimitedExpressFactory implements ModelFactory { public function createModel(): Model { return new LimitedExpress(); }
public function createChair(): Chair { return new ReservedSeatChair(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern\ModelFactories;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\ModelFactory; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\AbstractFactoryPattern\Model\Boeing747; use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\Chair; use App\FactoryPattern\Transport\AbstractFactoryPattern\Chair\PlaneChair;
class Boeing747Factory implements ModelFactory { public function createModel(): Model { return new Boeing747(); }
public function createChair(): Chair { return new PlaneChair(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?php
namespace App\FactoryPattern\Transport\AbstractFactoryPattern;
use App\FactoryPattern\Transport\AbstractFactoryPattern\Contracts\ModelFactory; use ReflectionClass;
class Program {
public function getModel($modelName) { $modelFactory = $this->createModelFactory($modelName); $model = $modelFactory->createModel(); return $model->getName(); }
public function getChair($modelName) { $modelFactory = $this->createModelFactory($modelName); $chair = $modelFactory->createChair(); return $chair->getName(); }
private function createModelFactory($modelName) { $namespace = 'App\FactoryPattern\Transport\AbstractFactoryPattern\ModelFactories'; $className = $modelName . 'Factory';
$reflector = new ReflectionClass($namespace . '\\' . $className); return $reflector->newInstance(); } }
|
透過工廠介面,我們組合了各種類型產品。
使得不同類型的產品之間,有了產品族的聯繫關係。
[單一職責原則]
我們將工廠類別 (Factory) 與產品類別 (Product) 視作兩種不同的職責。
[開放封閉原則]
當新增新的產品族時,我們僅需新增工廠類別。
當修改既有產品時,我們僅需修改其產品類別,不會影響到其他的產品類別。
[介面隔離原則]
工廠介面:用來創建機型及座椅。
產品介面:用來創建對應的產品。
[依賴反轉原則]
工廠介面依賴於抽象的機型介面與座椅介面。
工廠實作抽象的工廠介面。
機型實作抽象的機型介面。
座椅實作抽象的座椅介面。
ʕ •ᴥ•ʔ:雖然有點複雜,但這個模式好美。