在学习spring时,里面有提到代理模式,看了一些前辈的博文,为了加强记忆,今天总结一下,
1、概念
a) 为某个对象提供一个代理类,来隔开用户对这个对象的直接操作,相当于给这个对象分配了一个经纪人,有任何问题需要找这个对象时,都必须和他的经纪人(代理类)说,在由经纪人决定是否要和被代理对象说。
b) 代理类和委托类(被代理类)有共同的父类或父接口。
c) 代理类在执行委托类方法之前和之后,可以加入额外的操作,如打印日志,过滤,预处理等操作。
静态代理模式图,图下:
图一 图二
2、从图中可以看出,代理接口(Subject)、代理类(ProxySubject)、委托类(RealSubject)形成一个“品”字结构。
3、 根据代理类的生成时间不同可以将代理分为静态代理和动态代理两种,
a) 这篇博文讲第一种:静态代理。
b) 下篇博客将第二种:动态代理 ,见《Java设计模式之----动态代理(二)》
4、 下面模拟一个需求:
a) 委托类(被代理类)要处理一项耗时较长的任务,
b) 客户类需要打印出执行任务消耗的时间。
c) 解决这个问题需要记录任务执行前时间和任务执行后时间,两个时间差就是任务执行消耗的时间。
所谓静态就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类(被代理类)的关系在运行前就确定了。
1、定义接口:代码如下:
package com._test.proxy; /** * 定义一个接口 */ public interface Subject { /** * 定义执行的方法 * @param name */ public void doSomething(String taskName) ; }
2、定义被代理类,代码如下:
package com._test.proxy; /** * 委托类(被代理类) */ public class RealSubject implements Subject { /** * 委托类的方法 */ public void doSomething(String taskName) { System.out.println("委托类正在做某事:" + taskName); try { Thread.sleep(2000);//模拟耗时任务 } catch (InterruptedException e) { e.printStackTrace(); } } }
3、定义静态代理类,代码如下:
package com._test.proxy; /** * 定义静态代理类 */ public class ProxySubject implements Subject { private Subject realSubject; // 代理类持有委托类的对象引用 public ProxySubject(Subject realSubject) { this.realSubject = realSubject; } /** * 代理接下委托类的任务,然后告诉委托类要做什么,除此之外,还可以在委托类做事情的前后,增加相应的工作。 * 这里在委托类执行任务前后,记录时间,最后得出委托类耗时时长 */ public void doSomething(String taskName) { System.out.println("代理类接到这个任务:"+taskName); long stime = System.currentTimeMillis();// 委托类工作开始前时间 /** * 委托类开始做任务 */ realSubject.doSomething(taskName); long endTime = System.currentTimeMillis();// 委托类工作结束后时间 System.out.println("执行任务总耗时" + (endTime - stime) + "毫秒"); } }4、创建静态代理工厂,代码如下:
package com._test.proxy; /** * 静态代理类 */ public class SubjectStaticFactory { /** * 客户端调用此工厂方法获得代理对象, 对于客户端来说,并不知道工厂生产出来的是代理类还是委托类对象 * * @return */ public static Subject getInstance() { return new ProxySubject(new RealSubject()); } }
5、客户类,代码如下:
package com._test.proxy; public class Client { public static void main(String[] args) { Subject proxy = SubjectStaticFactory.getInstance(); String taskName = "来加班"; System.out.println("客户端:公司要求员工" + taskName); proxy.doSomething(taskName); } }
6、执行结果:
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。 缺点: 1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。 2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度.
参考博文地址:http://layznet.iteye.com/blog/1182924