設(shè)計(jì)模式—代理

代理模式UML

圖1-1拼余,代理模式UML建模

什么是代理模式?

給某個(gè)對(duì)象提供一個(gè)代理對(duì)象针肥,并由代理對(duì)象控制對(duì)于原對(duì)象的訪問(wèn),即客戶不直接操控原對(duì)象香伴,而是通過(guò)代理對(duì)象間接地操控原對(duì)象慰枕。

比如說(shuō),我想在喝星巴克的咖啡即纲;正常流程下具帮,我要自己去星巴克店里購(gòu)買,是我執(zhí)行買這個(gè)操作低斋,但現(xiàn)在我通過(guò)外賣服務(wù)蜂厅,這個(gè)買的人就變成了外賣小哥,而不是我本人膊畴,這里的外賣小哥其實(shí)就是我的代理掘猿,他代我實(shí)現(xiàn)了這個(gè)買的操作。這里的我相當(dāng)于Client唇跨,買咖啡是一個(gè)借口Subject稠通,外賣小哥就是ReallySubject,ProxySubject就是我要買咖啡的一個(gè)代理(我并不關(guān)心真正的執(zhí)行者是誰(shuí))

一個(gè)簡(jiǎn)單的代理實(shí)現(xiàn)代碼

public class Delegate {
    public void main() {
        // 真正執(zhí)行者
        Subject reallySubject =new ReallySubject();
        // 代理執(zhí)行者
        Subject proxySubject =new ProxySubject(reallySubject);
        // 看似是代理執(zhí)行者在做事【所謂的代理】
        proxySubject.doSomethings();
    }
}
interface Subject {
    void doSomethings();
}
public class ReallySubjectimplements Subject {
    @Override
    public void doSomethings() {
        Log.e("實(shí)際執(zhí)行人","真正要做事的");
    }
}
public class ProxySubjectimplements Subject {
    private Subjectsubject;
    public ProxySubject(Subject subject) {
        this.subject = subject;
    }
    @Override
    public void doSomethings() {
        Log.e("我是代辦人","通知真正辦事的者买猖,辦事改橘!");
        if (subject !=null)
            subject.doSomethings();
    }
}

什么是靜態(tài)代理和動(dòng)態(tài)代理?

靜態(tài)代理:在編譯時(shí)就將接口玉控、實(shí)現(xiàn)類飞主、代理類實(shí)現(xiàn)了,說(shuō)白點(diǎn)就是咱們自己手動(dòng)全部敲出來(lái)奸远。

動(dòng)態(tài)代理:在程序運(yùn)行時(shí)既棺,根據(jù)需要?jiǎng)討B(tài)的創(chuàng)建代理類及相關(guān)實(shí)例。

都是代理又為什么要區(qū)分靜態(tài)代理和動(dòng)態(tài)代理呢懒叛?
當(dāng)我們遇到某個(gè)需求要實(shí)現(xiàn)大量的代理的時(shí)候丸冕,每一個(gè)都要手動(dòng)去敲是一件很費(fèi)時(shí)操作,而且大部分的代碼又都是重復(fù)的薛窥,這個(gè)時(shí)候就有大神就提出了動(dòng)態(tài)代理的方案胖烛,來(lái)簡(jiǎn)化這些沒(méi)有營(yíng)養(yǎng)的操作了,即動(dòng)態(tài)代理的出現(xiàn)诅迷。

動(dòng)態(tài)代理的實(shí)現(xiàn)

public class DelegateSubject implements InvocationHandler {
    private Subject subject;

    public DelegateSubject(Subject subject) {
        this.subject = subject;
    }

