设计模式——代理模式

当前位置:首页乐虎lehu备用客户端 >

乐虎lehu备用客户端

设计模式——代理模式

时间:2019-06-14本站浏览次数:134

       

定义

  为其他对象提供一种代理以控制对这个对象的访问。

  代理模式也叫委托模式,日常生活中很常见。帮别人做某某事情时候,自己就是别人的代理;让别人帮自己做什么事情时候,别人就是自己的代理。

通用类图

Subject抽象主题角色

  抽象主题类是一个普通的业务类型的定义,规定要做什么事情。可以是一个抽象类也可以是一个接口。

RealSubject具体主题角色

  被委托(被代理)的角色,是真正事情处理的执行者。

Proxy代理主题角色

  委托类(代理类),负责对真实角色的调用,把所有主题限定的方法委托给具体主题角色,也可以在真实主题角色处理前做一些预处理,或在真实主题角色处理后做一些善后处理(比如Spring的AOP)。

普通代理

小时候在家都是妈妈做饭,做饭需要洗菜,切菜,炒菜……有时候妈妈有事忙没按时回家,姐姐就偷偷代替妈妈给大家做饭。如果将做饭简单理解为洗菜、切菜、炒菜三个步骤,从程序员的角度来记录做饭这件事就很简单了。妈妈和姐姐都需要洗菜、切菜然后再炒菜,所以可以规定炒菜的三个步骤,然后分别实现这三个步骤,所以可以简单表示为:

ICook定义了炒菜必须要经历的流程:

public interface ICook { /**洗菜*/ void washFood(); /**切菜*/ void cutFood(); /**炒菜*/ void stirFood();}

妈妈(对于一家人来说,天天吃妈妈做的饭,妈妈就是一个Cooker)做饭的流程:

public class Cooker implements ICook { @Override public void washFood() { System.out.println("妈妈在洗菜……"); } @Override public void cutFood() { System.out.println("妈妈在切菜……"); } @Override public void stirFood() { System.out.println("妈妈在炒菜……"); }}

一个能代理妈妈做饭(实现了ICook接口)的角色

public class CookerProxy implements ICook { private ICook cooker; public CookerProxy(ICook cooker){ this.cooker = cooker; } @Override public void washFood() { this.cooker.washFood(); } @Override public void cutFood() { this.cooker.cutFood(); } @Override public void stirFood() { this.cooker.stirFood(); }}

姐姐代替妈妈做饭

public void test() { Cooker cooker = new Cooker(); ICook cook = new CookerProxy(cooker); cook.washFood(); cook.cutFood(); cook.stirFood(); }

姐姐学会了妈妈的手艺,如果不是亲眼看到,还不知道是姐姐做的饭,这就是真实生活中一个简单的代理例子。

强制代理

普通代理是通过代理找到真实的对象,由真实对象去执行动作;但是强制代理却是要通过真实角色查找代理,否则不能访问。也就是不管是通过代理类还是直接new一个真实对象都不能访问,只有通过真实对象委托的代理才能访问。

还是上面的那个例子,后来妈妈上班去了,中午不能回家做饭了,拿普通代理方式来说,只要是一个会做菜的人,就可以趁着妈妈不在冒充妈妈的身份替妈妈做菜,万一做的很难吃,岂不是把妈妈的招牌给毁了吗?

于是,妈妈想到了个办法,必须由她指定谁可以代替她做菜,不是由她亲自指定的人无法替她做菜:

定义了一个getProxy方法,由Cooker来指定自己的代理,并且代理自己做事之前,先验证下身份:

public class Cooker implements ICook { private ICook cook; @Override public void washFood() { if (this.isProxy()) { System.out.println("妈妈在洗菜……"); } else { System.out.println("请妈妈指定的人来炒菜……"); } } @Override public void cutFood() { if (this.isProxy()) { System.out.println("妈妈在切菜……"); } else { System.out.println("请妈妈指定的人来炒菜……"); } } @Override public void stirFood() { if (this.isProxy()) { System.out.println("妈妈在炒菜……"); } else { System.out.println("请妈妈指定的人来炒菜……"); } } @Override public ICook getProxy() { this.cook = new CookerProxy(this); return this.cook; } private Boolean isProxy() { if (this.cook == null) { return false; } return true; }}

只有通过Cooker对象获取(getProxy)代理才能做菜。

代理扩展

姐姐做了几顿饭之后也开始不乐意了,凭什么我要占用玩的时间来给大家做饭?妈妈想了一个好主意,姐姐每做一顿饭可以从妈妈那里领到1块钱,于是姐姐又高高兴兴地给大家做饭了。做饭和付钱是两个单独的功能,是不能混在一起的,可以将上面类图稍作修改:

这样,在每次做好饭之后就可以记账应该拿到1元钱

public class CookerProxy implements ICook, IPay { private ICook cooker; public CookerProxy(ICook cooker){ this.cooker = cooker; } @Override public void washFood() { this.cooker.washFood(); } @Override public void cutFood() { this.cooker.cutFood(); } @Override public void stirFood() { this.cooker.stirFood(); this.pay(); } @Override public void pay() { System.out.println("做完饭拿到了1元钱"); } @Override public ICook getProxy() { /** 可以指定代理的代理,暂时没有就是自己 */ return this; }}

代理不仅可以实现主题的接口,还可以实现其他的接口,在目标行为基础之上做个性化处理。

动态代理

后来姐姐长大了,也出门在外了,我们也不能每次都等着吃饭,于是各自都学会了做饭,只要妈妈不在,谁方便了谁就做饭。也就是说,只有饭已经在被做了才知道是谁在做,更灵活了,这就不能提前指定谁来做饭了。对应程序中是:只有在运行时才知道真实类型是谁。

将类图稍作修改,如下所示。

InvocationHandler是java提供的动态代理接口,CookerHandler实现了InvocationHandler接口,这样可以动态指定代理,运行时才知道类型。

public class CookerHandler implements InvocationHandler { Class clazz = null; Object obj = null; public CookerHandler(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 void dynamicProxy(){ proxy.dynamicproxy.ICook cook = new proxy.dynamicproxy.Cooker(); ClassLoader classLoader = cook.getClass().getClassLoader(); Class<?>[] interfaces = cook.getClass().getInterfaces(); CookerHandler handler = new CookerHandler(cook); proxy.dynamicproxy.ICook proxyInstance = (proxy.dynamicproxy.ICook) Proxy.newProxyInstance(classLoader, interfaces, handler); proxyInstance.washFood(); proxyInstance.cutFood(); proxyInstance.stirFood(); }

 

参考

动态代理可以参考:Java动态代理之JDK实现和CGlib实现(简单易懂)

本文示例代码:Proxy Demo




公司地址:台湾省台北市民權東路六段56巷1弄4號1樓
联系人:田俊刚 15840874851
姚先生 13537893468
电话:13671166621 传真:usic0evk7p@hotmail.com
邮箱:o49sl@162.com

粤公网安备 44030702001579号

乐虎电子游戏官网@