代理模式学习
说到代理我能想到的是代理商,例如IBM需要卖本本,一般不会自己去卖,而是把货
给代理商,委托他们来卖,用户如果需要买ibm的本本,就可以通过这些代理商买到。
用官方的一句话说,代理模式通过使用代理来替代实际的对象,使程序能够控制对该对象的访问。
其实这些用类图来表示就是很简单的一个关系,代理模式并不是一个很复杂的模式,只是使用最简单的抽象类或者接口来封装一个实现的过程。
其实最重要的是代理对象中包含了真实对象的引用,这样代理对象就可以再执行真实对象的方法前进行一些操作,就像打日志,校验权限等,而且有不用破坏真实对象原有的逻辑,这样符合开-闭原则(Open-Closed principle,简称OCP)。
静态代理
代理模式在代码中的实现分静态代理和动态代理。静态代理则是基于上述原理我们自己的实现。
我们简单的实现一个类,接口就不贴了。
2
3 public class HelloWorldImpl implements HelloWorld {
4
5 public void print() {
6 System.out.println("helloworld");
7
8 }
9
10 public void say() {
11 System.out.println("Say Hello!");
12 }
13
14 }
作为静态代理来说,之需要简单的扩充一下实现类,把实现类作为一个属性传入代理即可。
2
3 public class StaticProxyInstance {
4
5 private HelloWorld helloWorld;
6
7 /**
8 * proxy {@link HelloWorld#print()} method
9 */
10 public void invoke() {
11 helloWorld.print();
12 }
13
14 public HelloWorld getHelloWorld() {
15 return helloWorld;
16 }
17
18 public void setHelloWorld(HelloWorld helloWorld) {
19 this.helloWorld = helloWorld;
20 }
21
22 }
这样总的来说比较灵活。这个依赖关系是我们自己做的,我们完全可以交给spring处理。按照上面的这种做法有一个缺点,如果接口中方法很多,那么我们实现每一个方法都要添加一个方法,影响了我们的业务处理。
Java实现的动态代理
Java中的动态代理需要实现InvocationHandler接口。同时,需要一个被代理的对象,当访问这个代理对象的时候,InvocationHandler接口的invoke方法将被触发。最出名的动态代理的例子就是spring的AOP,可以在方法前等地方打印日志,操纵数据等。
Java的动态代理必须要提供一个返回代理对象的地方。Invoke方法只是用来执行。
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Proxy;
6
7 public class DynamicProxyInstance implements InvocationHandler {
8
9 private Object object;
10
11 public Object invoke(Object proxy, Method method, Object[] args)
12 throws Throwable {
13 //在方法调用前输出
14 System.out.println("Welcome");
15 Object result = method.invoke(object, args);
16 System.out.println("after the method invoke");
17 return result;
18 }
19
20 public Object bindRelation(Object object) {
21 this.object = object;
22 return Proxy.newProxyInstance(object.getClass().getClassLoader(),
23 object.getClass().getInterfaces(), this);
24 }
25 }
像code中的那样,简单的使用一个bindRelation方法来返回代理对象,最重要的代码为:
2 object.getClass().getInterfaces(), this);
通过Proxy类新建了一个代理实例。
2 DynamicProxyInstance dp = new DynamicProxyInstance();
3 HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);
4 helloWorld1.print();
只有通过这个代理实例执行的方法才会被代理接口绑定做一些其他处理。