Factory Method Pattern(工廠方法模式)

是什麼?

Factory Method Pattern 定義一個建立物件的介面(或抽象方法),但把實際建立哪種物件的決定權交給子類別。呼叫端只透過介面操作產品,不需要知道具體的類別是什麼。

ℹ️GoF 分類

Factory Method 屬於建立型模式(Creational Pattern),重點在於將物件的建立邏輯延遲到子類別,達到解耦的效果。

什麼時候用?

用以下 if/then 條件判斷:

什麼時候不該用?

⚠️過度設計警告

如果產品類型固定且不會擴展,直接 new 就好。Factory Method 會增加繼承層級,只有在「產品種類會增長」或「需要讓框架使用者自訂建立邏輯」時才值得用。

執行流程

1

定義產品介面

宣告所有產品共用的方法簽名

2

定義工廠介面

宣告 Factory Method(回傳產品介面型別)

3

實作具體產品

每種產品各自實作產品介面

4

實作具體工廠

每個工廠子類別覆寫 Factory Method,建立對應的產品

5

客戶端透過工廠建立

呼叫工廠方法取得產品,不需知道具體類別

流程解讀:Factory Method 的關鍵是「把 new 的決定權交給子類別」。抽象工廠定義了一個回傳產品介面的方法(Factory Method),但不決定具體建立什麼。每個具體工廠覆寫這個方法,各自決定要 new 哪種具體產品。這讓 Client 只依賴抽象,新增產品時只需新增工廠子類別和產品子類別,不改既有程式碼。

程式碼範例

C# 版本

csharp
// 1. 產品介面
public interface INotification
{
    string Send(string message);
}
 
// 2. 具體產品
public class EmailNotification : INotification
{
    public string Send(string message) => $"[Email] {message}";
}
 
public class SmsNotification : INotification
{
    public string Send(string message) => $"[SMS] {message}";
}
 
public class PushNotification : INotification
{
    public string Send(string message) => $"[Push] {message}";
}
 
// 3. 工廠介面
public abstract class NotificationFactory
{
    public abstract INotification CreateNotification();
 
    public string Notify(string message)
    {
        var notification = CreateNotification();
        return notification.Send(message);
    }
}
 
// 4. 具體工廠
public class EmailFactory : NotificationFactory
{
    public override INotification CreateNotification() => new EmailNotification();
}
 
public class SmsFactory : NotificationFactory
{
    public override INotification CreateNotification() => new SmsNotification();
}
 
// 5. 使用
NotificationFactory factory = new EmailFactory();
Console.WriteLine(factory.Notify("你的訂單已成立")); // [Email] 你的訂單已成立
 
factory = new SmsFactory();
Console.WriteLine(factory.Notify("驗證碼:1234")); // [SMS] 驗證碼:1234

TypeScript 版本

typescript
// 1. 產品介面
interface Notification {
  send(message: string): string;
}
 
// 2. 具體產品
class EmailNotification implements Notification {
  send(message: string): string {
    return `[Email] ${message}`;
  }
}
 
class SmsNotification implements Notification {
  send(message: string): string {
    return `[SMS] ${message}`;
  }
}
 
// 3. 工廠介面
abstract class NotificationFactory {
  abstract createNotification(): Notification;
 
  notify(message: string): string {
    const notification = this.createNotification();
    return notification.send(message);
  }
}
 
// 4. 具體工廠
class EmailFactory extends NotificationFactory {
  createNotification(): Notification {
    return new EmailNotification();
  }
}
 
class SmsFactory extends NotificationFactory {
  createNotification(): Notification {
    return new SmsNotification();
  }
}
 
// 5. 使用
let factory: NotificationFactory = new EmailFactory();
console.log(factory.notify("你的訂單已成立")); // [Email] 你的訂單已成立
 
factory = new SmsFactory();
console.log(factory.notify("驗證碼:1234")); // [SMS] 驗證碼:1234

Python 版本

python
from abc import ABC, abstractmethod
 
# 1. 產品介面
class Notification(ABC):
    @abstractmethod
    def send(self, message: str) -> str:
        pass
 
# 2. 具體產品
class EmailNotification(Notification):
    def send(self, message: str) -> str:
        return f"[Email] {message}"
 
class SmsNotification(Notification):
    def send(self, message: str) -> str:
        return f"[SMS] {message}"
 
# 3. 工廠介面
class NotificationFactory(ABC):
    @abstractmethod
    def create_notification(self) -> Notification:
        pass
 
    def notify(self, message: str) -> str:
        notification = self.create_notification()
        return notification.send(message)
 
# 4. 具體工廠
class EmailFactory(NotificationFactory):
    def create_notification(self) -> Notification:
        return EmailNotification()
 
class SmsFactory(NotificationFactory):
    def create_notification(self) -> Notification:
        return SmsNotification()
 
# 5. 使用
factory: NotificationFactory = EmailFactory()
print(factory.notify("你的訂單已成立"))  # [Email] 你的訂單已成立
 
