Android設(shè)計(jì)模式(十七)-代理模式

代理模式也叫委托模式,是結(jié)構(gòu)型設(shè)計(jì)模式。代理就是讓別人幫你做事,比如幫你帶飯,請(qǐng)律師打官司什么的。

博客地址

定義

為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。

使用場(chǎng)景

  • 當(dāng)一個(gè)對(duì)象不能或者不想直接訪問另一個(gè)對(duì)象時(shí),可以通過一個(gè)代理對(duì)象來間接訪問。為保證客戶端使用的透明性,委托對(duì)象和代理對(duì)象要實(shí)現(xiàn)同樣的接口。
  • 被訪問的對(duì)象不想暴露全部?jī)?nèi)容時(shí),可以通過代理去掉不想被訪問的內(nèi)容。

UML

  • Subject: 抽象主題類,聲明真是主體與代理主題的共同接口方法。
  • RealSubject: 真實(shí)主題類,定義了代理所表示的真是對(duì)象,執(zhí)行具體的業(yè)務(wù)方法??蛻舳送ㄟ^代理類來間接的調(diào)動(dòng)這個(gè)真實(shí)主題中的方法。
  • ProxySubject: 代理類,持有一個(gè)真實(shí)類的引用,在接口方法中調(diào)用真實(shí)主題相應(yīng)的方法,達(dá)到代理的作用。

簡(jiǎn)單實(shí)現(xiàn)

就以打官司為例。我們一般人要打官司都要找個(gè)律師來代理。

靜態(tài)代理

先建立一個(gè)起訴類的接口:

public interface ILawsuit {
    void submit();//提交申請(qǐng)
    void burden();//進(jìn)行舉證
    void defend();//開始辯護(hù)
    void finish();//訴訟完成
}

真正的起訴者:

public class Civilian implements ILawsuit {
    @Override
    public void submit() {
        System.out.println("起訴");
    }

    @Override
    public void burden() {
        System.out.println("舉證");
    }

    @Override
    public void defend() {
        System.out.println("辯護(hù)");
    }

    @Override
    public void finish() {
        System.out.println("勝訴");
    }
}

找的律師:

public class Lawyer implements ILawsuit {
    private ILawsuit civilian;

    public Lawyer(ILawsuit civilian) {
        this.civilian = civilian;
    }

    @Override
    public void submit() {
        civilian.submit();
    }

    @Override
    public void burden() {
        civilian.burden();
    }

    @Override
    public void defend() {
        civilian.defend();
    }

    @Override
    public void finish() {
        civilian.finish();
    }
}

客戶端調(diào)用,調(diào)用律師的方法,通過律師調(diào)用真正的su起訴者的方法。

public class Client {
    public static void main(String[] args) {
        ILawsuit civilian = new Civilian();
        ILawsuit lawyer = new Lawyer(civilian);
        lawyer.submit();
        lawyer.burden();
        lawyer.defend();
        lawyer.finish();
    }
}

輸出:


一個(gè)代理可以代理多個(gè)類,就像這個(gè)律師可以給很多人打官司,只需要在實(shí)現(xiàn)一個(gè)具體的ILawsuit就行了。代理會(huì)根據(jù)傳進(jìn)來的被代理者調(diào)用傳進(jìn)來的被代理者的方法。

動(dòng)態(tài)代理

代理模式大致分為兩大部分:靜態(tài)代理和動(dòng)態(tài)代理。

上面是是一種靜態(tài)代理,代理者的代碼時(shí)先生成寫好,然后再對(duì)其進(jìn)行編譯,在代碼運(yùn)行前,代理類的class編譯文件就已經(jīng)存在了。

動(dòng)態(tài)代理是相反的,通過反射動(dòng)態(tài)的生成代理者對(duì)象,也就是說在寫代碼的時(shí)候根本不知道要代理誰,具體代理誰會(huì)在執(zhí)行階段決定。

Java提供了一個(gè)便捷的動(dòng)態(tài)代理接口InvocationHandler,動(dòng)態(tài)代理類只要實(shí)現(xiàn)這個(gè)接口就行:

public class DynamicProxy implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

看一下動(dòng)態(tài)代理的用法:

