代理模式總結(jié)

代理模式概念:

相關(guān)角色:代理接口(Subject)痴奏;代理類(ProxySubject);委托類(RealSubject);客戶端(Client)限府。

舉個(gè)不太恰當(dāng)?shù)睦樱硰V告公司C希望請明星A拍一支廣告痢缎,A有經(jīng)紀(jì)公司B胁勺,B幫助A和公司C進(jìn)行溝通,也就是說独旷,除了拍廣告本身這件事情仍然由A來做署穗,其他事情都由他的經(jīng)紀(jì)公司B來負(fù)責(zé)處理寥裂。
在這個(gè)例子中拍廣告是代理接口;經(jīng)紀(jì)公司B是代理類案疲;明星A是委托類封恰;而廣告公司C可以被認(rèn)為是客戶端。
一切順利的話褐啡,事情的結(jié)果自然是公司(Client)通過經(jīng)紀(jì)公司(ProxySubject)讓明星A(RealSubject)替他們拍了廣告诺舔。

StaticProxy

代理模式目的:

業(yè)務(wù)類只需要關(guān)注業(yè)務(wù)邏輯本身,保證了業(yè)務(wù)類的重用性备畦。為業(yè)務(wù)對象提供一個(gè)代理低飒,以控制對這個(gè)業(yè)務(wù)對象的訪問。并且無需對業(yè)務(wù)類本身進(jìn)行修改懂盐,可控制其上下文操作逸嘀。

代理模式分類:

根據(jù)代理類生成的時(shí)間不同可以分為靜態(tài)代理動態(tài)代理兩種。

靜態(tài)代理

在程序運(yùn)行之前允粤,代理類就已經(jīng)存在了崭倘。

  • 優(yōu)點(diǎn):業(yè)務(wù)類只需要關(guān)注業(yè)務(wù)邏輯本身,保證了業(yè)務(wù)類的重用性类垫。
  • 缺點(diǎn):如果接口增加了一個(gè)方法司光,除了所有實(shí)現(xiàn)類都要去實(shí)現(xiàn)這個(gè)方法之外,所有代理類也需要實(shí)現(xiàn)此方法悉患,增加了代碼維護(hù)的復(fù)雜度残家。

繼續(xù)用上面的例子說,明星A除了會拍廣告還學(xué)會了拍電影售躁,那么經(jīng)紀(jì)公司就不能只知道拍廣告是什么流程了坞淮,還得知道拍電影的流程。

動態(tài)代理

在程序運(yùn)行時(shí)陪捷,代理類才產(chǎn)生回窘。
目的:構(gòu)造通用的代理類。
思想:把所有觸發(fā)RealSubject的動作交給一個(gè)觸發(fā)管理器--InvocationHandler市袖。 外界對代理類中每個(gè)方法的調(diào)用啡直,代理類都回交給InvocationHandler來處理。
方法:在代理類中傳入具體對象時(shí)苍碟,通過其class反射獲取對象在方法區(qū)的結(jié)構(gòu)酒觅,包括其構(gòu)造方法,成員變量和實(shí)現(xiàn)方法等微峰。外界要求代理調(diào)用具體的方法時(shí)舷丹,就根據(jù)反射到的內(nèi)容返回出對應(yīng)的信息。這些信息是在運(yùn)行時(shí)才能夠被確定的蜓肆。

  • 優(yōu)點(diǎn):不需要像靜態(tài)代理那樣被接口方法牽著鼻子走颜凯。
  • 缺點(diǎn):每次都需要有一個(gè)具體對象被傳入到方法中谋币,但并不是所有時(shí)候都由被實(shí)例化的對象可以被傳入。
DynamicProxy.png
應(yīng)用:

Spring的AOP装获,面向切面編程瑞信。其實(shí)就是把幾個(gè)方法的公共部分提取出來做成切面類厉颤,如果這部分代碼需要被修改則只需要修改這一部分穴豫,其他不同的部分用不同的代理類實(shí)現(xiàn),保證了程序的靈活性逼友。

RPC框架精肃,遠(yuǎn)程服務(wù)調(diào)用。比如主機(jī)A上有一個(gè)服務(wù)帜乞,主機(jī)B和C都希望調(diào)用這個(gè)服務(wù)司抱,那么主機(jī)A上首先有一個(gè)該服務(wù)對應(yīng)的代理,用于解析其他服務(wù)器發(fā)來的請求中的參數(shù)黎烈,B和C也有各自的代理類习柠,用來封裝自己要發(fā)送的參數(shù)成二進(jìn)制,通過網(wǎng)絡(luò)發(fā)給A的代理照棋,A的代理類解析之后把服務(wù)返回的內(nèi)容封裝好通過網(wǎng)絡(luò)再發(fā)還給B和C的代理资溃,B和C的代理各自解析之后就獲得了對應(yīng)的結(jié)果。

對于B和C來說烈炭,無需知道底層是如何操作的溶锭,就好像調(diào)用了自己本地的方法一樣。

