工廠方法模式是簡單工廠模式的進一步抽象化與推廣。簡單工廠中單一工廠類承擔所有產品建立決策(如交通指揮員),而工廠方法將決策權下放給具體工廠子類(如交通局管理多個指揮員),從而支援更複雜的多維度產品變化。本文通過「小花果園引入蔬菜類」的擴展案例,系統講解工廠方法的結構定義、核心代碼、適用場景與 COM/EJB/JMS 三大企業級技術架構中的實戰應用。

當系統需新增「蔬菜類」(需施藥、不同殺蟲劑)時,若繼續用簡單工廠:
FruitGardener 加入蔬菜判斷 → 違反單一職責、類膨脹VeggieGardener → 兩個工廠類結構高度相似,缺乏共同抽象核心矛盾:產品維度增加(水果 → 水果+蔬菜),簡單工廠的單一工廠類無法優雅支援多產品族。

| 角色 | 說明 | 對應類 |
|---|---|---|
| 抽象工廠 | 核心抽象,與應用無關,定義工廠方法 | Gardener (abstract class/interface) |
| 具體工廠 | 應用相關,實作工廠方法建立具體產品 | FruitGardener, VeggieGardener |
| 抽象產品 | 產品共同介面/父類 | PlantIF |
| 具體產品 | 實際建立的物件 | Apple, Tomato 等 |

public interface PlantIF {
void plant();
void grow();
void harvest();
}
public abstract class Gardener {
public abstract PlantIF factory(String which) throws BadPlantException;
}
// 水果園丁
public class FruitGardener extends Gardener {
@Override
public PlantIF factory(String which) throws BadPlantException {
if (which.equalsIgnoreCase("apple")) return new Apple();
else if (which.equalsIgnoreCase("strawberry")) return new Strawberry();
else if (which.equalsIgnoreCase("grape")) return new Grape();
else throw new BadPlantException("Bad fruit request");
}
}
// 蔬菜園丁
public class VeggieGardener extends Gardener {
@Override
public PlantIF factory(String which) throws BadPlantException {
if (which.equalsIgnoreCase("tomato")) return new Tomato();
else if (which.equalsIgnoreCase("potato")) return new Potato();
else if (which.equalsIgnoreCase("broccoli")) return new Broccoli();
else throw new BadPlantException("Bad veggie request");
}
}
// 蔬菜:同時實作 PlantIF(工廠產品身份)與 VeggieIF(領域身份)
public class Broccoli implements VeggieIF, PlantIF {
public void pesticideDust() { ... } // VeggieIF 專屬
// PlantIF 方法...
}
// 水果:實作 PlantIF 與 FruitIF
public class Apple implements FruitIF, PlantIF {
private int treeAge; // FruitIF 專屬屬性
// PlantIF 方法...
}
設計精髓:VeggieIF 與 FruitIF 代表不同領域身份,PlantIF 代表工廠產品身份。雖功能上可合併,但原則上不應合併——介面即身份,身份分離是領域建模的核心。
| 判斷條件 | 選擇 |
|---|---|
| 系統僅有一個產品類別層次,且可預見未來不會增加新類別 | 簡單工廠 |
| 存在多個產品類別層次(水果/蔬菜/花卉),或未來需頻繁新增類別 | 工廠方法 |
| 產品建立邏輯極簡,無需多態擴展 | 簡單工廠 |
| 不同產品族需要不同建立邏輯、參數、資源管理 | 工廠方法 |

IClassFactory 介面CFactory 類CoCreateInstance → CoGetClassObject → DllGetClassObject → new CFactory() → IClassFactory::CreateInstance → new CEmployee()
// 客戶端代碼
Context ctx = new InitialContext();
EmployeeHome home = (EmployeeHome) ctx.lookup("Employee"); // 獲取 Home 介面(工廠)
Employee emp = home.create(1001, "John", "Smith"); // 工廠方法建立 EJB 實例
emp.setTel("212-657-7879");
create() = 工廠方法
Context ctx = new InitialContext(props);
TopicConnectionFactory tcf = (TopicConnectionFactory) ctx.lookup("myTCF"); // 工廠1
TopicConnection tCon = tcf.createTopicConnection(); // 工廠方法1
TopicSession tSess = tCon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // 工廠方法2
TopicPublisher publisher = tSess.createPublisher(topic); // 工廠方法3
TextMessage msg = tSess.createTextMessage("Hello"); // 工廠方法4
publisher.publish(msg);
factory(String which))以支援單工廠多產品createXxx()、factory()、newInstance() 等,明確表達工廠意圖VeggieIF = 蔬菜領域身份,PlantIF = 工廠產品身份。身份分離是良好領域建模的體現。工廠方法模式通過引入抽象工廠層,將「建立什麼產品」的決策下放給具體工廠子類,實現了開閉原則:新增產品族只需新增具體工廠類,無需修改核心抽象層。它是 COM、EJB、JMS 等企業級架構的基石模式。理解其與簡單工廠的本質區別——一維 vs 二維、硬編碼 vs 多態擴展——是架構師進行模式選型的關鍵判斷力。