設計模式 - Factory Method Pattern 工廠方法模式 Intro 假設我們要製作一個計算機,如果使用間單工廠的話,程式碼應該長得如下
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 class  OperationFactory     public  function  createOperator ($type Operation       {        switch  ($type ) {             case '+' :                 return  new  Add ();                 break ;             case '-' :                 return  new  Minus ();                 break ;         }     } } class  Add  extends  Operation     public  function  operate (float  $num1 , float  $num2 float       {        return  $num1  + $num2 ;     } } class  Minus  extends  Operation     public  function  operate (float  $num1 , float  $num2 float       {        return  $num1  - $num2 ;     } } abstract  class  Operation     abstract  public  function  operate (float  $num1 , float  $num2 float  } 
1 2 3 4 5 $OperatorFactory  = new  OperationFactory ();$Operator  = $OperatorFactory ->createOperator ('+' );$Operator ->operate (1 , 2 );
假設我們因應需求要新增一個運算符號‘乘法’,那我除了新增一個Product類別以外,我勢必還需要對OperationFactory作出修改
實作 將上面的例子改為工廠方法模式
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 abstract  class  Operation     abstract  public  function  operate (float  $num1 , float  $num2 float  } class  Add  extends  Operation     public  function  operate (float  $num1 , float  $num2 float       {        return  $num1  + $num2 ;     } } class  Minus  extends  Operation     public  function  operate (float  $num1 , float  $num2 float       {        return  $num1  - $num2 ;     } } class  Product  extends  Operation     public  function  operate (float  $num1 , float  $num2 float       {        return  $num1  * $num2 ;     } } interface  IOperationFactory     public  function  createOperator (Operation  } class  AddFactory  implements  IOperationFactory     public  function  createOperator (Operation       {        return  new  Add ();     } } class  MinusFactory  implements  IOperationFactory     public  function  createOperator (Operation       {        return  new  Minus ();     } } class  ProductFactory  implements  IOperationFactory     public  function  createOperator (Operation       {        return  new  Product ();     } } 
1 2 3 4 5 $AddFactory  = new  AddFactory ();$Operator  = $AddFactory ->createOperator ();$Operator ->operate (1 , 2 );
如此一來,我要新增新的運算類別的時候,我只需要對原本的設計做擴充,而不用修改
時機 
當你希望能用不同的生成邏輯或流程去生成物件時 
當類別希望讓子類別去指定欲生成的物件類型時 
 
目的 定義一個建立物件的介面,讓子類別決定該實體化哪一個類別。工廠方法使一個類別的實例化延遲到其子類別。
類別圖 
Plant UML 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 @startuml skinparam classAttributeIconSize 0 class Creator{ {method} +createProduct():Product } class ConcreteCreatorA{ {method} +createProduct():Product } class ConcreteCreatorB{ {method} +createProduct():Product } class Product class ConcreteProductA class ConcreteProductB Product <|-- ConcreteProductA Product <|-- ConcreteProductB Creator <|-- ConcreteCreatorA Creator <|-- ConcreteCreatorB Product <-- Creator : <<Create>> @enduml 
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 @startuml skinparam classAttributeIconSize 0 class OperationFactory{ {method}+createOperator(): Operator } class AddFactory{ {method}+createOperator(): Operator } class MinusFactory{ {method}+createOperator(): Operator } class InnerProductFactory{ {method}+createOperator(): Operator } class Operator{ {method} +operate(): float } class Add{ {method} +operate(): float } class Minus{ {method} +operate(): float } class InnerProduct{ {method} +operate(): float } Operator <|-- Add Operator <|-- Minus Operator <|-- InnerProduct OperationFactory <|-- AddFactory OperationFactory <|-- MinusFactory OperationFactory <|-- InnerProductFactory Operator <-- OperationFactory : <<Create>> @enduml 
優點 
可以避免創造者與產品間的緊密耦合(OperationFactory & Add/Minus) 
符合開放封閉原則,可以在不修改原本設計的狀況下去引入新的產品生成 
替生成的子類別預留掛鉤(hook),使生成過程更具有彈性 
 
缺點