代理模式
代理模式是在实际开发中经常使用的一种设计模式,其定义如下:
为其他对象提供一种代理以控制对这个对象的访问
这句话很好理解,比如在网络中,经常会用到代理,一个请求过来了,那么首先会被代理服务器去响应,代理服务器获得请求后去真正的服务器请求资源,并回应客户发送的请求。用户只需要告诉代理我需要什么东西,至于怎么去找这些东西,用户不用管,由代理服务器去做。
模式组成
代理模式的通用类图如下:
角色 | 关系 | 作用 |
---|---|---|
Subject | 抽象主题角色 | 抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,没有特殊的需求 |
RealSubject | 具体主题角色 | 也叫被委托角色、被代理角色。是业务逻辑的具体执行者 |
Proxy | 代理主题角色 | 也叫委托类、代理类。负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作 |
为什么使用代理
- 中介隔离作用:某些情况下,客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 符合开闭原则:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
表述代码
抽象主题接口:
public interface Subject {
//随意定义一个方法
public void request();
}
具体主题角色:
public class RealSubject implements Subject {
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("业务处理。。。");
}
}
代理类:
public class Proxy implements Subject {
private Subject subject = null;
public Proxy() {
this.subject = new Proxy();
}
public Proxy(Subject _subject) {
this.subject = _subject;
}
@Override
public void request() {
// TODO Auto-generated method stub
this.before();
this.subject.request();
this.after();
}
//预处理
private void before() {
System.out.println("预处理。。");
}
//善后处理
private void after() {
System.out.println("善后处理。。。");
}
}
代理模式的分类
为了更好的说明,简单的举个例子:我们都喜欢玩游戏,享受在游戏中肆意妄为的快感(不要误会^ ^),但是日常的升级和各种麻烦的任务确实是挺恶心的,那我们可以雇人帮我们完成日常的升级和任务,不需要我们自己来升级和完成任务。
普通代理
普通代理模式是最简单的一种,要使用代理首先要知道代理,才能访问使用。
那我们先来定义一个抽象游戏类:
public interface IGamePlayer {
//登陆游戏
public void login(String user, String password);
//杀怪,网络游戏的主要特色
public void killBoss();
//升级
public void upgrade();
}
我们定义了几个简单的接口,表示如何登陆游戏,在游戏中杀怪和升级。
定义一个具体的游戏类:
public class GamePlayer implements IGamePlayer {
private String name = "";
public GamePlayer(IGamePlayer _gamePlayer, String name) throws Exception {
if(_gamePlayer == null) {
throw new Exception("不能创建真实角色!");
}
else {
this.name = name;
}
}
@Override
public void login(String user, String password) {
// TODO Auto-generated method stub
System.out.println("登陆名为:" + user + "的用户" + this.name + "登陆成功");
}
@Override
public void killBoss() {
// TODO Auto-generated method stub
System.out.println(this.name + "在打怪");
}
@Override
public void upgrade() {
// TODO Auto-generated method stub
System.out.println(this.name + "又升了一级");
}
}
这就是在游戏中我们要完成的事情,当然,这个过程是十分简化的。那么定义一个代理,让这个代理来完成替我们打怪升级的过程:
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(String name) {
// TODO Auto-generated constructor stub
try {
gamePlayer = new GamePlayer(this, name);
} catch(Exception e) {
//异常
}
}
@Override
public void login(String user, String password) {
// TODO Auto-generated method stub
this.gamePlayer.login(user, password);
}
@Override
public void killBoss() {
// TODO Auto-generated method stub
this.gamePlayer.killBoss();
}
@Override
public void upgrade() {
// TODO Auto-generated method stub
this.gamePlayer.upgrade();
}
}
测试类:
public class Client {
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayerProxy("张三");
System.out.println("开始时间:。。。");
proxy.login("zhangsan", "password");
proxy.killBoss();
proxy.upgrade();
System.out.println("结束时间为:。。。");
}
}
普通代理的总结:
- 优点:可以符合在开闭原则的情况下完成对目标对象的功能扩展,进行代理功能。
- 缺点:需要为每一个服务创建代理类,不易管理。
强制代理
调用者直接调用真实角色,不需要知道代理的存在,其代理的产生是由真实角色决定的。听着是不是挺奇葩的,你必须通过真实角色找到代理角色,否则你没办法使用,也就是说真实角色管理代理角色。这么说,高层模块生成了一个真实的对象,返回的却是代理角色,就好比你和某个明星是朋友,有一件事请想请他帮忙协商,然后你给他打电话:
“在吗,我想见一下xxx明星”
“不行啊,我这几天比较忙,你找我的经济人吧!”
本来想绕过经纪人直接找明星,但是返回的还是经济人。这就是强制代理,你可以不用知道代理的存在,但是你的所作所为还是需要代理为你提供。
抽象游戏类:
public interface IGamePlayer {
//登陆游戏
public void login(String user, String password);
//杀怪,网络游戏的主要特色
public void killBoss();
//升级
public void upgrade();
//寻找自己的代理
public IGamePlayer getProxy();
}
增加了一个getProxy方法,用来返回代理。
具体游戏类:
public class GamePlayer implements IGamePlayer {
private String name = "";
private IGamePlayer proxy = null;
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login(String user, String password) {
// TODO Auto-generated method stub
if(this.isProxy()) {
System.out.println("登陆名为:" + user + "的用户" + this.name + "登陆成功");
}
else {
System.out.println("请使用指定的代理服务器");
}
}
@Override
public void killBoss() {
// TODO Auto-generated method stub
if(this.isProxy()) {
System.out.println(this.name + "在打怪");
}
else {
System.out.println("请使用指定的代理服务器");
}
}
@Override
public void upgrade() {
// TODO Auto-generated method stub
if(this.isProxy()) {
System.out.println(this.name + "又升了一级");
}
}
@Override
public IGamePlayer getProxy() {
// TODO Auto-generated method stub
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
private boolean isProxy() {
if(this.proxy == null) {
return false;
}
else {
return true;
}
}
}
代理类:
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}
@Override
public void login(String user, String password) {
// TODO Auto-generated method stub
this.gamePlayer.login(user, password);
}
@Override
public void killBoss() {
// TODO Auto-generated method stub
this.gamePlayer.killBoss();
}
@Override
public void upgrade() {
// TODO Auto-generated method stub
this.gamePlayer.upgrade();
}
@Override
public IGamePlayer getProxy() {
// TODO Auto-generated method stub
return this;
}
}
强制代理的概念就是强调要从真实角色查找到代理角色,不允许直接访问真实角色,高层模块只需要调用getProxy就可以访问真实角色的所有方法,根本就不需要产生一个代理出来,代理的管理已经由真实角色生成。