直接 new ConcreteClass() 將客戶端與具體實現強綁定。工廠方法模式(Factory Method Pattern)的核心思想:定義一個創建物件的介面,讓子類別決定實例化哪一個類別。Factory Method 使一個類別的實例化延遲到其子類別(GoF)。它不創建物件,而是「委託」創建——這一層間接,正是應對變化的關鍵。
// 反模式:集中式 switch,違反開放封閉原則
public class Log {
public void Write(string logType) {
switch (logType.ToLower()) {
case "event": WriteEvent(); break;
case "file": WriteFile(); break;
case "database": WriteDatabase(); break; // 新增需修改此處
}
}
}
問題:每新增一種日誌方式,就要修改 Log 類別,引入測試風險,違反單一職責。
public abstract class Log { public abstract void Write(); }
public class EventLog : Log { public override void Write() => Console.WriteLine("EventLog"); }
public class FileLog : Log { public override void Write() => Console.WriteLine("FileLog"); }
public class DatabaseLog : Log { public override void Write() => Console.WriteLine("DatabaseLog"); }

public abstract class LogFactory { public abstract Log Create(); }
public class EventLogFactory : LogFactory { public override Log Create() => new EventLog(); }
public class FileLogFactory : LogFactory { public override Log Create() => new FileLog(); }
public class DatabaseLogFactory : LogFactory { public override Log Create() => new DatabaseLog(); }

public class App {
public static void Main() {
// 僅此處綁定具體工廠,其餘程式碼零修改
LogFactory factory = new EventLogFactory();
// 或從配置檔讀取:factory = CreateFactoryFromConfig();
Log log = factory.Create();
log.Write();
}
}
切換實作僅需修改一行:factory = new FileLogFactory();。搭配配置檔 + 反射,可達到零程式碼修改切換:
// App.config
// 客戶端
string factoryName = ConfigurationManager.AppSettings["factoryName"];
LogFactory factory = (LogFactory)Assembly.Load("MyAssembly").CreateInstance(factoryName);
ASP.NET 處理請求的核心管線大量使用工廠方法:
HttpRuntime 接收請求,建立 HttpContextHttpApplicationFactory.GetApplicationInstance() 取得 HttpApplication(工廠方法)HttpApplication 根據副檔名從 <httpHandlers> 區段解析對應的 IHttpHandlerFactoryfactory.GetHandler(context, ...) 取得具體 IHttpHandler(如 PageHandlerFactory 產生 .aspx 處理器)

// 1. 實作介面
public class MyHandlerFactory : IHttpHandlerFactory {
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
=> new MyHandler();
public void ReleaseHandler(IHttpHandler handler) { }
}
public class MyHandler : IHttpHandler {
public void ProcessRequest(HttpContext context) => context.Response.Write("Custom handler!");
public bool IsReusable => false;
}
// 2. Web.config 註冊
// 3. IIS 映射 *.myext 到 aspnet_isapi.dll
這展示了工廠方法支援「框架定義介面、應用程式提供實作、配置檔連結雙方」的擴展性架構。
WebRequest.Create(uri):根據 URI Scheme 回傳 HttpWebRequest、FtpWebRequest、FileWebRequestSymmetricAlgorithm.Create() / HashAlgorithm.Create():根據配置/演算法名稱回傳對應加密實作DbProviderFactory:ADO.NET 統一存取模型的核心工廠IEnumerable.GetEnumerator():集合與迭代器的工廠方法關係Activator.CreateInstance():通用反射工廠| 形式 | 特徵 | 適用場景 |
|---|---|---|
| 抽象 Creator | Creator 為 abstract,不提供預設實作 | 強制子類別實作、框架設計 |
| 具體 Creator | Creator 為 concrete,提供預設工廠方法實作 | 應用層、允許覆寫預設行為 |
public abstract class LogFactory {
public virtual Log Create(LogType type) { // 參數化,單一工廠支援多產品
switch (type) {
case LogType.Event: return new EventLog();
case LogType.File: return new FileLog();
}
throw new ArgumentException();
}
}
參數化工廠方法減少具體工廠類別數量,但引入 switch——需在「類別數量」與「條件邏輯」間權衡。
工廠方法內可執行:參數驗證、預設值設定、相依服務注入、快取檢查、生命週期管理(如單例檢查)、記錄審計日誌等。這使其比單純 new 強大得多。
以下情況適用工廠方法:
new 即可,無需工廠LogFactory.Create() 為靜態方法非模式;模式強調「虛擬方法可被子類別覆寫」工廠方法模式是設計模式中應用最廣、變體最多的模式。它以「虛擬建構子」之姿,將「實例化決策」從使用者手中收回,交給專門的工廠階層管理。在 .NET 生態中,從 WebRequest 到 ADO.NET Provider、從 ASP.NET 管線到 DI 容器內部,工廠方法無處不在。掌握它,意味著你學會了「延遲綁定」這一應對變化的核心技巧——不在編譯期鎖定具體類別,而在運行期由配置、上下文、策略動態決定。