`
hell_liul
  • 浏览: 40778 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java组合模式简单理解

阅读更多
一、引子

在大学的数据结构这门课上,树是最重要的章节之一。还记得树是怎么定义的吗?树(Tree)是n(n≥0)个结点的有限集T,T为空时称为空树,否则它满足如下两个条件:

(1)    有且仅有一个特定的称为根(Root)的结点;

(2)   其余的结点可分为m(m≥0)个互不相交的子集Tl,T2,…,Tm,其中每个子集本身又是一棵树,并称其为根的子树(SubTree)。

上面给出的递归定义刻画了树的固有特性:一棵非空树是由若干棵子树构成的,而子树又可由若干棵更小的子树构成。而这里的子树可以是叶子也可以是分支。

今天要学习的组合模式就是和树型结构以及递归有关系。



二、定义与结构

组合(Composite)模式的其它翻译名称也很多,比如合成模式、树模式等等。在《设计模式》一书中给出的定义是:将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

从定义中可以得到使用组合模式的环境为:在设计中想表示对象的“部分-整体”层次结构;希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。

看下组合模式的组成。

1)         抽象构件角色Component:它为组合中的对象声明接口,也可以为共有接口实现缺省行为。

2)       树叶构件角色Leaf:在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。

3)       树枝构件角色Composite:在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。

下图为组合模式的类图表示。








如图所示:一个Composite实例可以像一个简单的Leaf实例一样,可以把它传递给任何使用Component的方法或者对象,并且它表现的就像是一个Leaf一样。



可以看出来,使用组合模式使得这个设计结构非常灵活,在下面的例子中会得到进一步的印证。

      

三、安全性与透明性

组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?

一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化(如下图所示)。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。








另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法(如下图所示)。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。


   






    《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。



四、举例

这里以JUnit中的组合模式的应用为例(JUnit入门)。

JUnit是一个单元测试框架,按照此框架下的规范来编写测试代码,就可以使单元测试自动化。为了达到“自动化”的目的,JUnit中定义了两个概念:TestCase和TestSuite。TestCase是对一个类或者jsp等等编写的测试类;而TestSuite是一个不同TestCase的集合,当然这个集合里面也可以包含TestSuite元素,这样运行一个TestSuite会将其包含的TestCase全部运行。

然而在真实运行测试程序的时候,是不需要关心这个类是TestCase还是TestSuite,我们只关心测试运行结果如何。这就是为什么JUnit使用组合模式的原因。

JUnit为了采用组合模式将TestCase和TestSuite统一起来,创建了一个Test接口来扮演抽象构件角色,这样原来的TestCase扮演组合模式中树叶构件角色,而TestSuite扮演组合模式中的树枝构件角色。下面将这三个类的有关代码分析如下:



//Test接口——抽象构件角色

public interface Test {

       /**

        * Counts the number of test cases that will be run by this test.

        */

       public abstract int countTestCases();

       /**

        * Runs a test and collects its result in a TestResult instance.

        */

       public abstract void run(TestResult result);

}



//TestSuite类的部分有关源码——Composite角色,它实现了接口Test

public class TestSuite implements Test {

//用了较老的Vector来保存添加的test

       private Vector fTests= new Vector(10);

       private String fName;

       …… 

/**

        * Adds a test to the suite.

        */

       public void addTest(Test test) {          

//注意这里的参数是Test类型的。这就意味着TestCase和TestSuite以及以后实现Test接口的任何类都可以被添加进来

              fTests.addElement(test);

       }

       ……

       /**

        * Counts the number of test cases that will be run by this test.

        */

       public int countTestCases() {

              int count= 0;

              for (Enumeration e= tests(); e.hasMoreElements(); ) {

                     Test test= (Test)e.nextElement();

                     count= count + test.countTestCases();

              }

              return count;

       }

       /**

        * Runs the tests and collects their result in a TestResult.

        */

       public void run(TestResult result) {

              for (Enumeration e= tests(); e.hasMoreElements(); ) {

                    if (result.shouldStop() )

                           break;

                     Test test= (Test)e.nextElement();
                           //关键在这个方法上面


                     runTest(test, result);

              }

       }
            //这个方法里面就是递归的调用了,至于你的Test到底是什么类型的只有在运行的时候得知
            public void runTest(Test test, TestResult result) {
                   test.run(result);
            }


……

}



//TestCase的部分有关源码——Leaf角色,你编写的测试类就是继承自它

public abstract class TestCase extends Assert implements Test {

       ……

       /**

        * Counts the number of test cases executed by run(TestResult result).

        */

       public int countTestCases() {

              return 1;

       }

/**

        * Runs the test case and collects the results in TestResult.

        */

       public void run(TestResult result) {

              result.run(this);

       }

……

}

       可以看出这是一个偏重安全性的组合模式。因此在使用TestCase和TestSuite时,不能使用Test来代替。



五、优缺点

从上面的举例中可以看到,组合模式有以下优点:

1)         使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。

2)       更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。这一点符合开闭原则的要求,对系统的二次开发和功能扩展很有利!

当然组合模式也少不了缺点:组合模式不容易限制组合中的构件。



六、总结

组合模式是一个应用非常广泛的设计模式,在前面已经介绍过的解释器模式、享元模式中都是用到了组合模式。它本身比较简单但是很有内涵,掌握了它对你的开发设计有很大的帮助。

这里写下了我学习组合模式的总结,希望能给你带来帮助,也希望您能给与指正。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ai92/archive/2005/02/23/298336.aspx
  • 大小: 55.2 KB
  • 大小: 44.5 KB
  • 大小: 20.5 KB
分享到:
评论
2 楼 青春的、脚步 2013-01-07  
1 楼 weishuguangeye 2011-03-25  
不错,总结的非常好!

相关推荐

    JAVA设计模式之结构模式

    这是JAVA设计模式中属于结构模式的部分,包括Flyweight(共享模式)、Bridge(桥模式)、Decorator(装饰模式)、Composite(组合模式)、Adapter(适配器模式)、Proxy(代理模式)、Facade (外观模式)的源代码。其中有些模式中...

    深入浅出java设计模式(高清中文PDF)

    组合模式 8.装饰模式 9.门面模式 10.享元模式 11.代理模式 12.责任链模式 13.命令模式 14.解释器模式 15.迭代器模式 16.调停者模式 17.备忘录模式 18.观察者模式 19.策略模式 20.状态模式 21.模板模式...

    Java设计模式,并加上个人理解

    11. 组合模式 (Composite Pattern) 12. 装饰者模式 (Decorator Pattern) 13. 访问者模式 (Visitor Pattern) 14. 迭代器模式 (Iterator Pattern) 15. 享元模式 (Flyweight Pattern) 16. 桥接模式 (Bridge ...

    Java 设计模式详解超详细(含示例代码)

    结构型模式关注对象之间的结构关系,包括适配器模式、桥接模式、组合模式等;行为型模式则关注对象的交互和职责分配,包括观察者模式、策略模式、模板方法模式等。 使用设计模式的好处包括: 提高软件的可维护性...

    JAVA设计模式例程-装饰模式

    JAVA设计模式例程-装饰模式-的例程,看完以后基本上能对JAVA上实现装饰模式能有所了解,个人认为常各种模式并不是为了死套各种模式,而应该是灵活的在项目中结合实际情况而用各种模式的组合应用,呵呵!但前提是得对...

    快速理解Java设计模式中的组合模式

    主要介绍了快速理解Java设计模式中的组合模式,具有一定参考价值,需要的朋友可以了解下。

    java中的设计模式,主要的设计模式

    适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式观察者模式、策略模式、模板模式、责任链模式、解析器模式、迭代子模式 命令模式、状态模式、备忘录模式、访问者模式、中介者模式

    Java的23种设计模式疯狂Java总结.doc

    设计模式3 1.1 创立型模式4 1.1.1 工厂方法4 1.1.2 抽象工厂6 1.1.3 建造者模式10 1.1.4 单态模式13 1.1.5 原型模式15 1.2 构造型模式17 1.2.1 适配器模式17 1.2.2 桥接模式19 1.2.3 组合模式23 1.2.4 装饰模式26 ...

    Java聊天室 观察者模式和单例模式

    基于观察者模式和单例模式的java聊天室 面向对象设计,抽象,封装,代理,组合和继承 适合理解java面向对象,socket编程,观察者模式和单例模式

    设计模式java源码

    理理思路,所以就写了23个模式的JAVA实例,假如以后有时间就写一些多个设计模式的组合实例, MVC\IOC\DAO\AOP运用那些模式,他们怎么拆分 IT其实就三部分 1〉基本编程技术java、C# 2〉设计模式就是运用基本编程...

    尚硅谷设计模式源码笔记课件.zip

    结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、...

    经典Java23种设计模式.rar

    Java的23种设计模式 构成模式的四个基本要素: (1)模式名称:一个助记名,它用一两个词来描述模式的问题、解决方案和效果。 (2)问题(problem) :描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,...

    java-design-patterns:Java 设计模式学习笔记

    Java Design PatternsJava 设计模式学习笔记,简单易懂,每个模式都有相应的代码示列,帮助学习理解。在线阅读地址:设计原则创建型模式作用:将创建与使用代码解耦结构型模式作用:将不同的功能代码解耦桥接模式...

    java 设计模式资料

    附件中是java实现全部的设计模式,包含代码和工程(jbuilder工程),值得收藏. 此目录里包括了一书中所有23种设计模式的实现(Java 版)源码 关于代码的几点说明: 1. 代码为根据个人对Design Pattern的学习理解写...

    java设计模式:DAO模式.doc

    java设计模式:DAO模式 DAO设计模式 DAO的理解 1、DAO其实是利用组合工厂模式来解决问题的,并没有带来新的功能,所以学的 其实就是个思路。 2、DAO理论上是没有层数限制的。 3、DAO的各层理论上是没有先后的。 DAO...

    Java 中组合模型之对象结构模式的详解

    主要介绍了Java 中组合模型之对象结构模式的详解的相关资料,希望通过本文能帮助到大家理解应用对象结构模型,需要的朋友可以参考下

    Java设计模式之桥接模式

    更容易理解的表述是:实现系统可从多种维度分类,桥接模式将各维度抽象出来,各维度独立变化,之后可通过聚合,将各维度组合起来,减少了各维度间的耦合。  一、例讲桥接模式  不必要的继承导致类爆炸  汽车可...

    java-design-patterns:java 学习模式

    结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、...

    java餐饮管理系统源码-pattern:设计模式扫盲,以身边故事来讲解设计模式

    组合模式 行为型 策略模式 命令模式 职责链模式 状态模式 观察者模式 中介者模式 迭代器模式 访问者模式 备忘录模式 模板方法模式 解释器模式 写在前面: UML图解 继承和实现是比较容易理解的两种类关系。在架构设计...

    Java Pet Store

    同时,Java Pet Store 2.0 演示程序还演示了支持 Ajax 的 JavaServer Faces 组件库和 Java Persistence API、model-view-controller (MVC) 和其他设计模式,以及 mashup 的用法,其中 mashup 是组合了多个源的数据的...

Global site tag (gtag.js) - Google Analytics