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
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern;
class Program {
public function getModel($modelName) { switch ($modelName) { case 'LocalTrain': return '區間車'; break;
case 'LimitedExpress': return '自強號'; break; } } }
|
需求一:新增復興號 (SemiExpress)
正當我們想直接在switch中新增一個case時,
發現這種做法違反了開放封閉原則。
明明是新增機型,卻修改到了既有的程式碼(取得機型名稱)。
此外在修改機型名稱時,也會修改到既有程式碼。
讓我們用簡單工廠模式,將創建物件與物件本身的職責分離。
(註:客戶端的程式碼、創建機型、機型本身,共三種職責)
1 2 3 4 5 6 7 8
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern\Contracts;
interface Model { public function getName(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern\Model;
use App\FactoryPattern\Transport\SimpleFactoryPattern\Contracts\Model;
class LocalTrain implements Model { public function getName() { return '區間車'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern\Model;
use App\FactoryPattern\Transport\SimpleFactoryPattern\Contracts\Model;
class LimitedExpress implements Model { 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 26 27
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern;
use App\FactoryPattern\Transport\SimpleFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\SimpleFactoryPattern\Model\LocalTrain; use App\FactoryPattern\Transport\SimpleFactoryPattern\Model\LimitedExpress;
class RailWayModelFactory {
public function createModel($modelName): Model { switch ($modelName) { case 'LocalTrain': return new LocalTrain(); break;
case 'LimitedExpress': return new LimitedExpress(); break; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern;
use App\FactoryPattern\Transport\SimpleFactoryPattern\RailwayModelFactory;
class Program {
public function getModel($modelName) { $railwayModelFactory = new RailwayModelFactory(); $model = $railwayModelFactory->createModel($modelName); return $model->getName(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern\Model;
use App\FactoryPattern\Transport\SimpleFactoryPattern\Contracts\Model;
class SemiExpress implements Model { 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 26 27 28 29 30 31 32
| <?php
namespace App\FactoryPattern\Transport\SimpleFactoryPattern;
use App\FactoryPattern\Transport\SimpleFactoryPattern\Contracts\Model; use App\FactoryPattern\Transport\SimpleFactoryPattern\Model\LocalTrain; use App\FactoryPattern\Transport\SimpleFactoryPattern\Model\LimitedExpress; use App\FactoryPattern\Transport\SimpleFactoryPattern\Model\SemiExpress;
class RailWayModelFactory {
public function createModel($model): Model { switch ($model) { case 'LocalTrain': return new LocalTrain(); break;
case 'LimitedExpress': return new LimitedExpress(); break;
case 'SemiExpress': return new SemiExpress(); break; } } }
|
[單一職責原則]
- 我們將 創建類別 (Creator) 與 產品類別 (Product) 視作兩種不同的職責。
- 將取得機型資訊的運輸系統視作第三種職責。
[開放封閉原則]
- 當新增新的產品時,我們僅需新增產品類別及修改創建類別。
- 當修改既有產品時,我們僅需修改其產品類別及創建類別,
不會影響到其他的產品類別。
- 無論是新增/修改產品,我們都不用再去修改到運輸系統類別。
[依賴反轉原則]
- 運輸類別依賴抽象的機型介面。
- 產品類別實作抽象的機型介面。
透過簡單工廠模式,運輸系統類別減少了改變的機會,
但創建類別依然常常需要變更。
ʕ •ᴥ•ʔ:不久之後,我們還會見到這個範例,敬請期待。