java代理模式
首先看一张类图,感觉这幅图的描述是比较准确的。subject是一个接口,底下代理类和被代理类实现了这个接口,而被代理类和代理类是关联关系(我理解为代理类包含了一个被代理类的实体)。
代理模式感觉就是把被代理类的装进代理类中,重写被代理类的方法,由于他们共同都实现了一个接口,在代理类中调用方法,实际上就是访问重新封装的方法了。这样做的好处是,一个代理类可以服务多个不同的类,重新封装他们的方法,当然这些类都必须实现同一个接口。
下面的例子我们使用顾客-点餐例子来讲述代理模式。
在点餐的时候,无论是商人、学生、小朋友都要通过服务员来点餐,此时服务员可以当成是一个代理。而不同种类的顾客可以当成是被代理的人。
代码如下:
Customer.java
package reflection.normalproxy; public interface Customer { public void orderDish(); }
WaiterProxy.java
package reflection.normalproxy; public class WaiterProxy implements Customer { Customer customer; public WaiterProxy(Customer customer){ this.customer=customer; } @Override public void orderDish() { // TODO Auto-generated method stub System.out.println("order before"); customer.orderDish(); System.out.println("order after"); } }
CustomerImpl.java
package reflection.normalproxy; public class CustomerImpl implements Customer { @Override public void orderDish() { // TODO Auto-generated method stub System.out.println("custom order"); } public static void main(String args[]){ Customer c=new CustomerImpl(); Customer p=new WaiterProxy(c); p.orderDish(); } }
我们把主函数写在了最后一个类里面
输出:
order before
custom order
order after
上面的例子有不方便的地方,就是代理类必须实现某个接口,于是我们可以使用java反射机制的代理类。
Customer.java 还是一样
package reflection.normalproxy; public interface Customer { public void orderDish(); }
WaiterHandler.java
package reflection.proxyclass; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class WaiterHandler implements InvocationHandler { Object customer; public WaiterHandler(Object customer){ this.customer=customer; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("order before"); Object result=method.invoke(customer, args); System.out.println("order after"); return result; } }
这个类要实现InvocationHandler接口,跟之前的WaiterProxy类类似,里面提供一个代理方法,只不过这个代理方法是有后面的代理类调用的。
构造函数里面传入被代理的类customer,它可以是非基础类型的Object。
method.invoke()的参数制定了需要代理的类也就是customer以及调用方法时候的参数args,返回值result对应调用代理类调用这个方法的返回结果。由于这个类没有实现接口,有一个问题,那么怎么知道它要调用什么方法呢?如下。
CustomImpl.java
package reflection.proxyclass; import java.lang.reflect.Proxy; public class CustomerImpl implements Customer { @Override public void orderDish() { // TODO Auto-generated method stub System.out.println("custom order"); } public static void main(String args[]){ CustomerImpl c=new CustomerImpl(); WaiterHandler h=new WaiterHandler(c); Customer ci=(Customer)Proxy.newProxyInstance(c.getClass().getClassLoader(), c.getClass().getInterfaces(), h); ci.orderDish(); } }
我们把需要代理的类以及handler传入Proxy.newProxyInstance(),这样利用java反射机制,Proxy会获得需要调用的接口的方法。在我们调用这些接口方法的时候,Proxy会调用invoke()方法进行代理。