一、什麼是代理模式 關於代理模式,我們聽到的見到的最多的可能就是靜態代理、動態代理之類的,當然還有大家都知道的Spring Aop,這裡我們先不談這些個代理,先說個簡單的例子。游戲代練應該都聽說過,許多人肯定也找過代練,曾經DNF、LOL、COC等等游戲的代練很多,當然現在各類游戲層出不窮,也都有各 ...
一、什麼是代理模式
關於代理模式,我們聽到的見到的最多的可能就是靜態代理、動態代理之類的,當然還有大家都知道的Spring Aop,這裡我們先不談這些個代理,先說個簡單的例子。游戲代練應該都聽說過,許多人肯定也找過代練,曾經DNF、LOL、COC等等游戲的代練很多,當然現在各類游戲層出不窮,也都有各種代練,那這裡所謂的代練是什麼?就是Proxy,也即代理類,那游戲代練這件事就是一個代理模式。
如果覺得不好理解可以這麼想,代練的流程是,你把自己的賬號交給代練人員,讓他們幫你打怪升級,而你只需要提供賬號即可。那代練人員那邊,他所要做的就是登陸你的賬號,然後替你打游戲,從第三者的角度來看,你這個角色在打怪升級,但這個第三者並不知道是不是你本人在打游戲,他只能看到你這個賬號正在打怪升級,但並不需要知道後面打游戲的是誰。這就是代理模式,由他人代理玩游戲。
如果覺得這個還不好理解,那再說一個例子。假設我現在要邀請明星來上節目,我是直接給這個明星打電話嗎?當然不是,是給他的經紀人打電話,然後再由經紀人通知到該明星,這裡經紀人充當的就是代理的角色。
更常見的例子就是Windows的快捷方式,通過快捷方式,我們可以訪問某個文件夾下的exe文件,這就是一個典型的代理模式,它將介面,按上面游戲的說法說就是代練的賬號,提供了出來,我們只需點擊快捷方式,它會幫我們運行指定目錄下的指定程式。說了這麼多,現在來看一下代理模式的定義。
代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。UML結構圖如下:
其中,Subject是主題角色,定義了RealSubject和Proxy的共同介面;RealSubject是具體主題角色,定義了Proxy所代表的真實實體;Proxy為代理主題角色,保存一個引用使代理可以訪問實體,並提供一個與Subject的介面相同的介面。
1. Subject抽象類
定義了RealSubject和Proxy的共同介面,這樣就在任何使用RealSubject的地方都可以使用Proxy。
1 public abstract class Subject { 2 3 public abstract void request(); 4 5 }
2. RealSubject類
定義了Proxy所代表的真實實體。
1 public class RealSubject extends Subject { 2 3 @Override 4 public void request() { 5 System.out.println("真實的請求RealSubject"); 6 } 7 8 }
3. Proxy類
代理類。一個代理類可以代理多個被委托者或被代理者,因此一個代理類具體代理哪個真實主題角色,是由場景類決定的。
1 public class Proxy extends Subject { 2 3 private RealSubject realSubject = null; 4 5 public Proxy() { 6 this.realSubject = new RealSubject(); 7 } 8 9 @Override 10 public void request() { 11 this.before(); 12 this.realSubject.request(); 13 this.after(); 14 } 15 16 //預處理 17 private void before() { 18 System.out.println("-------before------"); 19 } 20 21 //善後處理 22 private void after() { 23 System.out.println("-------after-------"); 24 } 25 }
4. Client客戶端
1 public class Client { 2 3 public static void main(String[] args) { 4 Proxy proxy = new Proxy(); 5 proxy.request(); 6 } 7 8 }
運行結果如下:
這個結果和Spring的AOP很類似,可以相互對照一下。
二、代理模式的應用
1. 何時使用
- 想在訪問一個類的時候做一些控制時
2. 方法
- 增加中間層
3. 優點
- 職責清晰。真實的角色就是實現實際的業務邏輯,不用擔心其他非本職責的事務
- 高擴展性。代理類完全可以在不做任何修改的情況下使用
- 智能化。比如動態代理
4. 缺點
- 有些類型的代理模式可能會造成請求的處理速度變慢
- 實現代理模式需要額外的工作,有些代理模式的實現非常複雜
5. 使用場景
- 遠程代理。為一個對象在不同的地址空間提供局部代表
- 虛擬代理。根據需要創建開銷很大的對象,通過它來存放實例化需要很長時間的真實對象
- 安全代理。用來控制真實對象訪問時的許可權
- 智能指引,當調用真實的對象時,代理處理另外一些事
6. 應用實例
- 游戲代練
- 邀請明星,聯繫其經紀人
- Windows快捷方式
- 火車票代售點
- Spring AOP
7. 註意事項
- 與適配器模式的區別:適配器模式主要改變所考慮對象的介面,而代理模式不能改變所代理類的介面
- 與裝飾模式區別:裝飾模式是為了增強功能,而代理模式是為了加以控制
三、代理模式的實現
這裡我們就以上面說過的游戲代練為例。UML圖如下:
1. IGamePlayer類
游戲玩家介面。由登陸、殺怪、升級三個方法。
1 public interface IGamePlayer { 2 //登陸 3 public void login(String user, String password); 4 //殺怪 5 public void killBoss(); 6 //升級 7 public void upgrade(); 8 }
2. GamePlayer類
游戲玩家。正常玩家登陸、打怪、升級。
1 public class GamePlayer implements IGamePlayer { 2 3 private String name = ""; 4 5 public GamePlayer(String name) { 6 this.name = name; 7 } 8 9 @Override 10 public void login(String user, String password) { 11 System.out.println("登錄名為<" + user + ">的用戶<" + this.name + ">登陸成功!"); 12 } 13 14 @Override 15 public void killBoss() { 16 System.out.println("<" + this.name + ">在打怪!"); 17 } 18 19 @Override 20 public void upgrade() { 21 System.out.println("<" + this.name + ">升了一級!"); 22 } 23 24 }
3. GamePlayerProxy類
游戲代練。也即代理類,用於代替玩家登陸、打怪、升級。
1 public class GamePlayerProxy implements IGamePlayer { 2 3 private IGamePlayer gamePlayer = null; 4 5 public GamePlayerProxy(IGamePlayer gamePlayer) { 6 this.gamePlayer = gamePlayer; 7 } 8 9 @Override 10 public void login(String user, String password) { 11 this.gamePlayer.login(user, password); 12 } 13 14 @Override 15 public void killBoss() { 16 this.gamePlayer.killBoss(); 17 } 18 19 @Override 20 public void upgrade() { 21 this.gamePlayer.upgrade(); 22 } 23 24 }
4. Client客戶端
玩家找了一個代練,代練登陸了該玩家的賬號,然後替該玩家打怪升級。
1 public class Client { 2 3 public static void main(String[] args) { 4 //定義一個玩家 5 IGamePlayer player = new GamePlayer("桐人"); 6 //定義一個代練 7 IGamePlayer proxy = new GamePlayerProxy(player); 8 9 //開始打游戲 10 //登陸 11 proxy.login("adam", "123456"); 12 //開始殺怪 13 proxy.killBoss(); 14 //升級 15 proxy.upgrade(); 16 } 17 18 }
運行結果如下:
從這個結果我們只能看到有人登陸了這個賬號,他正在打怪升級,但並不知道是不是代練,這就是代理模式。
源碼地址:https://gitee.com/adamjiangwh/GoF