裝飾器模式 是結構型模式經典實踐,通過包裝器在運行時動態給對象添加職責,避免了繼承導致的類爆炸與靜態綁定。本文以「形狀添加紅色邊框」為例,完整展示接口定義、抽象裝飾器、具體裝飾器、客戶端使用,並分析核心角色、優缺點、適用場景及 JDK 實戰應用。
Shape 接口,定義 draw()。Circle、Rectangle 實現 Shape。ShapeDecorator 實現 Shape,持有 Shape 引用,轉發請求。RedShapeDecorator 擴展 ShapeDecorator,在 draw() 前後添加紅框邏輯。// 1. Component
public interface Shape { void draw(); }
// 2. ConcreteComponent
public class Circle implements Shape {
@Override public void draw() { System.out.println("Shape: Circle"); }
}
public class Rectangle implements Shape {
@Override public void draw() { System.out.println("Shape: Rectangle"); }
}
// 3. Decorator (抽象裝飾器)
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape) { this.decoratedShape = decoratedShape; }
@Override public void draw() { decoratedShape.draw(); } // 默認轉發
}
// 4. ConcreteDecorator
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); }
@Override public void draw() {
decoratedShape.draw(); // 核心功能
setRedBorder(decoratedShape); // 新增功能
}
private void setRedBorder(Shape shape) { System.out.println("Border Color: Red"); }
}
// 5. Client
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border"); circle.draw();
System.out.println("\nCircle of red border"); redCircle.draw();
System.out.println("\nRectangle of red border"); redRectangle.draw();
}
}
Circle with normal border Shape: Circle Circle of red border Shape: Circle Border Color: Red Rectangle of red border Shape: Rectangle Border Color: Red
| 維度 | 說明 |
|---|---|
| 核心原則 | 開閉原則:對擴展開放(新增裝飾器),對修改關閉(不動原類)。 |
| 關鍵技術 | 組合 + 委派:裝飾器持有被裝飾者引用,接口一致,透明轉發。 |
| 動態性 | 運行時任意組合:new RedBorder(new BlueBorder(new Circle())) 疊加多層裝飾。 |
| 優點 | 1. 靈活擴展,避免繼承爆炸。2. 單一職責,每個裝飾器只管一項功能。3. 可運行時動態組合。 |
| 缺點 | 1. 產生大量小對象,增加 GC 壓力。2. 多層裝飾調試困難(調用棧深)。3. 破壞具體類型身份 (instanceof 失效)。 |
| 適用場景 | 1. 動態增強/撤銷功能。2. 職責疊加組合 (IO 流、日志、權限、緩存、壓縮、加密)。3. 無法繼承類 (final 類) 需擴展。 |
// 裝飾器鏈:文件 → 緩衝 → 數據類型 → 對象序列化
InputStream is = new ObjectInputStream(
new DataInputStream(
new BufferedInputStream(
new FileInputStream("data.bin"))));
// 每層裝飾器添加一項能力:緩衝、基本類型讀取、對象反序列化
// 所有類均繼承自 InputStream (Component),構造器接收 InputStream (Decorator)
其他 JDK 例子:Collections.synchronizedList() (同步裝飾)、Collections.unmodifiableList() (只讀裝飾)、HttpServletRequestWrapper (請求包裝)。