代理模式

代理模式

代理模式定義,為另外一個對象提供一個替身以控制對這個對象的訪問欲芹,是一個控制對象訪問的模式。常用的幾種控制訪問方式有

  • 遠程代理控制訪問遠程對象
  • 保護代理基于權(quán)限控制對對象訪問尔崔,如java 動態(tài)代理

假設(shè)現(xiàn)在有一個遠程的飲料販賣機器勤婚,想在本地監(jiān)控販賣情況,就可以在本地產(chǎn)生一個遠程的代理對象臣疑,本地程序通過本地遠程代理來和遠程真實對象進行通信盔憨。這樣客戶所做的就像在做遠程調(diào)用,但是其實只是調(diào)用本地代理對象上的方法讯沈。再由代理處理所有網(wǎng)絡(luò)通信的底層細節(jié)郁岩。

proxy1.png

保護代理,如果一個對象里面的方法不是對每一個對象都是公開的缺狠,就可以為對象創(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)建保護代理猴仑,先看看類圖

proxy2.png

在這里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 給視圖
proxy3.png

歡迎大家給我留言,提建議辉阶,指出錯誤先壕,一起討論學(xué)習(xí)技術(shù)的感受瘩扼!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市垃僚,隨后出現(xiàn)的幾起案子集绰,更是在濱河造成了極大的恐慌,老刑警劉巖谆棺,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栽燕,死亡現(xiàn)場離奇詭異,居然都是意外死亡改淑,警方通過查閱死者的電腦和手機碍岔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朵夏,“玉大人蔼啦,你說我怎么就攤上這事⊙霾” “怎么了捏肢?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饥侵。 經(jīng)常有香客問我鸵赫,道長,這世上最難降的妖魔是什么躏升? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任辩棒,我火速辦了婚禮,結(jié)果婚禮上煮甥,老公的妹妹穿的比我還像新娘盗温。我一直安慰自己,他們只是感情好成肘,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布卖局。 她就那樣靜靜地躺著,像睡著了一般双霍。 火紅的嫁衣襯著肌膚如雪砚偶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天洒闸,我揣著相機與錄音染坯,去河邊找鬼。 笑死丘逸,一個胖子當(dāng)著我的面吹牛单鹿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播深纲,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仲锄,長吁一口氣:“原來是場噩夢啊……” “哼劲妙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起儒喊,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤镣奋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后怀愧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侨颈,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年芯义,在試婚紗的時候發(fā)現(xiàn)自己被綠了哈垢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毕贼,死狀恐怖温赔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鬼癣,我是刑警寧澤陶贼,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站待秃,受9級特大地震影響拜秧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜章郁,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一枉氮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暖庄,春花似錦聊替、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肩钠,卻和暖如春泣港,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背价匠。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工当纱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人踩窖。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓坡氯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子箫柳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容