設(shè)計(jì)模式學(xué)習(xí)筆記09-Proxy(代理)模式

本文主要是看了《設(shè)計(jì)模式》做的筆記和思考蛆封,在此分享僅代表個(gè)人觀點(diǎn)杀糯,如有不對(duì)的地方歡迎批評(píng)和指正。

基礎(chǔ)

Proxy模式彤枢,中文名“代理模式”狰晚,該模式的主要想法是用來(lái)管理被代理的類(lèi),在訪問(wèn)真正的類(lèi)之前缴啡,你只能訪問(wèn)到一個(gè)代理類(lèi)壁晒,代理類(lèi)會(huì)根據(jù)需要合理地支配被代理類(lèi),UML如下所示业栅。


Proxy模式UML.png

此處秒咐,代理類(lèi)和被代理類(lèi)都應(yīng)當(dāng)實(shí)現(xiàn)同樣的接口,以方便實(shí)現(xiàn)一致性碘裕,使得代理類(lèi)和被代理類(lèi)的使用過(guò)程相同携取。

代理模式的四種使用情況

  1. 遠(yuǎn)程代理
  2. 虛代理
  3. 保護(hù)代理
  4. 智能指引

下面將逐個(gè)講講其概念以及給出簡(jiǎn)單的代碼作為演示。

遠(yuǎn)程代理

Remote Proxy可以隱藏一個(gè)對(duì)象存在與不同地址空間的事實(shí)帮孔。
為了達(dá)到Remote Proxy的描述雷滋,我的理解有以下兩種情況:

  1. Proxy類(lèi)中有多個(gè)RealSubject的指針,這些不同的RealSubject共同完成了一個(gè)功能文兢,而Proxy類(lèi)則向外提供了一個(gè)整體的入口晤斩,有點(diǎn)類(lèi)似Facade(外觀)模式,代碼示例如下:
class A extends Subject{}
class B extends Subject{}

class Proxy extends Subject{
    private A a;
    private B b;

    public doSomething(){
        a.doSomething();
        b.doSomething();
    }
}
  1. Proxy類(lèi)充當(dāng)一個(gè)負(fù)載均衡器的作用姆坚,在內(nèi)存的不同地方有多個(gè)RealSubject澳泵,Proxy類(lèi)根據(jù)實(shí)際情況提供某個(gè)地址的指針
class RealSubject extends Subject{}

class Proxy extends Subject{
    private ArrayList<RealSubject> list;
    private static int counter = 0;

    public doSomething(){
        list.get(counter%list.size()).doSomething();
        counter++;
    }
}

虛代理

如果RealSubject在執(zhí)行某種操作時(shí)開(kāi)銷(xiāo)很大,可以考慮使用Proxy類(lèi)緩存這些操作的結(jié)果兼呵,當(dāng)操作的輸入不變時(shí)兔辅,直接拿Proxy類(lèi)緩存的結(jié)果返回,節(jié)省開(kāi)銷(xiāo)击喂。又或者是RealSubject本身在創(chuàng)建時(shí)就消耗很多資源维苔,但有些功能并不需要完整的RealSubject類(lèi)執(zhí)行,那么這些小功能就可以由Proxy類(lèi)代勞茫负,到實(shí)在需要的時(shí)候再實(shí)例化RealSubject蕉鸳。示例代碼如下所示乎赴。

abstract class Image{
    public double getSize();
    public String getName();
    public void draw();
}



class RealImage extends Image{
    private String name;
    private int status;

    // 構(gòu)造方法忍法,注意它與Proxy中的不同
    public RealImage(String name){
        this.name = name;
        ...
    }

    public double getSize(){、
        // 經(jīng)過(guò)某些特殊處理...
    }
    public String getName(){...}
    public void draw(){
        // big project ...
    }

    // 返回一個(gè)狀態(tài)標(biāo)識(shí)
    public int getStatusFlag(){...}
}



class ImageProxy extends Image{
    private RealImage image;
    private int imageStatus = 0; //表示初始狀態(tài)
    private double imageSize = 0;
    private String imageName = "";


    public ImageProxy(String name){
        imageName = name;
        image = "";
    }

    public double getSize(){
        if(image == null){
            image = new RealImage();
        }

        // 如果RealImage的狀態(tài)沒(méi)有改變榕吼,那么直接返回緩存的值
        if(imageStatus 饿序!= image.getStatusFlag()){
            imageSize = image.getSize();
        }
        return imageSize;
    }

    // 這個(gè)方法就不經(jīng)過(guò)RealImage
    public String getName(){
        return imageName;
    }

    // 這時(shí)不用RealImage實(shí)在不行了
    public void draw(){
        if(image == null){
            image = new RealImage();
        }
        image.draw();
    }
} 

使用時(shí)就直接使用ImageProxy就好。

保護(hù)代理

這個(gè)就是我在外面看的好幾個(gè)博客講的情形羹蚣,大致描述一下:代理類(lèi)會(huì)審核發(fā)給被代理類(lèi)的請(qǐng)求原探。例子跟這個(gè)類(lèi)似:A找B玩,結(jié)果B媽來(lái)見(jiàn)A,B媽說(shuō)B要讀書(shū)學(xué)習(xí)咽弦,在A看來(lái)徒蟆,這跟B自己說(shuō)要學(xué)習(xí)結(jié)果一樣。這個(gè)例子中型型,B媽就是B的代理段审,在A提出玩的請(qǐng)求時(shí)她先把關(guān)一下,符合條件了再把A的請(qǐng)求轉(zhuǎn)發(fā)給B闹蒜。

