設計模式之代理模式and裝飾者模式

注意:本文不講具體的概念,只是談談自己的一些想法。


代理模式分爲:靜態代理,動態代理(jdk動態代理,cglib動態代理)

靜態代理:靜態代理就是在開發的時候直接編碼到程序中,也就是在編碼的時候,我們就已經確定了被代理的對象等信息。

靜態代理思路:創建一個接口,代理類和被代理類都實現該接口,然後代理類還要持有本代理類的一個實例。

                            持有被代理類實例的目的:是爲了能夠在代理類中進行本代理類方法的調用,因爲代理模式最終的目的還是調用被代理類的方法。

                            實現同一接口的目的:是爲了代理類和被代理類都具有相同的方法,然後在代理類的方法中調用被代理類相同的方法,而且我們可以在

                                                                      代理類中調用被代理類該方法的前後實現一些邏輯,例如:權限控制等。因此調用代理類方法的時候,也會

                                                                      調用 被代理類相同的方法。

動態代理

jdk動態代理:jdk自帶的動態代理,主要是利用反射實現,可以運行時動態進行生成。但是該實現必須要依賴於接口。

                       注意上面所說的動態生成,這裏的動態生成指的是什麼呢?

                       指的就是我們在使用動態代理的時候,會自動在代理類中給我們生成與被代理類相同的方法,其中包括該接口中定義的所有方法,以及屬於

                      object類的equals,hashcode,toString方法。

下面我們來看一個例子:

首先創建一個StudentFacade接口和studdentFacadeImpl實現類。

調用方法:                         

public static void main(String[] args) {  
        StudentFacadeProxy proxy = new StudentFacadeProxy();    // 代理類
        StudentFacade studentProxy = (StudentFacade) proxy.bind(new StudentFacadeImpl()/**被代理類*/);  
        studentProxy.study();    // 通過代理類調用study方法
    }  

注意:代碼中的代理類之所以可以轉爲StudentFacade,是因爲自動生成的代理類會根據我們傳遞的接口自動生成該接口的所有方法,也就是說自動生成的代理類
      中其實把接口中的所有方法都實現了一遍(下面會具體說明)

StudentFacadeProxy實現:

public class StudentFacadeProxy implements InvocationHandler {      // jdk動態代理要實現InvocationHandler接口
    private Object target;  
  
    // 創建代理時需要傳遞的參數:類加載器(傳遞被代理類的類加載器),被代理類實現的所有接口(用於動態生成代理類中的方法),實現了
       InvocationHandler接口的類(因爲這個類本身就是,所有這裏將this自身當做參數)
   public Object bind(Object target) {  
        this.target = target;  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }  
  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args)   // invoke方法,自動調用,無需我們手動調用(下面會說明在哪調用的)
            throws Throwable {  
        Object result=null;  
        System.out.println("方式執行之前");
        result=method.invoke(target, args);   // 執行方法(不瞭解的可以看看java反射)
        System.out.println("方法執行之後");  
        return result;  
    }  
  
}  
newProxyInstance源碼:

    public static Object newProxyInstance(ClassLoader loader,    
            Class<?>[] interfaces,    
            InvocationHandler h)    
    throws IllegalArgumentException    
    {    
        if (h == null) {    
            throw new NullPointerException();    
        }    
        
        /*  
         * Look up or generate the designated proxy class.  
         */    
        Class cl = getProxyClass(loader, interfaces);    // 通過類加載器和接口得到代理類的字節碼文件
        
        /*  
         * Invoke its constructor with the designated invocation handler.  
         */    
        try {    
               /*  
                * Proxy源碼開始有這樣的定義:  
                * private final static Class[] constructorParams = { InvocationHandler.class };  
                * cons即是形參爲InvocationHandler類型的構造方法  
               */    
            Constructor cons = cl.getConstructor(constructorParams);     // 通過反射得到形參爲InvocationHandler的構造器
            return (Object) cons.newInstance(new Object[] { h });        // 通過上面的構造器創建出代理對象的實例
        } catch (NoSuchMethodException e) {    
            throw new InternalError(e.toString());    
        } catch (IllegalAccessException e) {    
            throw new InternalError(e.toString());    
        } catch (InstantiationException e) {    
            throw new InternalError(e.toString());    
        } catch (InvocationTargetException e) {    
            throw new InternalError(e.toString());    
        }    
    }    

