`
YOUNG918
  • 浏览: 188788 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

从Java类库看设计模式(四)

    博客分类:
  • java
阅读更多
在上一部分中,介绍了两个结构型的模式:Bridge和Decorator。这一部分的内容,将会接着上面的讲解,继续我们的设计模式之旅。
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->

这一部分,除了还会介绍一个结构型的Composite模式之外,还会有两个行为模式登场。实际上在前面的内容中,我们已经接触到行为模式 了:Observer和Command就是两个典型的行为模式。行为模式更多的注重于算法和对象建间职责的分配,也就是说,它会更多的关注于这个模式系统 之类的各对象协作间的语义,以及在对象间进行通讯的流控制。

Composite模式

毫无疑问的,AWT中的Component-Container体系就是一个很好的Composite模式的例子。Container继承于 Component,而Container中有可以包含有多个Component,因为Container实际上也是Component,因而 Container也可以包含Container。这样通过Component-Container结构的对象组合,形成一个树状的层次结构。这也就是 Composite模式所要做的。

Composite模式是为了简化编程而提出的,一般的在编程的时候,如果严格的区分Component和Container的话,有时候会带来许 多不便,而且这些往往是没有必要的。比如,我要在一个Container中放置一个Component,我并不需要知道这个Component到底是一个 Container,或者就是一个一般的Component,在父级容器中所要做的,只是记录一个Component的引用,在需要的时候调用 Component的绘制方法来显示这个Component。当这个Component确实是一个Container的时候,它可以通过 Container重载后的绘制方法,完成对这个容器的显示,并把绘制消息传递给到它的子对象去。也就是说,对一个父级容器而言,它并不不关心,其子对象 到底是一个Component,还是一个Container。它需要将Component和Container统一对待。


图十一:Composite模式的类图

Composite模式比较简单,实现起来也不复杂,但是有一定的局限性。比如,在处理树的时候,我们往往需要处理三类对象:子树,页节点和非页节 点。而在Composite模式中对于子树和非叶节点的区分并不明显,而是把他们合成为一个Composite对象了。而且在GOF给出的 Composite的模式中,对于添加,删除子节点等属于Composite对象的的方法,是放在了Component对象中的,这虽然在实现的时候可以 区分开来,但容易造成一些概念上的误解。

由上所叙,我们可以提出一个改进了的Composite模式,引入子树对象,从而将子树和非叶节点分开,如下图所示:


图十二:Composite模式的一种变体

虽然将Composite从Component类层次中分离出来,但并没有损害Composite模式的内涵。这样做不一定就会比上面的那个要好,各有不同的应用,不过有时候用这样的方法来处理子树要容易些,概念上也更为清晰。

下面的代码,给出了一个Composite模式简单的Java实现:

public   abstract   class  Component{
    
public   abstract   void  operation();   
    
public   void  add(Component component){};
    
public   void  remove(Component component){};  
}
import  java.util. * ;
public   class  Composite  extends  Component{
    String name;
    ArrayList children 
=   new  ArrayList();
    
public  Composite(String name){
        
this .name  =  name;
    }
    
public   void  add(Component component){
        children.add(component);
    }
    
public   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  Component{
    String name;
    
public  Leaf(String name){
        
this .name  =  name;
    }
    
public   void  operation(){
        System.out.println(name);
    }
}

Strategy模式

Strategy模式主要用来将算法实现从类中分离出来,并封装在一个单独的类中。更简单的说,对象与其行为(behaviour)这本来紧密联系 的两部分被解耦,分别放在了两个不同的类中。这使得对同一个行为,可以方便的在任何时候切换不同的实现算法。而通过对策略的封装,为其提供统一的接口,也 可以很容易的引入新的策略。

AWT的LayoutManager,是Strategy模式的一个例子。对于GUI而言,每个组件(Component)在容器中 (Container)的排放是需要遵循一定的算法的。通常的方法是使用绝对坐标,就像VB,Delphi之类的工具所作的那样,记录每个组件在容器中的 位置。这当然会带来一些问题,比如在窗体缩放的时候,就需要手工编码改变组件的大小和位置,以使得原来的比例得以保存。而在AWT中,引入了布局管理器 (LayoutManager)的概念,使得布局的方法大大丰富,编码过程也变得简单。

一个容器,比如Applet,Panel等,仅仅记录其包含的组件,而布局管理器中封装了对容器中组件进行布局的算法,具体地说,就是指明容器中组 件的位置和尺寸的大小。通过布局管理器,你只需要确定想放置的组件间的相对位置即可,这一方面简化编码,另一方面也有助于实现软件的平台无关性。


图十三:AWT中的容器和布局管理器的关系

每一个容器均有一个布局管理器,当容器需要布置它的组件时,它调用布局管理器的方法布置容器内的组件。LayoutManager2继承于 LayoutManager,提供更为细致的布局功能,它可以让布局管理器为组件加上约束条件已确定组件如何被布置。例如,为了确定组件被摆放在边框内的 位置,BorderLayout在它的组件上加上方向指示。

特别的,通过实现LayoutManager或者LayoutManager2接口,可以很容易实现自定义的布局策略。

回到模式的话题上来,如果有几个很相似的类,其区别仅仅是在个别行为上的动作不同,这时候就可以考虑使用Strategy模式。这样,通过策略组 合,将原来的多个类精简为一个带有多个策略的类。这很符合OO设计的原则:找到变化的部分,并将其封装起来!Strategy模式同样的为子类继承提供了 一个好的替代方案,当使用继承机制的时候,行为的改变是静态的,你指能够改变一次--而策略是动态的,可以在任何时候,切换任何次数。更为重要的是,策略 对象可以在不同的环境中被不同的对象所共享。以布局管理器为例,虽然每一个容器只有一个布局管理器,但是一个布局管理器可以为多个容器工作。


图十四:Strategy模式的类图

Strategy模式也有一些缺点,比如,应用程序必须知道所有的策略对象,并从中选者其一。而且在策略对象被使用的时候,它和Context对象 之间通常是紧耦合的,Context对象必须为策略对象提供与具体算法相关的数据或者其它的东西,而这些数据的传递可能并不能够风装载抽象地策略类中,因 为并不是所有的算法都会需要这些数据的。另外,因为策略对象通常由应用程序所创建,Context对象并不能够控制Strategy的生命期,而在概念 上,这个策略应该从属于Context对象,其生命期不应该超出Context的范围对象。

通常的,Strategy很容易和Bridge模式相混淆。确实,他们有着很相近的结构,但是,他们却是为解决不同的问题而设计的。Strategy模式注重于算法的封装,而Bridge模式注重于分离抽象和实现,为一个抽象体系提供不同的实现。

Iterator模式

Iterator模式用来规格化对某一数据结构的遍历接口。

JDK中在Collection Framework中引入了Iterator接口,提供对一个Collection的遍历。每一个Collection类中都定义有从 Collection接口中继承而来的iterator()方法,来得到一个Iterator对象,我们称之为遍历器,Iterator接口很简单:

hasNext():用来判断在遍历器中是否还有下一个元素。

next():返回遍历器中的下一个元素。

remove():在被遍历的Collection类中删除最后被返回的那个对象。

我们就以最为常用的Vector为例,看看在Collection Framework中,Iterator模式是如何被实现的。在此之前,我们需要先了解一些Vector和Collection Framework的结构。

Collection接口作为这个Framework的基础,被所有其它的集合类所继承或者实现。对Collection接口,有一个基本的实现是 抽象类AbstractCollection,它实现了大部分与具体数据结构无关的操作。比如判断一个对象是否存在于这个集合类中的contains() 方法:

    public   boolean  contains(Object o) {
    Iterator e 
=  iterator();
    
if  (o == null ) {
        
while  (e.hasNext())
        
if  (e.next() == null )
            
return   true ;
    } 
else  {
        
while  (e.hasNext())
        
if  (o.equals(e.next()))
            
return   true ;
    }
    
return   false ;
    }

而这其中调用的iterator()方法是一个抽象方法,有赖于具体的数据结构的实现。但是对于这个containers()方法而言,并不需要知 道具体的Iterator实现,而只需要知道它所提供的接口,能够完成某类任务既可,这就是抽象类中抽象方法的作用。其它的在 AbstractCollection中实现的非抽象方法,大部分都是依赖于抽象方法iterator()方法所提供的Iterator接口来实现的。这 种设计方法是引入抽象类的一个关键所在,值得仔细领悟。

List接口继承Collection接口,提供对列表集合类的抽象;对应的AbstractList类继承 AbstractCollection,并实现了List接口,作为List的一个抽象基类。它对其中非抽象方法的实现,也大抵上与 AbstractCollection相同,这儿不再赘叙。

而对应于Collection的Iterator,List有其自己的ListIterator,ListIterator继承于Iterator,并添加了一些专用于List遍历的方法:

boolean hasPrevious():判断在列表中当前元素之前是否存在有元素。

Object previous():返回列表中当前元素之前的元素。

int nextIndex():

int previousIndex():

void set(Object o):

void add(Object o):

ListIterator针对List,提供了更为强劲的功能接口。在AbstractList中,实现了具体的iterator()方法和listIterator()方法,我们来看看这两个方法是如何实现的:

    public  Iterator iterator() {
    
return   new  Itr();  // Itr是一个内部类
    }
    
private   class  Itr  implements  Iterator {
    
int  cursor  =   0 ; // Iterator的计数器,指示当前调用next()方法时会被返回的元素的位置
     int  lastRet  =   - 1 ; // 指示刚刚通过next()或者previous()方法被返回的元素的位置,-1
// 表示刚刚调用的是remove()方法删除了一个元素。
// modCount是定义在AbstractList中的字段,指示列表被修改的次数。Iterator用 // 这个值来检查其包装的列表是否被其他方法所非法修改。
     int  expectedModCount  =  modCount;
    
public   boolean  hasNext() {
        
return  cursor  !=  size();
    }
    
public  Object next() {
        
try  {
// get方法仍然是一个抽象方法,依赖于具体的子类实现
        Object next  =  get(cursor);
        
// 检查列表是否被不正确的修改
        checkForComodification();
        lastRet 
=  cursor ++ ;
        
return  next;
        } 
catch (IndexOutOfBoundsException e) {
        checkForComodification();
        
throw   new  NoSuchElementException();
        }
    }
    
public   void  remove() {
        
if  (lastRet  ==   - 1 )
        
throw   new  IllegalStateException();
            checkForComodification();
        
try  {
// 同样remove(int)也依赖于具体的子类实现
        AbstractList. this .remove(lastRet);
        
if  (lastRet  <  cursor)
            cursor
-- ;
        lastRet 
=   - 1 ;
        expectedModCount 
=  modCount;
        } 
catch (IndexOutOfBoundsException e) {
        
throw   new  ConcurrentModificationException();
        }
    }
    
final   void  checkForComodification() {
        
if  (modCount  !=  expectedModCount)
        
throw   new  ConcurrentModificationException();
    }
    }

这儿的设计技巧和上面一样,都是使用抽象方法来实现一个具体的操作。抽象方法作为最后被实现的内容,依赖于具体的子类。抽象类看起来很像是一个介于接口和子类之间的一个东西。

从设计上来讲,有人建议所有的类都应该定义成接口的形式,这当然有其道理,但多少有些极端。当你需要最大的灵活性的时候,应该使用接口,而抽象类却 能够提供一些缺省的操作,最大限度的统一子类。抽象类在许多应用框架(Application Framework)中有着很重要的作用。例如,在一个框架中,可以用抽象类来实现一些缺省的服务比如消息处理等等。这些抽象类能够让你很容易并且自然的 把自己的应用嵌入到框架中去。而对于依赖于每个应用具体实现的方法,可以通过定义抽象方法来引入到框架中。

其实在老版本的JDK中也有类似的概念,被称为Enumeration。Iterator其实与Enmeration功能上很相似,只是多了删除的 功能。用Iterator不过是在名字上变得更为贴切一些。模式的另外一个很重要的功用,就是能够形成一种交流的语言(或者说文化)。有时候,你说 Enumeration大家都不明白,说Iterator就都明白了。

小结:

这部分介绍了三个模式:Composite,Strategy和Iterator。Composite是一个结构性的模式,用来协调整体和局部的关 系,使之能够被统一的安排在一个树形的结构中,并简化了编程。Strategy模式与Bridge模式在结构上很相似,但是与Bridge不同在于,它是 一个行为模式,更侧重于结构的语义以及算法的实现。它使得程序能够在不同的算法之间自由方便的作出选择,并能够在运行时切换到其他的算法,很大程度上增加 了程序的灵活性。Iterator模式提供统一的接口操作来实现对一个数据结构的遍历,使得当数据结构的内部算法发生改变时,客户代码不需要任何的变化, 只需要改变相应的Iterator实现,就可以无缝的集成在原来的程序中。

参考资料

  • 设计模式:可复用面向对象软件的基础 机械工业出版社

  • Java2类库增补版 机械工业出版社

  • Java2图形设计:AWT卷 机械工业出版社

  • 可视化面向对象建模技术 北京航天航空工业大学出版社

  • DK1.3源代码

  • UML用户指南 机械工业出版社
分享到:
评论

相关推荐

    从Java类库看设计模式

    ### 从Java类库看设计模式之Observer模式详解 #### 一、引言 在软件开发过程中,常常遇到需要在不同对象之间建立依赖关系的情况,其中一个对象的状态变化会影响到另一个对象的行为。这种需求可以用设计模式中的...

    从Java类库看设计模式.pdf

    本文以Java类库为视角,深入探讨了设计模式的核心概念、分类以及在Java中的具体应用案例,特别是组合模式和观察者模式。 设计模式的概念起源于对软件开发过程中遇到的各种问题的总结和归纳。它是一套经验证的、可...

    从类库看设计模式

    除了Observer模式,Java类库还体现了其他多种设计模式。如Singleton模式,用于确保一个类只有一个实例,并提供全局访问点,如`java.lang.Runtime`类;Factory模式,用于创建对象的接口,如`java.sql.DriverManager`...

    Java类库 java中常用的类 可以参考

    Java 类库为开发者提供了丰富的工具集,涵盖了从基础的数据类型处理到高级的网络通信等多个方面。本文档旨在介绍 Java 中一些常用的类库,帮助初学者更好地理解和使用这些类库。尽管文档内容并不全面,但包含了...

    Java类库大全.docx

    Struts 是一个基于MVC设计模式的Web应用框架,用于处理HTTP请求和响应: - Struts Action 用来处理来自用户的请求,执行业务逻辑,并将结果返回给用户。 - Struts Taglib 提供了一系列JSP标签,方便在页面上创建用户...

    java2类库 java类库的源文件

    同时,这也是一个很好的学习 Java 设计模式和最佳实践的方式,因为许多类库的设计都遵循了 SOLID 原则和面向对象设计的原则。因此,"java2 类库" 对于 Java 学习者来说是一本经典的参考材料,它不仅提供了丰富的代码...

    Java类库大全

    Java类库大全是一个集合了众多Java...通过这个"Java类库大全",开发者可以根据项目需求快速找到合适的类库,提高开发效率,同时也能学习到各种类库的设计理念和最佳实践。这个资源包无疑是对Java开发者的一份宝贵财富。

    Java类库手册

    `java.beans`包则支持JavaBeans组件,便于属性、事件和设计模式的处理。 最后,`javafx`包是JavaFX图形和媒体库,用于构建现代、丰富的跨平台桌面和Web应用程序,支持2D和3D图形、动画、音频和视频处理。 总的来说...

    java常用类库手册

    合理利用Java类库能够极大地提高编程效率,使得程序更加简洁易懂。 #### 二、Java类库的结构与组成 Java类库中的类和接口大多被组织成不同的包(package)。每个包通常包含了一组具有相似功能的类和接口,这些包...

    Java类库中Decorator模式的应用研究.pdf

    其中,**Decorator模式**作为一种常用的结构型设计模式,在Java类库中有着广泛的应用。本文将详细介绍Decorator模式的概念、应用场景及其在Java I/O系统中的具体实现。 #### 二、Decorator模式简介 **Decorator...

    超级经典java例子,涉及到大部分java类库的使用

    12. **设计模式**:如单例、工厂、观察者等,例子将展示如何在Java中实现常见的设计模式,提升代码的复用性和可维护性。 通过研究这些例子,开发者不仅可以巩固Java基础知识,还能学习到如何在实际项目中灵活运用...

    java设计模式pdf

    ### Java设计模式详解 #### 一、背景与概念 在软件工程领域,设计模式是一种用于解决常见问题的可重用解决方案。《Java设计模式PDF》是一本由James W. Cooper编写的经典书籍,该书详细介绍了Java编程语言中的设计...

    java编程思想4th版类库

    例如,它可能包含了一些数据结构、算法或者设计模式的实现,帮助读者更好地理解和应用Java编程思想。 在Java编程中,类库的使用可以极大地提高开发效率。例如,标准库如Java.util和Java.io提供了大量用于处理集合、...

    JAVA设计模式

    **JAVA设计模式** 在软件工程领域,设计模式是一种在特定情境下解决问题的可复用解决方案。它们是经验的总结,代表了在特定上下文中被广泛接受的、经过时间考验的最佳实践。Java设计模式是面向对象编程中的一种重要...

    设计模式+UML.rar

    包含以下文件: Java设计模式-图解-附代码.pdf 从Java类库看设计模式.doc 六大UML类图关系.docx 认识UML类图元素_java之UML.doc 设计模式6大原则.doc 设计模式学习笔记.doc 深入浅出设计模式(中文版).pdf

    java设计模式(绝对高清和完整)

    本资源“java设计模式(绝对高清和完整)”提供了全面且清晰的关于Java设计模式的学习材料,由“设计模式公司荣誉出品”,确保了内容的专业性和质量。 设计模式并不是具体的代码或库,而是描述在某些特定上下文中,...

Global site tag (gtag.js) - Google Analytics