設計模式 - 代理模式

1 代理模式概要

  • 分類:靜態(tài)代理彼乌、動態(tài)代理
  • 角色:抽象接口汁展、代理對象端三、被代理對象(目標)汉嗽,由被代理對象來做最終的決定
  • 代理對象通常來說會持有被代理對象的引用(以便代理角色完成工作之前,或者之后能找到被代理對象返顺,能夠通知被代理對象)

2 代理的實現(xiàn)

2.1 靜態(tài)代理

定義一個抽象接口 Person憨攒,定義一個實現(xiàn)類 Son冈敛,創(chuàng)建一個對象 Mother 實現(xiàn)接口 Person昂羡,同時持有 Person 的引用絮记,完整代碼如下
  • Person 接口
package com.lushwe.pattern.proxy;

/**
 * 說明:人
 *
 * @author Jack Liu
 * @date 2019-05-27 10:38
 * @since 1.0
 */
public interface Person {

    /**
     * 找對象
     */
    void findLove();

    /**
     * 找工作
     */
    void findJob();
}
  • Son
package com.lushwe.pattern.proxy;

/**
 * 說明:兒子
 *
 * @author Jack Liu
 * @date 2019-05-27 10:38
 * @since 1.0
 */
public class Son implements Person {

    public void findLove() {
        System.out.println("兒子找對象,膚白貌美大長腿");
    }

    public void findJob() {
        System.out.println("兒子找工作虐先,錢多事少離家近");
    }
}
  • Mother
package com.lushwe.pattern.proxy.staticed;

import com.lushwe.pattern.proxy.Person;

/**
 * 說明:母親(靜態(tài)代理)
 *
 * @author Jack Liu
 * @date 2019-05-27 10:40
 * @since 1.0
 */
public class Mother implements Person {

    private Person person;

    public Mother(Person person) {
        this.person = person;
    }

    public void findLove() {

        System.out.println("媽媽幫忙物色對象");

        this.person.findLove();

        System.out.println("對象是否合適");
    }

    public void findJob() {
        // do nothing
    }
}
測試代碼
package com.lushwe.pattern.proxy.staticed;

import com.lushwe.pattern.proxy.Son;

/**
 * 說明:靜態(tài)代理測試
 *
 * @author Jack Liu
 * @date 2019-05-27 10:43
 * @since 1.0
 */
public class StaProxyTest {

    public static void main(String[] args) {

        Mother mother = new Mother(new Son());
        mother.findLove();
    }
}
運行 StaProxyTest 怨愤,日志打印結果如下
媽媽幫忙物色對象
兒子找對象,膚白貌美大長腿
對象是否合適
總結
  • 優(yōu)點:開發(fā)簡單
  • 缺點:實現(xiàn)類 Son 方法發(fā)生變化蛹批,代理類 Mother 也要調(diào)整撰洗,不符合開閉原則

2.2 動態(tài)代理

2.2.1 JDK代理

創(chuàng)建 JdkMatchmaker 類篮愉,實現(xiàn) InvocationHandler 接口,通過 Proxy 工具類創(chuàng)建代理對象差导,完整代碼如下
package com.lushwe.pattern.proxy.jdk;

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

/**
 * 說明:媒婆(Jdk代理)
 *
 * @author Jack Liu
 * @date 2019-05-27 11:15
 * @since 1.0
 */
public class JdkMatchmaker<T> implements InvocationHandler {

    /**
     * 被代理對象
     */
    private T target;

    /**
     * 返回代理對象實例
     *
     * @param target
     * @return
     */
    public T getInstance(T target) {

        this.target = target;

        Class<?> targetClass = target.getClass();

        return (T) Proxy.newProxyInstance(targetClass.getClassLoader(), targetClass.getInterfaces(), this);
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("媒婆幫忙物色對象");

        // 調(diào)用被代理對象方法
        method.invoke(this.target, args);

        System.out.println("對象是否合適");

        return null;
    }
}
測試代碼
package com.lushwe.pattern.proxy.jdk;

import com.lushwe.pattern.proxy.Person;
import com.lushwe.pattern.proxy.Son;

/**
 * 說明:Jdk動態(tài)代理測試類
 *
 * @author Jack Liu
 * @date 2019-05-27 11:19
 * @since 1.0
 */
public class JdkProxyTest {

    public static void main(String[] args) {

        JdkMatchmaker<Person> jdkMatchmaker = new JdkMatchmaker();

        Person person = jdkMatchmaker.getInstance(new Son());

        person.findLove();
    }
}
運行 JdkProxyTest 试躏,日志打印結果如下
媒婆幫忙物色對象
兒子找對象,膚白貌美大長腿
對象是否合適
總結
  • 優(yōu)點:動態(tài)生成代理類柿汛,被代理類接口變更冗酿,JdkMatchmaker 不需要修改
  • 缺點:被代理類必須實現(xiàn)接口

