代理模式——七種結(jié)構(gòu)型模式之一

1.前言


前面講的模式提供了一種在創(chuàng)建對(duì)象的同時(shí)隱藏創(chuàng)建邏輯的方式唬血,而不是直接實(shí)例化對(duì)象全陨。但結(jié)構(gòu)型模式關(guān)注的是如何組合類和對(duì)象痴晦,來獲取作用更廣泛的結(jié)構(gòu)或者新的功能。
  結(jié)構(gòu)型模式分為類模式和對(duì)象模式花嘶。前者通過繼承類和實(shí)現(xiàn)接口的方式笋籽,使目標(biāo)類具備所有父類和接口的性質(zhì);后者則將一些已經(jīng)存在的對(duì)象組合起來椭员,擴(kuò)展了功能车海,同時(shí)可以動(dòng)態(tài)改變組合關(guān)系,具有很大的靈活性隘击。

2.概念


代理模式為其它對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問侍芝。當(dāng)無法或不想直接訪問某個(gè)對(duì)象時(shí),通過一個(gè)代理對(duì)象來間接訪問埋同。根據(jù)適用范圍分為四類(引用自《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》):

  • 遠(yuǎn)程代理:為某個(gè)對(duì)象在不同的內(nèi)存地址空間提供局部代理州叠。
  • 虛擬代理:代理一個(gè)十分消耗資源的對(duì)象,并在真正需要時(shí)才創(chuàng)建此對(duì)象凶赁。
  • 保護(hù)代理:使用代理控制對(duì)原始對(duì)象的訪問咧栗。
  • 智能引用:在訪問原始對(duì)象時(shí)執(zhí)行一些自己的附加操作逆甜。

3.場(chǎng)景


有張三、李四兩人分別想要租房和買房致板,但是他們都太忙了交煞,共同約了一個(gè)中介全權(quán)處理。需要注意的是斟或,租房有租房的流程素征,買房有買房的手續(xù)。

4.寫法


租房的房源較多萝挤,中介決定先幫張三處理好御毅。

// 1.聲明需要代理的操作
public interface Tenant {
    
    void rent();

}
// 2.被代理者實(shí)現(xiàn)操作
public class ZhangSan implements Tenant {

    @Override
    public void rent() {
        System.out.println("我要租這套房");
    }

}
// 3.代理者調(diào)用被代理者的方法
public class Middleman implements Tenant {
    
    private Tenant customer;

    public Middleman(Tenant customer) {
        super();
        this.customer = customer;
    }

    @Override
    public void rent() {
        customer.rent();
    }

}
public class Main {

    public static void main(String[] args) {
        // 租房子由中介出面
        Tenant zhangSan = new ZhangSan();
        Tenant middleMan = new Middleman(zhangSan);
        middleMan.rent();
    }

}

中介在替張三找房時(shí),又發(fā)現(xiàn)了一個(gè)非常適合李四的房源在出售怜珍。但是他現(xiàn)在走的是租憑流程亚享,想去辦理買房手續(xù)不全,顯得很難辦绘面。

public interface Buyer {
    
    void buy();

}
public class LiSi implements Buyer {

    @Override
    public void buy() {
        System.out.println("我要買這套房");
    }

}

雖然也可以讓Middleman類實(shí)現(xiàn)Buyer接口獲取買房的方法,但是代理者同時(shí)具有兩個(gè)被代理者的方法侈沪,容易產(chǎn)生混淆揭璃,導(dǎo)致代理過程不透明,不符合代理模式設(shè)計(jì)的愿望亭罪。
  上面這種方式瘦馍,由于代碼運(yùn)行前,代理者的.class編譯文件已存在应役,即代理關(guān)系已確定情组,所以稱之為靜態(tài)代理。如果不聲明代理者就可以不確定代理關(guān)系箩祥,從而在執(zhí)行階段決定代理誰院崇,需要用到Java的反射機(jī)制動(dòng)態(tài)地生成代理者對(duì)象,這便是動(dòng)態(tài)代理袍祖。與原型模式類似底瓣,Java也提供了一個(gè)動(dòng)態(tài)代理接口InvocationHandler,通過重寫 invoke() 方法實(shí)現(xiàn)動(dòng)態(tài)調(diào)用被代理者的方法蕉陋。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler {
    
    private Object customer;

    public DynamicProxy(Object customer) {
        super();
        this.customer = customer;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1.通過反射調(diào)用被代理對(duì)象的相應(yīng)方法
        Object result = method.invoke(customer, args);
        return result;
    }

}
import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {
        Tenant zhangSan = new ZhangSan();
        Buyer liSi = new LiSi();
        // 分別獲得兩人的全權(quán)代理
        DynamicProxy tenant = new DynamicProxy(zhangSan);
        DynamicProxy buyer = new DynamicProxy(liSi);
        // 2.通過ClassLoader加載業(yè)務(wù)接口和代理對(duì)象捐凭,生成新的代理對(duì)象
        Tenant zsProxy = (Tenant) Proxy.newProxyInstance(Tenant.class.getClassLoader(), new Class[] {Tenant.class}, tenant);
        zsProxy.rent();
        Buyer lsProxy = (Buyer) Proxy.newProxyInstance(Buyer.class.getClassLoader(), new Class[] {Buyer.class}, buyer);
        lsProxy.buy();
    }

}

雖然靜態(tài)代理符合面向?qū)ο蟮脑瓌t,將對(duì)象關(guān)系聲明清楚凳鬓,但是不夠靈活茁肠,需要聲明多個(gè)代理對(duì)象。而動(dòng)態(tài)代理缩举,將代理者與被代理者解耦垦梆,使代理者不受被代理者變化影響匹颤,令模式結(jié)構(gòu)清晰、簡(jiǎn)單奶赔。

5.總結(jié)


代理模式是之所以稱為結(jié)構(gòu)型模式惋嚎,是因?yàn)檫@種結(jié)構(gòu)為對(duì)象的訪問增加了獨(dú)立的處理空間,有利于添加相應(yīng)的功能站刑。就拿智能引用來說另伍,將它優(yōu)化一下,就是裝飾模式了绞旅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末摆尝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子因悲,更是在濱河造成了極大的恐慌堕汞,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晃琳,死亡現(xiàn)場(chǎng)離奇詭異讯检,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卫旱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門人灼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人顾翼,你說我怎么就攤上這事投放。” “怎么了适贸?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵灸芳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拜姿,道長(zhǎng)烙样,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任蕊肥,我火速辦了婚禮误阻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘晴埂。我一直安慰自己究反,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布儒洛。 她就那樣靜靜地躺著精耐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪琅锻。 梳的紋絲不亂的頭發(fā)上卦停,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天向胡,我揣著相機(jī)與錄音,去河邊找鬼惊完。 笑死僵芹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的小槐。 我是一名探鬼主播拇派,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼凿跳!你這毒婦竟也來了件豌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤控嗜,失蹤者是張志新(化名)和其女友劉穎茧彤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疆栏,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡曾掂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壁顶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片珠洗。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖博助,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情痹愚,我是刑警寧澤富岳,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站拯腮,受9級(jí)特大地震影響窖式,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜动壤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一萝喘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧琼懊,春花似錦阁簸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至醉旦,卻和暖如春饶米,著一層夾襖步出監(jiān)牢的瞬間桨啃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工檬输, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留照瘾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓丧慈,卻偏偏與公主長(zhǎng)得像析命,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伊滋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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