概念:代理模式就是爲其餘對象提供一種代理以控制對這個對象的訪問。安全
現實生活中也有不少行爲吻合代理模式。好比店外賣,客戶在APP上下單後,店長會接單。這個時候店長能夠選擇本身去送這份外賣,也能夠委託送餐員代理店長去送這份外賣。固然店長是能夠本身送,但店長送了外賣店就沒人看着了,而讓送餐員代理送外賣就不會這樣了。這裏很顯然店長是對象本尊(Subject),送餐員是代理對象(Proxy ),代理對象中有店長給的訂單信息,好比送到哪裏,幾點以前要送到,這就說明代理對象中須要包含本尊。下面根據實際代碼來講明代理模式和非代理的具體實現。ide
非代理模式即店長本身送,無須委託送餐員代理送。即直接建立本尊對象並訪問本尊方法,沒有中間的代理對象。測試
本尊代碼this
public class ShopKeeper { //客戶信息 private Consumer consumer; public ShopKeeper(Consumer consumer){ this.consumer = consumer; } //外賣訂單信息 public void send(){ System.out.println(consumer.getConName() + "的訂單,店長本身送,送到膠東路520弄,11:30以前送達..."); } }
客戶代碼spa
public class Consumer { private String conName; public Consumer(String conName){ this.conName = conName; } public String getConName() { return conName; } }
客戶端測試代碼代理
public class Show { public static void main(String[] args) { Consumer consumer = new Consumer("Tom"); ShopKeeper shopKeeper = new ShopKeeper(consumer); shopKeeper.send(); } }
這樣店長和客戶的代碼就耦合在一塊兒,不利於後期維護升級。再者店長和客戶原本就不須要相互包含,他們之間是無狀態的。像不少pub/sub的中間件,好比dubbo,activeMQ等等,他們都是基於消息的發佈的訂閱機制,生產者和消費者之間沒有必要有狀態交互,你消費者掛了我生產者仍是繼續生產消息,互不影響,其實不少技術都是想通的,這裏和代理模式就和相似。下面來看看代理模式是怎麼處理的。code
提供了一個共有的送外賣接口中間件
public interface Send { void sendName(); void sendTime(); void sendAddress(); }
店長本尊對象,實現了共有的送外賣接口。對象
/** * 店長對象(本尊)須要實現Send接口 * @author user */ public class ShopKeeper implements Send{ private Consumer consumer; public ShopKeeper(Consumer consumer){ this.consumer = consumer; } @Override public void sendName() { System.out.print(consumer.getConName() + "的訂單,"); } @Override public void sendTime() { System.out.print("12:00以前送達,"); } @Override public void sendAddress() { System.out.print("送到長島路520弄,由代理對象配送..."); }
新增了代理對象,代理對象須要包含本尊,而且也要實現送外賣(Send)接口blog
/** * 代理對象也須要實現Send接口 * @author user * */ public class ProxySend implements Send{ private ShopKeeper shopKeeper; public ProxySend(Consumer consumer){ this.shopKeeper = new ShopKeeper(consumer); } @Override public void sendName() { shopKeeper.sendName(); } @Override public void sendTime() { shopKeeper.sendTime(); } @Override public void sendAddress() { shopKeeper.sendAddress(); } }
客戶對象沒有變化
public class Consumer{ private String conName; public String getConName() { return conName; } public void setConName(String conName) { this.conName = conName; } }
客戶端測試代碼
public class Show { public static void main(String[] args) { Consumer consumer = new Consumer(); consumer.setConName("外賣張"); ProxySend proxy = new ProxySend(consumer); proxy.sendName(); proxy.sendTime(); proxy.sendAddress(); } }
看輸出
外賣張的訂單,12:00以前送達,送到長島路520弄...
這樣代理對象就幫本尊完成了任務,能夠看到客戶端的代碼變化很大,客戶端根本不知道本尊的存在,由於在客戶端代碼中至始至終都沒有看到本尊對象的建立,連實例都沒有,這其實就是代理對象的做用之一,隱藏本尊。
Subject類,定義了RealSubject和Proxy的共用接口,這樣就在任何使用RealSubject的地方均可以使用Proxy,這裏使用抽象類
public abstract class Subject { public abstract void request(); }
RealSubject類,定義了Proxy所表明的真是實體
public class RealSubject extends Subject { @Override public void request() { System.out.println("真實的請求"); } }
Proxy類,保存了一個引用使得代理對象能夠訪問實體對象,並提供一個與Subject的接口相同的接口,這樣代理就能夠用來代理實體。
public class Proxy extends Subject{ RealSubject realSubject; @Override public void request() { if (realSubject == null) { realSubject = new RealSubject(); } realSubject.request(); } }
客戶端代碼
public class Show { public static void main(String[] args) { Proxy proxy = new Proxy(); proxy.request(); } }
測試結果
真實的請求
代理模式通常用在一下幾種場合。一、遠程代理,也就是爲了一個對象在不一樣的地址空間提供局部表明。這樣能夠隱藏一個對象存在於不一樣地址空間的事實。二、虛擬代理,是根據須要建立開銷很大的對象。經過它來存放實例化須要很長時間的真實對象。三、安全代理,用來控制真實對象訪問是的權限。四、智能指引,是指當前調用真實的對象時,代理處理另一些事情。因此代理模式還算比較經常使用的。