设计模式之组合模式(Composite)

1.引言

在学习JUnit的时候,看到一段话“JUnit框架是一个典型的Composite模式:TestSuite可以容纳任何派生自Test的对象;当调用TestSuite对象的run()方法是,会遍历自己容纳的对象,逐个调用它们的run()方法”。就来学习什么是组合模式。

2.应用实例

在实现跟商品有关的应用系统的时候,一个很常见的功能就是商品类别树的管理,比如有以下的商品类别树:

——————————————————————————————————

-服装
-男装
-衬衣
-夹克
-女装
-裙子
-套装

——————————————————————————————————

通过上面的商品类别树我们可以发现商品类别树有两种类型的节点,分别是叶子节点(衬衣,夹克)和组合节点(服装,男装,女装)。组合节点中可以包含其他的组合节点或者叶子节点,而叶子节点不能。

给出一个简单的管理商品类别树的实例代码。

2.1不使用组合模式的解决方案

组合节点Composite

设计模式之组合模式(Composite)View Code

叶子节点

设计模式之组合模式(Composite)View Code

客户端Client

设计模式之组合模式(Composite)View Code

运行结果就是应用实例中显示的商品树形结构。

上述解决方案存在的问题:

虽然实现了要求的功能,但是有一个明显的问题:那就是必须区分组合对象和叶子对象,并进行区别对待,比如在Composite(addComposite方法和addLeaf方法)和Client(定义Composite对象和定义Leaf对象)里面,都需要去区别对待这两种对象。区别对待组合对象与叶子对象不但让程序更加复杂,还对功能的扩展带了了不便。用户不希望区别对待这两类对象。

2.2使用组合模式的解决方案

组合模式通过引入一个抽象的组件对象,作为组合对象和叶子对象的父对象,这样就把组合对象和叶子对象统一起来了,用户使用的时候,始终是在操作组件对象,而不再去区分是在操作组合对象还是叶子对象。

组合模式的关键就在于这个抽象类,这个抽象类既可以代表叶子对象,也可以代表组合对象,这样用户在操作的时候,对叶子对象和组合对象的使用就具有了一致性。

组件对象Component

设计模式之组合模式(Composite)View Code

组合对象Composite

设计模式之组合模式(Composite)View Code

叶子对象Leaf

设计模式之组合模式(Composite)View Code

客户端

设计模式之组合模式(Composite)View Code

程序架构如下图所示。这样的架构实现了用户的透明访问。

设计模式之组合模式(Composite)

3.透明性与安全性的权衡考虑

如上图所示,在Component组件中定义了操作组合节点的方法addChild,removeChild等,这些方法被Leaf继承,因此Leaf也能够调用,但是叶子节点是不能进行增加子节点和删除子节点的。这样就存在安全性的问题。

基于安全性考虑的组合模式的解决方案

组件节点Component

设计模式之组合模式(Composite)View Code

组合节点Composite和叶子节点Leaf没有改变

客户端发生改变,需要区分组合节点和叶子节点,这个跟第一个代码实例中类似。

设计模式之组合模式(Composite)View Code

上述实例的结构如下图所示:

设计模式之组合模式(Composite)

透明性组合模式与安全性组合模式的选择:

对于组合模式,在安全性和透明性上,会更加看重透明性,毕竟组合模式的功能就是让客户端对叶子对象和组合对象的使用具有一致性。

4.父组件引用

在上面的示例中,都是在父组件对象中,保存有子组件的引用,也就是说都是从父到子的引用,本节讨论一下子组件对象到父组件对象的引用,在实际开发过程中也非常有用,比如可以实现如下功能:

  1. 删除某个商品的类别, 如果是子对象,那么直接删除,如果是组合对象,那么将组合对象下的所有子对象的层级提高一层。
  2. 调整商品类别。

要实现上述功能, 一个较为简单的方案就是在保持从父组件到子组件引用的基础上,再增加保持从子组件到父组件的引用,这样在删除一个组件对象或者是调整一个组件对象的时候,可以通过调整父组件的引用来实现,可以大大简化实现。

实例说明如下:

组件对象Component

设计模式之组合模式(Composite)View Code

组合对象Composite

设计模式之组合模式(Composite)View Code

叶子节点没有变化,客户端有所改变

设计模式之组合模式(Composite)View Code

程序运行结果:

——————————————————————————

-服装
-男装
-衬衣
-夹克
-女装
-裙子
-套装
---------------------------------
-服装
-女装
-裙子
-套装
-衬衣
-夹克

——————————————————————

程序架构结构图如下图所示:

设计模式之组合模式(Composite)

5组合模式的优缺点及适用环境

优点:

  1. 定义了包含基本对象和组合对象的层次结构
  2. 统一了组合对象和叶子对象
  3. 简化了客户端调用
  4. 更容易扩展

缺点:

  1. 很难闲置组合中的组件类型

适用环境

  1. 如果你想表示对象的部分-整体层次结构,可以选用组合模式,把整体和部分的操作统一起来,是的层次结构实现更简单,从外部来使用这个层次结构也更加容易。
  2. 如果你希望统一得使用组合结构中的所有对象,可以选用组合模式,这正是组合模式提供的主要功能。



本文转自xwdreamer博客园博客,原文链接:http://www.cnblogs.com/xwdreamer/archive/2012/03/29/2424034.html,如需转载请自行联系原作者