設計模式的第一篇,我們就從簡單工廠模式來開個頭,因為簡單工廠模式,是筆者個人經常使用的模式之一,同時,應該也是新手最能快速應用的模式。
對於繼承相同介面的物件,在於程式碼中的用戶端,不用自己去建制物件,可以經由工廠模式,快速變更所使用的元件對象。
依據 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();
}
}
}
負責創建特定類型物件的創建方。
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 之中。
創建物件的的共同特性,其特性類型為 abstract/interface/class。
public interfalce IAccess
{
List<CostItem GetAllCost();
}
在範例中,介面 IAccess 是 Factory 回傳物件的共同介面。
繼承 abstract/interface/class 的具體實作物件。
public class SQLAccess : IAccess
{
public List<CostItem> GetAllCost()
{
...
}
}
public class CsvAccess : IAccess
{
public List<CostItem> GetAllCost()
{
...
}
}
在範例中,SQLAccess、CvsAccess 就繼承 IAccess 的具體實作。
對於用戶端而言,它不需要明確的知道 Product 的創建方式,它唯一需要知道的就是,當它傳入何種參數到 Factory 之中,就會取得所需的 Product。
若 Factory 配合組態檔(Config)的設定,甚至可以達到……
在程式碼之中不需傳入任何參數,全部依靠組態檔的設定,來決定要回傳的 Product,達到不需變更程式碼,就可以切換不同的 Proudct。
當 Facotry 需要增加新的 Product 時,必然需要對 Factory 的程式碼進行變更。
若以 SOLID 而言,這個動作是違反了 OCP 的原則。但如果撇開這點不說,這個缺點其實影響不大。
簡單工廠模式,可以讓元件的創建,不用讓用戶端自行負責,甚至可以減少或避免,元件創建時,所需要的麻煩而複雜的設定工作。