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

Java 設計模式實戰:Proxy 代理模式三種實作方式完整解析(靜態/動態/AOP)

     編輯:Java 相關知識

代理模式核心概念

代理模式:為其他物件提供一個代理以控制對該物件的存取。就像打官司請律師,律師在法律領域有專長,可替當事人操作表達意願。

兩大分類

類型建立時機特點
靜態代理程式設計師建立/編譯期代理類 .class 檔案在執行前就存在;代理與委託關係在執行前確定
動態代理JVM 運行期(反射)無代理類 .class 檔案;代理與委託關係在運行時確定;基於 InvocationHandler + Proxy

完整程式碼實作:遊戲代練場景

1. 共用介面與真實物件

public interface IGamePlayer {
    void login(String user, String password);
    void killBoss();
    void upgrade();
}

public class GamePlayer implements IGamePlayer {
    private String name;
    public GamePlayer(String name) { this.name = name; }

    public void killBoss() { System.out.println(name + " 在打怪!"); }
    public void login(String user, String password) { 
        System.out.println("登入帳號 " + user + " 的角色 " + name + " 登入成功!"); 
    }
    public void upgrade() { System.out.println(name + " 又升了一級!"); }
}

2. 靜態代理:基本代練

public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer gamePlayer;
    public GamePlayerProxy(String username) { 
        this.gamePlayer = new GamePlayer(username); 
    }
    public void killBoss() { gamePlayer.killBoss(); }
    public void login(String user, String password) { gamePlayer.login(user, password); }
    public void upgrade() { gamePlayer.upgrade(); }
}

3. 靜態代理:功能增強(記錄時間)

public class GamePlayerProxy2 implements IGamePlayer {
    private IGamePlayer gamePlayer;
    public GamePlayerProxy2(String username) { 
        this.gamePlayer = new GamePlayer(username); 
    }
    public void killBoss() { gamePlayer.killBoss(); }
    public void login(String user, String password) { 
        System.out.println("登入時間:" + new Date()); 
        gamePlayer.login(user, password); 
    }
    public void upgrade() { 
        gamePlayer.upgrade(); 
        System.out.println("升級時間:" + new Date()); 
    }
}

4. 動態代理:JDK Proxy 實作 AOP 切面

public class GamePlayerProxy3 {
    private IGamePlayer gamePlayer;
    public GamePlayerProxy3(IGamePlayer gamePlayer) { 
        this.gamePlayer = gamePlayer; 
        System.out.println("我是代練,角色是別人的,可動態傳遞"); 
    }

    public IGamePlayer getProxy() {
        return (IGamePlayer) Proxy.newProxyInstance(
            this.getClass().getClassLoader(),
            new Class[]{IGamePlayer.class},
            new MyInvocationHandler()
        );
    }

    private class MyInvocationHandler implements InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("login")) {
                System.out.println("登入時間:" + new Date());
            }
            if (method.getName().equals("upgrade")) {
                System.out.println("升級時間:" + new Date());
            }
            return method.invoke(gamePlayer, args); // 反射調用真實物件
        }
    }
}

5. 客戶端測試

public class Test {
    public static void main(String[] args) {
        // 靜態代理基本
        IGamePlayer proxy = new GamePlayerProxy("X");
        proxy.login("zhangSan", "abcd");
        proxy.killBoss();
        proxy.upgrade();

        // 靜態代理增強
        IGamePlayer proxy2 = new GamePlayerProxy2("M");
        proxy2.login("lisi", "efg");
        proxy2.killBoss();
        proxy2.upgrade();

        // 動態代理(AOP)
        GamePlayerProxy3 dynamic = new GamePlayerProxy3(new GamePlayer("Y"));
        IGamePlayer dynamicPlayer = dynamic.getProxy();
        dynamicPlayer.login("wangwu", "1234");
        dynamicPlayer.killBoss();
        dynamicPlayer.upgrade();
    }
}

執行輸出

登入帳號 zhangSan 的角色 X 登入成功!
X 在打怪!
X 又升了一級!
登入時間:2024-01-15 10:30:00
登入帳號 lisi 的角色 M 登入成功!
M 在打怪!
M 又升了一級!
升級時間:2024-01-15 10:30:00
我是代練,角色是別人的,可動態傳遞
登入時間:2024-01-15 10:30:00
登入帳號 wangwu 的角色 Y 登入成功!
Y 在打怪!
升級時間:2024-01-15 10:30:00
Y 又升了一級!

代理模式三大優勢

  1. 職責清晰:真實角色專注業務邏輯,非本職事務(日誌、權限、事務)交由代理處理
  2. 中介保護:代理位於客戶端與目標物件之間,可隱藏實作細節、控制存取權限
  3. 高擴展性:動態代理配合反射實現 AOP,可在不修改原始碼前提下橫向擴展功能(事務、快取、監控)

Spring AOP 與動態代理的關聯

Spring AOP 底層正是基於 JDK 動態代理(介面代理)與 CGLIB(類別代理)實現。InvocationHandler.invoke() 對應 AOP 中的「通知」,方法名匹配對應「切點」,從而實現日誌、事務、權限等橫切關注點的解耦。

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