什么用
顾名思义,代理模式就是本该由客户直接调用某一目标对象,但却由于客户不想或不能或者由于其他某些原因,没有直接调用该对象,而是通过中间对象去调用目标对象。该中间对象即为代理,它不仅起到中介的作用,还能隐去客户不能看见的内容,或者添加客户需要的额外服务。
RMI调用就是一种代理模式。远程服务器中的服务在本地有一个stub代理,该代理封装了访问远程服务的方法,客户可通过该代理来调用远程服务。
Spring AOP也是一种代理。用户在调用原服务前后,添加的@Before和@AfterReturning注解,就是解决用户需求的新服务。
模式结构
- 抽象主题角色:
声明了代理主题角色和真是主题角色的公共接口。 - 代理主题角色:
封装了可以调用真实主题角色服务的方法。 - 真实主题角色
实现了用户所需要的真正的服务,用户通过代理主题角色使用该服务。
优缺点
优点
- 一定程度上使用户与服务之间解耦,并且可以在原服务的基础上插入新的服务。
- 远程代理可以使客户可以访问远程机器上的资源。
- 虚拟代理可以先用小对象代表大对象,减少对资源的占用,当确实需要大对象时再创建大对象。
- 保护代理可以控制对真实对象的使用权限。
缺点
- 由于多了一层代理,可能会使处理速度变慢。
- 有些代理模式的实现可能比较复杂。
适用情况
- 远程代理:当本地客户端需要调用不同地址空间上的对象时,使用代理模式。这个不同地址空间可以是在另一台主机上。
- 虚拟代理:当需要创建一个资源消耗较大的对象时,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
- 保护代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
- 智能引用代理:当一个对象被引用时,提供一些额外的操作,如在使用前后打印日志。
- 缓冲代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
实际应用
- RMI机制
- Spring AOP
代码示例
https://github.com/zero4eva/design_pattern
这里实现的对登录进行代理设置,只是为了打印日志封装出来的。实际上可以使用Spring AOP对所
有request和response进行打印日志。
-
LoginTest.java
public class LoginTest { public static void main(String[] args) { String name = "admin"; String password = "admin"; LoginServiceProxy loginServiceproxy = new LoginServiceProxy(); boolean loginSuccess = loginServiceproxy.login(name, password); if (loginSuccess){ System.out.println("login success!"); }else{ System.out.println("login failed!"); } } }
-
ILoginService.java
public interface ILoginService { public boolean login(String name, String password); }
-
LoginServiceImpl.java
public class LoginServiceImpl implements ILoginService { @Override public boolean login(String name, String password) { return "admin".equals(name) && "admin".equals(password); } }
-
LoginServiceProxy.java
public class LoginServiceProxy implements ILoginService{ LoginServiceImpl loginService; public LoginServiceProxy() { loginService = new LoginServiceImpl(); } @Override public boolean login(String name, String password) { beforeService(name, password); boolean ret = loginService.login(name, password); afterService(ret); return ret; } public void beforeService(String name, String password) { System.out.println("-----------------------------------------------------------------"); System.out.println("login info: "); System.out.println(" name: " + name + ", password: " + password); } public void afterService(boolean loginResult) { System.out.println("login result: " + loginResult); System.out.println("-----------------------------------------------------------------"); } }