public class DynamicProxy implements InvocationHandler {
    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //當(dāng)然這里可以對(duì)方法名進(jìn)行判斷過濾 if(method.getName().equals("***"))
        Object result = method.invoke(object,args);
        return result;
    }
}

客戶端調(diào)用:

public class Main {
    public static void main(String[] args) {
        ILawsuit lawsuit = new Civilian();
        DynamicProxy proxy = new DynamicProxy(lawsuit);
        ClassLoader loader = lawsuit.getClass().getClassLoader();
        //動(dòng)態(tài)創(chuàng)建代理類,需要傳入一個(gè)類加載器ClassLoader;一個(gè)你希望這個(gè)代理實(shí)現(xiàn)的接口列表,這里要代理ILawsuit接口;
        //和一個(gè)InvocationHandler的實(shí)現(xiàn),也就是前面創(chuàng)建的proxy。
        ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},proxy);
        lawyer.submit();
        lawyer.burden();
        lawyer.defend();
        lawyer.finish();
    }
}

輸出和上面一毛一樣:

動(dòng)態(tài)代理并不局限與代理一個(gè)接口的實(shí)現(xiàn),可以根據(jù)運(yùn)行時(shí)傳入的接口,動(dòng)態(tài)的生成代理類,然后通過Method的invoke方法來執(zhí)行被代理類的真實(shí)方法。非常靈活。

其他分類

靜態(tài)代理和動(dòng)態(tài)代理是從code方便進(jìn)行分類的。這兩個(gè)分類根據(jù)適用范圍來分都可以分為下面幾種:

  • 遠(yuǎn)程代理:為摸個(gè)對(duì)象在不同的內(nèi)存地址空間提供局部代理,是系統(tǒng)Server部分隱藏,以便Client不用考慮Server的存在。
  • 虛擬代理:如果要?jiǎng)?chuàng)建一個(gè)資源消耗較大的對(duì)象,可以先用一個(gè)代理對(duì)象表示,在真正需要的時(shí)候才真正創(chuàng)建。
  • 保護(hù)代理:用代理對(duì)象控制對(duì)一個(gè)對(duì)象的訪問,給不同的用戶提供不同的訪問權(quán)限。
  • 智能引用:在引用原始對(duì)象的時(shí)候附加額外操作,并對(duì)指向原始對(duì)象的引用增加引用計(jì)數(shù)。

總結(jié)

代理模式使用非常廣泛,從分類就能感覺出來,而且其他的設(shè)計(jì)模式中也會(huì)有代理模式的影子。

優(yōu)點(diǎn)

優(yōu)點(diǎn)可以從他的適用范圍看出來

  • 協(xié)調(diào)調(diào)用者和被調(diào)用者,降低系統(tǒng)耦合度。
  • 用小對(duì)象代表大對(duì)象,減少系統(tǒng)資源消耗,提高系統(tǒng)運(yùn)行速度,如虛擬代理。
  • 控制用戶對(duì)唄調(diào)用者的使用權(quán)限,如保護(hù)代理。

缺點(diǎn)

  • 首先當(dāng)然是比直接調(diào)用原始對(duì)象多了一個(gè)中間者,會(huì)讓結(jié)構(gòu)有點(diǎn)復(fù)雜。
  • 調(diào)用原始對(duì)象的方法要通過代理來調(diào)用,可能會(huì)造成請(qǐng)求處理速度變慢。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、設(shè)計(jì)模式的分類 總體來說設(shè)計(jì)模式分為三大類: 創(chuàng)建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者...
    RamboLI閱讀 825評(píng)論 0 1
  • 原文鏈接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤獨(dú)雜貨鋪閱讀 1,628評(píng)論 0 3
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,075評(píng)論 1 15
  • 整體Retrofit內(nèi)容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李頭閱讀 3,387評(píng)論 2 10
  • 我的母親,感謝您懷胎十月生下了我。 我的母親,感謝您這么多年養(yǎng)育了我。 我的母親,感謝您把您女兒嫁個(gè)了我。 母親,...
    君子有終閱讀 404評(píng)論 0 2

友情鏈接更多精彩內(nèi)容