---
# System prepended metadata

title: Abstract Factory(5)
tags: [Design Pattern, Creational Pattern]

---

---
tags: Design Pattern,Creational Pattern
title: Abstract Factory(5)
---
{%hackmd Sy5Quc5JY %}
## <font color="#F59F00">**Abstract Factory (5)**</font>
*    <font color="#92d1ff">**Factory Method 的限制**</font>
        ==**工廠方法 FactoryMethod 只能創造一個物件**==，像是 `Pizza`
        但如果我們想要更加細分創造的東西，比如說 `Pizza` 所需原料 : `Dough`、`Sauce`、`Cheese` ... ，如果我們工廠方法的話，每一個原料都要創一個工廠。
*    **Example**
        ```java
            public abstract class PizzaStore
            {
                public abstract Pizza createPizza(String type);
                public Pizza orderPizza(String type)
                {
                    Pizza pizza = createPizza(type);
                    pizza.prepare();
                    pizza.cook;
                    return pizza;
                }
            }
            public class NewYorkPizzaStore extends PizzaStore
            {
                public createPizza(String type)
                {
                    DoughFactory doughFactory = new NewYorkDoughFactory();
                    SauceFactory sauceFactory = new NewYorkSauceFactory();
                    CheeseFactory cheeseFactory = new NewYorkCheeseFactory();
                    if(type.equals("cheese"))
                    {
                        return new NewYorkCheesePizza(
                        doughFactory,
                        sauceFactory,
                        cheeseFactory);
                    }
                    else if(type.equals("veggie"))
                    {
                        return new NewYorkVeggiePizza(
                        doughFactory,
                        sauceFactory,
                        cheeseFactory);            
                    }
                    else if(type.equals("clam"))
                    {
                        return new NewYorkClamPizza(
                        doughFactory,
                        sauceFactory,
                        cheeseFactory);     
                    }
                    else if(type.equals("pepperoni"))
                    {
                        return new NewYorkPepperoniPizza(
                        doughFactory,
                        sauceFactory,
                        cheeseFactory);     
                    }
                    else 
                    {
                        return null;
                    }
                }
            }
        ```
        這個例子就是
        NewYork : `DoughFactory` 、 `SauceFactory`、 `CheeseFactory`
        Chicago : `DoughFactory` 、 `SauceFactory`、 `CheeseFactory`
        **因為每個工廠方法只能生產一個產品**
        這樣太難 maintain 了，**所以我們把相關的產品 : `NewYorkDoughFactory` 、 `NewYorkSauceFactory` 、 `NewYorkCheeseFactory` ，組成一個產品族，交給一個工廠來生產，也就是抽象工廠。**
        <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory1.png" width="750" height="650"></img></span><br>
        抽象的 `PizzaIngredientFactory` 定義了每個原料工廠需要建立的物件的介面，每個繼承了 `PizzaIngredientFactory` 的具體工廠，都乖乖執行所有需要建立的物件。

        ==**其實也就是工廠的責任從產生一個產品變成產生一個產品族(所有所需的產品)**==
*    **Example**
        1. 產生一個房子的所有家具 : 沙發、電視、桌子、電風扇...
        2. 產生一個武士的所有配件 : 佩刀、盔甲、鞋子、手套...
*    <font color="#92d1ff">**產品等級結構 product hierarchical structure  產品族 product family**</font>
        *    <font color="#98c37a">**product hierarchical structure**</font>
                比如說抽象類 `Dough` 子類別有 `NewYorkDough`  、 `ChicagoDough` ，這三個形成了一個 product hierarchical structure
        *    <font color="#98c37a">**product family**</font>
                同一個工廠生產的所有產品，其中的每個產品都是座落在不同的產品等級結構中的其中一個產品。
        <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory2.png" width="750" height="650"></img></span><br>
