设计模式之禅——代理模式(一)普通代理&强制代理&虚拟代理&动态代理
来源:互联网 发布:防sql注入攻击 编辑:程序博客网 时间:2024/06/08 07:33
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。
例子:玩家玩网游打怪、升级~
见UML图
见代码
//玩家接口类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(String _name){ this.name = _name; } @Override public void login(String user, String password) { System.out.println("登录名为" + user + "的用户" + this.name + "登陆成功"); } @Override public void killBoss() { System.out.println(this.name + " 在打怪"); } @Override public void upgrade() { System.out.println(this.name + " 又生了一级"); }}
//场景类public class Client { public static void main(String[] args) { IGamePlayer player = new GamePlayer("张三"); System.out.println("开始时间是2016-8-25 9:57"); player.login("张三", "password"); player.killBoss(); player.upgrade(); System.out.println("结束时间是:2016-8-25 9:58"); }}/*Output开始时间是2016-8-25 9:57登录名为张三的用户张三登陆成功张三 在打怪张三 又生了一级结束时间是:2016-8-25 9:58*/
玩过网游的人都知道,升级打怪很累的,一般的网游都是满级之后才开始真正入门(好像暴露了什么~),所以就有了代打。我替你升级,你给我money~
见UML图
见代码
//新增代理类public class GamePlayerProxy implements IGamePlayer { private IGamePlayer gamePlayer = null; public GamePlayerProxy(IGamePlayer _gamePlayer){ this.gamePlayer = _gamePlayer; } @Override public void login(String user, String password) { this.gamePlayer.login(user, password); } @Override public void killBoss() { this.gamePlayer.killBoss(); } @Override public void upgrade() { this.gamePlayer.upgrade(); }}
//新场景类public class Client { public static void main(String[] args) { IGamePlayer player = new GamePlayer("张三"); IGamePlayer proxy = new GamePlayerProxy(player); System.out.println("开始时间是:2016-8-25 10:14"); proxy.login("张三", "password"); proxy.killBoss(); proxy.upgrade(); System.out.println("结束时间是: 2016-8-25 10:15"); }}
一个主题类和一个代理类,这就是最简洁的代理模式。
它虽然简单但好多设计模式的本质其实就是代理模式(我觉得它就跟继承差不多了,别的模式不涉及到它才怪~)
这里就不说代理模式的优点了~
代
理模式的拓展
一、普通代理
要求:客户端(场景类只能访问代理角色,而不能访问真实角色)
见UMl图
见代码
//修改后的玩家类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) { System.out.println("登录名为" + user + "的用户" + this.name + "登陆成功"); } @Override public void killBoss() { System.out.println(this.name + " 在打怪"); } @Override public void upgrade() { System.out.println(this.name + " 又生了一级"); }}
//修改后的代理类public class GamePlayerProxy implements IGamePlayer { private IGamePlayer gamePlayer = null; //通过构造函数传递参数确定对谁进行代练(传递 代理者名字就可以代理了) public GamePlayerProxy(String name){ try{ gamePlayer = new GamePlayer(this, name); }catch(Exception e){ e.printStackTrace(); } } @Override public void login(String user, String password) { this.gamePlayer.login(user, password); } @Override public void killBoss() { this.gamePlayer.killBoss(); } @Override public void upgrade() { this.gamePlayer.upgrade(); }}
//场景类public class Client { public static void main(String[] args) { IGamePlayer proxy = new GamePlayerProxy("张三"); System.out.println("开始时间是:2016-8-25 10:14"); proxy.login("张三", "password"); proxy.killBoss(); proxy.upgrade(); System.out.println("结束时间是: 2016-8-25 10:15"); }}/*Output开始时间是2016-8-25 9:57登录名为张三的用户张三登陆成功张三 在打怪张三 又生了一级结束时间是:2016-8-25 9:58*/
运行结果完全相同。但是!场景类只知道代理而不知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响,真实的玩家(主题角色)想怎么修改就怎么修改,对高层次的模块没有任何的影响,只要你实现了接口对应的方法。
该模式非常适合对拓展性要求非常高的场合。当然,在实际项目中一般都是通过约定来禁止new一个真实的角色,这也是很好的方案。
//书中作者原话注意 如果团队当中约定应该通过普通代理来完成任务。应该尽量通过团队内的编程规范类约束,因为每一个主题类(玩家)都是可被重用的和可维护的,使用技术约束的方式对系统维护室一种非常不利的因素
//写到这里的我真的是 感觉身体被掏空~ 不过后面还有 强制代理 虚拟代理 动态代理 mdzz啊
二、强制代理(例子不太好)
要求:强制代理不是要求代理替自己干活,而是通过代理来访问我。然后我自己干活~
(其实这个例子的意思是:你去看一个明星,那必须通过他的经纪人。你通过这个经纪人找到这个明星后肯定是和明星交流,而不是和经纪人交流)
UML图看不出来修改了什么地方还占地儿~我们直接来看代码好不好~
好
的,见代码
//修改后的玩家接口(增加了getProxy()接口)public interface IGamePlayer { public void login(String user, String password); public void killBoss(); public void upgrade(); //每个人通过getProxy来找到自己的代理 public IGamePlayer getProxy();}
//修改后的玩家类public class GamePlayer implements IGamePlayer { private String name = ""; //我的代理是谁 private IGamePlayer proxy = null; public GamePlayer(String _name){ this.name = name; } //找到自己的代理 @Override public IGamePlayer getProxy() { // TODO Auto-generated method stub this.proxy = new GamePlayerProxy(this.name); return this.proxy; } @Override public void login(String user, String password) { if(this.isProxy()){ System.out.println("登录名为" + user + "的用户" + this.name + "登陆成功"); }else{ System.out.println("请使用指定代理访问"); } } @Override public void killBoss() { if(this.isProxy()){ System.out.println(this.name + " 在打怪"); }else{ System.out.println("请使用指定代理访问"); } } @Override public void upgrade() { if(this.isProxy()){ System.out.println(this.name + " 又生了一级"); }else{ System.out.println("请使用指定代理访问"); } } private boolean isProxy(){ if(this.proxy == null) return false; else return true; }}
//修改后的代理类public class GamePlayerProxy implements IGamePlayer { private IGamePlayer gamePlayer = null; private String name; //通过构造函数传递参数确定对谁进行代练 public GamePlayerProxy(String name){ this.name = name; } @Override public void login(String user, String password) { this.gamePlayer.login(user, password); } @Override public void killBoss() { this.gamePlayer.killBoss(); } @Override public void upgrade() { this.gamePlayer.upgrade(); } @Override public IGamePlayer getProxy() { // 代理的代理暂时还没有 就是自己 return this; }}
ok,现在有三个场景类
1、直接访问真实角色
public class Client { public static void main(String[] args) { IGamePlayer player = new GamePlayer("张三"); System.out.println("开始时间是:2016-8-25 10:14"); player.login("张三", "password"); player.killBoss(); player.upgrade(); System.out.println("结束时间是: 2016-8-25 10:15"); }}/*Output开始时间是:2016-8-25 10:14请使用指定代理访问请使用指定代理访问请使用指定代理访问结束时间是: 2016-8-25 10:15*/
2、直接访问代理类
public class Client { public static void main(String[] args) { IGamePlayer player = new GamePlayer("张三"); IGamePlayer proxy = new GamePlayerProxy(player, ((GamePlayer) player).getName()); System.out.println("开始时间是:2016-8-25 10:14"); proxy.login("张三", "password"); proxy.killBoss(); proxy.upgrade(); System.out.println("结束时间是: 2016-8-25 10:15"); }}/*Output开始时间是:2016-8-25 10:14请使用指定代理访问请使用指定代理访问请使用指定代理访问结束时间是: 2016-8-25 10:15*/
3、强制代理
public class Client { public static void main(String[] args) { IGamePlayer player = new GamePlayer("张三"); IGamePlayer proxy = player.getProxy(); System.out.println("开始时间是:2016-8-25 10:14"); proxy.login("张三", "password"); proxy.killBoss(); proxy.upgrade(); System.out.println("结束时间是: 2016-8-25 10:15"); }}/*Output开始时间是:2016-8-25 10:14登录名为张三的用户登陆成功 在打怪 又生了一级结束时间是: 2016-8-25 10:15*/
优点就是:不允许你直接访问真实角色
三、虚拟代理
这个其实就是在需要的时候初始化对象,避免被代理对象较多而引起的初始化缓慢而修改了一下代理类初始化的代码
public class Proxy implements Subject{//要代理的实现类 private Subject subject; //实现接口中定义的方法 public void requst(){ if(subject == null){ subject = new RealSubject(); }else{ subject.request(); } }}
四、动态代理
嗯,上面所有的代理模式都是引子,这个才是重头戏
动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定带了哪一个。相对来说,自己写代理类的方式就是静态代理。现在有一个非常流行的名称叫做面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制。还是以打游戏为例
见UML图
这里的InvocationHandler是JDK提供的动态代理接口
见程序代码
//JDK的接口package java.lang.reflect;public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}
//动态代理类//动态代理就是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称"我已经实现该接口的所有方法了"。public class GamePlayIH implements InvocationHandler { //被代理者 Class cls = null; //被代理的实例 Object obj = null; public GamePlayIH(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ Object result = method.invoke(this.obj, args); return result; }}
//最开始的玩家类public class GamePlayer implements IGamePlayer { private String name = ""; public GamePlayer(String _name){ this.name = _name; } @Override public void login(String user, String password) { System.out.println("登录名为" + user + "的用户" + this.name + "登陆成功"); } @Override public void killBoss() { System.out.println(this.name + " 在打怪"); } @Override public void upgrade() { System.out.println(this.name + " 又生了一级"); }}
//场景类public class Client { public static void main(String[] args) { IGamePlayer player = new GamePlayer("张三"); InvocationHandler handler = new GamePlayIH(player); System.out.println("开始时间: 2016-8-28 10:12"); ClassLoader cl = player.getClass().getClassLoader(); IGamePlayer proxy = (IGamePlayer)Proxy.newProxyInstance(cl, new Class[]{IGamePlayer.class}, handler); proxy.login("zhangsan", "password"); proxy.killBoss(); proxy.upgrade(); System.out.println("结束时间: 2016-8-28 10:14"); }}/*Output开始时间: 2016-8-28 10:12登录名为zhangsan的用户张三登陆成功张三 在打怪张三 又生了一级结束时间: 2016-8-28 10:14*/
没有创建代理类,也没有实现IGamePlayer接口,只需要一个GamePlayH类就可以代理任何需要被代理的类了,这就是动态代理。
AOP是如何依赖动态代理的内容在下一章讲
- 设计模式之禅——代理模式(一)普通代理&强制代理&虚拟代理&动态代理
- 设计模式之——代理模式(动态代理)
- 代理模式(普通代理及动态代理)
- 代理模式之强制代理模式以及动态代理原理
- 代理模式—动态代理
- 设计模式之代理模式-------动态代理
- 《设计模式之禅》样章连载6:代理模式扩展之“普通代理”和“强制代理”
- [转]《设计模式之禅》样章连载6:代理模式扩展之“普通代理”和“强制代理”
- 【设计模式之二:代理模式】代理模式(静态代理VS动态代理)
- 设计模式(代理模式--动态代理)
- 【设计模式】代理模式(动态代理)
- 设计模式之代理模式(静态代理、JDK动态代理和cglib动态代理)
- 代理模式——静态代理、动态代理、cglib代理
- 设计模式之代理模式--静态代理和动态代理
- Java设计模式之—静态代理和动态代理
- 设计模式之静态代理&动态代理
- 代理模式之动态代理
- 代理模式之动态代理
- PHP中操作MongoDB
- RSA公钥,私钥的生成与配置
- Xamarin.iOS模拟器调试找不到资源文件
- 顺序表应用3:元素位置互换之移位算法
- 数据库视图view简介
- 设计模式之禅——代理模式(一)普通代理&强制代理&虚拟代理&动态代理
- Swift 枚举
- (LeetCode)Palindrome Linked List --- 单链表回文
- POJ-3258-River Hopscotch
- android虚线
- 将现有的SQL工作负载迁移至hadoop竟然如此简单!
- Android fragment间传递数据以及Dialog
- C#中&结&构&体&与&字&节&流&互&相&转&换
- windows删除node_modules[文件名或扩展名太长,目录层级太深]