---
# System prepended metadata

title: Factory Method (4)
tags: [Design Pattern, Creational Pattern]

---

---
tags: Design Pattern,Creational Pattern 
title: Factory Method (4)
---
{%hackmd Sy5Quc5JY %}
# <font color="#F59F00">**Factory Method (4)**</font>
我們以 Pizza 作為例子解釋
*    **Example**
```java
public class PizzaStore
{
    Pizza orderPizza(String type)
    {
        Pizza pizza;
        if(type.equals("cheese"))
        {
	        pizza = new CheesePizza();
    	}
        else if(type.equals("greek"))
        {
	        pizza = new GreekPizza();
    	}
        else if(type.equals("pepperoni"))
        {
	        pizza = new PepperoniPizza();
    	}
        pizza.prepare();
         pizza.cook()
;        retrun pizza;
    }

```
## <font color="#F59F00">**SimpleFactory Pattern**</font>
根據 ==**rule #1**== ，把 `orderPizza` 裡面的 if-else 拉出來到一個工廠裡面，這個工廠專門製作 `pizza`，**簡單工廠管理物件的創造，如果 client 要取得物件，只要給簡單工廠參數就可以**，然後在 `PizzaStore` 的 constructor 丟一個工廠進去就好。
```java
    public class SimplePizzaFactory
    {
        public Pizza createPizza(String type)
        {
            Pizza pizza = null;
            if(type.equals("cheese"))
            {
                pizza = new CheesePizza();
            }
            else if(type.equals("greek"))
            {
                pizza = new GreekPizza();
            }
            else if(type.equals("pepperoni"))
            {
                pizza = new PepperoniPizza();
            }
            return pizza;
        }
    }
    public class PizzaStore
    {
        SimplePizzaFactory factory;
        public PizzaStore(SimplePizzaFactory factory)
        {
            this.factory = factory;
        }
        public Pizza orderPizza(String type)
        {
            Pizza pizza;
            pizza = factory.creatPizza(tpye);
            pizza.prepare();
            pizza.cook();
            return pizza;
        }
    }
```
簡單工廠模式，讓我們把 ==**pizza 的創造和 pizza 的使用分開了**==，減少了 client 對實作的依賴。<br>
<span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/factory1.png" width="600" height="380"></img></span>
今天生意不錯，開個分店。
同樣是 `cheese pizza`，但是 `NewYork` 和 `Chicago` 做法不一樣，修改 `SimplePizzaFactory` `createPizza` 多一個參數。
```java
    public class SimplePizzaFactory
    {
        public Pizza createPizza(String style, String type)
        {
            Pizza pizza = null;
            if(style.equal("NewYork"))
            {
                if(type.equals("cheese"))
                {
                    pizza = new NewYorkCheesePizza();
                }
                else...
            }
            else if (style.equal("Chicago"))
            {
                if(style.equals("cheese"))
                {
                    pizza = new ChicagoCheesePizza();
                }
                else...
            }
            return pizza;
        }
    }
```
然後讓 `NewYorkPizzaFactory` `ChicagoPizzaFactory` 都繼承 `SimplePizzaFactory` 因為我們現在要為不同 `style` 的 PizzaStore 建立不同的工廠。

今天點 NewYork 風味的起司 pizza
```java
    NewYorkPizzaFactory newYorkPizzaFactory = new NewYorkPizzaFactory();
    PizzaStore newYorkStore = new PizzaStore(newYorkPizzaFactory);
    newYorkStore.orderPizza("cheese");
```
今天點 Chicago 風味的起司 pizza
```java
    ChicagoPizzaFactory chicagoPizzaFactory = new ChicagoPizzaFactory();
    PizzaStore newYorkStore = new PizzaStore(chicagoPizzaFactory);
    chicagoStore.orderPizza("cheese");
```
但是現在在 Factory 之間我們使用了繼承，我們知道 `SimplePizzaFactory` 只是個介面，真正實作的是 subclass 的實體工廠。

==**decouple + hierarchy 兩種功能同時需要時，我們就可以使用 Factory Method Pattern**==
## <font color="#F59F00">**Factory Method Pattern**</font>
**工廠方法模式，定義了一個建立物件的介面，由子類決定實例化的類別為何。**
如果我們現在把 `createPizza` 放回 `PizzaStore` 讓子類別來決定怎麼 createPizza。
```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;
        } 
    }
```
讓 NewYorkStore 繼承 PizzaStore，實作 createPizza
```java
    public class NewYorkPizzaStore extends PizzaStore
    {
        public createPizza(String type)
        {
            if(type.equals("cheese"))
            {
                return new NewYorkCheesePizza();
            }
            else if(type.equals("veggle"))
            {
                return new NewYorkVegglePizza();
            }
            else if (type.equals("clam"))
            {
                return new NewYorkClamPizza();
            }
            else if (type.equals("pepperoni"))
            {
                return new NewYorkPepperoniPizza();
            }
            else
            {
                return null;
            }
        }
    }
```
原本物件的建立，交給一個外來的工廠處理，現在交給子類別處理，而且父類別還可以呼叫子類別實作的函式 `createPizza`，這種互相呼叫的函式通常依賴性很高，但是我們利用工廠讓父類別和子類別讓依賴變鬆散了。

套用工廠後，**也就是讓實作在 `PizzaStore` 的 subclass 實作，讓物件的製作和使用做分離。**
```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)
        {
            if(type.equals("cheese"))
            {
                return new NewYorkCheesePizza();
            }
            else if(type.equals("veggle"))
            {
                return new NewYorkVegglePizza();
            }
            else if (type.equals("clam"))
            {
                return new NewYorkClamPizza();
            }
            else if (type.equals("pepperoni"))
            {
                return new NewYorkPepperoniPizza();
            }
            else
            {
                return null;
            }
        }
    }
```
order `pizza` 的方法
```java
    PizzaStore pizzaStore = new NewYorkPizzaStore();
    Pizza pizza = pizzaStore.orderPizza();
```
*    <font color="#92d1ff">**Factory Method 的結構**</font>
        <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/factory4.png" width="650" height="300"></img></span><br>
        *    <font color="#98c37a">**Product : Pizza**</font>
                定義 factoryMethod : createPizza 創造物件的介面。
        *    <font color="#98c37a">**ConcreteProduct : NewYorkCheesePizza/...**</font>
                實作 Production。
        *    <font color="#98c37a">**Creator : PizzaStore**</font>
                宣告 factoryMethod，必須回傳 Product 和宣告其他 client 需要用到的 API
        *    <font color="#98c37a">**ConcreteCreator : NewYorkPizzaStore**</font>
                實作 factoryMethod 回傳 ConcreteProduct 的 instance。
*    <font color="#92d1ff">**Pros & Cons**</font>
        *    <font color="#98c37a">**Pros**</font>
                和簡單工廠一樣
                    1. 區隔物件的使用和生成
                    2. 隱藏了物件的細節
                    3. 加入新產品不用更改 Creator，直接繼承就好，client 一樣不用更改，完全符合 OCP。
        *    <font color="#98c37a">**Cons**</font>
                ConcreteCreator 和 ConcreteProduct 會成對的增加，如果今天想在加一個 `CaliforniaPizza` 就必須在定義完 `CaliforniaPizza` 後，再定義 CaliforniaPizzaFactory