### <font color="#F59F00">**Abstract Factory Pattern**</font>
套用 abstract factory
```java
    public class CheesePizza extend Pizza
    {
        PizzaIngredientFactory pizzaIngredientFactory;
        public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory)
        {
            this.pizzaIngredientFactory = pizzaIngredientFactory;
        }
        void prepare()
        {
            dough = pizzaIngredientFactory.createDough();
            sauce = pizzaIngredientFactory.createSauce();
            cheese = pizzaIngredientFactory.createCheese();
        }
    }
```
至於 `PizzaStore` 跟它的子類別，概念和 factory method 一樣，由子類別實作
```java
    abstract class PizzaStore
    {
        public abstract Pizza createPizza(String type);
        public Pizza orderPizza(String type)
        {
            Pizza pizza = createPizza(type);
            pizza.prepare();
            pizza.cook;
            return pizza;
        }
    }    
    public class NewYorkPizzaStore extends PizzaStore 
    {
        Pizza createPizza(String type)
        {
            Pizza pizza = null;
            PizzaIngredientFactory pizzaIngredientFactory = new NewYorkPizzaIngredientFactory();
            if(type.equals("cheese")) 
            { 
                pizza = new CheesePizza(ingredientFactory);
            } 
            else if(type.equals("veggie")) 
            {
                pizza = new VeggiePizza(ingredientFactory);
            }
            else if(type.equals("clam")) 
            {
                pizza = new ClamPizza(ingredientFactory);
            } 
            else if(type.equals("pepperoni")) 
            {
                pizza = new PepperoniPizza(ingredientFactory);		
            } 
            return pizza;
        }
    }
```
order `pizza` 的方法和工廠方法一樣，對於 client 來說，用法一樣並不知道產品已經變成產品族。
```java
    PizzaStore pizzaStore = new NewYorkPizzaStore();
    Pizza pizza = pizzaStore.orderPizza("cheese");
```
*    <font color="#92d1ff">**Abstract Factory 的結構**</font>
        **用一個抽象工廠來定義一個產品族的介面，產品族裡面的每個產品的具體類別由繼承的具體工廠來決定**
        <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory3.png" width="750" height="330"></img></span><br>
        *    <font color="#98c37a">**AbstractFactory : PizzaIngredientFactory**</font>
                宣告出各個創造同一產品族產品介面。
        *    <font color="#98c37a">**ConcreteFactory : NewYorkPizzaIngredientFactory**</font>
                實作 AbstractFactory。
        *    <font color="#98c37a">**AbstractProduct : Dough**</font>
                宣告產品等級結構的介面。
        *    <font color="#98c37a">**ConcreteProduct : ThickCrustDough**</font>
                實作 AbstractProduct。
*    <font color="#92d1ff">**Pros & Cons**</font>
        *    <font color="#98c37a">**Pros**</font>
                跟 factory method 一樣
                1. 區隔物件的使用和生成
                2. 隱藏了物件的細節
                3. 性質類似的產品集中管理，比如 NewYork 的原料，client 只要知道有哪些方法要呼叫就好。
        *    <font color="#98c37a">**Cons**</font> 
                缺點非常明顯，當我們想加一個產品族很容易，但是加一個產品時卻非常困難，要所有的子類別工廠跟著變動，這被稱為開閉原則的傾斜性，並不符合 OCP。
*    <font color="#92d1ff">**Application**</font>
        1. 一個系統和產品的生成/組合，保持獨立。
        2.  許多類型的產品可以組成產品族，方便集中管理，而且多一個的產品族。
        3.  只公開產品 interface 不想公開實作細節。
### <font color="#F59F00">**Abstract Factory in Detail**</font>
abstractFactory 定義了需要創造的產品族，由 concreteFactory 去實作，
所以通常 abstractFactory 每一個創造 product 的抽象方法這兩個都是叫 **工廠方法**。
<br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory7.png" width="700" height="380"></img></span><br>
由此圖可以看出來，如果我們用 Abstract Factory Pattern 來實作 `PizzaStore` ，我們只需要實作 2 個工廠 `ChicagoPizzaIngredientFactory` 、 `NewYorkPizzaIngredientFactory`，但如果我們用 Factory Method Pattern，我們需要 8 個工廠。

所以這個方法也就是，你發現工廠方法們循著一個產品族的 pattern ， 試著把這個產品族分離出來寫成 Abstract Factory interface ， 這也就是 ==**rule #2 : Program to an interface, not an implementation**== 。
*    <font color="#92d1ff">**退化成 Factory Method Pattern**</font>
        <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory5.png" width="700" height="380"></img></span><br>
        把上圖的 `Dough` 改成 `Pizza` 也就是 Factory Method Pattern，一個工廠只生產一個物件，
*    <font color="#92d1ff">**退化成 SimpleFactory Pattern**</font>
        <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory9.png" width="700" height="380"></img></span><br>
        因為每個配料只要一個實作，所以沒有使用 interface 的必要，把上圖的各種配料改成各種 `Pizza` 就是 SimpleFactory Pattern。
        