示例:
/* 自定義代理通過實(shí)現(xiàn)此接口實(shí)現(xiàn)對原方法前后的各種操作
*  proxy為要實(shí)現(xiàn)的代理類符隙,method為所調(diào)用服務(wù)的原生方法趴捅,args為method的參數(shù)
*  在實(shí)現(xiàn)此接口的代理類中,可以在invoke方法中增加任意功能
*  比如method是一個(gè)添加用戶的方法霹疫,那么在實(shí)現(xiàn)類中可以在此方法執(zhí)行之前增加檢查權(quán)限等操作
*/
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args){
        throws Throwable;
    }
}


// 首先需要一個(gè)接口拱绑,用于被各種自定義類統(tǒng)一實(shí)現(xiàn)
public interface UserManager{
    public void addUser(String name);
}

// 然后需要一個(gè)實(shí)現(xiàn)此接口的類(委托類)
public class UserManagerImpl implements UserManager{
    public void addUser(String name){
        System.out.println("User " + name + " is added");
    }
}

// 自定義代理類
public CheckHandler implements InvocationHandler{
    //代理的目標(biāo)對象
    private Object target;
    //通過構(gòu)造函數(shù)動態(tài)傳入對象
    public CheckHandler(Object target){
        this.target = target;
    }
    
    //動態(tài)代理執(zhí)行操作
     @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //檢查當(dāng)前用戶是否有權(quán)限添加user
        System.out.println("Checking...");
        //有權(quán)限就執(zhí)行,可以添加判斷操作丽蝎,此處省略
        //此處參數(shù)為被代理對象
        return method.invoke(target, args);
        
        System.out.println("Success.");
    }    
}

// 相關(guān)的類:
public class Proxy implements java.io.Serializable{
    ……
    //此靜態(tài)方法用于創(chuàng)建對應(yīng)的代理類對象
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{
        Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
    ……
}

在客戶端調(diào)用動態(tài)代理

public class Client{
    public static void main(String[] args){
        String name = "a";
        //創(chuàng)建要代理的對象
        UserManager um = new UserManagerImpl(name);
        //創(chuàng)建代理
        InvocationHandler handler = new CheckHandler(um);
        UserManager m = (UserManager)Proxy.newProxyInstance(um.getClass().getClassLoader(),um.getClass().getInterfaces(), handler);
        m.addUser(name);
    }
}

結(jié)果輸出

//在不改變addUser()方法的前提下欺栗,增加了檢查和反饋的操作

Checking...
User a is added.
Success.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市征峦,隨后出現(xiàn)的幾起案子迟几,更是在濱河造成了極大的恐慌,老刑警劉巖栏笆,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件类腮,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛉加,警方通過查閱死者的電腦和手機(jī)蚜枢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門缸逃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厂抽,你說我怎么就攤上這事需频。” “怎么了筷凤?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵昭殉,是天一觀的道長。 經(jīng)常有香客問我藐守,道長挪丢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任卢厂,我火速辦了婚禮乾蓬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慎恒。我一直安慰自己任内,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布融柬。 她就那樣靜靜地躺著死嗦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丹鸿。 梳的紋絲不亂的頭發(fā)上越走,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音靠欢,去河邊找鬼廊敌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛门怪,可吹牛的內(nèi)容都是我干的骡澈。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼掷空,長吁一口氣:“原來是場噩夢啊……” “哼肋殴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坦弟,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤护锤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后酿傍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烙懦,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年赤炒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氯析。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亏较。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖掩缓,靈堂內(nèi)的尸體忽然破棺而出雪情,到底是詐尸還是另有隱情,我是刑警寧澤你辣,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布巡通,位于F島的核電站,受9級特大地震影響绢记,放射性物質(zhì)發(fā)生泄漏扁达。R本人自食惡果不足惜正卧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一蠢熄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炉旷,春花似錦签孔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至罐盔,卻和暖如春但绕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惶看。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工捏顺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纬黎。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓幅骄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親本今。 傳聞我的和親對象是個(gè)殘疾皇子拆座,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

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

  • 在我們學(xué)校的南邊,有一排高大挺拔的梧桐樹冠息。 好高大的梧桐樹啊挪凑,我們?nèi)齻€(gè)同學(xué)手拉手才能把它抱住好茂盛的梧桐樹...
    住了1啦啦啦啦閱讀 759評論 0 0
  • 地球不只是一個(gè)物質(zhì), 是有生命的逛艰, 像我們的母親一樣躏碳。 人類就是她的孩子, 她一直在養(yǎng)育著我們瓮孙, 但是人類并不知道...
  • “難道就因?yàn)槲邑毟F唐断,地位低下选脊,相貌平平而且身材矮小就沒有靈魂,沒有一顆心了嗎脸甘?你想錯了恳啥!我的心靈和你一樣豐富,我心...
    螞蟻逗大象6閱讀 590評論 0 4
  • 我天生自帶一種技能丹诀,就是只要和女生成為朋友钝的,熟悉到一定程度之后就會變成她們的情感垃圾桶。 無論是碰上奇葩領(lǐng)導(dǎo)了铆遭,和...
    洞洞2閱讀 3,669評論 1 0
  • 1.下載JDK 1.1 JDK下載鏈接 1.2 安裝 下載完成后直接點(diǎn)擊安裝枚荣,下一步即可碗脊,JDK安裝會分為兩個(gè)步驟...
    cybeyond閱讀 223評論 0 1