# 2.3 Abstract Factory

Abstract factory的精神: 提供一個創造一系列相關或相互依賴物件的介面, 而無需指定它們具體的類別

![](/files/-M523uqgH7QnZZ81Qas_)

* AbstractFactory: 定義創造一系列產品物件的操作接口
* ConcreteFactory: 實作抽象工廠定義的方法, 具體實作一系列產品物件的創造
* AbstractProduct: 定義一類產品物件的介面
* ConcreteProduct: 具體的產品實作物件, 通常在ConcreteFactory裡面, 會選擇具體的產品實作物件, 以創造符合抽象工廠定義的方法回傳的產品類型之物件.
* Client: 主要使用抽象工廠來獲得一系列所需要的產品物件, 然後面對這些產品物件的介面編程, 以實作需要的功能.
* 原始碼[點我](https://github.com/yotsuba1022/design-pattern/tree/master/src/main/java/idv/design/pattern/abstractFactory/example1)

認識抽象工廠

* 功能: **抽象工廠是為一系列相關物件或相互依賴的物件建立一個介面**. 從某種意義上來看, 這其實是一個產品系列, 或著是產品族
* 實作成介面: **AbstractFactory在Java中通常實作成介面, 不要被名稱誤導而以為是抽象類別了**
* 使用factory method: AbstractFactory定義了創造產品所需要的介面, 具體的實作是在實作類別裡面, 通常在實作類別中就需要選擇多種更具體的實作, 所以AbstractFactory定義的創造產品的方法可以看成是工廠方法, 而這些工廠方法的具體實作就延遲到了具體的工廠裡面. 也就是說使用工廠方法來實作抽象工廠
* 切換產品族: 抽象工廠定義了一個產品族, 因此切換產品族的時候提供不同的抽象工廠即可

定義可擴展的工廠

* 在[此範例](https://github.com/yotsuba1022/design-pattern/tree/master/src/main/java/idv/design/pattern/abstractFactory/example3)中, 抽象工廠為每一種它能創造的產品物件都定義了相應的方法, 如創造CPU和主機板的方法等
* 這種實作有個麻煩的地方就是若在產品族中要新增加一種產品, 如記憶體, 那就需要在抽象工廠裡添加創造記憶體的方法.當抽象工廠一發生變化, 所有的具體工廠實作都要發生變化, 這很不靈活
* 現在有一種相對靈活, 但是不太安全的改進方式來解決此問題: 抽象工廠裡不需要定義那麼多方法, 定義一個方法即可,給這個方法設置一個參數, 通過這個參數來判斷具體要創造什麼產品物件; 由於只有一個方法,在回傳型別上就不能是具體的某個產品類型了, 只能是所有的產品物件都繼承或著實作的一個類型, 如讓所有的產品都實作某個介面, 或著乾脆使用Object類型

抽象工廠的優缺點

* 分離介面與實作
* 使切換產品族變得更容易
* 不太容易擴展新的產品
* 容易造成類別層次的複雜化

抽象工廠的本質: 選擇產品族的實作

何時選用

* 如果希望一個系統獨立於其產品的創造、組合與表示時, 即希望一個系統只知道產品的介面, 而不關心實作的情況
* 若一個系統要由多個產品系列中的一個來配置的時候, 換句話說, 就是可以動態切換產品族的時候
* 要強調一系列相關產品的介面, 以便聯合使用它們之時


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://clu.gitbook.io/design-pattern/23-abstract-factory.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