自動生成的代理類的源碼:

    public final class $Proxy0 extends Proxy implements StudentFacade{    
        private static Method m1;    
        private static Method m0;    
        private static Method m3;    
        private static Method m2;    
        
        static {    
            try {    
              // 這裏就是獲取接口中的方法以及object的方法,因爲invoke方法中需要傳遞該method
                m1 = Class.forName("java.lang.Object").getMethod("equals",    
                        new Class[] { Class.forName("java.lang.Object") });    
        
                m0 = Class.forName("java.lang.Object").getMethod("hashCode",    
                        new Class[0]);    
        
                m3 = Class.forName("***.StudentFacade").getMethod("study",    
                        new Class[0]);    
        
                m2 = Class.forName("java.lang.Object").getMethod("toString",    
                        new Class[0]);    
        
            } catch (NoSuchMethodException nosuchmethodexception) {    
                throw new NoSuchMethodError(nosuchmethodexception.getMessage());    
            } catch (ClassNotFoundException classnotfoundexception) {    
                throw new NoClassDefFoundError(classnotfoundexception.getMessage());    
            }    
        }   
        
        public $Proxy0(InvocationHandler invocationhandler) {    
            super(invocationhandler);    
        }    
        
        // 根據接口就可以知道有哪些方法需要被代理
        @Override    
        public final boolean equals(Object obj) {    
            try {    
                return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();    
            } catch (Throwable throwable) {    
                throw new UndeclaredThrowableException(throwable);    
            }    
        }    
        
        @Override    
        public final int hashCode() {    
            try {    
                return ((Integer) super.h.invoke(this, m0, null)).intValue();    
            } catch (Throwable throwable) {    
                throw new UndeclaredThrowableException(throwable);    
            }    
        }    
        
        public final void study() {                  // 第一段代碼中調用的study()方法其實就是調用的這個方法
            try {    
                super.h.invoke(this, m3, null);       // 這裏自動調用的上面的invoke方法,m3是上面通過反射獲取到的study的method
                return;    
            } catch (Error e) {    
            } catch (Throwable throwable) {    
                throw new UndeclaredThrowableException(throwable);    
            }    
        }    
        
        @Override    
        public final String toString() {    
            try {    
                return (String) super.h.invoke(this, m2, null);    
            } catch (Throwable throwable) {    
                throw new UndeclaredThrowableException(throwable);    
            }    
        }    
    }    

執行邏輯就是:通過代理類調用方法(調用的方法是自動生成的代理類中根據接口生成的方法) --> 在方法中調用invoke()方法,即我們實現了

InvocationHandler的類中我們覆寫的invoke()方法 -=> 執行invoke方法中我們實現的邏輯以及通過反射調用被代理類中我們調用的方法


cglib動態代理:原理就是生成一個被代理目標的子類,然後覆蓋目標中的方法(需要注意的是,對於final類型的類不能使用cglib代理,final類型

                             的方法也不能被覆寫,但是這種方式可以不用實現接口)

實例代碼:

public class ProxyCglib implements MethodInterceptor {     // 實現MethodInterceptor接口 
    private Object target;  
  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        enhancer.setCallback(this);   // 設置回調(就是實現MethodInterceptor接口的類)
        return enhancer.create();     // 創建代理對象
    }  
      
    @Override   
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        System.out.println("方法調用之前");  
        proxy.invokeSuper(obj, args);       // 調用實現類中的該方法
        System.out.println("方法調用之後");  
        return null;  
  
  
    }  
  
}  


最後說一下:靜態代理模式和裝飾者模式的區別

相信很多人和我一樣,剛開時的時候感覺這兩種設計模式實際寫法沒太大區別啊,爲什麼還要搞成兩種設計模式呢?

慢慢我瞭解到,這兩種設計模式雖然思路相同,但是目的卻是不同的。

靜態代理模式目的是爲了調用被代理對象中的方法。而裝飾者模式是爲了增強這個方法的能力,最終目的是調用被裝飾之後的對象

也就是靜態代理是爲了通過別人去代理完成這件事,而裝飾者模式是通過增強自身去完成這件事。

舉例說明一下:

就好比一個程序員要開發一個遊戲,可以編寫這個遊戲的語言沒有學過。那麼他將有兩個不同的做法:

1、自己學習這種語言,然後開發這款遊戲。

2、找一個外包公司去幫助自己開發這款遊戲。

方法一就屬於是裝飾者模式,方法二就屬於是靜態代理模式。


以上純屬學習中自己的見解,如有不對的地方歡迎留言指正。



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章