设计模式之代理模式
1. 什么是代理模式
Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。
所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
代理模式为一个对象提供一个替身,以控制对这个对象的访问被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象代理模式有很多变体,都是为了控制与管理对象访问
代理模式的一般结构:
subject(抽象主题角色):真实主题与代理主题的共同接口。
RealSubject(真实主题角色):定义了代理角色所代表的真实对象。
Proxy(代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
动态代理:
- InvocationHandler 接口
- invoke方法
- Proxy.newProxyInstance();
代理模式和装饰者模式差异:装饰者模式,装饰以后会添加新功能,而代理模式目的是对目标对象访问的控制和管理。
2. 具体实例
对于在状态模式中介绍的糖果机项目,我们现在要添加一个监控糖果机:监控糖果机的地点、糖果库存和当前状态。这时候我们使用远程代理的模式来设计这个项目是合适的。通过代理模式获取远程对象(糖果机)的本地代表,通过它可以让远程对象当本地对象来调用。这样就相当于在本地查看糖果机的状态了。
可以使用JAVA的RMI来实现远程代理:
RMI的结构图:
RMI远程方法调用是计算机之间通过网络实现对象调用的一种通讯机制。使用这种机制,一台计算机上的对象可以调用另外 一台计算机上的对象来获取远程数据。
在过去,TCP/IP通讯是远程通讯的主要手段,面向过程的开发。而RPC使程序员更容易地调用远程程序,但在面对复杂的信息传讯时,RPC依然未能很好的支持。
RMI被设计成一种面向对象开发方式,允许程序员使用远程对象来实现通信。
RMI的实现步骤:
- 制作远程接口:接口文件
- 远程接口的实现:Service文件
- RMI服务端注册,开启服务
- RMI代理端通过RMI查询到服务端,建立联系,通过接口调用远程方法
通过上面的步骤,实现一个简单的JavaRMI 的实例:
远程接口:
1 | public interface MyRemote extends Remote{ |
接口的实现:
1 | public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{ |
1 | public class MyRemoteClient { |
然后通过使用RMI怎么来实现上面所讲的糖果机的项目呢?具体代码如下:
接口:
1 | public interface CandyMachineRemote extends Remote{ |
接口的实现:
1 | public class CandyMachine extends UnicastRemoteObject implements CandyMachineRemote { |
注册:
1 | public class Monitor { |
1 | public class RemoteMainTest { |
测试:
1 | public class MainTest { |
3. 几种其他常见的代理模式
- 虚拟代理: 虚拟代理为创建开销大的对象提供代理服务。真正的对象在创建前和创建中时,由虚拟代理来扮演替身。例如手机加载图片,一开始是个模糊的,加载完成才显示清楚,开始就就是本地代理的显示。
- 动态代理:运行时动态的创建代理类,并将方法调用转发到指定类
- 保护代理:这种代理用于对真实对象的功能做一些访问限制, 在代理层做身份验证. 通过了验证, 才调用真实的主体对象的相应方法.
- 几种变体:、防火墙代理、缓存代理、智能引用代理、同步代理、写入时复制代理
关于保护代理和动态代理的使用举一个简单的例子:
一个相亲网的项目,每个人都有自己的信息和评分,评分别人可以评价自己不能评价,个人信息自己可以修改别人只能查看。
具体的代码:
接口:
1 | public interface PersonBean { |
接口的实现:
1 | public class PersonBeanImpl implements PersonBean{ |
非本人代理
1 | public class NonOwnerInvocationHandler implements InvocationHandler{ |
本人代理
1 | public class OwnerInvocationHandler implements InvocationHandler{ |
调用代理方法的类
1 | public class MatchService { |
测试类:
1 | public class MainTest { |