代理模式(Proxy Pattern)。
定義:
為其他物件一種代理以控制對這個物件的訪問。
代理模式也叫作委託模式,它是一項基本設計技巧,許多其他模式,如狀態模式、策略模式、訪問者模式本質上是在更特殊的場合採用了委託模式,而且在日常的應用中,代理模式提供非常好的訪問控制。在一些著名的開元然間中也經常見到他的身影,如Struts2的Form元素對映就採用了代理模式(準確的說是動態代理模式)。
通用程式碼:
抽象主題類
抽象主題類可以是抽象類也可以是介面,是一個最普通的業務型別定義,無特殊要求。
public interface Subject {
// 定義一個方法
public void request();
}
真實主題類
也叫作被委託角色,被代理角色,是業務邏輯的具體執行者。
publc class RealSubject implements Subject {
// 實現方法
public void request() {
// 業務邏輯處理
}
}
代理類
也叫作委託類、代理類。它負責對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做預處理和善後處理工作。
public class Proxy implements Subject { // 要代理哪個實現類 private Subject subject = null; // 預設被代理類 public Proxy() { this.subject = new Proxy(); } // 通過建構函式傳遞代理者 public Proxy(Object... objects) {} // 實現介面中定義的方法 public void request() { this.before(); this.subject.request(); this.after(); } // 預處理 public void before() { // do Something } // 善後處理 public void after() { // do Something } }
一個代理類可以代理多個被委託者或被代理者,因此一個代理類具體代理哪個真實主題角色,是由場景類決定的。當然,最簡單的情況就是一個主題類和一個代理類,這是最簡單的代理模式。在通常情況下,一個介面只需要一個代理類就可以了,具體代理哪個實現類由高層模組來決定,也就是在代理的建構函式中傳遞被代理類,你要代理誰就產生該代理的例項,然後把被代理者傳遞進來,該模式在實際的專案應用中使用比較廣泛。
優點:
- 職責清晰
真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件事務,附帶的結果就是編碼簡潔清晰。
- 高擴充套件性
具體主題角色是隨時都會發生變化的,只要它實現了介面,甭管他如何變化,都逃不脫如來佛的手掌(介面),那我們的代理完全就可以在不做任何修改的情況下使用。
- 智慧化
例如Struts是如何把表單元素對映到物件上的。
使用場景:
代理模式的使用場景非常多,大家可以看看Spring AOP,這是一個非常典型的動態代理。
擴充套件:
1、普通代理
普通代理是我們要知道代理的存在,然後才能訪問;
2、強制代理
強制代理是呼叫者直接呼叫真是角色,而不用關心代理是否存在,其代理的產生是由真是角色決定的。
3、代理是有個性的
4、動態代理
最佳實踐:
代理模式應用的非常廣泛,大到一個系統框架、企業平臺,小到程式碼片段、事務處理,稍不留意就用到代理模式。可能該模式是大家接觸最多的模式,而且有了AOP大家寫代理就更加簡單了,有類似Spring AOP和AspectJ這樣非常優秀的工具,拿來主義即可!不過大家可以看看原始碼,特別是除錯時,只要看到類似$Proxy()這樣的結構,你應該知道這是一個動態代理了。
程式碼案例:
遊戲者介面
public interface IGamePlayer {
// 登入遊戲
public void login(String user,String password);
// 殺怪,網路遊戲的主要特色
public void killBoss();
// 升級
public void upgrade();
}
遊戲者
public GamePlayer implements IGamePlayer {
private String name ="";
// 通過建構函式傳遞名稱
public GamePlayer(String _name) {
this.name = _name;
}
// 打怪,最期望的就是殺boss
public void killBoss() {
System.out.println(this.name +"在打怪!");
}
// 進遊戲之前你肯定要登入吧,這是一個必要條件
public void login(String user, String password) {
System.out.println("登入名為" + user + "的使用者" + this.name + "登入成功!");
}
// 升級,升級有很多方法,花錢買是一種,做任務也是一種
public void upgrade() {
System.out.println(this.name + " 又升級了!");
}
}
代練者
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
// 通過建構函式傳遞要對誰進行代練
public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}
// 代練殺怪
public void killBoss() {
this.gamePlayer.killBoss();
}
// 代練登入
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
}
場景類
public class Client {
public static void main(String[] args) {
// 定義一個痴迷的玩家
IGamePlayer player = new GamePlayer("張三");
// 然後再定義一個代練者
IGamePlayer proxy = new GamePlayerProxy(player);
// 開始打遊戲,記下時間戳
System.out.println("開始時間是:2017-01-01 23:27");
proxy.login("zhangSan","password");
// 開始殺怪
proxy.killBoss();
// 升級
proxy.upgrade();
// 記錄結束遊戲時間
System.out.println("結束時間是:2017-01-02 01:30");
}
}
普通代理的遊戲者
public class GamePlayer implements IGamePlayer {
private String name ="";
// 建構函式限制誰能建立物件
public GamePlayer(IGamePlayer _gamePlayer, String _name) throws Exception {
if(_gamePlayer == null) {
throws new Exception("不能建立真實角色!");
} else {
this.name = _name;
}
}
// 打怪,最期望的就是殺老怪
public void killBoss() {
System.out.println(this.name +"在打怪!");
}
// 進遊戲之前你肯定要登入吧,這是一個必要條件
public void login(String user, String password) {
System.out.println("登陸名為" + user + "的使用者" + this.name + "登入成功!");
}
// 升級,升級有很多方法,花錢買也是一種,做任務也是一種
public void upgrade() {
System.out.println(this.name + "又升了一級!");
}
}
// 普通代理的代理者
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
// 通過建構函式傳遞要對誰進行代練
public GamePlayerProxy(String name) {
try{
gamePlayer = new GamePlayer(this.name);
} catch (Exception e) {
// TDO 異常處理
}
}
// 打怪,最期望的就是殺老怪
public void killBoss() {
this.gamePlayer.killBoss();
}
// 進遊戲之前你肯定要登入吧,這是一個必要條件
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
// 升級,升級有很多方法,花錢買也是一種,做任務也是一種
public void upgrade() {
this.gamePlayer.upgrade();
}
}
// 普通代理的場景類
public class Client {
public static void main(String[] args) {
// 然後再定義一個代練者
IGamePlayer proxy = new GamePlayerProxy("張三");
// 開始打遊戲,記下時間戳
System.out.println("開始時間是:2017-01-01 23:27");
proxy.login("zhangSan","password");
// 開始殺怪
proxy.killBoss();
// 升級
proxy.upgrade();
// 記錄結束遊戲時間
System.out.println("結束時間是:2017-01-02 01:30");
}
}
// 強制代理的介面類
public interface IGamePlayer {
// 登入遊戲
public void login(String user , String password);
// 殺怪,這是網路遊戲的 主要特色
public void killBoss();
//升級
public void upgrade();
// 每個人都可以找一下自己的代理
public IGamePlayer getProxy();
}
// 強制代理的真實角色
public class GamePlayer Implements IGamePlayer {
private String name = "";
// 我的代理是誰
private IGamePlayer proxy = null;
public GamePlayer(String _name) {
this.name = _name;
}
// 找到自己的代理
public IGamePlayer getProxy() {
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
// 打怪,最期望的是殺老怪
public void killBoss() {
if(this.isProxy()) {
System.out.println(this.name + "在打怪!");
} else {
System.out.println("請使用指定的代理訪問");
}
}
// 進遊戲之前你肯定要登入遊戲吧,這是一個必要條件
public void login(String user , String password) {
if(this.isProxy()) {
System.out.println("登陸名為" + user + "的使用者" + this.name + "登入成功!");
} else {
System.out.println("請使用指定的代理訪問");
}
}
// 升級,升級有很多方法,花錢買是一種,做任務也是一種
public void upgrade(){
if(this.isProxy()) {
System.out.println(this.name + " 又升了一級!");
} else {
System.out.println("請使用指定的代理訪問");
}
}
// 校驗是否是代理訪問
private boolean isProxy() {
if(this.proxy == null) {
return false;
} else {
return true;
}
}
}
// 強制代理的代理者
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
// 通過建構函式傳遞要對誰進行代練
public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}
// 打怪,最期望的就是殺老怪
public void killBoss() {
this.gamePlayer.killBoss();
}
// 進遊戲之前你肯定要登入吧,這是一個必要條件
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
// 升級,升級有很多方法,花錢買也是一種,做任務也是一種
public void upgrade() {
this.gamePlayer.upgrade();
}
// 代理的代理暫時還沒有,就是自己
public IgamePlayer getProxy() {
return this;
}
}
// 強制代理的場景類
public class Client {
public static void main(String[] args) {
// 定義一個遊戲的角色
IGamePlayer player = new GamePlayer("張三");
// 獲得指定的代理
IGamePlayer proxy = player.getProxy();
// 開始打遊戲,記下時間戳
System.out.println("開始時間是:2017-01-01 23:27");
proxy.login("zhangSan","password");
// 開始殺怪
proxy.killBoss();
// 升級
proxy.upgrade();
// 記錄結束遊戲時間
System.out.println("結束時間是:2017-01-02 01:30");
}
}
// 代理是有個性的
代理類的介面
public interface IProxy {
// 計算費用
public void count();
}
// 代理類
public class GamePlayerProxy implements IGamePlayer, IProxy {
private IGamePlayer gamePlayer = null;
// 通過建構函式傳遞要對誰進行代練
public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}
// 代練殺怪
public void killBoss() {
this.gamePlayer.killBoss();
}
// 代練登入
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
// 代練升級
public void upgrade() {
this.gamePlayer.upgrade();
this.count();
}
// 計算費用
public void count() {
System.out.println("升級總費用是:150元");
}
}