




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
引用 从Java类库看设计模式(2)gengwei138 的 从Java类库看设计模式(2)在上一部分的内容中,我们讲到什么是模式,什么是设计模式,以及对一个设计模式Observer的详细阐叙。相信大 家对于模式的概念应该是比较的理解了。这部分及以后的内容,将会步入正题,从Java类库的分析入手,来阐叙设计模式是如何应用到一个完美的设计中的。实 际上,Java类库非常的庞杂,这儿不可能把所有能够找到的设计模式的例子一一列举,只是找了一些容易发现的例子。实际上也没有必要,因为只要对一个设计 模式有足够的理解,对于它的具体应用而言,倒是一件不是很困难的事情。 Command模式 在设计一般用途的软件 的时候,在C或者C+语言中,用的很多的一个技巧就是回调函数(Callback),所谓的回调函数,意指先在系统的某个地方对函数进行注册,让系统知 道这个函数的存在,然后在以后,当某个事件发生时,再调用这个函数对事件进行响应。在C或者C+中,实现的回调函数方法是使用函数指针。但是在Java 中,并不支持指针,因而就有了Command模式,这一回调机制的面向对象版本。 Command模式用来封装一个命令/请求,简单的 说,一个Command对象中包含了待执行的一个动作(语句)序列,以执行特定的任务。当然,并不是随便怎么样的语句序列都可以构成一个Command对 象的,按照Command模式的设计,Command对象和它的调用者Incvoker之间应该具有接口约定的。也就是说,Invoker得到 Command对象的引用,并调用其中定义好的方法,而当Command对象改变(或者是对象本身代码改变,或者干脆完全另外的一个Command对象) 之后,Invoker中的代码可以不用更改。这样,通过封装请求,可以把任务和任务的实现加以分离。 图二:Command模式的类图 而 对于请求的处理又有两种不同的方法,一种是Command只充当代理,将请求转发给某个接受者对象,还有一种是Command对象自己处理完所有的请求操 作。当然,这只是两个极端,更多的情况是Command完成一部分的工作,而另外的一部分这则交给接受者对象来处理。 在新的JDK的 代理事件模型中,就可以看作是这样的一个Command模式。在那个模型中,一个事件监听者类EventListener监听某个事件,并根据接口定义, 实现特定的操作。比如,当用Document对象的addDocumentListener(DocumentListener listener) 方法注册了一个DocumentListener后,以后如果在Document对象中发生文本插入的事件,DocumentListener中实现的 insertUpdate(DocumentEvent e)方法就会被调用,如果发生文本删除事件,removeUpdate(DocumentEvent e)方法就会被调用。怎么样,想想看,这是不是一个Command模式的应用呢? 然而,最经典的Command模式的应用,莫过于 Swing中的Action接口。Action实际上继承的是ActionListener,也就是说,它也是一个事件监听者 (EventListener)。但是Action作为一种ActionListener的扩展机制,提供了更多的功能。它可以在其中包含对这个 Action动作的一个或者多个文字的或图标的描叙,它提供了Enable/Disable的功能许可性标志。并且,一个Action对象可以被多个 Invoker,比如实现相同功能的按钮,菜单,快捷方式所共享。而这些Invoker都知道如何加入一个Action,并充分利用它所提供的扩展机制。 可以说,在这儿Action更像一个对象了,因为它不仅仅提供了对方法的实现,更提供了对方法的描叙和控制。可以方便的描叙任何的事务,这更是面向对象方 法的威力所在。 下面我们看一个Command模式的应用的例子。假设要实现这样的一个任务:Task Schedule。也就是说,我想对多个任务进行安排,比如扫描磁盘,我希望它每1个小时进行一次,而备份数据,我希望它半个小时进行一次,等等等等。但 是,我并不希望作为TaskSchedule的类知道各个任务的细节内容,TaskSchedule应该只是知道Task本身,而对具体的实现任务的细节 并不理会。因而在这儿,我们就需要对TaskSchedule和Task进行解耦,将任务和具体的实现分离出来,这不正是Command模式的用武之地 吗? 图三:Command模式的应用例子 程序清单: /抽象的Task接口,作为回调的Command模式的主体 public interface Task public void taskPerform(); /具体的实现了Task接口的子类,实现特定的操作。 public class BackupTask implements Task public void taskPerform() System.out.println(Backup Task has been performed); /具体的实现了Task接口的子类,实现特定的操作。 public class ScanDiskTask implements Task public void taskPerform() System.out.println(ScanDisk Task has been performed); /一个封装了Task的一个封装类,提供了一些与Task相关的内容,也可以把这些内容 /这儿不过为了突出Command模式而把它单另出来,实际上可以和Task合并。 public class TaskEntry private Task task; private long timeInterval; private long timeLastDone; public Task getTask() return task; public void setTask(Task task) this.task = task; public void setTimeInterval(long timeInterval) this.timeInterval = timeInterval; public long getTimeInterval() return timeInterval; public long getTimeLastDone() return timeLastDone; public void setTimeLastDone(long timeLastDone) this.timeLastDone = timeLastDone; public TaskEntry(Task task,long timeInteral) this.task=task; this.timeInterval =timeInteral; /调度管理Task的类,继承Thread只是为了调用其sleep()方法, /实际上,如果真的作Task调度的话,每个Task显然应该用单独的Thread来实现。 public class TaskSchedule extends java.lang.Thread private java.util.Vector taskList=new java.util.Vector(); private long sleeptime=10000000000l;/最短睡眠时间 public void addTask(TaskEntry taskEntry) taskList.add(taskEntry); taskEntry.setTimeLastDone(System.currentTimeMillis(); if (sleeptimetaskEntry.getTimeInterval() sleeptime=taskEntry.getTimeInterval(); /执行任务调度 public void schedulePermorm() try sleep(sleeptime); Enumeration e = taskList.elements(); while (e.hasMoreElements() TaskEntry te = (TaskEntry) e.nextElement(); if (te.getTimeInterval() + te.getTimeLastDone() System.currentTimeMillis() te.getTask().taskPerform(); te.setTimeLastDone(System.currentTimeMillis(); catch (Exception e1) e1.printStackTrace(); public static void main (String args) TaskSchedule schedule=new TaskSchedule(); TaskEntry taks1=new TaskEntry(new ScanDiskTask(),10000); TaskEntry taks2=new TaskEntry(new BackupTask(),3000); schedule.addTask(taks1); schedule.addTask(taks2); while (true) schedule.schedulePermorm(); 程序本身其实没有多大的意义,因而,程序在编码的时候也只是用的最简单的方法来实现的,如果要做一个真正的TaskSchedule的话,这个程序除了结构上的,其它没有什么好值得参考的了。 AbstractFactory 和 FactoryMethod 基 本上来说,AbstractFacotry模式和FactoryMethod模式所作的事情是一样的,都是用来创建与具体程序代码无关的对象,只是面对的 对象层次不一样,AbstractFactory创建一系列的对象组,这些对象彼此相关。而FactoryMethod往往只是创建单个的对象。 再 开始这两个模式之前,有必要先陈叙一个在设计模式,或者说在整个面向对象设计领域所遵循的一个设计原则:针对接口编程,而不是针对具体的实现。这个思想可 以说是设计模式的基石之一。现在的很多对象模型,比如EJB,COM+等等,无不是遵照这个基本原则来设计的。针对接口编程的好处有很多,通过接口来定义 对象的抽象功能,方便实现多态和继承;通过接口来指定对象调用之间的契约,有助于协调对象之间的关系;通过接口来划分对象的职责,有助于寻找对象,等等。 AbstractFactory和FactoryMethod,还有其他的一些创建型的设计模式,都是为了实现这个目的而设计出来 的。它们创建一个个符合接口规范的对象/对象组,使得用同一个Factory创建出来的对象/对象组可以相互替换。这种可替换性就称为多态,是面向对象的 核心思想之一。而多态,是通过动态绑定来实现的。 图四:AbstractFactory模式的类图 客 户程序使用具体的AbstractFacotry对象(ConcreteFactoryX)调用CreateProductX()方法,生成具体的 ConcreteProductX。每个AbstractFactory所能生成的对象,组成一个系列的对象组,他们可能是相互相关的,紧耦合的。应为各 个AbstractFactory对象所能够生成的对象组都遵循一组相同的接口(AbstractProductX),因而当程序是针对接口进行编程的时 候,这些实现方法各不相同的对象组却可以相互的替换。 实际上,客户程序本身并不关心,也不知道具体使用的是那些产品对象。它甚至能够 不理会到底是哪个AbstractFactory对象被创建。在这种情况下,你可能会问,那么一个AbstractFactory又该如何生成呢?这时 候,就该用该FactoryMethod模式了。前面有说过,AbstractFactory着重于创建一系列相关的对象,而这些对象与具体的 AbstractFactory相关。而FactoryMethod则着重于创建单个的对象,这个对象决定于一个参数或者一个外部的环境变量的值;或者, 在一个抽象类中定义一个抽象的工厂方法(也成为虚拟构造器),然后再实现的子类中返回具体的产品对象。 FactoryMethod可 以借助一个参数或者一个外部的标志来判断该具体生成的哪一个子类的实例。比如对于不同的具体情况,需要有不同的AbstractFactory来生成相应 的对象组。这时候,FactoryMethod通常作为一个AbstractFactory对象的静态方法出现,使得其能够在具体的对象被创建之前就能够 被调用。 在JAVA中,应用这两个模式的地方实在太多,下面我们来看一个在JAXP中这两个模式的应用。JAXP是用来处理XML文 档的一个API。我们都知道XML文件的一个特点就是其平台无关,流通性能好。因而往往也需要处理他们的程序具有更好的平台无关性。Java语言是一个比 较好的平台无关语言,可以作为一个选择,但是对XML进行解析的解析器确有很多。有时候需要在不同的解析器之间进行切换,这时候,JAXP的良好设计就能 够体现出来了。它能够允许在不同解析器之间竟进行切换的时候,不用更改程序的代码。 我们就拿JAXP中的DOM解析器来作为例子,来例示AbstractFactory和FactoryMethod的用法。 图五:DOM中工厂模式的应用 上图中为了方便起见,只画出了抽象类和接口,DocumentBuilderFactory和DocumentBuilder都是抽象类。 DocumentBuilderFactory 的静态方法newInstance()方法根据一个外部的环境变量javax.xml.parsers.DocumentBuilderFactory的 值来确定具体生成DocumentBuilderFactory的哪一个子类。这儿的newInstance()是一个工厂方法。当 DocumentBuilderFactory被创建后,可以调用其newDocumentBuilder()来创建具体一个 DocumentBuilder的子类。然后再由DocumentBuilder来生成Document等DOM对象。 下面是创建一个DOM对象的代码片段: /第一步:创建一个DocumentBuilderFactory。 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); /第二步:创建一个DocumentBuilder DocumentBuilder db = dbf.newDocumentBuilder(); /第三步:解析XML文件得到一个Document对象 Document doc = db.parse(new File(filename); 在这儿,DocumentBuilder,Document,Node等等对象所组成的一个产品组,是和具体的DocumentBuilderFactory相关的。这也就是AbstractFactory模式的含义所在。 当然,FactoryMethod模式应用的很广。这是一个具体的例子,但他不应该限制我们的思路,FactoryMethod和AbstractFactory是解决面向对象设计中一个基本原则-面向接口编程的主要方法。 Singleton模式 Singleton 模式要解决的是对象的唯一性问题。由Singleton模式创建的对象在整个的应用程序的范围内,只允许有一个对象的实例存在。这样的情况在Java程序 设计的过程中其实并不少见,比如处理JDBC请求的连接池(Connection Pool),再比如一个全局的注册表(Register),等等,这都需要使用到Singleton,单件模式。 在Java中,最简 单的实现Singleton模式的方法是使用static修饰符,static可以用在内部类上,也可以用在方法和属性上,当一个类需要被创建成 Singleton时,可以把它所有的成员都定义成static,然后再用final和private来修饰其构造函数,使其不能够被创建和重载。这在程 序语法上保证了只会有一个对象实例被创建。比如java.util.Math就是这样的一个类。 而Singleton模式所作的显然 要比上面介绍的解决方法要复杂一些,也更为安全一些。它基本的思路也还是使用static变量,但是它用一个类来封装这个static变量,并拦截对象创 建方法,保证只有一个对象实例被创建,这儿的关键在于使用一个private或者protected的构造函数,而且你必须提供这样的一个构造函数,否则 编译器会自动的为你创建一个public的构造函数,这就达不到我们想要的目的了。 public class Singleton /保存唯一实例的static变量 static private Singleton _instance = null; /*为了防止对象被创建,可以为构造
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 关于合作推广本地农业资源利用项目的协议
- 2024-2025学年广东省潮州市湘桥区人教PEP版(2012)六年级下学期期中英语试卷(含答案含听力原文无听力音频)
- 企业知识产权保护服务协议
- 教师招聘之《小学教师招聘》综合检测模拟卷及答案详解(夺冠)
- 2025内蒙古呼伦贝尔农垦集团有限公司校园招聘50人笔试备考及一套答案详解
- 企业内训课程开发设计工具包
- 中华汉字900字(15篇)
- 教师招聘之《小学教师招聘》测试卷及答案详解一套
- 2025年教师招聘之《幼儿教师招聘》通关试题库及答案详解(典优)
- 幼儿园圣诞节活动策划方案
- 2025年山东高考真题化学试题(原卷版)
- 2025湖南湘潭市市直事业单位招聘(选调)工作人员48人考试参考试题及答案解析
- 第2课 教师节快乐 第2课时(课件)2025-2026学年道德与法治二年级上册统编版
- 2025年福建省福州市辅警考试题库(附答案)
- 2025年国家网络安全宣传周知识竞赛考试练习题库(完整版)含答案
- 2025秋新部编版一年级上册语文教学计划+教学进度表
- 大学英语四级高频词汇1500+六级高频词汇1500
- GB/T 20841-2007额定电压300/500V生活设施加热和防结冰用加热电缆
- DB11T 1893-2021 电力储能系统建设运行规范
- 诊所备案申请表格(卫健委备案)
- LANTEK兰特钣金软件手册(下)
评论
0/150
提交评论