iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 20
1
Software Development

保持前進、持續優化程式碼內涵系列 第 19

20. 簡單工廠模式 - Simple Factory

  • 分享至 

  • xImage
  •  

設計模式的第一篇,我們就從簡單工廠模式來開個頭,因為簡單工廠模式,是筆者個人經常使用的模式之一,同時,應該也是新手最能快速應用的模式。

對於繼承相同介面的物件,在於程式碼中的用戶端,不用自己去建制物件,可以經由工廠模式,快速變更所使用的元件對象。

1. 概念

依據 GoF 所定義的模式類型,簡單工廠模式應該歸屬於創建類型之中。

當存在一個類別(Factory) 專門負責創建繼承相同介面(Product)物件(ConcreteProduct) 的模式,而這種模式,就稱為簡單工廠模式

另外,為了簡單快速的使用 Factory,經常在將其宣告為 static 的狀態。因此,簡單工廠模式又稱靜態工廠模式。

還記得依賴反轉的範例嗎?我們將程式碼再回憶一下。

public class ReportStatistic()
{
    private IAccess _access = new SQLAccess();
    
    public double Sum()
    {
        var items = _access.GetAllCost();
        ...
    }
}

public interfalce IAccess
{
    List<CostItem GetAllCost();
}

public class SQLAccess : IAccess
{
    public List<CostItem> GetAllCost()
    {
        ...
    }
}

public class CsvAccess : IAccess
{
    public List<CostItem> GetAllCost()
    {
        ...
    }
}

接下來, 將上面的程式碼,套用簡單工廠模式後,會變成下面的程式。

public class ReportStatistic()
{
    private IAccess _access = AccessFactory.Create("sql");
    
    public double Sum()
    {
        var items = _access.GetAllCost();
        ...
    }
}

public interfalce IAccess
{
    List<CostItem GetAllCost();
}

public class AccessFactory
{
    public static IAccess Create(string category)
    {
        switch(category)
        {
            case "sql"
                retrun new SQLAccess();
                
            case "csv"
                return new CsvAccess();
        }
    }
}

1.1 Factory

負責創建特定類型物件的創建方。

public class AccessFactory
{
    public static IAccess Create(string category)
    {
        switch(category)
        {
            case "sql"
                retrun new SQLAccess();
                
            case "csv"
                return new CsvAccess();
        }
    }
}

在範例中,AccessFactory 就是 Factory,其中的 Create(string) 負責建立繼承 IAccess 的物件。利用傳入參數(category)的不同,回傳不同的物件。

同時,我們可以將物件創建時,所需要的初始化設定都在 Create 內完成,對外部的用戶端而言,就不需知道詳細的設定方式,只需知道如何使用即可。

這樣說有點模糊,我們看一下下面的程式碼,就可以知道筆者要表達的意思。

public class AccessFactory
{
    public static IAccess Create(string category)
    {
        switch(category)
        {
            case "sql"
                retrun new SQLAccess();
                
            case "csv"
                return new CsvAccess();
            
            cast "txt"
                var txtAccess = new TxtAccess();
                txtAccess.Path = @".\userdata.txt";
                txtAccess.CanWrite = false;
                txtAccess.CanRead = true;
                txtAccess.IsCompression = true;
                
                return txtAccess;
        }
    }
}

當用戶端呼收 AccessFactory.Create("txt") 時,它就取得了 txtAccess 物件,完全不用理會詳細的創建方式。因為跟創建有關的動作,全部包在 Factory 之中。

1.2 Product

創建物件的的共同特性,其特性類型為 abstract/interface/class。

public interfalce IAccess
{
    List<CostItem GetAllCost();
}

在範例中,介面 IAccess 是 Factory 回傳物件的共同介面。

1.3 ConcreteProudct

繼承 abstract/interface/class 的具體實作物件。

public class SQLAccess : IAccess
{
    public List<CostItem> GetAllCost()
    {
        ...
    }
}

public class CsvAccess : IAccess
{
    public List<CostItem> GetAllCost()
    {
        ...
    }
}

在範例中,SQLAccess、CvsAccess 就繼承 IAccess 的具體實作。

2. 優點

對於用戶端而言,它不需要明確的知道 Product 的創建方式,它唯一需要知道的就是,當它傳入何種參數到 Factory 之中,就會取得所需的 Product。

若 Factory 配合組態檔(Config)的設定,甚至可以達到……

在程式碼之中不需傳入任何參數,全部依靠組態檔的設定,來決定要回傳的 Product,達到不需變更程式碼,就可以切換不同的 Proudct。

3. 注意事項

當 Facotry 需要增加新的 Product 時,必然需要對 Factory 的程式碼進行變更。

若以 SOLID 而言,這個動作是違反了 OCP 的原則。但如果撇開這點不說,這個缺點其實影響不大。

4. 後言

簡單工廠模式,可以讓元件的創建,不用讓用戶端自行負責,甚至可以減少或避免,元件創建時,所需要的麻煩而複雜的設定工作。

5. 推薦

5.1 文章


上一篇
18. 常見軟體架構之三 - MVP (待補完)
下一篇
22. 樣板方法模式- Template Method (未完, 待補)
系列文
保持前進、持續優化程式碼內涵24
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言