首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

裝飾器模式深度解析:從繼承臃腫到組合靈活的 Java 實戰重構

     編輯:Java 程式設計入門

裝飾器模式以組合替代繼承,動態為對象添加職責,是開閉原則的經典實踐。本文對比繼承與裝飾兩種擴展方式,透過房屋裝修、IO 流、自定義裝飾器三個層級案例,展示模式核心價值與實戰技巧。

核心痛點:繼承導致的類爆炸

場景:房屋風格裝修

// 繼承方案:類爆炸
abstract class House { abstract void show(); }
class PingFang extends House { void show() { print("平房"); } }
class LouFang extends House { void show() { print("樓房"); } }

// 想加田園風格?
class TianYuanPingFang extends PingFang { void show() { super.show(); print("田園"); } }
class TianYuanLouFang extends LouFang { void show() { super.show(); print("田園"); } }

// 想再加歐式風格?再加 2 個類...
// 組合數 = 房屋類型 × 風格類型,指數級增長

裝飾器模式重構

核心結構

  • Component:抽象構件介面 (House)
  • ConcreteComponent:具體構件 (PingFang, LouFang)
  • Decorator:抽象裝飾器,持有 Component 引用
  • ConcreteDecorator:具體裝飾器 (TianYuan, OuShi)

實現代碼

// 抽象構件
abstract class House {
    public abstract void show();
}

// 具體構件
class PingFang extends House {
    public void show() { System.out.print("平房"); }
}
class LouFang extends House {
    public void show() { System.out.print("樓房"); }
}

// 抽象裝飾器
abstract class HouseDecorator extends House {
    protected House house;
    public HouseDecorator(House house) { this.house = house; }
    public void show() { house.show(); } // 默認委派
}

// 具體裝飾器:田園風格
class TianYuan extends HouseDecorator {
    public TianYuan(House house) { super(house); }
    @Override public void show() {
        super.show(); // 執行被裝飾對象邏輯
        System.out.print(" + 田園風格");
    }
}

// 具體裝飾器:歐式風格
class OuShi extends HouseDecorator {
    public OuShi(House house) { super(house); }
    @Override public void show() {
        super.show();
        System.out.print(" + 歐式風格");
    }
}

// 客戶端:靈活組合
public class DecoratorDemo {
    public static void main(String[] args) {
        House house = new PingFang();
        house = new TianYuan(house);      // 平房 + 田園
        house = new OuShi(house);         // 平房 + 田園 + 歐式
        house.show(); // 輸出:平房 + 田園風格 + 歐式風格
    }
}

JDK 經典應用:IO 流體系

// 裝飾器鏈:節點流 + 多層處理流
InputStream in = new FileInputStream("data.txt");     // 節點流
in = new BufferedInputStream(in);                     // 緩衝裝飾
in = new DataInputStream(in);                         // 數據類型讀取裝飾
in = new GZIPInputStream(in);                         // 解壓裝飾

// 每層裝飾器增強單一職責,靈活組合
// new BufferedReader(new InputStreamReader(new FileInputStream(...)))

設計精髓:FilterInputStream 為抽象裝飾器,持有 InputStream in,各具體裝飾器 (BufferedInputStream, DataInputStream) 僅關注單一增強邏輯。

自定義場景:日誌增強器

interface Logger { void log(String msg); }

class ConsoleLogger implements Logger {
    public void log(String msg) { System.out.println(msg); }
}

abstract class LoggerDecorator implements Logger {
    protected Logger logger;
    public LoggerDecorator(Logger logger) { this.logger = logger; }
    public void log(String msg) { logger.log(msg); }
}

class TimestampDecorator extends LoggerDecorator {
    public TimestampDecorator(Logger logger) { super(logger); }
    @Override public void log(String msg) {
        logger.log("[" + LocalDateTime.now() + "] " + msg);
    }
}

class LevelDecorator extends LoggerDecorator {
    private String level;
    public LevelDecorator(Logger logger, String level) { super(logger); this.level = level; }
    @Override public void log(String msg) {
        logger.log("[" + level + "] " + msg);
    }
}

// 使用:控制台 + 時間戳 + INFO 級別
Logger logger = new LevelDecorator(new TimestampDecorator(new ConsoleLogger()), "INFO");
logger.log("服務啟動"); // [2024-01-15T10:30:00] [INFO] 服務啟動

裝飾器 vs 繼承 vs 代理 vs 適配器

模式核心意圖關系關鍵差異
裝飾器動態添加職責組合 (has-a)透明擴展,支援疊加,遵循開閉原則
繼承靜態擴展繼承 (is-a)編譯期固定,類爆炸,破壞封裝
代理控制訪問組合代理生命週期通常與被代理綁定,不疊加
適配器介面轉換組合/繼承事後補救,使不兼容介面協同工作

最佳實踐提醒

  1. 裝飾器與被裝飾對象同一介面,客戶端無感知
  2. 避免過度裝飾:層數超過 3-4 層考慮重構
  3. 裝飾器不應依賴具體構件類型,只依賴抽象介面
  4. 不可變對象裝飾:返回新對象而非修改原對象
  5. Spring @Decorator / CDI @Decorator:框架級支援聲明式裝飾
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved