本文共 8113 字,大约阅读时间需要 27 分钟。
代理模式的定义:
Provide a surrogate or placeholder for another to control access to it.(为其他对象提供一种代理以控制对这个对象的访问)
代理模式也叫委托模式,许多的其他模式,如状态模式,策略模式,访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制.
在一些著名的开源软件中也经常见到它的身影,如Struts2的Form元素映射就是采用了代理模式(准确的说是动态代理模式),Struts2的拦截器,Spring 的AOP.
代理模式的使用场景:
现实世界中,打官司要找律师,你不想参与中间过程的是是非非,只要完成自己的答辩就可以,其他的事情事前调查,事后追查都由律师来搞定,这就是为了减轻你的负担.
Spring的AOP就是一个非常典型的动态代理.
代理模式的扩展:
(类比)网络上的代理服务器分为透明代理和普通代理. 透明代理就是用户不用设置代理服务器地址,就可以直接访问,也就是说代理服务器对用户来说是透明的,不用知道它存在的.
普通代理则是需要用户自己设置代理服务器的IP地址,用户必须知道代理的存在.
我们设计模式在红的普通代理和强制代理也是类似的结构.普通代理就是我们要知道代理的存在.然后才能访问.(类比网络的普通代理)
强制代理这是调用者直接调用真实角色,而不 用关心代理是否存在.其代理的产生是由真是角色决定的.(类比网络的透明代理)
普通代理
要求客户端只能访问代理角色,而不能访问真实角色.
上面的GamePlayer的构造函数增加了_gamePlayer参数,而代理角色GamePlayerProxy则只要传入代理者的名字即可,而不是需要说是替那个对象做代理.
普通代理的接口类:
1 /** 2 * 游戏玩家 3 */ 4 public interface IGamePlayer { 5 6 //登录游戏 7 public void login(String user,String password); 8 9 //杀怪,这是网络游戏的主要特色10 public void killBoss();11 12 //升级13 public void upgrade();14 }
普通代理中的游戏者:
1 /** 2 * 真是的玩家 3 */ 4 public class GamePlayer implements IGamePlayer { 5 private String name = ""; 6 7 //构造函数限制谁能创建对象,并同时传递姓名 8 public GamePlayer(IGamePlayer _gamePlayer,String _name) throws Exception{ 9 if(_gamePlayer == null ){10 throw new Exception("不能创建真是角色!");11 }else{12 this.name = _name;13 }14 15 }16 //打怪,最期望的就是杀老怪17 public void killBoss() {18 System.out.println(this.name + "在打怪!");19 }20 21 //进游戏之前你肯定要登录吧,这是一个必要条件22 public void login(String user, String password) {23 System.out.println("登录名为"+user + " 的用户 " + this.name + "登录成功!");24 }25 26 //升级,升级有很多方法,花钱买是一种,做任务也是一种27 public void upgrade() {28 System.out.println(this.name + " 又升了一级!");29 }30 31 }
普通代理中的代理者:
1 /** 2 * 代练者 3 */ 4 public class GamePlayerProxy implements IGamePlayer { 5 private IGamePlayer gamePlayer = null; 6 7 //通过构造函数传递要对谁进行代练 8 public GamePlayerProxy(String name){ 9 try {10 gamePlayer = new GamePlayer(this,name);11 } catch (Exception e) {12 // TODO 异常处理13 }14 }15 16 //代练杀怪17 public void killBoss() {18 this.gamePlayer.killBoss();19 }20 21 //代练登录22 public void login(String user, String password) {23 this.gamePlayer.login(user, password);24 25 }26 27 //代练升级28 public void upgrade() {29 this.gamePlayer.upgrade();30 31 }32 33 }
普通代理的场景类:
1 /** 2 * 场景类 3 */ 4 public class Client { 5 6 public static void main(String[] args) { 7 8 //然后再定义一个代练者 9 IGamePlayer proxy = new GamePlayerProxy("张三");10 11 //开始打游戏,记下时间戳12 System.out.println("开始时间是:2009-8-25 10:45");13 proxy.login("zhangSan", "password");14 //开始杀怪15 proxy.killBoss();16 //升级17 proxy.upgrade();18 //记录结束游戏时间19 System.out.println("结束时间是:2009-8-26 03:40");20 21 }22 23 }
打印输出:
开始时间是:2009-8-25 10:45
登录名为zhangSan 的用户 张三登录成功! 张三在打怪! 张三 又升了一级! 结束时间是:2009-8-26 03:40
强制代理:
强制代理在设计模式中比较另类,一般的思维都是通过代理找到真实的角色的,但是强制代理却是要"强制",你必须通过真实角色查找到代理角色,否则你不能访问.
只有通过真实角色指定的代理类才可以访问,也就是由真实角色管理代理角色.
高层模块new了一个真实角色的对象,返回的却是代理角色.
这好比你和一个明星比较熟,相互认识,有件事情你需要想她确认一下,于是你就直接拨通了明星的电话:
"喂,沙比呀,我要见一下XXX导演,你帮下忙!" "不行呀衰哥,我这几天很忙呀,你找我的经纪人吧......" 郁闷了吧,你是想直接绕过她的代理,谁知道返回的还是她的代理,这就是强制代理.修改一下IGamePlayer接口,增加一个getProxy的方法.
强制代理的接口类:
1 /** 2 * 游戏玩家 3 */ 4 public interface IGamePlayer { 5 6 //登录游戏 7 public void login(String user,String password); 8 9 //杀怪,这是网络游戏的主要特色10 public void killBoss();11 12 //升级13 public void upgrade();14 15 //每个人都可以找一下自己的代理 指定要访问自己必须通过哪个代理16 public IGamePlayer getProxy();17 }
强制代理的真实角色:
1 /** 2 * 真是的玩家 3 */ 4 public class GamePlayer implements IGamePlayer { 5 private String name = ""; 6 //我的代理是谁 7 private IGamePlayer proxy = null; 8 9 public GamePlayer(String _name){10 this.name = _name; 11 }12 13 //找到自己的代理14 public IGamePlayer getProxy(){15 this.proxy = new GamePlayerProxy(this);16 return this.proxy;17 }18 19 //打怪,最期望的就是杀老怪20 public void killBoss() {21 if(this.isProxy()){22 System.out.println(this.name + "在打怪!");23 }else{24 System.out.println("请使用指定的代理访问");25 }26 27 }28 29 //进游戏之前你肯定要登录吧,这是一个必要条件30 public void login(String user, String password) {31 if(this.isProxy()){32 System.out.println("登录名为"+user + " 的用户 " + this.name + "登录成功!");33 }else{34 System.out.println("请使用指定的代理访问");;35 }36 37 }38 39 //升级,升级有很多方法,花钱买是一种,做任务也是一种40 public void upgrade() {41 if(this.isProxy()){42 System.out.println(this.name + " 又升了一级!");43 }else{44 System.out.println("请使用指定的代理访问");45 }46 }47 48 //校验是否是代理访问 检查自己是否是指定的代理,指定的代理则允许访问,否则不允许访问.49 private boolean isProxy(){50 if(this.proxy == null){51 return false;52 }else{53 return true;54 }55 }56 }
强制代理的代理类:
1 /** 2 * 代练者 3 */ 4 public class GamePlayerProxy implements IGamePlayer { 5 private IGamePlayer gamePlayer = null; 6 7 //构造函数传递用户名 8 public GamePlayerProxy(IGamePlayer _gamePlayer){ 9 this.gamePlayer = _gamePlayer;10 }11 12 //代练杀怪13 public void killBoss() {14 this.gamePlayer.killBoss();15 }16 17 //代练登录18 public void login(String user, String password) {19 this.gamePlayer.login(user, password);20 21 }22 23 //代练升级24 public void upgrade() {25 this.gamePlayer.upgrade();26 27 }28 29 //代理的代理暂时还没有,就是自己30 public IGamePlayer getProxy(){31 return this;32 }33 }
(错误一:)直接访问真实角色:
1 /** 2 * 场景类(直接访问真实角色) 3 */ 4 public class Client { 5 public static void main(String[] args) { 6 //定义个游戏的角色 7 IGamePlayer player = new GamePlayer("张三"); 8 9 //开始打游戏,记下时间戳10 System.out.println("开始时间是:2009-8-25 10:45");11 player.login("zhangSan", "password");12 //开始杀怪13 player.killBoss();14 //升级15 player.upgrade();16 //记录结束游戏时间17 System.out.println("结束时间是:2009-8-26 03:40");18 19 }20 }
打印输出:
开始时间是:2009-8-25 10:45
请使用指定的代理访问 请使用指定的代理访问 请使用指定的代理访问 结束时间是:2009-8-26 03:40必须通过代理类访问,不能直接访问.
(错误二:)直接访问代理类:
1 /** 2 * 场景类(直接访问代理类) 3 */ 4 public class Client { 5 public static void main(String[] args) { 6 //定义个游戏的角色 7 IGamePlayer player = new GamePlayer("张三"); 8 //然后再定义一个代练者 9 IGamePlayer proxy = new GamePlayerProxy(player);10 11 //开始打游戏,记下时间戳12 System.out.println("开始时间是:2009-8-25 10:45");13 proxy.login("zhangSan", "password");14 //开始杀怪15 proxy.killBoss();16 //升级17 proxy.upgrade();18 //记录结束游戏时间19 System.out.println("结束时间是:2009-8-26 03:40");20 21 }22 }
打印输出:
开始时间是:2009-8-25 10:45
请使用指定的代理访问 请使用指定的代理访问 请使用指定的代理访问 结束时间是:2009-8-26 03:40这个代理类不是真实角色指定的对象(代理类),这个代理对象(类)是你自己new出来的,当然真实对象不认了,这就好比是那个明星,人家告诉你去找她的代理人了,你随便找个代理人能成吗?你必须去找她指定的代理才行.
(正确:)强制代理的场景类:
1 /** 2 * 场景类 3 */ 4 public class Client { 5 6 public static void main(String[] args) { 7 //定义个游戏的角色 8 IGamePlayer player = new GamePlayer("张三"); 9 //获得指定的代理10 IGamePlayer proxy = player.getProxy();11 //开始打游戏,记下时间戳12 System.out.println("开始时间是:2009-8-25 10:45");13 proxy.login("zhangSan", "password");14 //开始杀怪15 proxy.killBoss();16 //升级17 proxy.upgrade();18 //记录结束游戏时间19 System.out.println("结束时间是:2009-8-26 03:40");20 }21 }
打印输出:
开始时间是:2009-8-25 10:45
登录名为zhangSan 的用户 张三登录成功! 张三在打怪! 张三 又升了一级! 结束时间是:2009-8-26 03:40
OK,可以正常访问代理了.强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色.高层模块只要调用getProxy就可以访问真实角色的所有方法,它根本就不需要一产生一个代理出来,代理的管理已经由真实的角色自己完成.
本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5408401.html,如需转载请自行联系原作者