    /**
     *
     * @param proxy 代理對(duì)象(表示哪個(gè)代理對(duì)象調(diào)用了method方法)
     * @param method 調(diào)用方法
     * @param args 調(diào)用方法參數(shù)
     * @return 代理實(shí)例調(diào)用具體的方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        // 添加自己的代碼1
        // 根據(jù)自己的需要甚至可以不調(diào)用method.invoke()方法
        object = method.invoke(subject, args);
        // 添加自己的代碼2
        return object;
    }

}
public class Delegate {

    public void main() {
        // 真正執(zhí)行者
        ReallySubject reallySubject = new ReallySubject();
        // 代理執(zhí)行器
        DelegateSubject delegateSubject = new DelegateSubject(reallySubject);
        // 構(gòu)造動(dòng)態(tài)代理
        // 第一個(gè)參數(shù) 真正執(zhí)行者加載器
        // 第二個(gè)參數(shù) 真正執(zhí)行者實(shí)現(xiàn)的接口
        // 第三個(gè)參數(shù) 代理執(zhí)行器
        Subject subject = (Subject) Proxy.newProxyInstance(
                ReallySubject.class.getClassLoader(),
                ReallySubject.class.getInterfaces(),  // 或者 new Class<?>[] { Subject.class },
                delegateSubject);
        // 通過(guò)代理執(zhí)行對(duì)象方法
        // 調(diào)用此方法執(zhí)行 DelegateSubject的invoke()
        subject.doSomethings();
    }

}

看看retrofit是怎么使用動(dòng)態(tài)代理

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

看了retrofit的代碼你會(huì)不會(huì)產(chǎn)生疑問(wèn)佩番,retrofit只有接口沒(méi)并沒(méi)有具體的執(zhí)行者啊0丈肌L宋贰!
還記得上面的這段代碼么滩租?

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        // 添加自己的代碼1
        // 根據(jù)自己的需要甚至可以不調(diào)用method.invoke()方法
        object = method.invoke(subject, args);
        // 添加自己的代碼2
        return object;
    }

中提到過(guò) “根據(jù)需要你甚至可以不調(diào)用method.invoke()”赋秀,沒(méi)錯(cuò)retrofit就這么干的

ServiceMethod<Object, Object> serviceMethod =
     (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

這段代碼只要是使用OkHttp進(jìn)行網(wǎng)絡(luò)請(qǐng)求利朵,并將OkHttp的返回結(jié)果作為最終函數(shù)的返回結(jié)果。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末猎莲,一起剝皮案震驚了整個(gè)濱河市绍弟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌著洼,老刑警劉巖樟遣,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異身笤,居然都是意外死亡豹悬,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門展鸡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)屿衅,“玉大人埃难,你說(shuō)我怎么就攤上這事莹弊。” “怎么了涡尘?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵忍弛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我考抄,道長(zhǎng)细疚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任川梅,我火速辦了婚禮疯兼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贫途。我一直安慰自己吧彪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布丢早。 她就那樣靜靜地躺著姨裸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怨酝。 梳的紋絲不亂的頭發(fā)上傀缩,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音农猬,去河邊找鬼赡艰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛斤葱,可吹牛的內(nèi)容都是我干的慷垮。 我是一名探鬼主播勋又,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼换帜!你這毒婦竟也來(lái)了楔壤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惯驼,失蹤者是張志新(化名)和其女友劉穎蹲嚣,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祟牲,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隙畜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了说贝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片议惰。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖乡恕,靈堂內(nèi)的尸體忽然破棺而出言询,到底是詐尸還是另有隱情,我是刑警寧澤傲宜,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布运杭,位于F島的核電站,受9級(jí)特大地震影響函卒,放射性物質(zhì)發(fā)生泄漏辆憔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一报嵌、第九天 我趴在偏房一處隱蔽的房頂上張望虱咧。 院中可真熱鬧,春花似錦锚国、人聲如沸腕巡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逸雹。三九已至,卻和暖如春云挟,著一層夾襖步出監(jiān)牢的瞬間梆砸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工园欣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帖世,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像日矫,于是被迫代替她去往敵國(guó)和親赂弓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評(píng)論 25 707
  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是代理模式 模式的結(jié)構(gòu) 典型代碼 代理模式分類 代碼示例 代理模式和裝飾者模式的...
    w1992wishes閱讀 1,534評(píng)論 0 13
  • 1. 定義 為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)哪轿。 2. 使用場(chǎng)景 當(dāng)想對(duì)某個(gè)對(duì)象做功能增強(qiáng)拓展盈魁,但又不想...
    程序員修仙閱讀 378評(píng)論 1 2
  • 人生道路很長(zhǎng),遺憾的事情總會(huì)有的窃诉。這種時(shí)候杨耙,很多人都唏噓不已,希望能做成的事飘痛,因?yàn)榉N種原因沒(méi)有做成珊膜。 那...
    算法成癮者閱讀 134評(píng)論 3 2
  • 今天早上七點(diǎn)二十和床做了幾分鐘斗爭(zhēng),終于成功下床宣脉。 沖了個(gè)澡车柠,感覺(jué)精神抖擻,下樓去學(xué)校門前的早市還沒(méi)散塑猖,各種新鮮便...
    讓人頭痛的青春boy閱讀 415評(píng)論 0 1