當系統需要建立物件,但具體建立哪種類別、如何建立由子類別決定時,工廠方法模式提供標準方案:定義一個建立物件的介面(工廠方法),讓子類別決定實例化哪個類別。這將物件建立邏輯從使用者中分離,支援開閉原則——新增產品類別只需新增對應工廠子類別,無需修改既有程式碼。本文以訊息系統為例,展示 SqlMessageFactory/XmlMessageFactory 如何分別建立 SqlMessage/XmlMessage,客戶端透過抽象工廠介面統一使用。
AbstractMessage,定義 Get()、Insert() 共同操作。SqlMessage、XmlMessage,實作不同儲存邏輯。AbstractMessageFactory,宣告工廠方法 CreateMessage(),可包含使用產品的業務邏輯(如 AnOperation())。SqlMessageFactory、XmlMessageFactory,實作工廠方法回傳對應產品實例。
public abstract class AbstractMessage
{
public abstract List<MessageModel> Get();
public abstract bool Insert(MessageModel mm);
}
public class SqlMessage : AbstractMessage
{
public override List<MessageModel> Get()
{
var l = new List<MessageModel>();
l.Add(new MessageModel("SQL方式獲取Message", DateTime.Now));
return l;
}
public override bool Insert(MessageModel mm) { return true; }
}
public class XmlMessage : AbstractMessage
{
public override List<MessageModel> Get()
{
var l = new List<MessageModel>();
l.Add(new MessageModel("XML方式獲取Message", DateTime.Now));
return l;
}
public override bool Insert(MessageModel mm) { return true; }
}
public abstract class AbstractMessageFactory
{
public abstract AbstractMessage CreateMessage(); // 工廠方法
// 可選:使用產品的業務邏輯(模板方法風格)
public void AnOperation()
{
var product = CreateMessage();
// 使用 product...
}
}
public class SqlMessageFactory : AbstractMessageFactory
{
public override AbstractMessage CreateMessage() => new SqlMessage();
}
public class XmlMessageFactory : AbstractMessageFactory
{
public override AbstractMessage CreateMessage() => new XmlMessage();
}
關鍵:每個具體建構者只負責建立一種具體產品,建立邏輯封裝在工廠方法中。
AbstractMessageFactory amf = new SqlMessageFactory(); // 選擇具體工廠
AbstractMessage am = amf.CreateMessage(); // 建立產品
Response.Write(am.Insert(new MessageModel("插入", Now)));
Response.Write(am.Get()[0].Message);
amf = new XmlMessageFactory(); // 切換工廠
am = amf.CreateMessage();
Response.Write(am.Insert(new MessageModel("插入", Now)));
Response.Write(am.Get()[0].Message);
True
SQL方式獲取Message 2007-5-4 22:34:39
True
XML方式獲取Message 2007-5-4 22:34:39
客戶端程式碼僅依賴 AbstractMessageFactory 與 AbstractMessage 介面,切換工廠即切換產品系列,零修改業務邏輯。
| 模式 | 核心機制 | 適用場景 | 擴展方式 |
|---|---|---|---|
| 簡單工廠 | 單一類別含 switch 建立邏輯 | 產品類別固定、少量、客戶端不關心建立細節 | 修改工廠類別 (違反開閉) |
| 工廠方法 | 抽象建構者 + 具體建構者階層 | 產品類別可擴展、建立邏輯複雜、需支援多種產品系列 | 新增建構者子類別 (符合開閉) |
| 抽象工廠 | 建構者介面定義多個工廠方法 (產品族) | 需建立相關/相依的產品族 (如:SQL 連線+命令+讀取器) | 新增建構者子類別實作整族產品 |
工廠方法接受參數決定建立哪種子類型:
public abstract class MessageFactory
{
public abstract AbstractMessage CreateMessage(string type); // "sql" | "xml"
}
public class UnifiedMessageFactory : MessageFactory
{
public override AbstractMessage CreateMessage(string type)
{
return type switch { "sql" => new SqlMessage(), "xml" => new XmlMessage(), _ => throw new ArgumentException() };
}
}
優點:減少建構者類別數量。缺點:引入條件判斷、違反開閉原則(新增類型需修改 switch)。
// 註冊
services.AddTransient();
// 或多實現
services.AddKeyedTransient("sql");
services.AddKeyedTransient("xml");
// 客戶端注入
public class MessageService
{
private readonly AbstractMessageFactory _factory;
public MessageService(AbstractMessageFactory factory) => _factory = factory;
public void Process() => _factory.CreateMessage().Insert(...);
}
Creator 中定義 AnOperation() 呼叫 CreateMessage(),子類別只需實作工廠方法即可客製化演算法中的物件建立步驟。這是「框架設計」核心技巧:框架定義骨架(AnOperation),應用提供具體化(CreateMessage)。
DbProviderFactory (Creator) → SqlClientFactory (ConcreteCreator) → CreateConnection/Command/Parameter (Factory Methods)。IControllerFactory → DefaultControllerFactory → CreateController。IDbContextFactory → PooledDbContextFactory → CreateDbContext。IHttpClientFactory → DefaultHttpClientFactory → CreateClient。ILoggerFactory → LoggerFactory → CreateLogger。工廠方法模式以「虛擬建構子」將物件實例化延遲至子類別,實現「建立與使用分離」與「開閉原則」。本範例以 SqlMessageFactory/XmlMessageFactory 分別建立 SqlMessage/XmlMessage 為例,完整展示了產品介面、具體產品、抽象建構者、具體建構者四角色協作,驗證了客戶端面向抽象介面程式設計、切換工廠即切換產品系列的核心優勢。實務中,從 ADO.NET Provider、Controller Factory、DbContext Factory 到 HttpClient Factory、Logger Factory,工廠方法模式是框架庫、中間件、可擴展系統實現「多型建立、插件化架構」的基石。掌握其核心——「Creator 定義工廠方法、ConcreteCreator 實作建立邏輯、Client 依賴 Creator 介面」、與簡單工廠/抽象工廠的區別、DI 容器整合現代寫法,能讓你在設計需要「彈性建立、多實現切換、框架可擴展」的系統時,構建出清晰分層、低耦合、高擴展性的物件建立架構。