首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

設計模式面試必考:代理模式 vs 裝飾器模式,核心區別與實戰場景深度解析

     編輯:程式設計疑難解答

代碼長得像、結構長得像,面試官一問「區別在哪」,許多候選人支支吾吾。本文從對象持有方式、控制權歸屬、核心意圖三個維度,徹底劃清界限,並對應 Spring AOP、IO 流、權限控制等經典實戰場景。

一張表看懂核心區別

維度代理模式裝飾器模式
被代理/裝飾對象來源代理類內部 new 或注入,客戶端不知情客戶端主動傳入,必須知曉被裝飾者
對象生命週期控制代理控制創建/銷毀/訪問權限客戶端控制,裝飾器只負責「加衣服」
核心意圖控制訪問:延遲加載、權限攔截、遠程調用、緩存增強職責:動態添加行為、組合功能、不修改原類
方法調用鏈可阻斷調用(如權限不足直接返回)必須轉發給被裝飾者(裝飾前/後增強)
典型介面設計代理與被代理實現同一介面裝飾器實現同一介面,持有介面引用

代碼層面的關鍵差異

代理模式:控制訪問

public class UserServiceProxy implements UserService {
    private UserService target = new UserServiceImpl(); // 內部持有,客戶端不知情
    
    public void save(User user) {
        if (!SecurityUtils.hasPermission("user:save")) {
            throw new AccessDeniedException("無權限"); // 可阻斷
        }
        target.save(user); // 選擇性調用
    }
}

裝飾器模式:增強職責

public class LoggingInputStream extends InputStream {
    private InputStream decorated; // 必須傳入
    
    public LoggingInputStream(InputStream decorated) {
        this.decorated = decorated;
    }
    
    public int read() {
        int b = decorated.read(); // 必須轉發
        log.info("讀取字節: {}", b); // 前/後增強
        return b;
    }
}

實戰場景對號入座

✅ 代理模式經典場景

  • Spring AOP: JDK 動態代理/CGLIB 代理目標 Bean,織入事務、日誌、權限切面(控制調用)。
  • Hibernate 懶加載: 代理實體類,首次訪問關聯屬性時觸發 SQL 查詢(延遲加載)。
  • RPC 框架: 客戶端持有遠程服務的 Stub 代理,本地調用實為網路通信(遠程代理)。
  • 緩存代理: 先查 Redis,未命中再調用真實服務(訪問控制)。

✅ 裝飾器模式經典場景

  • Java IO 流: BufferedInputStream 裝飾 FileInputStream 添加緩衝;GZIPInputStream 添加解壓(動態組合功能)。
  • Spring TransactionInterceptor: 雖名為 Interceptor,實質是裝飾器,在方法前開啟事務、後提交/回滾(增強行為)。
  • Web 請求處理鏈: Filter/Interceptor 鏈,每個環節裝飾請求/響應(添加 Header、壓縮、加密)。
  • GUI 組件裝飾: Swing JScrollPane 裝飾 JTextArea 添加滾動條。

面試加分回答模板

「兩者結構相似,但意圖本質不同:

代理關注訪問控制,代理類決定是否、何時、如何調用真實對象,客戶端往往不知道代理存在(如 Spring Bean 代理)。

裝飾器關注職責疊加,客戶端主動組合裝飾器鏈,每個裝飾器必須轉發調用並在前後增強,不改變被裝飾者接口契約(如 IO 流)。

判斷技巧:若客戶端必須感知並決定裝飾順序 → 裝飾器;若框架透明植入、客戶端無感 → 代理。」

避坑指南

  • 不要為了用模式而用模式:簡單的 if-else 權限判斷不需要代理類。
  • 裝飾器層級過深(>3 層)會導致調試困難,考慮組合優於繼承重構。
  • Spring 中 @Transactional 失效常見原因:內部方法調用繞過代理,本質是代理模式「自我調用不走代理」的限制。

下次面試被問到,直接甩出「控制權在誰手裡、能不能阻斷調用、客戶端知不知情」三連問,再配上 Spring AOP vs IO 流兩大經典案例,穩拿設計模式考察分。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved