1. 代理模式主要有兩種:靜態(tài)代理和動態(tài)代理
2. 靜態(tài)代理:
比如要在輸出“HelloWorld”前打印一個字符串“Welcome”
A:先定義一個接口類
- package ttitfly.proxy;
- public interface HelloWorld {
- public void print();
- // public void say();
- }
B: 定義一個該接口的實現(xiàn)類
- package ttitfly.proxy;
- public class HelloWorldImpl implements HelloWorld{
- public void print(){
- System.out.println("HelloWorld");
- }
- // public void say(){
- // System.out.println("Say Hello!");
- // }
- }
C:定義一個靜態(tài)代理類
- package ttitfly.proxy;
- public class StaticProxy implements HelloWorld{
- public HelloWorld helloWorld ;
- public StaticProxy(HelloWorld helloWorld){
- this.helloWorld = helloWorld;
- }
- public void print(){
- System.out.println("Welcome");
- //相當(dāng)于回調(diào)
- helloWorld.print();
- }
- // public void say(){
- // //相當(dāng)于回調(diào)
- // helloWorld.say();
- // }
- }
D: 一個測試類:
- package ttitfly.proxy;
- public class TestStaticProxy {
- public static void main(String[] args){
- HelloWorld helloWorld = new HelloWorldImpl();
- StaticProxy staticProxy = new StaticProxy(helloWorld);
- staticProxy.print();
- // staticProxy.say();
- }
- }
可以看出靜態(tài)代理類有一個很不爽的缺點:當(dāng)如果接口加一個方法(把上面所有的代碼的注釋給去掉),所有的實現(xiàn)類和代理類里都需要做個實現(xiàn)。這就增加了代碼的復(fù)雜度。動態(tài)代理就可以避免這個缺點。
靜態(tài)代理的問題:
1. 一個真實角色必須對應(yīng)一個代理角色,如果大量使用會導(dǎo)致類的急劇膨脹;
2. 當(dāng)如果接口加一個方法(比如上面的say),所有的實現(xiàn)類和代理類里都需要做個實現(xiàn)。這就增加了代碼的復(fù)雜度;
3.如果事先并不知道真實角色,該如何使用代理呢?
采用動態(tài)解決以上問題。
3 。動態(tài)代理
動態(tài)代理與普通的代理相比較,最大的好處是接口中聲明的所有方法都被轉(zhuǎn)移到一個集中的方法中處理(invoke),這樣,在接口方法數(shù)量比較多的時候,我們可以進(jìn)行靈活處理,而不需要像靜態(tài)代理那樣每一個方法進(jìn)行中轉(zhuǎn)。
動態(tài)代理類只能代理接口,代理類都需要實現(xiàn)InvocationHandler類,實現(xiàn)invoke方法。該invoke方法就是調(diào)用被代理接口的所有方法時需要調(diào)用的,該invoke方法返回的值是被代理接口的一個實現(xiàn)類
代理類:
- package ttitfly.proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- //動態(tài)代理類只能代理接口,代理類都需要實現(xiàn)InvocationHandler類,實現(xiàn)invoke方法。該invoke方法就是調(diào)用被代理接口的所有方法時需要調(diào)用的,該invoke方法返回的值是被代理接口的一個實現(xiàn)類
- public class DynamicProxy implements InvocationHandler{
- private Object object;
- //綁定關(guān)系,也就是關(guān)聯(lián)到哪個接口(與具體的實現(xiàn)類綁定)的哪些方法將被調(diào)用時,執(zhí)行invoke方法。
- //Proxy.newProxyInstance的第三個參數(shù)是表明這些被攔截的方法執(zhí)行時需要執(zhí)行哪個InvocationHandler的invoke方法
- public Object bindRelation(Object object){
- this.object = object;
- return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
- }
- //攔截關(guān)聯(lián)的這個實現(xiàn)類的方法被調(diào)用時將被執(zhí)行
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- System.out.println("Welcome");
- Object result = method.invoke(object, args);
- return result;
- }
- }
測試類:
- package ttitfly.proxy;
- public class TestDynamicProxy {
- public static void main(String[] args){
- HelloWorld helloWorld = new HelloWorldImpl();
- DynamicProxy dp = new DynamicProxy();
- //在這里綁定的是HelloWorld,也就是HelloWorld是被代理接口。所以綁定關(guān)系時,需要傳遞一個HelloWorld的實現(xiàn)類的實例化對象。
- HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);
- helloWorld1.print();
- helloWorld1.say();
- //helloWorld2將不被攔截
- HelloWorld helloWorld2 = new HelloWorldImpl();
- helloWorld2.print();
- helloWorld2.say();
- }
- }