代理模式(PROXY),别名Surrogate(代理),通过为其他对象提供一种代理以控制对这个对象的访问,属于对象结构型模式。软件开发中,经常会出现特殊对象,创建这些对象时开销很大,比如文档中的图片,数据库连接等,我们应该根据需要对这些对象进行创建,当图片可见时创建图片对象,当数据库连接真的需要执行时创建连接。通过创建代理,我们可以控制对象的创建,访问时机。创建图片代理,将其作为占位符插入到文档中,当图片可见时,再通过图片代理加载图片(图片的下载获取操作可以放到单独的线程中处理,代理只需将图片加载并显示即可。当然,代理也可以把获取图片和显示图片都做了),以优化程序的响应速度。通过代理还可以在运行时环境中为对象方法添加业务逻辑,比如日志记录,时间消耗统计。spring AOP,hibernate等流行框架大量使用代理增强现有对象的能力,以获取好的性能,灵活的扩展性。
一、模式分类
根据功能和实现效果的不同,代理模式被划分为很多种,常用的如下:
1、远程代理,又称"大使"(Ambassador),为一个对象在不同的地址空间提供局部代表。不同的地址空间可以是局域网中的不同主机或互联网中的不同主机。Java中的远程方法调用就是通过远程代理实现的。
2、虚代理,根据需要创建开销很大的对象,将对象的创建尽可能延迟。文档中的图片代理就是虚代理,先提供代理作为占位符,等图片显示时再创建对象。
3、保护代理,控制对原始对象的访问,一般用于为对象添加访问权限的判断。
4、缓冲代理,为操作结果提供临时的缓存存储空间,以便后续共享。
5、智能指针,取代简单的指针,在访问对象时执行一些附加操作。比如,对指向对象添加引用计数,当该对象没有引用时自动释放它。当持久化对象第一次被引用时,将其装入内存,Hibernate等ORM框架经常这样做。在访问一个实际对象前,检查是否已锁定它,以确保其他对象不能改变它。
二、使用场景
1、当客户端对象需要访问远程主机中的对象时可以使用远程代理,比如远程方法调用。
2、 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理。
3、 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理。通过使用缓冲代理,系统无须在 客户端每一次访问时都重新执行操作,只需直接从临时缓冲区获取操作结果即可。
4、 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理。
5、 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能指针。
三、UML图
注:适配器模式为它所适配的对象提供一个不同的接口,而代理模式则提供与它的实体对象相同的接口。虽然装饰模式和适配器一样,都提供和实体一致的接口,但它们的目的不一样。装饰模式侧重为对象添加一个或多个功能,而代理则侧重控制对对象的访问。
四、Java实现
1、静态代理
运行结果:2、动态代理
运行结果: 注:静态代理,如果接口增加或删除一个方法,该接口的所有实现类和代理类都需要改变,灵活性和扩展性低。动态代理,由于动态代理是在运行时动态生成的,所以对接口的改变可以很好的适应。这主要得力于动态代理将接口中声明的所有方法都转移到一个集中的方法中处理,而不是像静态代理那样对接口的每一个方法进行中转。缺点是只能代理接口,且代理类需要实现特定接口(invocationHandler接口),覆盖其invoke方法。
五、模式优缺点
优点:
1、远程代理可以隐藏一个对象存在于不同地址空间的事实,对客户端透明,降低客户端操作的复杂性。
2、 虚拟代理可以根据需要进行最优化,例如延迟对象创建。
3、缓冲代理通过缓存和共享操作执行结果,缩短执行时间,优化系统性能。
4、保护代理和智能指针都可以在访问对象时添加附加的业务逻辑,比如权限判断,引用计数。
5、总体来说,代理模式在访问对象时引入一定程度的间接性,这种间接性很好的起到隔离作用,降低系统的耦合度。
缺点:
1、 实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂,例如远程代理。