【原创·教程·连载】《Android之大话设计模式》--设计模式之结构型模式 第十一章:代理模式 QQ聊天机器人
<大话设计模式>
本教程说明及版权声明
国士工作室是一支专注于Android平台企业级应用开发的技术团队,致力于做中国最棒的Android应用程序开发机构,提供最棒的Android企业级应用开发培训服务。
企业培训和开发合作官方联系方式:
电话:18610086859
Email:hiheartfirst@gmail.com
QQ:1740415547
QQ群:148325348
国士工作室 有你更美好!
l 该文档参考和使用了网络上的免费开放的图片和内容,并以免费开放的方式发布,希望为移动互联网和智能手机时代贡献绵薄之力!可以随意转载,但不得使用该文档谋利。
l 如果对该文档有任何疑问或者建议,请进入官方博客
http://www.cnblogs.com/guoshiandroid/留言或者直接与国士工作室联系(后附联系方式),我们会慎重参考您的建议并根据需要对本文档进行修改,以造福更多开发者!
l 《大话设计模式》的最新及完整内容会在国士工作室官方博客定期更新,请访问国士工作室博客
http://www.cnblogs.com/guoshiandroid/获取更多更新内容。
代理模式 QQ聊天机器人
代理模式应用场景举例:
跟自己的MM在网上聊天的时候,总会遇到其它MM的骚扰,一开头总是“hi,你好”,“你从哪儿来呀?”,“你多大了?”,“身高多少呀?”这些话,真烦人,写个QQ机器人程序做为我的代理吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。其实对于其它MM来说,不管是我自己还是我的机器人,她觉得只是个“聊天的家伙”,但是我却轻松了许多。这样就可以让我和自己的MM好好的专心的聊天,好好的享受沐浴在初恋的滋润^_^
代理模式解释:
代理模式(Proxy Pattern)是构造型的设计模式之一,代理模式就是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。就是一个人或者一个机构代替另一个人或者另一个机构去采取一些行动,以控制对这个对象的访问。
所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
英文定义为:Provide a surrogate or placeholder for another object to control access to it.
代理模式的UML图:
代理模式所涉及的角色如下:
抽象主题(Subject)角色:真实主题与代理主题的共同接口。
真实主题(RealSubject)角色:定义了代理角色所代表的真实对象。
代理主题(Proxy)角色: 含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
代理模式的UML图如下 所示:
代理模式深入分析:
代理模式为其他对象提供一种代理以控制对这个对象的访问。在一些情况下客户不想或者不能直接引用一个对象,而代理对象可以在客户和目标对象之间起到中介作用,去掉客户不能看到的内容和服务或者增添客户需要的额外服务。
那么什么时候要使用代理模式呢?在对已有的方法进行使用的时候出现需要对原有方法进行改进或者修改,这时候有两种改进选择:修改原有方法来适应现在的使用方式,或者使用一个“第三者”方法来调用原有的方法并且对方法产生的结果进行一定的控制。第一种方法是明显违背了“对扩展开放、对修改关闭”原则,而且在原来方法中作修改可能使得原来类的功能变得模糊和多元化,而使用第二种方式可以将功能划分的更加清晰,有助于后面的维护。
当然,话又说回来了,如果是一个很小的系统,功能也不是很繁杂,那么使用代理模式可能就显得臃肿,不如第一种方式来的快捷。这就像一个三口之家,家务活全由家庭主妇或者一个保姆来完成是比较合理的,根本不需要雇上好几个保姆层层代理^_^
根据《Java与模式》书中对代理模式的分类,代理模式分为8种,这里将几种常见的、重要的列举如下:
远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。比如:你可以将一个在世界某个角落一台机器通过代理假象成你局域网中的一部分。
虚拟(Virtual)代理:根据需要将一个资源消耗很大或者比较复杂的对象延迟的真正需要时才创建。比如:如果一个很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,这个大图片可能就影响了文档的阅读,这时需要做个图片Proxy来代替真正的图片。
Copy-on-Write代理:虚拟代理的一种。把复制拖延到只有在客户端需要的时候,才真正的采取行动。
保护(Protect or Access)代理:控制对一个对象的访问权限。比如:在论坛中,不同的身份登陆,拥有的权限是不同的,使用代理模式可以控制权限(当然,使用别的方式也可以实现)。
Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
防火墙(Firewall)代理:保护目标,不让恶意用户接近。
同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
智能引用(Smart Reference)代理:提供比对目标对象额外的服务。比如:纪录访问的流量(这是个再简单不过的例子),提供一些友情提示等等。
代理模式是一种比较有用的模式,能够协调调用者和被调用者,能够在一定程度上降低系统的耦合度。
代理模式使用场景分析及代码实现:
在上面的使用场景中,MM的笔记本电脑的电源插头不可以正常使用,也即是说笔记本的插头和MM学校寝室的接口不相符合,于是GG就到可以市场买了一个适合MM的笔记本和寝室电源接口的转换器,这个转换器插头就是适配器。
建立一个抽象角色:
package com.diermeng.designPattern.Proxy; /** * 抽象角色,提供代理类和具体类的公共接口 * */ public interface Chat {
public void reply(String message); } |
建立一个具体的角色类:
package com.diermeng.designPattern.Proxy.impl;
import com.diermeng.designPattern.Proxy.Chat;
/** * 具体角色类,被代理的类 * */ public class MyChat implements Chat{
public void reply(String message) {
System.out.println("需要我亲自回复的内容。。。"); } }
|
建立一个代理类:
package com.diermeng.designPattern.Proxy.impl;
import com.diermeng.designPattern.Proxy.Chat; /** * 代理类,持有被代理类的一个引用 * */ public class ChatProxy implements Chat{
private Chat myChat = new MyChat();
public void reply(String message) {
if(message.equals("hi,你好")) { System.out.println("hi, 你也好"); }else if(message.equals("你从哪里来?")){ System.out.println("我来自中国!"); }else if(message.equals("你多大了?")) { System.out.println("我今年22啦!"); }else if(message.equals("身高多少呀?")){ System.out.println("我身高 } else { myChat.reply(message); } } }
|
建立一个测试客户端:
package com.diermeng.designPattern.Proxy.client;
import com.diermeng.designPattern.Proxy.Chat; import com.diermeng.designPattern.Proxy.impl.ChatProxy;
public class ProxyTest {
public static void main(String[] args) { //直接调用代理类 Chat cp = new ChatProxy();
//代理类提供的实现 cp.reply("hi,你好"); cp.reply("你从哪里来?"); cp.reply("你多大了?"); cp.reply("身高多少呀?");
//具体类提供的实现 cp.reply("你喜欢我吗?"); } } |
运行结果如下:
hi, 你也好 我来自中国! 我今年22啦! 我身高 需要我亲自回复的内容。。。
|
如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法。这个抽象方法在代理类中动态实现。
(2). Proxy:该类即为动态代理类,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口。通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
代理模式的优缺点分析:
总体而言:使用代理模式能够在不改变原来代码功能的基础上对某一个对象进行额外的控制访问,同时这种分工也体现了单一职责原则。
远程代理:使得系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。
客户完全可以认为代理的对象是局域的而不是远程的,而代理对象承担了大部分的网络通信工作。
虚拟代理:优点是代理对象可以在必要的时候才将被代理的对象加载。代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的时候,虚拟代理的优点就非常明显。
保护代理:优点是它可以在运行的时间对用户的有关权限进行检查,然后在核实后决定将被调用传递给被代理的对象。
智能引用代理:在访问一个对象时可以执行一些内务处理操作。
代理模式的实际应用简介:
代理模式一般应用于以下情况:
一个比较大的对象,例如说一幅很大的图像,此时需要很长的载入时间。
一个需要很长时间才可以完成的计算结果,并且需要它在计算过程中显示中间结果。
一个存在于远程计算机上的对象,需要通过网络载入这个远程对象就需要很长的时间,特别是在网络传输的高峰期。
用户对对象只有有限的访问权限,此时代理模式可以验证用户的权限。
温馨提示:
在某些情况下,客户不想或者不能直接引用一个对象,这个时候就用到了代理类,代理对象可以再客户和目标对象之间起到中介的作用,客户端分辨不出代理对象与真实对象的区别,代理模式可以不知道真正的代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。