1、从 Java 类库看设计模式(1) Observer 模式Observer 模式的功用,是希望两个(或多个)对象,我们称之为 Subject 和 Observer,当一方的状态发生改变的时候,另一方能够得 到通知。也就是说,作为 Observer 的一方,能够监视到Subject 的某个特定的状态变化,并为之做出反应。一个简单的例子就是:当一个用户视图中 的数据被用户改变后,后端的数据库能够得到更新,而当数据库被其他方式更新后,用户视图中的数据显示也会随之改变。图一:Obverser 模式的类图在 JDK 中实际上有一个对 Observer 模式的简单的实现:就是类 java.util.Obs
2、erverable 和接口 java.util.Observer。java.util.Observerable 类对应于 Subject,而 java.util.Observer 就是观察者了。JDK 中并没有把这两个部分都设计为接口,而是让类 java.util.Observerable 提供了部分的实现,简化了许多编程的工 作。当然,这也减少了一定的灵活性。下面列出了 Observer 和 Observeral 的函数列表,及其简单的功能说明java.util.Observer: public void update(Observable obs, Object obj) java.uti
3、l.Observer 接口很简单,只定义了这一个方法,狭义的按照 Observer 模式的说法,Observer 应该在这个方法中调用 Subject 的 getXXX()方法来 取得最新的状态,而实际上,你可以只是在其中对 Subject 的某些事件进行响应。这便是 Java 中的代理事件模型的一个雏形-对事件进行响应。只不 过,在 Observer 模式中将事件特定化为某个状态/数据的改变了。 java.util.Observablepublic void addObserver(Observer obs)向 Subject 注册一个 Observer。也就是把这个 Observer 对象
4、添加到了一个java.util.Observable 内部的列表 中。在 JDK 中对于这个列表是简单的通过一个java.util.Vector 类来实现的,而实际上,在一些复杂的 Observer 模式的应用中,需要把 这个部分单另出来形成一个 Manager 类,来管理 Subject 和 Observer 之间的映射。这样,Subject 和Observer 进一步的被解 藕,程序也会具有更大的灵活性。public void deleteObserver(Observer obs) 从 Subject 中删除一个已注册了 Observer 的引用。 protected void setC
5、hanged() 设置一个内部的标志以指明这个 Ovserver 的状态已经发生改变。注意这是一个 protected 方法,也就是说只能在 Observer 类和其子类中被调用,而在其它的类中是看不到这个方法的。 public void notifyObservers(Object obj) 它首先检查那个内部的标志,以判断状态是否改变,如果 是的话,它会调用注册在 Subject 中的每个 Observer 的 update()方法。在 JDK 中这个方法内部是作为 synchronized 来实现 的,也就是如果发生多个线程同时争用一个 java.util.Observerable 的
6、notifyObservers()方法的话,他们必须按调度的 等待着顺序执行。在某些特殊的情况下,这会有一些潜在的问题:可能在等待的过程中,一个刚刚被加入的 Observer 会被遗漏没有被通知到,而一个刚刚被 删除了的 Observer会仍然收到它已经不想要了的通知。 1 package javamodel.observer;3 import java.util.Observable;4 import java.util.Observer;7 * 猫叫,老鼠跑,主人被惊醒,用代码实现这个连锁反应 。8 * author Administrator1112 public class TestO
7、bserver 14 public static void main(String args)15 Cat c=new Cat();16 Observer o1=new Mouse();17 Observer o2=new Man();18 c.addObserver(o1);19 Mouse oo1=(Mouse)o1;/向下转型20 oo1.addObserver(o2);21 c.CatSay();22 24 2526 class Cat extends Observable/猫被老鼠观察,猫是被观察者28 public void CatSay()29 System.out.printl
8、n(“猫叫了“);30 this.setChanged();31 this.notifyObservers();32 33 3435 class Mouse extends Observable implements Observer/老鼠观察猫,猫是观察者,对于人,老鼠是被观察者37 public void update(Observable arg0, Object arg1) 38 / TODO Auto-generated method stub39 System.out.println(“猫叫了,老鼠跑了“);40 this.setChanged();41 this.notifyOb
9、servers();42 44 46 class Man implements Observer/人观察老鼠,人是观察者48 public void update(Observable arg0, Object arg1) 49 / TODO Auto-generated method stub50 System.out.println(“老鼠跑了,人惊醒了“);51 52 我认为在 JDK 中这个 Observer 模式的实现,对于一般的 Observer 模式的应用,已经是非常的足够了的。但是一方面它用一个类来实现了 Subject,另一方面它使用 Vector 来保存 Subject 对
10、于Observer 的引用,这虽然简化了编程的过程,但会限制它在一些需要更为灵活, 复杂的设计中的应用,有时候(虽然这种情况不多),我们还不得不重新编写新的 Subject 对象和额外的Manager 对象来实现更为复杂的 Observer 模式的应用。小结:观察者模式的应用场景:1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。观察者模式的优点:1、 Subject 和 Observer 之间是松偶合的,分别可以各自独立改变。2、 Subject 在发送广播通知的时候,无须指定具体的 Obser
11、ver,Observer 可以自己决定是否要订阅 Subject 的通知。3、 遵守大部分 GRASP 原则和常用设计原则,高内聚、低偶合。观察者模式的缺陷:1、 松偶合导致代码关系不明显,有时可能难以理解。(废话)2、 如果一个 Subject 被大量 Observer 订阅的话,在广播通知的时候可能会有效率问题。(毕竟只是简单的遍历)从 Java 类库看设计模式(2) Command 模式在设计一般用途的软件的时候,在 C 或者 C+语言中,用的很多的一个技巧就是回调函数(Callback),所谓的回调函数,意指先在系统的某个地 方对函数进行注册,让系统知道这个函数的存在,然后在以后,当某
12、个事件发生时,再调用这个函数对事件进行响应。在 C 或者 C+中,实现的回调函数方法是使 用函数指针。但是在 Java 中,并不支持指针,因而就有了 Command 模式,这一回调机制的面向对象版本。Command 模式用来封装一个命令/请求,简单的说,一个 Command 对象中包含了待执行的一个动作(语句)序列,以执行特定的任务。当然,并不是随便怎么样的语句序列都可以构成一个Command 对象的,按照 Command 模式的设计,Command 对象和它的调用者 Incvoker 之间应该 具有接口约定的。也就是说,Invoker 得到 Command 对象的引用,并调用其中定义好的方法
13、,而当Command 对象改变(或者是对象本身代码改 变,或者干脆完全另外的一个 Command 对象)之后,Invoker 中的代码可以不用更改。这样,通过封装请求,可以把任务和任务的实现加以分离。图二:Command 模式的类图而对于请求的处理又有两种不同的方法,一种是 Command 只充当代理,将请求转发给某个接受者对象,还有一种是 Command 对象自己处理完所有的请求操作。当然,这只是两个极端,更多的情况是 Command 完成一部分的工作,而另外的一部分这则交给接受者对象来处理。在新的 JDK 的代理事件模型中,就可以看作是这样的一个 Command 模式。在那个模型中,一个事
14、件监听者类 EventListener 监听某个事 件,并根据接口定义,实现特定的操作。比如,当用Document 对象的 addDocumentListener(DocumentListener listener) 方法注册了一个DocumentListener 后,以后如果在 Document 对象中发生文本插入的事件,DocumentListener 中实现的 insertUpdate(DocumentEvent e)方法就会被调用,如果发生文本删除事件,removeUpdate(DocumentEvent e)方法就会被调用。怎么样,想想看,这是不是一个 Command 模式的应用呢?
15、然而,最经典的 Command 模式的应用,莫过于 Swing 中的 Action 接口。Action 实际上继承的是ActionListener,也就 是说,它也是一个事件监听者(EventListener)。但是 Action 作为一种ActionListener 的扩展机制,提供了更多的功能。它可 以在其中包含对这个 Action 动作的一个或者多个文字的或图标的描叙,它提供了 Enable/Disable 的功能许可性标志。并且,一个Action 对象可以被多个 Invoker,比如实现相同功能的按钮,菜单,快捷方式所共享。而这些Invoker 都知道如何加入一个 Action,并充分
16、利用它所提 供的扩展机制。可以说,在这儿Action 更像一个对象了,因为它不仅仅提供了对方法的实现,更提供了对方法的描叙和控制。可以方便的描叙任何的事务,这 更是面向对象方法的威力所在。下面我们看一个 Command 模式的应用的例子。假设要实现这样的一个任务:Task Schedule。也就是说,我想对多个任务进行安排,比如扫描磁盘,我希望它每 1 个小时进行一次,而备份数据,我希望它半个小时进行一次,等等等等。但 是,我并不希望作为 TaskSchedule 的类知道各个任务的细节内容,TaskSchedule 应该只是知道 Task 本身,而对具体的实现任务的细节 并不理会。因而在这儿
17、,我们就需要对 TaskSchedule 和 Task 进行解耦,将任务和具体的实现分离出来,这不正是 Command 模式的用武之地 吗?图三:Command 模式的应用例子程序清单:/抽象的 Task 接口,作为回调的 Command 模式的主体public interface Task public void taskPerform();/具体的实现了 Task 接口的子类,实现特定的操作。public class BackupTask implements Taskpublic void taskPerform()System.out.println(“Backup Task has
18、been performed“);/具体的实现了 Task 接口的子类,实现特定的操作。public class ScanDiskTask implements Taskpublic void taskPerform()System.out.println(“ScanDisk Task has been performed“);/一个封装了 Task 的一个封装类,提供了一些与 Task 相关的内容,也可以把这些内容/这儿不过为了突出 Command 模式而把它单另出来,实际上可以和 Task 合并。public class TaskEntry private Task task;privat
19、e 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 timeL
20、astDone;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 exten
21、ds 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.ge
22、tTimeInterval();/执行任务调度public void schedulePermorm()trysleep(sleeptime);Enumeration e = taskList.elements();while (e.hasMoreElements() TaskEntry te = (TaskEntry) e.nextElement();if (te.getTimeInterval() + te.getTimeLastDone() “);setTrailer(“ “);public void addLine(String line)report += line + “ “;pu
23、blic class ASCIIReporter extends Reporterpublic void addLine(String line) report += line + “ “;实际上,Bridge 模式是一个很强大的模式,可以应用在很多方面。其基本思想:分离抽象和实现,是设计模式的基础之一。正如 GOF 所提到的:“找 到变化的部分,并将其封装起来“;“更多的考虑用对象组合机制,而不是用对象继承机制“。Bridge 模式很好的体现了这几点。Decorator 模式在使用 Java 中的 IO 类库的时候,是不是快要被它那些功能相似,却又绝对可称得上庞杂的类搞得要发疯了?或许你很不
24、明白为什么要做这么多功能相似的几十个类出来,这就是 Decorator 模式将要告诉你的了。在 IO 处理中,Java 将数据抽象为流(Stream)。在 IO 库中,最基本的是 InputStream 和OutputStream 两个分别处理输 出和输入的对象(为了叙述简便起见,这儿只涉及字节流,字符流和其完全相似),但是在 InputStream 和 OutputStream 中之提供了最简单 的流处理方法,只能读入/写出字符,没有缓冲处理,无法处理文件,等等。它们只是提供了最纯粹的抽象,最简单的功能。如何来添加功能,以处理更为复杂的事情呢?你可能会想到用继承。不错,继承确实可以解决问题,
25、但是继承也带来更大的问题,它对每一个功能,都需要一 个子类来实现。比如,我先实现了三个子类,分别用来处理文件,缓冲,和读入/写出数据,但是,如果我需要一个既能处理文件,又具有缓冲功能的类呢?这时候 又必须在进行一次继承,重写代码。实际上,仅仅这三种功能的组合,就已经是一个很大的数字,如果再加上其它的功能,组合起来的 IO 类库,如果只用继承来实 现的话,恐怕你真的是要被它折磨疯了。图六:JDK 中 IO 流的类层次Decorator 模式可以解决这个问题。Decorator 字面的意思是装饰的意思,在原有的基础上,每添加一个装饰,就可以增加一种功能。这就 是 Decorator 的本意。比如,
26、对于上面的那个问题,只需要三个 Decorator 类,分别代表文件处理,缓冲和数据读写三个功能,在此基础上所衍生 的功能,都可以通过添加装饰来完成,而不必需要繁杂的子类继承了。更为重要的是,比较继机制承而言,Decorator 是动态的,可以在运行时添加或者去 除附加的功能,因而也就具有比继承机制更大的灵活性。上面就是 Decorator 的基本思想,下面的是 Decorator 模式的静态结构图:图七:Decorator 模式的类图可以看到,一个 Decorator 与装饰的 Subject 对象有相同的接口,并且除了接口中给出的方法外,每个 Decorator 均有自己添加的方 法,来添
27、加对象功能。每个 Decorator 均有一个指向 Subject对象的引用,附加的功能被添加在这个 Subject 对象上。而 Decorator 对象本身也是一个Subject 对象,因而它也能够被其他的 Decorator 所修饰,提供组合的功能。在 Java IO 操作中,经常可以看到诸如如下的语句:myStringBuffer=new StringBuffer(“This is a sample string to be read“);FilterInputStream myStream=new LineNumberInputStream( new BufferInputStream
28、( new StringBufferInputStream( myStringBuffer);myStream.read();myStream.line();多个的 Decorator 被层叠在一起,最后得到一个功能强大的流。既能够被缓冲,又能够得到行数,这就是 Decorator 的威力!不仅仅如此,Java 中的 IO 还允许你引入自定义的 Decorator,来实现自己想要的功能。在良好的设计背景下,这做起并不复杂,只需要 4 步:1. 创建两个分别继承了 FilterInputStream 和 FilterOutputStream 的子类 2. 重载 read()和 write()方法
29、来实现自己想要的功能。 3. 可以定义或者重载其它方法来提供附加功能。 4. 确定这两个类会被一起使用,因为它们在功能上是对称的。 就这样,你就可以无限的扩展 IO 的功能了。在了解了 IO 中的 Decorator 后,我们再来看一个 Decorator 模式应用的具体的例子。这个例子原本是出现在 GOF 书中的,这儿稍作改动,引来示例。在一个图形用户界面(GUI)中,一个组件有时候需要用到边框或者滚动条,而有时候又不需要,有时候可能两者都要用到。当需要动态的去处或者添加职 能的时候,就可以考虑使用 Decorator模式了。这儿对于一个 VisualComponent 组件对象,我们引入了
30、两个 Decorator 类:BoderDecorator 和 ScrollDecorator,分别用来为组件添加边框和处理滚动。程序类图如下:图八:Decorator 模式的应用例子程序写得很简单,没有包括具体的代码,只是有一个可以运行的框架以供参考。代码如下:/Client 类用来创建窗体和组件对象,这儿可以看到 Decorator 是如何组合和应用的class Clientpublic static void main (String args )Window window = new Window ();TextView textView = new TextView ();windo
31、w.setContents (new BorderDecorator (new ScrollDecorator (textView, 500), 1); /Windows 类用来容纳组件对象class WindowVisualComponent contents;public Window () public void setContents (VisualComponent vc)contents = vc; /VisualComponent 类定义了组件的接口class VisualComponentpublic VisualComponent ()public void draw ()p
32、ublic void resize ()/TextView 类是一个显示文本的具体的组件class TextView extends VisualComponentpublic TextView ()public void draw ()public void resize ()/Decorator 类继承于 VisualComponent,定义所有 Decorator 的缺省方法实现class Decorator extends VisualComponentprivate VisualComponent component;public Decorator (VisualComponent
33、 vc) ponent=vc;public void draw () component.draw ();public void resize () component.resize ();/BorderDecorator 类为组件提供边框class BorderDecorator extends Decoratorprivate int width;public BorderDecorator (VisualComponent vc, int borderWidth)super (vc);width = borderWidth;public void draw ()super.draw ()
34、;drawBorder (width);private void drawBorder (int width)/ScrollDecorator 类为组件提供滚动条class ScrollDecorator extends Decoratorprivate int scrollSize;public ScrollDecorator (VisualComponent vc, int scrSize)super (vc);scrollSize = scrSize;public void draw ()scroll();super.draw ();private void scroll ()Decor
35、ator 确实能够很好的缓解当功能组合过多时子类继承所能够带来的问题。但是在得到很大的灵活性的同时,Decorator 在使用时也表现得较 为复杂。看看仅仅为了得到一个 IO 流,除了要创建核心的流外,还要为其加上各种各样的装饰类,这使得代码变得复杂而难懂。有几个人一开始时没有被 Java 的 IO 库吓一跳呢?小结:Bridge 模式用来分离抽象和实现,使得这两个部分能够分别的演化而不必修改另外一部分的内容。通常的,可以在实现部分定义一些基本的原子方法, 而在抽象部分则通过组合定义在实现层次中的原子方法来实现系统的功能。Decorator 模式通过聚合机制来为对象动态的添加职责,解决了在子类
36、继承中容 易引起的子类爆炸的问题。从 Java 类库看设计模式(4) 在上一部分中,介绍了两个结构型的模式:Bridge 和 Decorator。这一部分的内容,将会接着上面的讲解,继续我们的设计模式之旅。这一部分,除了还会介绍一个结构型的 Composite 模式之外,还会有两个行为模式登场。实际上在前面的内容中,我们已经接触到行为模式 了:Observer 和 Command 就是两个典型的行为模式。行为模式更多的注重于算法和对象建间职责的分配,也就是说,它会更多的关注于这个模式系统 之类的各对象协作间的语义,以及在对象间进行通讯的流控制。Composite 模式毫无疑问的,AWT 中的
37、Component-Container 体系就是一个很好的 Composite 模式的例子。Container 继承于 Component,而 Container 中有可以包含有多个 Component,因为 Container 实际上也是 Component,因而 Container 也可以包含 Container。这样通过 Component-Container结构的对象组合,形成一个树状的层次结构。这也就是 Composite 模式所要做的。Composite 模式是为了简化编程而提出的,一般的在编程的时候,如果严格的区分 Component 和Container 的话,有时候会带来许
38、多不便,而且这些往往是没有必要的。比如,我要在一个Container 中放置一个 Component,我并不需要知道这个 Component 到底是一个 Container,或者就是一个一般的 Component,在父级容器中所要做的,只是记录一个 Component 的引用,在需要的时候调用 Component 的绘制方法来显示这个 Component。当这个 Component 确实是一个Container 的时候,它可以通过 Container 重载后的绘制方法,完成对这个容器的显示,并把绘制消息传递给到它的子对象去。也就是说,对一个父级容器而言,它并不不关心,其子对象 到底是一个 Co
39、mponent,还是一个 Container。它需要将 Component 和 Container 统一对待。图十一:Composite 模式的类图Composite 模式比较简单,实现起来也不复杂,但是有一定的局限性。比如,在处理树的时候,我们往往需要处理三类对象:子树,页节点和非页节 点。而在 Composite 模式中对于子树和非叶节点的区分并不明显,而是把他们合成为一个 Composite 对象了。而且在 GOF 给出的 Composite的模式中,对于添加,删除子节点等属于 Composite 对象的的方法,是放在了 Component 对象中的,这虽然在实现的时候可以 区分开来,但
40、容易造成一些概念上的误解。由上所叙,我们可以提出一个改进了的 Composite 模式,引入子树对象,从而将子树和非叶节点分开,如下图所示:图十二:Composite 模式的一种变体虽然将 Composite 从 Component 类层次中分离出来,但并没有损害 Composite 模式的内涵。这样做不一定就会比上面的那个要好,各有不同的应用,不过有时候用这样的方法来处理子树要容易些,概念上也更为清晰。下面的代码,给出了一个 Composite 模式简单的 Java 实现:public abstract class Componentpublic abstract void operatio
41、n(); public void add(Component component);public void remove(Component component); import java.util.*;public class Composite extends ComponentString name;ArrayList children = new ArrayList();public Composite(String name)this.name = name;public void add(Component component)children.add(component);pub
42、lic void remove(Component component)children.remove(component);public void operation()System.out.println(name);Iterator iterator = children.iterator();while(iterator.hasNext()Component child = (Component)iterator.next();child.operation();public class Leaf extends ComponentString name;public Leaf(Str
43、ing name)this.name = name;public void operation()System.out.println(name);Strategy 模式Strategy 模式主要用来将算法实现从类中分离出来,并封装在一个单独的类中。更简单的说,对象与其行为(behaviour)这本来紧密联系 的两部分被解耦,分别放在了两个不同的类中。这使得对同一个行为,可以方便的在任何时候切换不同的实现算法。而通过对策略的封装,为其提供统一的接口,也 可以很容易的引入新的策略。AWT 的 LayoutManager,是 Strategy 模式的一个例子。对于 GUI 而言,每个组件(Comp
44、onent)在容器中 (Container)的排放是需要遵循一定的算法的。通常的方法是使用绝对坐标,就像VB,Delphi 之类的工具所作的那样,记录每个组件在容器中的 位置。这当然会带来一些问题,比如在窗体缩放的时候,就需要手工编码改变组件的大小和位置,以使得原来的比例得以保存。而在 AWT 中,引入了布局管理器 (LayoutManager)的概念,使得布局的方法大大丰富,编码过程也变得简单。一个容器,比如 Applet,Panel 等,仅仅记录其包含的组件,而布局管理器中封装了对容器中组件进行布局的算法,具体地说,就是指明容器中组 件的位置和尺寸的大小。通过布局管理器,你只需要确定想放置
45、的组件间的相对位置即可,这一方面简化编码,另一方面也有助于实现软件的平台无关性。图十三:AWT 中的容器和布局管理器的关系每一个容器均有一个布局管理器,当容器需要布置它的组件时,它调用布局管理器的方法布置容器内的组件。LayoutManager2 继承于 LayoutManager,提供更为细致的布局功能,它可以让布局管理器为组件加上约束条件已确定组件如何被布置。例如,为了确定组件被摆放在边框内的 位置,BorderLayout 在它的组件上加上方向指示。特别的,通过实现 LayoutManager 或者 LayoutManager2 接口,可以很容易实现自定义的布局策略。回到模式的话题上来,
46、如果有几个很相似的类,其区别仅仅是在个别行为上的动作不同,这时候就可以考虑使用 Strategy 模式。这样,通过策略组 合,将原来的多个类精简为一个带有多个策略的类。这很符合 OO 设计的原则:找到变化的部分,并将其封装起来!Strategy 模式同样的为子类继承提供了 一个好的替代方案,当使用继承机制的时候,行为的改变是静态的,你指能够改变一次-而策略是动态的,可以在任何时候,切换任何次数。更为重要的是,策略 对象可以在不同的环境中被不同的对象所共享。以布局管理器为例,虽然每一个容器只有一个布局管理器,但是一个布局管理器可以为多个容器工作。图十四:Strategy 模式的类图Strateg
47、y 模式也有一些缺点,比如,应用程序必须知道所有的策略对象,并从中选者其一。而且在策略对象被使用的时候,它和 Context 对象 之间通常是紧耦合的,Context 对象必须为策略对象提供与具体算法相关的数据或者其它的东西,而这些数据的传递可能并不能够风装载抽象地策略类中,因 为并不是所有的算法都会需要这些数据的。另外,因为策略对象通常由应用程序所创建,Context 对象并不能够控制 Strategy 的生命期,而在概念 上,这个策略应该从属于 Context对象,其生命期不应该超出 Context 的范围对象。通常的,Strategy 很容易和 Bridge 模式相混淆。确实,他们有着很
48、相近的结构,但是,他们却是为解决不同的问题而设计的。Strategy 模式注重于算法的封装,而 Bridge 模式注重于分离抽象和实现,为一个抽象体系提供不同的实现。Iterator 模式Iterator 模式用来规格化对某一数据结构的遍历接口。JDK 中在 Collection Framework 中引入了 Iterator 接口,提供对一个 Collection 的遍历。每一个 Collection 类中都定义有从 Collection 接口中继承而来的 iterator()方法,来得到一个Iterator 对象,我们称之为遍历器,Iterator 接口很简单:hasNext():用来判断
49、在遍历器中是否还有下一个元素。next():返回遍历器中的下一个元素。remove():在被遍历的 Collection 类中删除最后被返回的那个对象。我们就以最为常用的 Vector 为例,看看在 Collection Framework 中,Iterator 模式是如何被实现的。在此之前,我们需要先了解一些 Vector 和 Collection Framework 的结构。Collection 接口作为这个 Framework 的基础,被所有其它的集合类所继承或者实现。对Collection 接口,有一个基本的实现是 抽象类 AbstractCollection,它实现了大部分与具体数据结构无关的操作。比如判断一个对象是否存在于这个集合类中的 contains() 方法:public boolean contains(Object o) Iterator e = iterator