编程之美---代理模式

来源:互联网 发布:洗车店软件 编辑:程序博客网 时间:2024/04/30 09:59

一.定义

为其他对象提供一种代理,以代替这个对象的访问。
代理,这个词,非常形象,就是什么东西代替什么东西做某些事情。上初中的时候,大家处于感情懵懂的阶段,那时候校园里非常流行写情书。但那时,大家都不好意思自己当面给,就写好了情书,找其他同学代送。那这就是典型的代理模式。代理模式,放在我们程序中,就是A因为某些原因不方面直接调用C,我们会找一个B,让A调用B,达到我们A调用C相同的效果。


二.从代码引入

代理模式那,就是因为某些原因,我们在中间加入一个中介的多余但能优化系统的类,来完成一些工作。说他多余,是因为,没有这个类,我们一样可以实现我们的功能,但有了这个类,可能会让我们的系统更容易扩展,或者速度更快,或者代码复用性更强,总而言之,优化了系统(注:优化了系统,而不是优化了代码。基本上设计模式的引入,都是在增加我们的代码量。但一时的增加,可能会带来整个系统的优化,可能会让你后面容易维护,或者少写更多的代码。所以,学习模式,我们要站在优化系统的角度上考虑)。

比如说,我现在想做一个登录的功能,那么,我写了一个登录的类:

package com.cn.zjf.proxy2;public class Login {public void login(){System.out.println("某某用户登录了");}}

package com.cn.zjf.proxy2;public class TestLogin {public static void main(String[] args) {Login login = new Login();login.login();}}
测试类,测试一下,输出结果:

某某用户登录了

代码很简单,就是让某某用户登录。但现在我觉得需要登录过程中插入log日志,而且,我不想修改之前的源代码(这里是开放--封闭原则,我们在设计系统的时候,尽量是避免修改代码,而是扩展代码)。那么我就可以再写一个类,来代替Login这个类,完成他要完成的工作。当然你可能会说,我们在Login类里面直接加日志不就行了。当然可以,但之前说了,模式不是必须的,而是优化系统的。
新加代理类:

package com.cn.zjf.proxy2;public class Proxy {public Login login;public Proxy(){login = new Login();}public void login(){System.out.println("登录前记录日志");login.login();System.out.println("登录后记录日志");}}
测试类改为
package com.cn.zjf.proxy2;public class TestLogin {public static void main(String[] args) {Proxy login = new Proxy();login.login();}}
测试结果为:

登录前记录日志
某某用户登录了
登录后记录日志

这样我们客户端根本没有见过我们的Login类,只是通过代理类,就完成了我们的功能,而且加入了我们想添加的扩展代码。就像,A同学没有见过C同学,但是通过B同学就将情书送给了C同学。就像房东根本没有见过租房者,通过中介就将房子租给了租房者。
回过头来,再观察一下,其实我们的Login类,和Proxy类的动作(方法)是一样的。就像A同学送情书这个动作,跟让C同学去送情书是同一个动作(方法)。只不过我们Login类的login动作封装在了Proxy类的login动作里面了。那这不刚好符合接口的定义吗?接口是将有相同的行为抽象出来,形成一个约束。那么我们也可以将Proxy和Login相同的行为(他们的行为本来就相同)抽象出来形成一个约束。所以最后我们代码改为:
增加接口:

package com.cn.zjf.proxy2;public interface ILogin {public void login();}
Login类
package com.cn.zjf.proxy2;public class Login implements ILogin{public void login(){System.out.println("某某用户登录了");}}
Proxy类
package com.cn.zjf.proxy2;public class Proxy implements ILogin{public ILogin login;public Proxy(){login = new Login();}public void login(){System.out.println("登录前记录日志");login.login();System.out.println("登录后记录日志");}}
相比较与前面的代码,只不过是加了一个接口(面向对象编程),让我们的Login类和Proxy来都实现这个接口,增加一个约束。
总结之前的例子:代理模式步骤:
(1).首先,因为我们的真实类(Login)和代理类(Proxy)拥有同样的行为,所以我们抽象出他们的接口Interface
(2).我们定义我们的真实类和代理类,并让真实类和代理类都实现接口(面向对象编程思想,只是为了得到相同的约束行为,即相同的方法)
(3).在真实类的方法里面实现业务逻辑,在代理类里面增加接口的成员变量,后面我们会初始化为某个实现类
(4).初始化代理类,初始化代理类里面的真实类的成员变量
(5).在代理类的方法里面调用真实类(前面已经初始化)的方法,当调用代理类时,实现我们的功能

注:模式设计只是一种思想,并没有具体说代码怎样写,步骤必须是怎样的。比如说,我们是在代理类的构造器里面初始化的真实类,我们同样可以写一个init()方法去初始化真实类。再比如说,我们后面引入了接口。就算我们不引入接口,他也是代理模式。只不过当我们系统庞大的时候,引入接口,更加优化。所以模式只是一种思想。我们可以大体这样说,只要有中间者去代替一个某个对象完成某些事,就是代理模式,跟具体的代码实现无关。
所以最后我们最后得到代理模式的类图:。



Subject:就是接口,相当于我们定义的ILogin接口
RealSubject:就是真实类,它实现Subject接口,方法中实现我们具体的业务逻辑,相当于我们Login类
Proxy:代理类,实现Subject接口,并且有Subject接口的成员变量(为什么不直接将RealSubject作为成员变量?这就是接口的一个优点,解耦,不跟具体的某个实现类绑定),并且在方法中调用真实类

这就是代理模式的思想以及简单的实现。
代理模式的一些应用:

        1,远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。

              2,虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。例如,网页中在图片出来以前现出来文字。

              3,安全代理,用来控制真实对象访问时的权限。

              4,智能代理,是指当调用真实的对象时,代理处理另外一些事。









0 0