> For the complete documentation index, see [llms.txt](https://clu.gitbook.io/design-pattern/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://clu.gitbook.io/design-pattern/22-factory.md).

# 2.2 Factory

* 定義一個用來創造物件的介面(並非完全指interface, 也可能是一個方法), 讓子類決定實例化哪一個類別, Factory method使一個類別的實例化延遲到其子類別.

![](https://1264106928-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M523o3BFdjQwXhOl9_Z%2F-M523s31WfODDGzKviNo%2F-M523uwTU4vCihhRob0g%2F2.2-1.png?generation=1587042038636038\&alt=media)

* 結構與說明:
  * Product: 定義factoryMethod所創造之物件的介面, 也就是實際需要使用的物件的介面
  * ConcreteProduct: 具體的Product介面的實作物件
  * Creator: 宣告factoryMethod
  * ConcreteCreator: 具體的Creator, overwrite/implement Creator定義的factoryMethod, 回傳具體的Product實例

Product:

```java
package idv.design.pattern.factory.example1;

/**
 * @author Carl Lu
 */
public interface Product {
}
```

ConcreteProduct:

```java
package idv.design.pattern.factory.example1;

/**
 * @author Carl Lu
 */
public class ConcreteProduct implements Product {
}
```

Creator:

```java
package idv.design.pattern.factory.example1;

/**
 * @author Carl Lu
 */
public abstract class Creator {

    protected abstract Product factoryMethod();

    public void operation() {
        Product product = factoryMethod();
    }

}
```

ConcreteCreator:

```java
package idv.design.pattern.factory.example1;

/**
 * @author Carl Lu
 */
public class ConcreteCreator extends Creator {

    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }

}
```

* 匯出資料的應用框架
  * 考慮這樣一個實際應用: 實作一個匯出資料的應用框架, 來讓使用者選擇資料的導出方式, 並真正執行資料匯出
  * 通常這種系統在匯出資料上會有一些約定的方式, 譬如說匯出成純文字格式, DB備份形式, Excel, xml, pdf..., etc.
  * 原始碼[點我](https://github.com/yotsuba1022/design-pattern/tree/master/src/main/java/idv/design/pattern/factory/example2)
* 認識Factory Pattern
  * 功能: **讓父類別在不知道具體實作的情況下, 完成自身的功能呼叫, 而具體的實作延遲到子類別去實作**
  * 實作成抽象類別: 在此pattern的實作中, 通常會把父類別宣告成抽象類別, 裡面包含創造所需物件的抽象方法, 這些抽象方法就是factory method
  * 實作成具體類別: 其實也可以把父類別實作成一般類別, 這種情況下, 通常是在父類別中提供獲取所需物件的預設實作方法, 這樣就算沒有具體的子類別也可以正常運作
  * 參數與回傳值: 在此pattern的實作中, 可能會需要依靠參數來決定到底選用哪一種具體的實作. 一般factory method回傳的是被創造物件的介面, 當然也可以是抽象類或著一個具體的類別實例
  * 給誰用
    * 在此pattern中, 應該是Creator中的其他方法在使用factory method創造的物件
    * Client應該是使用Creator物件, 或著是使用由Creator創造出來的物件, 這時候factory method創造的物件, 是由Creator中的某些方法使用
    * 在某些情況下, Client可能會使用由Creator創造出來的物件, 這時候factory method創造的物件, 是構成Client需要的物件之一部份
* 小結: **Client要就使用Creator物件, 不然就使用Creator創造的物件, 一般Client不直接使用factory method. 當然也可以直接把factory method暴露給Client, 但不建議**
* 平行的類層次結構(Parallel Class Hierarchies)
  * 何謂平行類層次結構: 簡而言之, 若有兩個類層次結構, 其中一個類層次中的每個類別在另一個類層次中都有一個對應的類別的結構, 就被稱為平行的類層次結構
  * 用來做什麼: 主要用來把一個類層次中的某些行為分離出來, 使類層次中的類別把原本屬於自己的職責, 委託給分離出去的類別實作, 從而使得類層次本身變得簡單且更容易擴展與重用
  * 跟Factory Pattern有什麼關係: 可以使用Factory Pattern來連接平行的類層次
* 參數化factory method
  * 所謂參數化指的就是通過給factory method傳遞參數, 讓其可根據參數的不同來創造不同的產品物件
  * 此種情形下要擴展新的實作也算很容易的
* Factory Pattern的優缺點
  * 可以在不知具體實作的情況下編程
  * 更容易擴展物件的新版本
  * 連接平行的類層次
  * 具體產品物件和factory method的耦合性
* Factory Pattern的本質: 延遲到子類別來選擇實作
* 對設計原則的體現: 此模式很好地體現了”**依賴反轉原則(dependency inversion principle)**”, 其精神為”**依賴抽象, 不依賴具體類**”, 簡單點說就是: 不能讓高層組件依賴於低層組件, 且不管高層還是低層, 都應該依賴於抽象.
* 何時選用
  * 若一個類別需要創造某個介面的物件, 但又不知道具體的實現, 就可以採用此模式, 把創造物件的工作延遲到子類去實作
  * 若一個類別本身就希望由其子類來創造所需的物件時, 就可以使用此模式