2.2.2 CGlib代理

創(chuàng)建 CglibMatchmaker 類埠对,實現(xiàn) MethodInterceptor 接口络断,通過 Enhancer 工具類創(chuàng)建代理對象,完整代碼如下
package com.lushwe.pattern.proxy.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 說明:媒婆(Cglib代理)
 *
 * @author Jack Liu
 * @date 2019-05-30 11:12
 * @since 1.0
 */
public class CglibMatchmaker<T> implements MethodInterceptor {

    public T getInstance(Class<T> clazz) {

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(clazz);

        enhancer.setCallback(this);

        return (T) enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("媒婆開始物色對象");

        methodProxy.invokeSuper(o, objects);

        System.out.println("如果適合项玛,交往");

        return null;
    }

}
測試代碼
package com.lushwe.pattern.proxy.cglib;

/**
 * 說明:Tom
 *
 * @author Jack Liu
 * @date 2019-05-30 11:12
 * @since 1.0
 */
public class Tom {

    public void findLove() {

        System.out.println("Tom找對象貌笨,膚白貌美大長腿");

    }
}
package com.lushwe.pattern.proxy.cglib;

/**
 * 說明:Cglib動態(tài)代理測試類
 *
 * @author Jack Liu
 * @date 2019-05-30 11:17
 * @since 1.0
 */
public class CglibProxyTest {

    public static void main(String[] args) {

        CglibMatchmaker<Tom> cglibMatchmaker = new CglibMatchmaker();

        Tom tom = cglibMatchmaker.getInstance(Tom.class);

        tom.findLove();
    }
}
運行 CglibProxyTest ,日志打印結果如下
媒婆開始物色對象
Tom找對象襟沮,膚白貌美大長腿
如果適合锥惋,交往
總結
  • 優(yōu)點:

    • i 動態(tài)生成代理類,被代理類接口變更开伏,CglibMatchmaker 不需要修改
    • ii 代理類不需要實現(xiàn)接口
  • 缺點:

    • i 不能對 final 類進行繼承

3 代理模式的應用

  • Spring Aop 就是運用動態(tài)代理實現(xiàn)膀跌,當被代理類實現(xiàn)了接口,使用 Jdk動態(tài)代理 固灵,沒有實現(xiàn)接口捅伤,則使用 Cglib動態(tài)代理
  • MyBatis DAO 也是運用動態(tài)代理,使用 MyBatis 開發(fā) DAO 過程中巫玻,并不需要寫 DAO 的實現(xiàn)類丛忆,由 MyBatis 通過 Jdk動態(tài)代理 自動生成 DAO 的實現(xiàn)類
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市仍秤,隨后出現(xiàn)的幾起案子熄诡,更是在濱河造成了極大的恐慌,老刑警劉巖诗力,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凰浮,死亡現(xiàn)場離奇詭異,居然都是意外死亡苇本,警方通過查閱死者的電腦和手機袜茧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圈澈,“玉大人惫周,你說我怎么就攤上這事】嫡唬” “怎么了递递?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵喷橙,是天一觀的道長。 經(jīng)常有香客問我登舞,道長贰逾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任菠秒,我火速辦了婚禮疙剑,結果婚禮上,老公的妹妹穿的比我還像新娘践叠。我一直安慰自己言缤,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布禁灼。 她就那樣靜靜地躺著管挟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弄捕。 梳的紋絲不亂的頭發(fā)上僻孝,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音守谓,去河邊找鬼穿铆。 笑死,一個胖子當著我的面吹牛斋荞,可吹牛的內(nèi)容都是我干的荞雏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼譬猫,長吁一口氣:“原來是場噩夢啊……” “哼讯檐!你這毒婦竟也來了?” 一聲冷哼從身側響起染服,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤别洪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柳刮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挖垛,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年秉颗,在試婚紗的時候發(fā)現(xiàn)自己被綠了痢毒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚕甥,死狀恐怖哪替,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情菇怀,我是刑警寧澤凭舶,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布晌块,位于F島的核電站,受9級特大地震影響帅霜,放射性物質(zhì)發(fā)生泄漏匆背。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一身冀、第九天 我趴在偏房一處隱蔽的房頂上張望钝尸。 院中可真熱鬧,春花似錦搂根、人聲如沸珍促。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踢星。三九已至澳叉,卻和暖如春隙咸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背成洗。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工五督, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瓶殃。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓充包,卻偏偏與公主長得像,于是被迫代替她去往敵國和親遥椿。 傳聞我的和親對象是個殘疾皇子基矮,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

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