1. 代理模式主要有兩種:靜態代理和動態代理 

2. 靜態代理: 

比如要在輸出“HelloWorld”前打印一個字符串“Welcome” 

A:先定義一個接口類 
Java代碼
  1. package ttitfly.proxy;      
  2.      
  3. public interface HelloWorld {      
  4.     public void print();      
  5. //  public void say();      
  6. }   
  7.      
 


B: 定義一個該接口的實現類 

Java代碼
  1. package ttitfly.proxy;      
  2.      
  3. public class HelloWorldImpl implements HelloWorld{      
  4.      
  5.     public void print(){      
  6.         System.out.println("HelloWorld");      
  7.     }      
  8. //  public void say(){      
  9. //      System.out.println("Say Hello!");      
  10. //  }      
  11. }     
 


C:定義一個靜態代理類 
Java代碼
  1. package ttitfly.proxy;      
  2.      
  3. public class StaticProxy implements HelloWorld{      
  4.      
  5.     public HelloWorld helloWorld ;      
  6.     public StaticProxy(HelloWorld helloWorld){      
  7.         this.helloWorld = helloWorld;      
  8.     }      
  9.           
  10.     public void print(){      
  11.         System.out.println("Welcome");      
  12.         //相當于回調      
  13.         helloWorld.print();      
  14.     }      
  15.           
  16. //  public void say(){      
  17. //      //相當于回調      
  18. //      helloWorld.say();      
  19. //  }      
  20. }      
 


D: 一個測試類: 
   
Java代碼
  1. package ttitfly.proxy;      
  2.      
  3. public class TestStaticProxy {      
  4.      
  5.     public static void main(String[] args){      
  6.         HelloWorld helloWorld = new HelloWorldImpl();      
  7.         StaticProxy staticProxy = new StaticProxy(helloWorld);      
  8.         staticProxy.print();      
  9.               
  10. //      staticProxy.say();      
  11.     }      
  12. }      


可以看出靜態代理類有一個很不爽的缺點:當如果接口加一個方法(把上面所有的代碼的注釋給去掉),所有的實現類和代理類里都需要做個實現。這就增加了代碼的復雜度。動態代理就可以避免這個缺點。
靜態代理的問題:

     1. 一個真實角色必須對應一個代理角色,如果大量使用會導致類的急劇膨脹;

     2. 當如果接口加一個方法(比如上面的say),所有的實現類和代理類里都需要做個實現。這就增加了代碼的復雜度;

     3.如果事先并不知道真實角色,該如何使用代理呢?

 

采用動態解決以上問題。



3 。動態代理 

動態代理與普通的代理相比較,最大的好處是接口中聲明的所有方法都被轉移到一個集中的方法中處理(invoke),這樣,在接口方法數量比較多的時候,我們可以進行靈活處理,而不需要像靜態代理那樣每一個方法進行中轉。 

動態代理類只能代理接口,代理類都需要實現InvocationHandler類,實現invoke方法。該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的一個實現類 

代理類: 
      
Java代碼
  1. package ttitfly.proxy;          
  2.          
  3. import java.lang.reflect.InvocationHandler;          
  4. import java.lang.reflect.Method;          
  5. import java.lang.reflect.Proxy;          
  6. //動態代理類只能代理接口,代理類都需要實現InvocationHandler類,實現invoke方法。該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的一個實現類          
  7. public class DynamicProxy implements InvocationHandler{          
  8.               
  9.     private Object object;           
  10.     //綁定關系,也就是關聯到哪個接口(與具體的實現類綁定)的哪些方法將被調用時,執行invoke方法。      
  11.     //Proxy.newProxyInstance的第三個參數是表明這些被攔截的方法執行時需要執行哪個InvocationHandler的invoke方法      
  12.     public Object bindRelation(Object object){           
  13.         this.object = object;          
  14.         return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);           
  15.     }           
  16.     //攔截關聯的這個實現類的方法被調用時將被執行          
  17.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {           
  18.         System.out.println("Welcome");          
  19.         Object result = method.invoke(object, args);           
  20.         return result;          
  21.     }          
  22.          
  23. }          


測試類: 
     
Java代碼
  1. package ttitfly.proxy;          
  2.          
  3. public class TestDynamicProxy {          
  4.     public static void main(String[] args){          
  5.         HelloWorld helloWorld = new HelloWorldImpl();          
  6.         DynamicProxy dp = new DynamicProxy();          
  7.         //在這里綁定的是HelloWorld,也就是HelloWorld是被代理接口。所以綁定關系時,需要傳遞一個HelloWorld的實現類的實例化對象。          
  8.         HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);           
  9.         helloWorld1.print();           
  10.         helloWorld1.say();          
  11.               
  12.         //helloWorld2將不被攔截      
  13.         HelloWorld helloWorld2 = new HelloWorldImpl();      
  14.         helloWorld2.print();           
  15.         helloWorld2.say();      
  16.               
  17.     }          
  18. }