智能指針

這里的智能主要描述的是內(nèi)存管理寺枉,包括內(nèi)存回收、長(zhǎng)期持有一個(gè)對(duì)象绷落、同步鎖檢測(cè)姥闪。

要做到內(nèi)存回收,那么通常需要記下引用計(jì)數(shù)砌烁,當(dāng)計(jì)數(shù)降到一個(gè)閾值后觸發(fā)內(nèi)存回收筐喳,以下代碼同時(shí)還展示了同步鎖的使用。

abstract class Box{
    public void putSomething(Object o);
    public void takeSomething(Object o);
}

// 省略被代理類(lèi)RealBox
// 假設(shè)因?yàn)槟撤N原因函喉,RealBox中并沒(méi)有計(jì)數(shù)疏唾,也沒(méi)有同步鎖
class ProxyBox extends Subject{
    private int thingsQty = 0;
    private RealBox box;    // ProxyBox將在構(gòu)造方法中創(chuàng)建
    private bool isReleaseBox = false;


    public void synchronize putSomething(Object o){
        if(isReleaseBox){
            System.out.println("這個(gè)盒子已空");
            return;
        }
        thingsQty++;
        box.putSomething(o);
    }


    public void synchronize takeSomething(Object o){
        if(isReleaseBox){
            System.out.println("這個(gè)盒子已空");
            return;
        }
        if(thingsQty == 0){
            System.out.println("這個(gè)盒子已空");
            box = null;
            isReleaseBox = true;
        }else{
            box.takeSomething(o);
        }
    }
}


main(){
    Box box = new ProxyBox();
    box.putSomething("apple");
    box.takeSomething("apple");
}

我覺(jué)得這種計(jì)數(shù)在RealSubject類(lèi)本身其實(shí)就能做,除非語(yǔ)言不支持在類(lèi)中釋放自己函似。當(dāng)然還有像上面例子中的情況可以使用槐脏,就是當(dāng)你的隊(duì)友出現(xiàn)了疏忽,你又不愿意改他的類(lèi)撇寞,那么可以通過(guò)寫(xiě)一個(gè)Proxy類(lèi)繞過(guò)這些坑顿天。此時(shí),這個(gè)Proxy已經(jīng)跟Decorator很像了蔑担,只要去除Proxy的權(quán)限牌废,這個(gè)就是Decorator模式,此處是根據(jù)isReleaseBox設(shè)置權(quán)限啤握,如果讀者有更好的方法歡迎提出鸟缕。

Proxy(代理)模式與Decorator(裝飾)模式

需要說(shuō)明的是,在Decorator只有一層的時(shí)候排抬,這兩個(gè)模式連UML都極為相似懂从,如上文所說(shuō),一旦Proxy類(lèi)放棄對(duì)RealSubject的控制蹲蒲,它很大概率就是個(gè)Decorator類(lèi)番甩。但從設(shè)計(jì)思想來(lái)說(shuō),它們區(qū)別挺大的届搁。Decorator模式主要適用于應(yīng)對(duì)不可預(yù)見(jiàn)的功能(設(shè)計(jì)者甚至不知道用戶會(huì)拿它的類(lèi)嵌套實(shí)現(xiàn)什么功能)缘薛,因此它非常的靈活窍育,也能夠遞歸地、層級(jí)式地完成某些功能宴胧。Proxy模式主要適用于不便于訪問(wèn)RealSubject時(shí)使用漱抓,因而,Proxy類(lèi)與RealSubject的關(guān)系是可以靜態(tài)表達(dá)的恕齐、可預(yù)見(jiàn)的辽旋,也因?yàn)檫@一點(diǎn),它不夠靈活檐迟。因此补胚,推薦從設(shè)計(jì)思想出發(fā),在盡可能地表達(dá)業(yè)務(wù)中各個(gè)角色的關(guān)系的同時(shí)追迟,追求靈活與穩(wěn)定溶其。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市敦间,隨后出現(xiàn)的幾起案子瓶逃,更是在濱河造成了極大的恐慌,老刑警劉巖廓块,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厢绝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡带猴,警方通過(guò)查閱死者的電腦和手機(jī)昔汉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拴清,“玉大人靶病,你說(shuō)我怎么就攤上這事】谟瑁” “怎么了娄周?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沪停。 經(jīng)常有香客問(wèn)我煤辨,道長(zhǎng),這世上最難降的妖魔是什么木张? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任众辨,我火速辦了婚禮,結(jié)果婚禮上窟哺,老公的妹妹穿的比我還像新娘泻轰。我一直安慰自己技肩,他們只是感情好且轨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布浮声。 她就那樣靜靜地躺著,像睡著了一般旋奢。 火紅的嫁衣襯著肌膚如雪泳挥。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天至朗,我揣著相機(jī)與錄音屉符,去河邊找鬼。 笑死锹引,一個(gè)胖子當(dāng)著我的面吹牛矗钟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嫌变,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吨艇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了腾啥?” 一聲冷哼從身側(cè)響起东涡,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倘待,沒(méi)想到半個(gè)月后疮跑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凸舵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年祖娘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啊奄。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贿条,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出增热,到底是詐尸還是另有隱情整以,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布峻仇,位于F島的核電站公黑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏摄咆。R本人自食惡果不足惜凡蚜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吭从。 院中可真熱鬧朝蜘,春花似錦、人聲如沸涩金。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至副渴,卻和暖如春奈附,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背煮剧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工斥滤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勉盅。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓佑颇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親草娜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漩符,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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