代理模式主要有兩種:靜態代理和動態代理
1,靜態代理:
比如要在輸出“HelloWorld”前打印一個字符串“Welcome”
A:先定義一個接口類
public interface HelloWorldIF {
public void print();
// public void say();
}
B:定義一個該接口的實現類
public class HelloWorldImpl implements HelloWorldIF{
public void print(){
System.out.println("HelloWorld");
}
// public void say(){
// System.out.println("Say Hello!");
// }
}
C:定義一個靜態代理類
public class StaticProxy implements HelloWorldIF{
public HelloWorld helloWorld ;
public StaticProxy(HelloWorld helloWorld){
this.helloWorld = helloWorld;
}
public void print(){
System.out.println("Welcome");
//相當於回調
helloWorld.print();
}
// public void say(){
// //相當於回調
// helloWorld.say();
// }
}
可以看出靜態代理類有一個很不爽的缺點:當如果接口加一個方法(把上面所有的代碼的註釋給去掉),所有的實現類和代理類裏都需要做個實現。這就增加了代碼的複雜度。動態代理就可以避免這個缺點。
2,動態代理
動態代理與普通代理相比較,最大的好處是接口中聲明的所有方法都被轉移到一個集中的方法中處理(invoke),這樣,在接口方法數量比較多的時候,我們可以進行靈活處理,而不需要像靜態代理那樣每個方法進行中轉。
動態代理類只能代理接口,代理類都需要實現InvocationHandler類,實現invoke方法。該方法就是調用被代理接口的所有方法時需要調用的,而invoke方法返回的值是被代理接口的一個實現類。
代理類:
import
Java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//動態代理類只能代理接口,代理類都需要實現InvocationHandler類,實現invoke方法。該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的一個實現類
public class DynamicProxy implements InvocationHandler{
private Object object;
//綁定關係,也就是關聯到哪個接口(與具體的實現類綁定)的哪些方法將被調用時,執行invoke方法。
//Proxy.newProxyInstance的第三個參數是表明這些被攔截的方法執行時需要執行哪個InvocationHandler的invoke方法
public Object bindRelation(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
//攔截關聯的這個實現類的方法被調用時將被執行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Welcome");
Object result = method.invoke(object, args);
return result;
}
}
測試類:
public class TestDynamicProxy {
public static void main(String[] args){
HelloWorld helloWorld = new HelloWorldImpl();
DynamicProxy dp = new DynamicProxy();
//在這裏綁定的是HelloWorld,也就是HelloWorld是被代理接口。所以綁定關係時,需要傳遞一個HelloWorld的實現類的實例化對象。
HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);
helloWorld1.print();
helloWorld1.say();
//helloWorld2將不被攔截
HelloWorld helloWorld2 = new HelloWorldImpl();
helloWorld2.print();
helloWorld2.say();
}
}
在測試類裏調用實現類的print和say方法,因爲代理類裏代理了HelloWorld的所有方法。所以就不需要像靜態代理類那樣一一實現了。