設計模式是軟件工程的基石。創建型模式關注對象的實例化過程,將創建邏輯與使用邏輯解耦,提高系統的靈活性與可維護性。本文深度解析 **工廠方法、抽象工廠、單例、建造者、原型** 五大創建型模式,提供標準 UML 結構說明、完整可運行 Java 代碼、核心優缺點對比及實戰應用場景。
| 原則 | 核心含義 | 指導意義 |
|---|---|---|
| 開閉原則 (OCP) | 對擴展開放,對修改關閉 | 熱插拔,通過接口/抽象擴展而不改動核心代碼 |
| 里氏替換 (LSP) | 子類必須能替換父類 | 繼承需謹慎,優先組合;參數卻變、返回協變、異常收窄 |
| 依賴倒置 (DIP) | 依賴抽象不依賴具體 | 面向接口編程,高層模塊不依賴低層模塊 |
| 接口隔離 (ISP) | 多個專用接口優於單一總接口 | 降低耦合,避免「胖接口」強制實現無用方法 |
| 迪米特法則 (LoD) | 最少知識原則 | 只與直接朋友通信,減少對象間耦合 |
| 合成復用 (CRP) | 優先組合/聚合,少用繼承 | 保持封裝性,靈活復用 |
定義:定義一個創建對象的接口,由子類決定實例化哪個類。包含三種變體:
// 產品接口
interface Product { void use(); }
// 具體產品
class ConcreteProductA implements Product { public void use() { System.out.println("產品A"); } }
class ConcreteProductB implements Product { public void use() { System.out.println("產品B"); } }
// 工廠類
class SimpleFactory {
public Product create(String type) {
switch (type) {
case "A": return new ConcreteProductA();
case "B": return new ConcreteProductB();
default: throw new IllegalArgumentException("未知類型");
}
}
}
// 客戶端
Product p = new SimpleFactory().create("A"); p.use();
缺點:違反 OCP,添加產品需修改工廠類。
將創建邏輯延遲到子類,每個產品對應一個工廠子類。
abstract class Factory {
public abstract Product create(); // 工廠方法
}
class FactoryA extends Factory { public Product create() { return new ConcreteProductA(); } }
class FactoryB extends Factory { public Product create() { return new ConcreteProductB(); } }
// 客戶端只依賴抽象工廠
Factory factory = new FactoryA(); // 或從配置/注入獲取
Product product = factory.create();
優點:符合 OCP,新增產品只需新增工廠子類,不修改現有代碼。
工廠方法聲明為 static,無需實例化工廠。如 Collections.singletonList()、Boolean.valueOf()。
定義:提供一個接口,用於創建**相關或依賴對象的家族**,而不指定具體類。解決「產品族」一致性問題。
場景:皮膚主題(按鈕+輸入框+窗口)、跨平台 GUI、多数據庫適配(Connection+Statement+ResultSet)。
// 抽象產品族
interface Button { void render(); }
interface Checkbox { void render(); }
// 具體產品族 Win/Mac
class WinButton implements Button { public void render() { System.out.println("Win按鈕"); } }
class WinCheckbox implements Checkbox { public void render() { System.out.println("Win複選框"); } }
class MacButton implements Button { /* ... */ }
class MacCheckbox implements Checkbox { /* ... */ }
// 抽象工廠
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具體工廠
class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
class MacFactory implements GUIFactory { /* ... */ }
// 客戶端
GUIFactory factory = new WinFactory(); // 運行時決定
Button btn = factory.createButton();
Checkbox cb = factory.createCheckbox();
// 保證 btn 和 cb 風格一致
定義:保證一個類僅有一個實例,並提供全局訪問點。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
public class Singleton {
private static volatile Singleton instance; // volatile 禁止指令重排
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
public class Singleton {
private Singleton() {}
private static class Holder { static final Singleton INSTANCE = new Singleton(); }
public static Singleton getInstance() { return Holder.INSTANCE; }
}
public enum Singleton { INSTANCE; public void doSomething() {} }
// 調用:Singleton.INSTANCE.doSomething();
定義:將複雜對象的構建與表示分離,使相同構建過程可創建不同表示。適用於:構造器參數超過 4 個、參數有默認值、需要不可變對象。
角色:Product(產品)、Builder(抽象建造者)、ConcreteBuilder(具體建造者)、Director(指揮者)。
// 產品
class Person {
private String head, body, foot;
// getter/setter...
@Override public String toString() { return "Person{head=" + head + ", body=" + body + ", foot=" + foot + "}"; }
}
// 抽象建造者
interface PersonBuilder {
void buildHead();
void buildBody();
void buildFoot();
Person build();
}
// 具體建造者
class ManBuilder implements PersonBuilder {
private Person person = new Person();
public void buildHead() { person.setHead("男人頭"); }
public void buildBody() { person.setBody("男人身體"); }
public void buildFoot() { person.setFoot("男人腳"); }
public Person build() { return person; }
}
class WomanBuilder implements PersonBuilder { /* ... */ }
// 指揮者:控制構建順序
class PersonDirector {
public Person construct(PersonBuilder builder) {
builder.buildHead();
builder.buildBody();
builder.buildFoot();
return builder.build();
}
}
// 客戶端
PersonDirector director = new PersonDirector();
Person man = director.construct(new ManBuilder());
Person woman = director.construct(new WomanBuilder());
現代變體:鏈式調用 Builder(如 Lombok @Builder、StringBuilder、HttpClientBuilder),省去 Director,直接鏈式設置屬性最後 .build()。
定義:通過複製現有實例(原型)創建新對象,而非通過構造器。核心在於 clone() 實現淺拷貝與深拷貝的區別。
| 類型 | 基本類型 | 引用類型 | 實現方式 |
|---|---|---|---|
| 淺拷貝 | 重新創建(值傳遞) | 複製引用(指向同一對象) | super.clone() 默認實現 |
| 深拷貝 | 重新創建 | 遞歸創建新對象 | 序列化/反序列化、手動 new、拷貝構造器 |
class Prototype implements Cloneable, Serializable {
private int primitiveField;
private MutableObject referenceField; // 可變引用對象
// 淺拷貝
@Override protected Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
// 深拷貝:序列化+反序列化(通用但有性能開銷)
public Prototype deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Prototype) ois.readObject();
}
}
// 測試
Prototype p1 = new Prototype(); p1.setPrimitiveField(1); p1.setReferenceField(new MutableObject(2));
Prototype p2 = p1.clone(); // 淺拷貝:p2.referenceField == p1.referenceField 為 true
Prototype p3 = p1.deepClone(); // 深拷貝:p3.referenceField != p1.referenceField 為 true
| 場景 | 推薦模式 | 關鍵判斷依據 |
|---|---|---|
| 單一產品、創建邏輯固定、客戶端不關心細節 | 簡單工廠 | 不需擴展、代碼集中 |
| 產品族固定、需支持多平台/主題、保證族內一致性 | 抽象工廠 | 「一組相關對象」而非單個 |
| 全局唯一實例、狀態共享、延遲加載 | 單例(枚舉/靜態內部類) | 線程安全、防破壞 |
| 構造參數多、可選參數多、需不可變對象、構建步驟固定 | 建造者 | 鏈式調用、Director 控制順序 |
| 創建成本高、對象狀態相似、需動態增減原型 | 原型 | clone()、深/淺拷貝選擇 |