《Java 與模式》(阎宏 著)是國內經典的設計模式入門著作,以 Java 語言為載體,深入淺出講解 GoF 23 種模式。本筆記提煉書籍核心內容:六大設計原則、創建型模式五種模式的結構角色、適用場景及代碼骨架,作為快速查閱與復習參考。
| 原則 | 核心定義 | 指導意義 |
|---|---|---|
| 開閉原則 (OCP) | 對擴展開放,對修改關閉 | 抽象層穩定,實現層擴展;用接口/抽象類定義規範 |
| 里氏替換原則 (LSP) | 子類必須能替換父類且不影響正確性 | 繼承必須是 is-a 關係;避免破壞父類契約的重寫 |
| 依賴倒置原則 (DIP) | 依賴抽象,不依賴具體實現 | 高層模塊不依賴低層,雙方依賴抽象;控制反轉 (IoC) 基石 |
| 合成復用原則 (CARP) | 優先使用組合/聚合,少用繼承 | 降低耦合,提高靈活性;委託替代繼承 |
| 迪米特法則 (LoD) | 最少知識原則:一個對象應盡量少與其他對象交互 | 降低類間耦合;僅與直接朋友通信 |
| 接口隔離原則 (ISP) | 接口應小而專,不應強迫客戶依賴不用的方法 | 拆分臃腫接口;多個專用接口優於單一總接口 |
核心目的:**封裝對象創建過程**,將「客戶端代碼」與「具體類實例化」解耦。分為兩類:
角色:
// 工廠類
public class ShapeFactory {
public static Shape createShape(String type) {
if ("circle".equalsIgnoreCase(type)) return new Circle();
if ("rect".equalsIgnoreCase(type)) return new Rectangle();
throw new IllegalArgumentException("Unknown shape");
}
}
// 客戶端
Shape s = ShapeFactory.createShape("circle");
缺點:違反 OCP,新增產品需修改工廠類代碼。
角色:
// 抽象工廠
public abstract class LoggerFactory {
public abstract Logger createLogger(); // 工廠方法
// 模板方法
public void log(String msg) {
Logger logger = createLogger();
logger.write(msg);
}
}
// 具體工廠
public class FileLoggerFactory extends LoggerFactory {
@Override public Logger createLogger() { return new FileLogger(); }
}
public class ConsoleLoggerFactory extends LoggerFactory {
@Override public Logger createLogger() { return new ConsoleLogger(); }
}
優勢:符合 OCP,新增產品只需新增對應工廠類,無需修改現有代碼。
核心區別:工廠方法針對「單一產品等級結構」;抽象工廠針對「多個產品族/等級結構」(如:不同 OS 下的 Button、ScrollBar、Window)。
角色:抽象工廠 (聲明多個創建方法)、具體工廠 (實現一族產品創建)、多組抽象/具體產品。
// 抽象工廠接口
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具體工廠族
public class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
public class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
}
三要素:私有構造器、靜態私有實例、靜態公有獲取方法。
線程安全寫法推薦 (雙重檢查鎖 DCL / 靜態內部類 / 枚舉):
// 1. 靜態內部類 (推薦:延遲加載、線程安全、簡潔)
public class Singleton {
private Singleton() {}
private static class Holder { static final Singleton INSTANCE = new Singleton(); }
public static Singleton getInstance() { return Holder.INSTANCE; }
}
// 2. 枚舉 (最簡潔、防反射/序列化破壞)
public enum SingletonEnum { INSTANCE; }
核心場景:構建復雜對象(參數多、有順序依賴、不可變對象)。將「構建過程」與「表示」分離。
角色:Product (產品)、Builder (抽象建造者)、ConcreteBuilder (具體建造者)、Director (指揮者/可選)。
// 產品類 (不可變)
public class User {
private final String name;
private final int age;
private final String email;
private final String address;
private User(Builder builder) { // 私有構造器
this.name = builder.name; this.age = builder.age;
this.email = builder.email; this.address = builder.address;
}
// 靜態內部建造者類
public static class Builder {
private String name; private int age; private String email; private String address;
public Builder name(String v) { name = v; return this; }
public Builder age(int v) { age = v; return this; }
public Builder email(String v) { email = v; return this; }
public Builder address(String v) { address = v; return this; }
public User build() { return new User(this); }
}
}
// 客戶端鏈式調用
User user = new User.Builder().name("Tom").age(25).email("tom@mail.com").build();
| 模式 | 核心意圖 | 適用場景 | 關鍵點 |
|---|---|---|---|
| 簡單工廠 | 集中創建邏輯 | 產品類較少、固定、客戶端不關心創建細節 | 靜態工廠方法,違反 OCP |
| 工廠方法 | 延遲創建到子類 | 框架設計、插件架構、需支持擴展新產品 | 一個工廠對應一個產品,符合 OCP |
| 抽象工廠 | 創建產品族 | 系統需支持多產品族切換(如跨平台 UI、多数據源適配) | 接口定義多個創建方法,產品族內部約束 |
| 單例 | 全局唯一實例 | 配置管理器、連接池、線程池、緩存管理器 | 私有構造、靜態內部類/枚舉實現 |
| 建造者 | 構建復雜對象 | 參數多、可選參數多、構建順序敏感、不可變對象 | 鏈式調用、Director 可選、與工廠區別在於「過程」 |
Calendar.getInstance() (工廠方法)、Collections.singletonList() (單例)、StringBuilder (建造者)、DocumentBuilderFactory (抽象工廠)。