代理模式的定义:
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,如需转载请自行联系原作者