factory = SmsFactory()
print(factory.notify("驗證碼:1234"))  # [SMS] 驗證碼:1234

Java 版本

java
// 1. 產品介面
public interface Notification {
    String send(String message);
}
 
// 2. 具體產品
public class EmailNotification implements Notification {
    public String send(String message) { return "[Email] " + message; }
}
 
public class SmsNotification implements Notification {
    public String send(String message) { return "[SMS] " + message; }
}
 
// 3. 工廠介面
public abstract class NotificationFactory {
    public abstract Notification createNotification();
 
    public String notify(String message) {
        Notification notification = createNotification();
        return notification.send(message);
    }
}
 
// 4. 具體工廠
public class EmailFactory extends NotificationFactory {
    public Notification createNotification() { return new EmailNotification(); }
}
 
public class SmsFactory extends NotificationFactory {
    public Notification createNotification() { return new SmsNotification(); }
}
 
// 5. 使用
NotificationFactory factory = new EmailFactory();
System.out.println(factory.notify("你的訂單已成立")); // [Email] 你的訂單已成立
 
factory = new SmsFactory();
System.out.println(factory.notify("驗證碼:1234")); // [SMS] 驗證碼:1234

結構圖

Client
uses
NotificationFactory (abstract)
creates (abstract)
Notification (interface)
EmailFactory / SmsFactory
extends
EmailNotification / SmsNotification

結構解讀:Client 只認識 NotificationFactory(抽象)和 Notification(介面),不知道具體實作是什麼。EmailFactory 覆寫 Factory Method 來建立 EmailNotification,SmsFactory 建立 SmsNotification。新增 PushNotification 時只需新增 PushFactory + PushNotification,Client 和既有工廠完全不用改。

實戰補充

💡資深開發者經驗

框架中的 Factory Method:ASP.NET Core 的 IControllerFactory、Java 的 BeanFactory、Angular 的 ComponentFactoryResolver 都是 Factory Method 的應用。框架定義介面,使用者透過實作來自訂行為。

搭配 DI:在 .NET 中,你可以註冊一個 Func<INotification>INotificationFactory,讓 DI 容器負責管理工廠的生命週期,避免手動 new Factory。

Simple Factory vs Factory Method:Simple Factory 用一個 switch/if 決定建什麼(不是 GoF 模式),Factory Method 用繼承讓子類別決定。當產品種類穩定用 Simple Factory 即可,會擴增就用 Factory Method。

理解測驗

🤔 Factory Method 和直接在程式碼中 new 物件相比,最大的好處是什麼?

🤔 在 Factory Method Pattern 中,誰決定要建立哪種具體產品?

🤔 以下哪個場景最適合用 Factory Method?

面試常見問題

Q: Simple Factory、Factory Method、Abstract Factory 三者怎麼區分?

A: Simple Factory 用一個 switch/if 決定建什麼(不是 GoF 模式,適合產品固定的場景)。Factory Method 用繼承讓子類別各自決定建一種產品(適合產品會增加)。Abstract Factory 用介面讓具體工廠建一整套相關產品(適合產品有家族概念)。選擇路徑:產品只有一種且固定 → Simple Factory;產品會增加但各自獨立 → Factory Method;產品有家族且必須搭配 → Abstract Factory。

Q: Factory Method 和 DI 容器有什麼關係?

A: DI 容器本質上就是一個超級工廠,根據介面型別回傳對應的具體實作。在 .NET 中,services.AddScoped<INotification, EmailNotification>() 就是在「註冊」工廠方法。差異在於 DI 容器是通用的,Factory Method 是針對特定產品家族設計的。

相關模式

| 模式 | 關係 | |------|------| | Abstract Factory | Abstract Factory 內部通常用多個 Factory Method 來建立每種產品 | | Template Method | Factory Method 常出現在 Template Method 內部 — 模板定義流程,其中一步是 Factory Method 建立需要的物件 | | Prototype | 都是建立型模式,但 Prototype 透過複製建立,Factory Method 透過子類別覆寫建立 | | Strategy | Factory 可以用 Strategy 來決定建立邏輯,而非用繼承 |

重點整理

💡一句話記住

Factory Method = 把 new 的決定權交給子類別。 口訣:「父類別定框架,子類別填產品」

| 概念 | 說明 | |------|------| | Product(產品介面) | 定義產品的共用方法 | | ConcreteProduct(具體產品) | 各自實作產品介面 | | Creator(工廠抽象類別) | 宣告 Factory Method,可包含業務邏輯 | | ConcreteCreator(具體工廠) | 覆寫 Factory Method,建立特定產品 | | 核心好處 | 開放封閉原則 — 新增產品不用改既有程式碼 | | 代價 | 每新增一種產品就要多一個工廠子類別 |

你可能也想看

Singleton PatternAbstract Factory Pattern

按 ← → 鍵切換課程