代理模式
代理模式定義,為另外一個對象提供一個替身以控制對這個對象的訪問欲芹,是一個控制對象訪問的模式。常用的幾種控制訪問方式有
- 遠程代理控制訪問遠程對象
- 保護代理基于權(quán)限控制對對象訪問尔崔,如java 動態(tài)代理
假設(shè)現(xiàn)在有一個遠程的飲料販賣機器勤婚,想在本地監(jiān)控販賣情況,就可以在本地產(chǎn)生一個遠程的代理對象臣疑,本地程序通過本地遠程代理來和遠程真實對象進行通信盔憨。這樣客戶所做的就像在做遠程調(diào)用,但是其實只是調(diào)用本地代理對象上的方法讯沈。再由代理處理所有網(wǎng)絡(luò)通信的底層細節(jié)郁岩。
保護代理,如果一個對象里面的方法不是對每一個對象都是公開的缺狠,就可以為對象創(chuàng)建保護代理问慎,每次調(diào)用對象方法時觸發(fā)保護。
假設(shè)有一個幫忙實現(xiàn)約會的服務(wù)系統(tǒng)挤茄,這套系統(tǒng)能鼓勵顧客找到可能的配對對象如叼。系統(tǒng)有一個Person bean 對象,允許設(shè)置或取得一個人的信息穷劈。
public interface PersonBean{
String getName();
String getGender();
// 取得興趣愛好
String getInterests();
// 取得評分1~10
int getHotOrNotRating();
void setName(String name);
void setGender(String gender);
// 設(shè)置興趣愛好
void setInterests(String interests);
// 每一次評分都會笼恰,再計算平均評分
void setHotOrNotRating(int rating);
}
// PersonBean 實現(xiàn)
public class PersonBeanImpl implements PersonBean{
String name;
String gender;
String interests;
int rating;
int ratingCount = 0;
public String getName(){
return name;
}
public int getHotOrNotRating(){
if(ratingCunt == 0) return 0;
return (rating/ratingCount);
}
// 其他方法 .....
public void setInterests(String interests){
this.interests = interests;
}
public void setHotOrNotRating(int rating){
this.rating += rating;
ratingCount++;
}
}
但是不久就會有人抱怨有人居然篡改了我的興趣踊沸,還有有人居然給自己評高分,以拉高自己的HotOrNotRating 值社证。所以顧客不可以給自己評分逼龟,也不可以修改別人的信息。我們可以為PersonBean 創(chuàng)建保護代理猴仑,先看看類圖
在這里PersonBean 就是RealSubject审轮,
- 圖中proxy是由Java 產(chǎn)生的,而且實現(xiàn)了完整的PersonBean 接口
- InvocationHanlder 是由我們提供的辽俗,Proxy 上的任何方法調(diào)用都會被傳入此類疾渣,由它控制對RealSubject 方法的訪問
接下來看看具體的代碼實現(xiàn),創(chuàng)建控制自己對主題訪問的對象OwnerInvocationHandler崖飘,控制別人對主題訪問的NonOwnerInvocationHandler 代碼類似
import java.lang.reflect.*;
// InvocationHandler 是reflect 里面的接口榴捡,實現(xiàn)其中的invoke 方法
public class OwnerInvocationHandler implements InvocationHandler{
PersonBean Person;
public OwnerInvocationHandler(PersonBean person){
this.person = person;
}
public Object invoke(Object proxy, Method method, object[] args) throws IllegallAccessException{
try{
if(method.getName().startsWith("get")){
return method.invoke(perosn, agrs);
}else if(method.getName().equals("setHotOrNotRating")){
// 自己不能給自己評分,調(diào)用此方法時拋異常
throw new IllegalAccessException();
}else if(method.getName().startWith("set")){
return method.invoke(perosn, agrs);
}
}catch(InvocationTargetException e){
e.printStackTrace();
}
return null;
}
}
創(chuàng)建getOwnerProxy 代理的方法返回personBean 對象朱浴,該代理用于保護自己對personBean 的訪問吊圾。
// 創(chuàng)建getOwnerProxy 代理
PersonBean getOwnerProxy(PersonBean person){
// Proxy 是java reflect 包里面的類
return (PersonBean)Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person)
);
}
// 類似的getNonOwnerProxy(),返回NonOwnerInvocationHandler 的代理
// 測試一下,
PersonBean personA = new PersonBean();
personBean ownerProxy = getOwnerProxy(personA);
try{
// 代理會觸發(fā) OwnerInvocationHandler invoke()
ownerProxy.setHotOrNotRating(10);
}catch (Exception e){
System.out.println('Canot set rating from owner proxy);
}
Java 在java.lang.reflect 包中有自己的代理支持翰蠢,利用這個包可以再運行時動態(tài)創(chuàng)建一個代理類项乒,實現(xiàn)一個或多個接口,并將方法的調(diào)用轉(zhuǎn)發(fā)到你所指定的類梁沧。因為實際的代理類是來運行時創(chuàng)建的檀何,所以稱這個Java 技術(shù)為:動態(tài)代理。
復(fù)合模式
復(fù)合模式:結(jié)合兩個或兩個以上的模式廷支,組成一個解決方案频鉴,解決一再發(fā)生的一般性問題。我們看看 mvc 模式在web 中的應(yīng)用恋拍,里面也用了好幾種設(shè)計模式
- 策略模式垛孔,controller 對客戶端請求的響應(yīng),策略對象是controller施敢,同一個請求可以更換不同的controller 來處理周荐。這不就是策略模式
- 組合模式,網(wǎng)頁由HTML 描述僵娃,內(nèi)部很類似形成組合的對象系統(tǒng)
- 觀察者模式羡藐,當(dāng)model 改變狀態(tài)時,視圖間接地從控制器收到了相當(dāng)于通知的東西悯许,控制器甚至把模型Bean 給視圖
歡迎大家給我留言,提建議辉阶,指出錯誤先壕,一起討論學(xué)習(xí)技術(shù)的感受瘩扼!