---
# System prepended metadata

title: 工廠方法模式
tags: [Design Pattern]

---

# 工廠方法模式
###### tags: `Design Pattern`
> 創建型設計模式,在父類中提供一個創建對象的方法,允許子類決定實例化的類型

## 範例
```cpp=
class Logistics
{
    public:
    void planDelivery()  //creator
    {
        Transport t = createTransport();
    }
    virtual void createTransport() = 0;
};

class RoadLogistics : public Logistics
{
    public:
    void createTransport()
    {
        return RoadLogistics;
    }
};

class SeaLogistics : public Logistics
{
    public:
    void createTransport()
    {
        return RoadLogistics;
    }
};
```
上方的範例中運輸方式(Logistics)為父類,planDelivery()是父類中提供創建對象的方法,而創建對象的方法可由子類來override。
在設計的時候 所有的子類應該要使用同一個介面如下：
```cpp=
//interface
class Transport
{
    public:
        virtual void deliver() = 0;
};

class Truck : public Transport
{
    public:
    void deliver() //繼承父類純虛函數必須實做出來
    {
    
    }
};

class Ship : public Transport
{
    public:
    void deliver() //繼承父類純虛函數必須實做出來
    {
    
    }
};
```
以上方來說 Truck 與 Ship 兩種運輸方法,都必須要使用Transport的介面。在這個介面當中有個純虛函數deliver(運輸/派送) , 而上方的 Logistics 實際上返回的則會是這兩種運輸方法。

```cpp=
//介面 針對於所由有Creator與子類所創造的物件
class Product
{
    public:
      virtual void doStuff() = 0;
};
//這是產品介面的實做A
class ConcreteProductA : public Product
{
    public:
      void doStuff(){}
};
//這是產品介面的實做B
class ConcreteProductB : public Product
{
    public:
      void doStuff(){}
};
//用來回傳產品物件的工廠方法
class Creator
{
    public:
        void someOperation()
        {
            auto ptr = createProduct();
            ptr->doStudd();
        }
        virtual std::shared_ptr<Product> createProduct() = 0;
};

class ConcreteCreatorA : public Creator
{
    std::shared_ptr<product> createProduct()
    {
        std::shared_ptr<Product> ptr = std::make_shared<ConcreteProductA>();
        return ptr;
    }
};

class ConcreteCreatorB : public Creator
{
    std::shared_ptr<product> createProduct()
    {
        std::shared_ptr<Product> ptr = std::make_shared<ConcreteProductB>();
        return ptr;
    }
};

void client(std::shared_ptr<Creator> ptr)
{
    ptr->someOperation();
}

int main()
{
    std::shared_ptr<Creator> ptr = std::make_shared<ConcreteCreatorA>();
    client(ptr);
    return 0;
}
```
調用工廠方法的函數被稱謂客戶端 , 如上方的client()。

## 適合使用的場景

1. 無法預知需要設計哪些類別與他們之間的依賴關係時

> 工廠方法可以將創建產品這個物件的代碼與實際上使用物件的方法函數分離,可以在不更改其他程式的情況下,實現擴充功能的部份,我們只需要創建一個子類並且透過override的方式實做他,最後在Creator中新增創建此類別的子類即可。

2. 希望其他人可以擴充我們寫的庫的內部架構（函數 / 類別等）

3. 希望可以重複使用現有的物件來節省系統資源 , 而不是重複的創建新的物件。

## 優點
1. 可以避免Creator與我們生產出的其他類別（在這邊是Product）過度的耦合
2. 單一職責,我們可以將所有的Product放在同個地方,對於維護也會比較方便
3. 符合開閉原則 , 方便擴展的同時可以不更改原先程式碼
## 缺點
1. 必須要寫很多的子類別,會讓整個程式架構更複雜。