设计模式——代理模式
Posted 向向向阳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式——代理模式相关的知识,希望对你有一定的参考价值。
所谓代理模式,简单地说将原来直接由客户实现或者调用功能代码块通过一个中间代理的对象去调用或者实现,目的是可以降低非业务代码对业务代码的污染以及提高代码复用性及可维护性。
一般Java代理模式编写有以下几种方式实现:
1、继承的方式
2、聚合的方式
3、JDK动态代理的方式
4、cglib动态代理的方式
接下类我将依次分析这几种代理模式的实现原理及有缺点:
一、继承的方式实现代理
1、Machine为抽象接口,定义抽象方法action
public interface Machine { public void action(); }
2、Computer 实现该接口与action方法
public class Computer implements Machine { @Override public void action() { int num = 1+2; System.out.println("计算机计算结果为:"+num); } }
3、但是我们为了实现对action()方法运行的监控又定义了一个新的Computer的子类ComputerProxy代理类,该类的目的是在执行Computer的action()方法的时候执行用时监控事务。
public class ComputerProxy extends Computer { public void action(){ long startTime = System.currentTimeMillis(); System.out.println("计算机开始计算"); super.action(); System.out.println("计算机停止执行"); long endTime=System.currentTimeMillis(); System.out.println("计算用时"+(endTime-startTime)+"毫秒"); } }
4、客户端通过ComputerProxy类的的acton()(代理)方法实现action功能以及实现事务监控
public class Client { public static void main(String[] args) { // TODO Auto-generated method stub Machine m = new ComputerProxy(); m.action(); } }
结果:
总结:
继承的方式很简单就能实现代理,但这种方式实现的代理有一个明显的缺点就是面对不同事务的组合需要进行编写很多的子类,并且无法根据需求快速的调整事务的组合。
二、聚合的方式实现代理
1、如上图所示,创建了两个实现Machine接口的实现类MachineTimerImp和
MachineLogImp,这两个实现类实现了类聚合封装的功能,以实现Machine接口类实例作为传入构造方法的参数,在action()中实现事务的聚合封装。具体操作在Client中进行。
- MachineLogImp
public class MachineTimerImp implements Machine{ public MachineTimerImp(Machine machine) { super(); this.machine = machine; } private Machine machine; public void action(){ long startTime = System.currentTimeMillis(); System.out.println("计算机开始计算"); machine.action(); System.out.println("计算机停止执行"); long endTime=System.currentTimeMillis(); System.out.println("计算用时"+(endTime-startTime)+"毫秒"); } }
- MachineLogImp
public class MachineLogImp implements Machine{ private Machine machine; public MachineLogImp(Machine machine) { super(); this.machine = machine; } @Override public void action() { // TODO Auto-generated method stub System.out.println("日志开始"); machine.action(); System.out.println("日志记录结束"); } }
2、Client中的聚合封装的实现
public class Client { public static void main(String[] args) { // TODO Auto-generated method stub Computer computer = new Computer(); Machine mt = new MachineTimerImp(computer); Machine mw = new MachineLogImp(mt); mw.action(); } }
结果:
3、结论:
显然聚合封装的形式更加灵活在多重事务的组合方面,而且也保证了代码的可复用性。
三、JDK动态代理的方式
jdk动态代理顾名思义,通过接口,jvm能够动态生成代理类,并且InvocationHandler接口的实现类中填写需要实现的业务代码就可以实现动态代理。
1、如上图所示,TimeHandler是InvocationHandler接口的实现类,该接口的实现类是Proxy.newProxyInstance生成动态代理对象的静态方法的传入参数
测试类代码:
public class Test { /** * jdk动态代理的测试类 * @throws SecurityException * @throws NoSuchMethodException */ public static void main(String[] args) throws NoSuchMethodException, SecurityException { Computer computer = new Computer(); InvocationHandler h = new TimeHandler(computer); Class<?> cls = computer.getClass(); System.out.println(cls.getInterfaces().getClass().getName()); Machine m= (Machine)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),h); m.action(); } /** * loader 类加载器 * interfaces 实现接口 * h InvocationHandler */ }
其中Proxy.newProxyInstance官方API:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这个方法传入
loader - the class loader to define the proxy class //定义代理类的类加载器
interfaces - the list of interfaces for the proxy class to implement //代理类实现的接口的列表
h - the invocation handler to dispatch method invocations to //InvocationHandler的实现类
目的是通过这个封装好的方法返回动态生成的代理对象。
具体JVM的实现可以参考,这位大神已经写的很详细了
2、在InvocationHandler的实现类TimeHandler中
public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) { super(); this.target = target; } /** * proxy 被代理的对象 * method 被代理的对象的方法 * args 方法的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub long startTime = System.currentTimeMillis(); System.out.println("计算机开始计算"); method.invoke(target, args); System.out.println("计算机停止执行"); long endTime=System.currentTimeMillis(); System.out.println("计算用时"+(endTime-startTime)+"毫秒"); return null; } }
稍等。。。
以上是关于设计模式——代理模式的主要内容,如果未能解决你的问题,请参考以下文章