国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Java通俗易懂系列設計模式之代理模式

發(fā)布時(shí)間:2021-07-17 21:51 來(lái)源:腳本之家 閱讀:0 作者:JaJian 欄目: 編程語(yǔ)言 歡迎投稿:712375056

目錄

    前言

    國內程序員好像普遍對百度都沒(méi)好感,而且百度近些年產(chǎn)生了不少負面的新聞,像16年的魏則西事件,近期的導演吳京黑白照事件,以及最近作家六六斥百度李彥宏:“你是做搜索引擎還是騙子首領(lǐng)”,還有一件就是與程序員有關(guān)的:搜索Julia語(yǔ)言,在百度和Google得出首條搜索結果的差異性而被吐槽。Google雖然受歡迎,但是在國內因內容審查問(wèn)題未解決而不能使用,如果我們要使用它就必須使用代理服務(wù)器,由于放置代理服務(wù)器的地區區域可以訪(fǎng)問(wèn)google,所以我們可以先訪(fǎng)問(wèn)代理服務(wù)器,通過(guò)代理服務(wù)器轉發(fā)我們的請求。這是現實(shí)生活中的一種代理模式的實(shí)例,當然現實(shí)生活中這種實(shí)例很不少,像明星都有助理,打官司有代理律師等等,這種思想也可以用到我們程序設計中。

    介紹

    在設計模式中代理模式可以分為靜態(tài)代理和動(dòng)態(tài)代理,而動(dòng)態(tài)代理根據代理的對象類(lèi)型不同又可以分為Jdk動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理。

    意圖:為其他對象提供一種代理以控制對這個(gè)對象的訪(fǎng)問(wèn)。

    主要解決:在直接訪(fǎng)問(wèn)對象時(shí)帶來(lái)的問(wèn)題,比如說(shuō):要訪(fǎng)問(wèn)的對象在遠程的機器上。在面向對象系統中,有些對象由于某些原因(比如對象創(chuàng )建開(kāi)銷(xiāo)很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪(fǎng)問(wèn)),直接訪(fǎng)問(wèn)會(huì )給使用者或者系統結構帶來(lái)很多麻煩,我們可以在訪(fǎng)問(wèn)此對象時(shí)加上一個(gè)對此對象的訪(fǎng)問(wèn)層。

    何時(shí)使用:想在訪(fǎng)問(wèn)一個(gè)類(lèi)時(shí)做一些控制。

    如何解決:增加中間層。

    關(guān)鍵代碼:實(shí)現與被代理類(lèi)組合。

    實(shí)現

    近幾年中國電影行業(yè)蓬勃發(fā)展,電影攝制需要的一種特殊演員->替身,主要任務(wù)是代替影片中原演員表演某些特殊的、高難度的動(dòng)作和技能或原演員所不能勝任的驚險動(dòng)作,如武打、騎術(shù)、駕車(chē)等。拍攝的時(shí)候雖然是替身在拍攝,但是呈現在熒幕前我們觀(guān)眾卻不知道是替身而認為是明星的真實(shí)拍攝,代理模式也有這種特點(diǎn),雖然是代理類(lèi)在完成任務(wù),但是呈現出來(lái)的卻是真實(shí)類(lèi)的實(shí)現。接下來(lái)我們以這種生活中的實(shí)例來(lái)作示例:

    公共表演接口的定義

    /** 表演 */
    public interface Performance {
        void act();
    }

    一.靜態(tài)代理

    明星的實(shí)體類(lèi)

    /** 明星 */
    public class Actor implements Performance {
        @Override
        public void act() {
            System.out.println("明星上場(chǎng)拍功夫電影");
        }
    }

    替身演員的實(shí)體類(lèi)

    /**
     * 替身演員
     */
    public class Stuntman implements Performance {
    
        private Actor actor;
    
        @Override
        public void act() {
            if (actor == null) {
                actor = new Actor();
            }
            System.out.println("替身演員表演跳火車(chē).");
            actor.act();
            System.out.println("替身演員表演空中360°旋轉飛踢.");
        }
    }

    執行Demo

    public class ProxyPatternDemo {
        public static void main(String[] args) {
            System.out.println("------電影拍攝開(kāi)始------");
            Performance perform = new Stuntman();
            perform.act();
            System.out.println("------電影拍攝結束------");
        }
    }

    執行程序,輸出結果:

    ------電影拍攝開(kāi)始------

    替身演員表演跳火車(chē).

    明星上場(chǎng)拍功夫電影

    替身演員表演空中360°旋轉飛踢.

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

    1、Jdk動(dòng)態(tài)代理是由Java內部的反射機制來(lái)實(shí)現的,目標類(lèi)基于統一的接口InvocationHandler。

    2、代理對象是在程序運行時(shí)產(chǎn)生的,而不是編譯期;

    3、對代理對象的所有接口方法調用都會(huì )轉發(fā)到InvocationHandler.invoke()方法,在invoke()方法里我們可以加入任何邏輯,比如修改方法參數,加入日志功能、安全檢查功能等;之后我們通過(guò)某種方式執行真正的方法體,

    4、對于從Object中繼承的方法,JDK動(dòng)態(tài)代理會(huì )把hashCode()、equals()、toString()這三個(gè)非接口方法轉發(fā)給InvocationHandler,其余的Object方法則不會(huì )轉發(fā)。詳見(jiàn)JDK Proxy官方文檔。

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

    public class JdkDynamicProxy implements InvocationHandler {
    
        private Object target;
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("替身演員表演跳火車(chē).");
            Object o = method.invoke(target, args);
            System.out.println("替身演員表演空中360°旋轉飛踢.");
            return o;
        }
    
        public Object bind(Object target) {
            //取得代理對象
            this.target = target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    }

    執行Demo

    public static void main(String[] args) {
         //創(chuàng  )建JDK動(dòng)態(tài)代理類(lèi)
         JdkDynamicProxy proxy = new JdkDynamicProxy();
         //綁定對象
         Performance performProxy = (Performance) proxy.bind(new Actor());
         System.out.println("------電影拍攝開(kāi)始------");
         performProxy.act();
         System.out.println("------電影拍攝結束------");
    }

    執行結果

    ------電影拍攝開(kāi)始------

    替身演員表演跳火車(chē).

    明星上場(chǎng)拍功夫電影

    替身演員表演空中360°旋轉飛踢.

    Java動(dòng)態(tài)代理為我們提供了非常靈活的代理機制,但Jdk動(dòng)態(tài)代理是基于接口的,如果對象沒(méi)有實(shí)現接口我們該如何代理呢?答案是Cglib動(dòng)態(tài)代理。

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

    cglib動(dòng)態(tài)代理底層則是借助asm來(lái)實(shí)現的,它允許我們在運行時(shí)對字節碼進(jìn)行修改和動(dòng)態(tài)生成,cglib這種第三方類(lèi)庫實(shí)現的動(dòng)態(tài)代理應用更加廣泛,且在效率上更有優(yōu)勢。
    目標類(lèi)基于統一的接口MethodInterceptor。

    CGLIB的核心類(lèi):
    net.sf.cglib.proxy.Enhancer – 主要的增強類(lèi)。
    net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類(lèi),它是Callback接口的子接口,需要用戶(hù)實(shí)現。
    net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類(lèi)的代理類(lèi),可以方便的實(shí)現對源對象方法的調用。

    我們要使用cglib代理必須引入cglib的jar包(package net.sf.cglib.proxy;),我在這里使用的是spring包中cglib,其實(shí)和單獨的引cglib包是一樣的,只不過(guò)spring為了版本不沖突,將cglib包含在自己的包中。

    cglib動(dòng)態(tài)代理實(shí)現:

    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    import java.lang.reflect.Method;
    
    public class CglibDynamicProxy implements MethodInterceptor {
    
        private Object target;
    
        //創(chuàng  )建代理對象
        public Object getInstance(Object target) {
            this.target = target;
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(this.target.getClass());
            // 回調方法
            enhancer.setCallback(this);
            // 創(chuàng  )建代理對象
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("替身演員表演跳火車(chē).");
            Object result = methodProxy.invokeSuper(o, objects);
            System.out.println("替身演員表演空中360°旋轉飛踢.");
            return result;
        }
    }

    執行Demo

    public static void main(String[] args) {
           CglibDynamicProxy cglibProxy = new CglibDynamicProxy();
            Performance userService = (Performance) cglibProxy.getInstance(new Actor());
            System.out.println("------電影拍攝開(kāi)始------");
            userService.act();
            System.out.println("------電影拍攝結束------");
        }

    執行結果

    ------電影拍攝開(kāi)始------

    替身演員表演跳火車(chē).

    明星上場(chǎng)拍功夫電影

    替身演員表演空中360°旋轉飛踢.

    總結

    1、通過(guò)以上的例子我們可以發(fā)現代理模式的特點(diǎn):

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

    • 職責清晰。
    • 高擴展性。
    • 智能化。

    缺點(diǎn):

    • 由于在客戶(hù)端和真實(shí)主題之間增加了代理對象,因此有些類(lèi)型的代理模式可能會(huì )造成請求的處理速度變慢。
    • 實(shí)現代理模式需要額外的工作,有些代理模式的實(shí)現非常復雜。

    2、Jdk動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理的區別:

    • JDK的動(dòng)態(tài)代理機制只能代理實(shí)現了接口的類(lèi),而不能實(shí)現接口的類(lèi)就不能實(shí)現JDK的動(dòng)態(tài)代理。
    • cglib是針對類(lèi)來(lái)實(shí)現代理的,他的原理是對指定的目標類(lèi)生成一個(gè)子類(lèi),并覆蓋其中方法實(shí)現增強,但因為采用的是繼承,所以不能對final修飾的類(lèi)進(jìn)行代理。同樣的,final方法是不能重載的,所以也不能通過(guò)CGLIB代理,遇到這種情況不會(huì )拋異常,而是會(huì )跳過(guò)final方法只代理其他方法。
    • JDK動(dòng)態(tài)代理是Java原生支持的,不需要任何外部依賴(lài),但是它只能基于接口進(jìn)行代理;CGLIB通過(guò)繼承的方式進(jìn)行代理,無(wú)論目標對象有沒(méi)有實(shí)現接口都可以代理,但是無(wú)法處理final的情況。
    • 和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類(lèi)的接口。
    • 和裝飾器模式的區別:裝飾器模式為了增強功能,而代理模式是為了加以控制。

    以上就是Java通俗易懂系列設計模式之代理模式的詳細內容,更多關(guān)于Java設計模式的資料請關(guān)注腳本之家其它相關(guān)文章!

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

    美女裸身裸乳免费视频无毒不卡| 亚洲成在人线A免费77777| 国产精品亚洲а∨天堂免下载| 成在人线AV无码免费高潮喷水| 最好看的电影2019中文字幕| 亚洲精品狼友在线播放|