一天一種設計模式之五-----代理模式

一.代理模式簡介

  1. 代理模式屬於結構型模式java

  2. 定義:代理模式爲其餘對象提供一種代理以控制對這個對象的訪問。編程

  3. 代理模式是java框架層面應用最普遍的少數幾種設計模式之一,很是重要。設計模式

  4. 適用場景:安全

    1. 遠程代理,爲一個對象在不一樣的地址空間提供局部表明,這樣能夠隱藏一個對象存在於不一樣地址空間的事實。性能優化

    2. 虛擬代理,根據須要建立開銷很大的對象,經過它來存放實例化須要很長時間的對象,這樣能夠達到性能優化;框架

    3. 安全代理,用來控制真實對象訪問時的權限。通常用於對象應該有不一樣的訪問權限的時候;ide

    4. 智能指引,是指當調用真實的對象的時候,代理處理另外的一些事情(用的比較多)性能

  5. 代理模式要求代理實現與被代理對象相同的接口(cglib與被代理對象是子類與父類的關係),以保證任什麼時候候都能代替真實對象。這也是它與適配器模式的區別!!測試

  6. 代理模式普遍應用於aop編程。可以在不改變源代碼的前提下提供統一的日誌管理,先後置攔截器,符合開放封閉原則、依賴倒置原則,優化

二.測試代碼

  1.     下面代碼屬於靜態代理,大體場景是追求者會追妹子,但他不認識某girl,而經過代理類認識,因此追求者經過代理類對妹子展開了追求。

  2. public class ProxyTest {
        public static void main(String[] args) {
            PursuitWay pursuitWay=new Proxy(new Pursuiter(new Girl("小白")));
            pursuitWay.giveFlower();
            pursuitWay.giveGift();
        }
    }
    interface PursuitWay{
        void giveFlower();
        void giveGift();
    }
    class Girl{
        private String name;
        public Girl(String name) {
            this.name=name;
        }
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
    }
    class Pursuiter implements PursuitWay{
        Girl girl;
        public Pursuiter(Girl girl){
            this.girl=girl;
        }
        @Override
        public void giveFlower() {
            System.out.println("追求者送"+girl.getName()+"花");
        }
    
        @Override
        public void giveGift() {
            System.out.println("追求者送"+girl.getName()+"禮物");
        }
        
    }
    
    class Proxy implements PursuitWay{
        PursuitWay pursuter;
        public Proxy(PursuitWay pursuiter){
            this.pursuter=pursuiter;
        }
        @Override
        public void giveFlower() {
            pursuter.giveFlower();
        }
    
        @Override
        public void giveGift() {
            pursuter.giveGift();
        }
        
    }
  3. 既然是經過代理去追妹子,那每次苦力活代理作作日誌,設置個障礙就不難理解了吧。

  4. 上述功能若是要經過適配器模式實現,則proxy沒必要非要實現PursuitWay,它會有本身的方法而沒必要非要是giveXXX,只須要在它本身的方法中實現pursuter的giveXXX方法就能夠了,具體代碼略。

  5. 上述代理模式屬於靜態代理,由於代理類是咱們本身編寫出來的,而動態代理則是經過java虛擬機,在運行期間生成的字節碼。

  6. 下述代碼是經過動態代理實現的相同功能

      1.   獲取追求者上的全部接口列表;
        2.   肯定要生成的代理類的類名,默認爲:com.sun.proxy.$ProxyXXXX ;

        3.   根據須要實現的接口信息,在代碼中動態建立 該Proxy類的字節碼;

        4 .  將對應的字節碼轉換爲對應的class 對象;

        5.   建立InvocationHandler 實例handler,用來處理Proxy全部方法調用;

        6.   Proxy 的class對象 以建立的handler對象爲參數,實例化一個proxy對象

  7. public class ProxyTest {
        public static void main(String[] args) {
            Class clazz=Proxy.getProxyClass(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces());
            System.out.println("proxy類爲"+clazz.getName());
            System.out.println("proxy實現的接口有"+clazz.getInterfaces()[0].getName());
            System.out.println("-----開始生成代理對象(實際上該代理對象就是一個該接口的實現類)");
            PursuitWay pursuter=(PursuitWay) Proxy.newProxyInstance(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces(), new MyInvocationHandler(new Pursuiter(new Girl("小白"))));
            pursuter.giveFlower();
            pursuter.giveGift();
        }
    }
    interface PursuitWay{
        void giveFlower();
        void giveGift();
    }
    class Girl{
        private String name;
        public Girl(String name) {
            this.name=name;
        }
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
    }
    class Pursuiter implements PursuitWay{
        Girl girl;
        public Pursuiter(Girl girl){
            this.girl=girl;
        }
        @Override
        public void giveFlower() {
            System.out.println("追求者送"+girl.getName()+"花");
        }
    
        @Override
        public void giveGift() {
            System.out.println("追求者送"+girl.getName()+"禮物");
        }
        
    }
    class MyInvocationHandler implements InvocationHandler{
        Object object;
        public MyInvocationHandler(Object object){
            this.object=object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            return method.invoke(object, args);
        }
        
    }
  8. 上述代碼經過jdk自帶的代理類實現,它和靜態代理類有一樣的侷限性,就是要求被代理類必須有一個或者多個對應具體業務邏輯的接口。myInvocationHandler裏邊的invoke方法中能夠提供攔截、寫日誌等功能。

  9. cglib包的代理類CglibProxy是針對某個類生成一個子類,該子類天然會包括其父類的全部業務邏輯方法。並且不在侷限於必須有上層接口。可是cglib包也要求被代理類不能爲final類,不然繼承不了,測試代碼和動態代理很像,略。

  10. cglib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,理論上比使用Java反射效率要高,不過有大神曾經測試過,貌似性能差很少,並且jdk的動態代理還要比cglib效率高一點點。有興趣的朋友能夠去試試。

  11. 歡迎大神交流意見。

  12. 下一節將會講解工廠方法模式,該模式在service層應用很廣泛。敬請期待。

相關文章
相關標籤/搜索