👈?上一篇:創建型設計模式對比 ? ?|?? 下一篇:裝飾器模式👉?
目 錄
- 代理模式
- 定義
- 英文原話
- 直譯
- 如何理解?
- 3個角色
- UML類圖
- 1. 抽象主題(Subject)角色
- 2. 代理類:代理主題(Proxy Subject)角色
- 3. 被代理類:真實主題(Real Subject)角色
- 代碼示例
- 1. 真實主題,被代理類
- 2. 抽象主題
- 3. 代理類
- 4. 測試類
- 代理模式的種類
- 代理模式的優點
- 示例解析:玩游戲打怪、升級示例
- UML類圖
- 1. 真實主題RealSubject:GamePlayer實現IGamePlayer接口中的方法
- 抽象主題Subject:IGamePlayer接口對游戲玩家進行抽象
- 代理主題ProxySubject:GamePlayerProxy是代理類
- 測試類
代理模式
定義
英文原話
Provide a surrogate or placeholder for another object to control access to it.
直譯
為另一個對象提供代理或占位符以控制對它的訪問
如何理解?
字面上不好理解的話可以結合代碼進一步理解下,從具體實現上分析:
抽象主題角色,是對被代理類的抽象,被代理類就看作是對抽象主題角色類的實現,被代理類的實現就是核心功能的實現
同時,代理對象中持有被代理對象的引用,
代理類也實現了被代理類相同的接口,
這樣,通過代理類可以增強被代理類的邏輯,
在被代理對象的邏輯前后可以增加一些邏輯,比如獲取請求參數,添加日志等,這些非核心的邏輯,可以在代理類中進行增強。
代理模式應用非常廣泛,大到一個系統框架、企業平臺,小到事務處理、代碼片段,隨處可見代理模式的使用,例如,Java RMI的遠程調用就是一種代理模式的應用,AOP也可以通過代理模式實現。
3個角色
UML類圖
1. 抽象主題(Subject)角色
該角色是真實主題和代理主題的共同接口,以便在任何可以使用真實主題的地方都可以使用代理主題。
2. 代理類:代理主題(Proxy Subject)角色
也叫做委托類、代理類,該角色負責控制對真實主題的引用,負責在需要的時候創建或刪除真實主題對象,并且在真實主題角色處理完畢前后做預處理和善后處理工作。
3. 被代理類:真實主題(Real Subject)角色
該角色也叫做被委托角色、被代理角色,是業務邏輯的具體執行者。
代碼示例
1. 真實主題,被代理類
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;public class Target implements AbstractSubject {@Overridepublic void m1() {System.out.println("target implements. Core business logic");}
}
2. 抽象主題
抽取核心業務邏輯接口方法m1()
出來,該方法源自被代理對象,因此被代理類的m1()
方法就可以看作是對它的實現,被代理類添加 implements AbstractSubject
表示對抽象主題的實現;
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;public interface AbstractSubject {void m1();
}
3. 代理類
代理被代理的類,對被代理類的邏輯(抽象主題進行了抽象)進行增強,
前提是代理類實現了抽象主題的抽象方法,同時持有被代理類的對象(可通過構造函數傳入)
注意這里的構造函數傳入的是Target實例,更通用的可以使用抽象主題角色AbstractSubject
類型;
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;public class Proxy implements AbstractSubject {private Target target;public Proxy(Target target) {this.target = target;}@Overridepublic void m1() {before();target.m1();after();}private void before() {System.out.println("enhanced logic: before...");}private void after() {System.out.println("enhanced logic: after...");}
}
4. 測試類
package com.polaris.designpattern.list2.structural.pattern1.proxy.proto;public class DemoTest {public static void main(String[] args) {Target target = new Target();Proxy proxy = new Proxy(target);proxy.m1();}
}/* Output:
enhanced logic: before...
target implements. Core business logic
enhanced logic: after...
*///~
代理模式的種類
簡單了解一下:
- 遠程(Remote)代理:為一個位于不同的地址空間的對象提供一個局部代表對象。這個不同的地址空間可以是在本機器中,也可以在另一臺機器中。
- 虛擬(Virtual**)**代理:有時需要創建一些消耗較多資源的對象,可以首先創建代理對象,而將真實對象的創建延遲。例如,加載一個很大的圖片,可以通過圖片的代理來代替真正的圖片。
- 保護(Protect or Access)代理:控制對一個對象的訪問,如果需要,可以給不同的用戶提供不同級別的使用權限。
- 緩存(Cache)代理:為某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以共享這些結果。
- 同步(Synchronization)代理:使幾個用戶能夠同時使用一個對象而沒有沖突。
- 智能引用(Smart Reference)代理:當一個對象被引用時,提供一些額外的操作,例如,記錄訪問的流量和次數等。
代理模式的優點
- 職責清晰:真實的角色實現實際的業務邏輯,不用關心其他非本職的事務,通過后期的代理完成附加的事務,附帶的結果就是編程簡潔清晰。
- 高擴展性:具體主題角色隨需求不同可能有很多種,但只要實現了接口,代理類就完全可以在不做任何修改的情況下代理各種真實主題角色。
- 智能化:代理類可以在運行時才確定需要去代理的真實主題,這是一種強大的功能。
示例解析:玩游戲打怪、升級示例
UML類圖
- 主題類和代理類同時實現接口
- 主題類,就是被代理類,完成主要業務邏輯
- 附加業務在代理類中完成
- 客戶端調用:
- 聲明接口的兩個示例分別指向主題類與代理類的實例對象;
- 其中,在代理類示例創建時傳入主題類的實例(參數類型可以放大,參數定義為接口類型,當然主題類實現類此接口,屬于此接口類型,可以被傳入)。
1. 真實主題RealSubject:GamePlayer實現IGamePlayer接口中的方法
被代理類的具體實現,是最核心的業務邏輯,這里玩游戲最核心的就是打怪,升級;
package com.polaris.designpattern.list2.structural.pattern1.proxy;public class GamePlayer implements IGamePlayer {private String name = "";public GamePlayer(String name) {this.name = name;}@Overridepublic void killBoss() {System.out.println(this.name + "在打怪!");}@Overridepublic void upGrade() {System.out.println(this.name + "成功升了1級!");}
}
抽象主題Subject:IGamePlayer接口對游戲玩家進行抽象
抽象主題,抽象出
打怪
、升級
兩個核心業務邏輯,方便代理類進行實現,增強被代理類的邏輯
package com.polaris.designpattern.list2.structural.pattern1.proxy;public interface IGamePlayer {//殺怪void killBoss();//升級void upGrade();
}
代理主題ProxySubject:GamePlayerProxy是代理類
代理主題,在被代理類的核心業務邏輯實現(打怪、升級)的基礎上增加非核心業務邏輯:加日志、計時,
因此代理類是對被代理類的增強、強化
他持有被代理類的引用,通過構造函數初始化
package com.polaris.designpattern.list2.structural.pattern1.proxy;import java.util.Date;public class GamePlayerProxy implements IGamePlayer {private IGamePlayer player = null;public GamePlayerProxy(IGamePlayer player) {this.player = player;}//記錄打怪的時間private void log() {System.out.println("打怪時間 " + new Date().toString());}@Overridepublic void killBoss() {this.log();player.killBoss();}@Overridepublic void upGrade() {player.upGrade();this.countTime();}//計時private void countTime() {System.out.println("升1級耗時50小時");}}
測試類
package com.polaris.designpattern.list2.structural.pattern1.proxy;public class DemoTest {public static void main(String[] args) {IGamePlayer player = new GamePlayer("李逍遙");IGamePlayer proxy = new GamePlayerProxy(player);proxy.killBoss();proxy.upGrade();}
}/* Output:
打怪時間 Mon May 20 23:35:58 CST 2024
李逍遙在打怪!
李逍遙成功升了1級!
升1級耗時50小時
*///~
👈?上一篇:創建型設計模式對比 ? ?|?? 下一篇:裝飾器模式👉?