[Design Pattern] 工廠方法模式 (Factory Method Pattern) 各自的飲料工廠

以飲料店為例,介紹套用工廠方法模式的範例說明。

前言


  上一篇說明了簡單工廠模式後接下來繼續說明工廠方法模式,工廠方法模式主要的定義為「讓次類別決定要實體化的類別為何」,也就是說當建立產品時你可以自行決定由哪個次類別來建立實際產品。

 

  簡單工廠方法其實與工廠方法有些相似,但是仔細看看,簡單工廠是將全部的事情於簡單工廠的方法中處理完成,而工廠方法卻會將要處理的事情交由實際實踐的次類別處理,也就是當產品的種類增加時在簡單工廠的情況下必須要修改簡單工廠方法,而在工廠方法模式下只需要多增加一個新產品工廠的次類別去實踐,如此就符合「開放封閉」原則,但工廠方法有個缺點就是會產生大量的工廠次類別。

 

  組成工廠方法模式有四個角色,如下

  • 抽象工廠角色:定義抽象方法或介面,交由次類別去實踐。
  • 具體工廠角色:實作抽象方法或介面,包含實例化物件的商業邏輯。
  • 抽象產品角色:定義產品抽象方法或介面,定義產品共同執行的動作。
  • 具體產品角色:實作抽象產品的方法或介面,實踐產品共同方法的商業邏輯。

 

從簡單工廠轉為工廠方法


  同樣以上一篇的範例為例,在簡單工廠時我將建立實體的動作置於簡單工廠方法中的 CreateBeverage() 方法中,如下


public class SimpleBeverageFactory
{
    public IBeverageProvide CreateBeverage(string pBeverageType)
    {
        IBeverageProvide beverage;
        if (pBeverageType == "GreenTea")
            return  new GreenTea();
        if (pBeverageType == "BlackTea")
            return  new BlackTea();
        else
            return null;
    }
}

 

  但現在飲料店為了滿足顧客對於飲料種類的喜好而需要讓提供更多不同種類飲料時,就必須要修改 CreateBeverage() 此方法中的判斷,添加更多不同種類的飲料物件,如下


public IBeverageProvide CreateBeverage(string pBeverageType)
{
    if (pBeverageType.Equals("GreenTea"))
        return new GreenTea();
    if (pBeverageType.Equals("BlackTea"))
        return new BlackTea();
    if (pBeverageType.Equals("MilkTea")) // 多了奶茶
        return new MilkTea();
    else
        return null;
}

 

  由上所展示的代碼可以看出為了應付更多種類的飲料,此簡單工廠方法開始變得複雜且相依性提高,並且不管是要更改綠茶或紅茶的口味都需要動到此方法,所以為了降低此方法的複雜度跟相依性,我們應該將飲料種類進行切割處理。

 

  首先需要建立一個產品的介面,由實作此產品介面的產品類別來建立產品的實體,因此我們需要將綠茶與紅茶分別建立各自的工廠方法並且實作產品介面的 CreateBeverage 方法,如下


public interface IBeverageFactory
{
    IBeverageProvide CreateBeverage();
}

class GreenTeaFactory : IBeverageFactory
{
    public IBeverageProvide CreateBeverage()
    {
        return new GreenTea();        
    }
}

class BlackTeaFactory : IBeverageFactory
{
    public IBeverageProvide CreateBeverage()
    {
        return new BlackTea(); 
    }
}

 

  將綠茶與紅茶切開建立各自的工廠方法後,現在我們如果要再增加奶茶時也不需要動到原本綠茶與紅茶的工廠方法了,只需要增加一個實作 IBeverageFactory 介面的次類別,如下


class MilkTeaFactory : IBeverageFactory
{
    public IBeverageProvide CreateBeverage()
    {
        return new MilkTea();        
    }
}

 

  接著定義抽象產品角色,透過介面定義產品的共同方法讓實作此介面的產品類別去實踐,如下


public interface IBeverageProvide
{
    void AddMaterial();
    void Brew();
    void PouredCup();
}

 

  當產品的介面定義完成後,就要建立該產品工廠所要創建的產品類別,也就是加入綠茶、紅茶的產品類別並且實踐 IBeverageProvide 介面的方法,如下


class GreenTea : IBeverageProvide
{
    public void AddMaterial()
    {
        Console.WriteLine("店員:加入綠茶包");
    }

    public void Brew()
    {
        Console.WriteLine("店員:沖泡");
    }

    public void PouredCup()
    {
        Console.WriteLine("店員:將紅茶裝杯");
    }
}

class BlackTea : IBeverageProvide
{
    public void AddMaterial()
    {
        Console.WriteLine("店員:加入綠茶包");
    }

    public void Brew()
    {
        Console.WriteLine("店員:沖泡");
    }

    public void PouredCup()
    {
        Console.WriteLine("店員:將紅茶裝杯");
    }
}

 

  經過以上的幾個動作後,來看看轉變為工廠方法模式後的類別圖,如下

 

  由上圖可見,GreenTeaFactory 與 BlackTeaFactory 工廠方法共同實作了 IBeverageFactory 介面的 CreateBeverage() 方法,在 CreateBeverage() 方法中單純的實例化了各自的產品類別 GreenTea 與 BlackTea ,看的出來實踐飲料的作法已經交由各自的工廠方法處理,而當飲料種類增加時只需要加入新的具體工廠角色與具體產品角色也就有效降低物件的耦合性了。

 

  最後來呼叫看看執行的語法,如下


static void Main(string[] args)
{
    BeverageStores greenStore = new BeverageStores(new GreenTeaFactory());
    Console.WriteLine("A 客人點了綠茶");
    greenStore.BeverageOrders();

    BeverageStores blackStore = new BeverageStores(new BlackTeaFactory());
    Console.WriteLine("B 客人點了紅茶");
    blackStore.BeverageOrders();

    Console.Read();
}

 

  執行的結果如下

 

範例程式碼 2016/09/24 補檔


https://drive.google.com/open?id=0B40daTESrAXwSTFlMFdEZm9sWE0

 

參考資料


Head First Design Patterns 深入淺出設計模式




以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)