簡單工廠模式(Simple Factory Pattern)雖非 GoF 23 種經典設計模式之一,但作為工廠模式家族的入門基礎,廣泛應用於業務開發中。本文將通過「人類創建」案例,深度解析其結構、兩種實作方式(邏輯判斷 vs 反射)、優缺點與適用場景。
核心角色:
Human)Man、Woman)UML 關係: Factory 依賴 Product,Client 僅依賴 Factory 與 Product,解耦具體實現類。
public interface Human {
void say();
}
public class Man implements Human {
@Override public void say() { System.out.println("男人"); }
}
public class Woman implements Human {
@Override public void say() { System.out.println("女人"); }
}
public class SimpleFactory {
public static Human createHuman(String type) {
if ("man".equalsIgnoreCase(type)) {
return new Man();
} else if ("woman".equalsIgnoreCase(type)) {
return new Woman();
} else {
System.err.println("無法創建類型: " + type);
return null;
}
}
}
特點: 直觀易懂,但違反開閉原則,新增類型需修改工廠代碼。
public class SimpleFactoryReflect {
public static Human createHuman(Class<? extends Human> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException e) {
throw new IllegalArgumentException("不支援抽象類/介面: " + clazz);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("權限不足,無法訪問構造器: " + clazz);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("缺少無參構造器: " + clazz);
} catch (InvocationTargetException e) {
throw new RuntimeException("構造器拋出異常: " + clazz, e.getCause());
}
}
}
優勢: 符合開閉原則,新增產品類無需修改工廠代碼;支援動態擴展(配置文件驅動)。
劣勢: 反射效能稍低(可緩存 Constructor)、丟失編譯期類型檢查、異常處理較繁瑣。
public class Client {
public static void main(String[] args) {
// 方式一:字符串參數
Human man1 = SimpleFactory.createHuman("man");
man1?.say();
// 方式二:Class 參數(推薦)
Human man2 = SimpleFactoryReflect.createHuman(Man.class);
Human woman2 = SimpleFactoryReflect.createHuman(Woman.class);
man2.say(); woman2.say();
}
}
| 維度 | 優點 | 缺點 |
|---|---|---|
| 職責分離 | 客戶端脫離具體創建邏輯,專注業務 | 工廠類集中所有創建邏輯,違反高內聚 |
| 擴展性 | 反射版本支援無侵入式擴展 | 邏輯判斷版本需修改工廠源碼 |
| 維護性 | 創建邏輯集中,易於統一管理 | 產品類增多時工廠膨脹,條件分支複雜 |
| 效能 | 邏輯判斷極快 | 反射有額外開銷(可緩存優化) |
| 類型安全 | 邏輯判斷編譯期可檢查 | 反射運行期才發現錯誤 |
public class OptimizedFactory {
private static final Map<Class<?>, Constructor<?>> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public static <T> T createInstance(Class<T> clazz) {
Constructor<?> constructor = CONSTRUCTOR_CACHE.computeIfAbsent(clazz, c -> {
try { return c.getDeclaredConstructor(); }
catch (NoSuchMethodException e) { throw new IllegalArgumentException(e); }
});
try {
constructor.setAccessible(true);
return (T) constructor.newInstance();
} catch (Exception e) {
throw new RuntimeException("實例化失敗: " + clazz, e);
}
}
}
簡單工廠是「封裝變化」思想的入門實踐。邏輯判斷版適合簡單固定場景,反射版適合可擴展系統。實際開發中,Spring 的 BeanFactory、ApplicationContext 本質上是功能強大的工廠容器,掌握簡單工廠原理有助於深度理解 IOC 容器設計哲學。建議:簡單場景直寫邏輯,複雜場景交給 Spring 管理,避免過度設計。