目录

组合模式的定义与特点

组合模式的结构与实现

组合模式的应用实例

组合模式的应用场景

组合模式的扩展


树形结构在软件中随处可见,例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题,组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点)。下面将学习这种用于处理树形结构的组合模式。

组合模式的定义与特点

组合(Composite)模式的定义:有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。

组合模式的主要优点有:

(1) 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。

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

(3) 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。

(4) 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

其主要缺点是:

在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。

组合模式的结构与实现

组合模式的结构不是很复杂,下面对它的结构和实现进行分析。

1. 模式的结构

组合模式包含以下主要角色。

  1. 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。
  2. 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中 声明的公共接口。
  3. 树枝构件(Composite)角色:是组合中的分支节点对象,它有子节点。它实现了抽象构件角色中声明的接口,它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

组合模式分为透明式的组合模式和安全式的组合模式。

(1) 透明方式:在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。其结构图如图 1 所示。


图1 透明式的组合模式的结构图

(2) 安全方式:在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。其结构图如图 2 所示。


图2 安全式的组合模式的结构图

2. 模式的实现

假如要访问集合 c0={leaf1,{leaf2,leaf3}} 中的元素,其对应的树状图如图 3 所示。


图3 集合c0的树状图

下面给出透明式的组合模式的实现代码,与安全式的组合模式的实现代码类似,只要对其做简单修改就可以了。

package composite;
import java.util.ArrayList;
public class CompositePattern
{public static void main(String[] args){Component c0=new Composite(); Component c1=new Composite(); Component leaf1=new Leaf("1"); Component leaf2=new Leaf("2"); Component leaf3=new Leaf("3");          c0.add(leaf1); c0.add(c1);c1.add(leaf2); c1.add(leaf3);          c0.operation(); }
}
//抽象构件
interface Component
{public void add(Component c);public void remove(Component c);public Component getChild(int i);public void operation();
}
//树叶构件
class Leaf implements Component
{private String name;public Leaf(String name){this.name=name;}public void add(Component c){ }           public void remove(Component c){ }   public Component getChild(int i){return null;}   public void operation(){System.out.println("树叶"+name+":被访问!"); }
}
//树枝构件
class Composite implements Component
{private ArrayList<Component> children=new ArrayList<Component>();   public void add(Component c){children.add(c);}   public void remove(Component c){children.remove(c);}   public Component getChild(int i){return children.get(i);}   public void operation(){for(Object obj:children){((Component)obj).operation();}}
}

程序运行结果如下:

树叶1:被访问!
树叶2:被访问!
树叶3:被访问!

组合模式的应用实例

【例1】用组合模式实现当用户在商店购物后,显示其所选商品信息,并计算所选商品总价的功能。

说明:假如李先生到韶关“天街e角”生活用品店购物,用 1 个红色小袋子装了 2 包婺源特产(单价 7.9 元)、1 张婺源地图(单价 9.9 元);用 1 个白色小袋子装了 2 包韶关香藉(单价 68 元)和 3 包韶关红茶(单价 180 元);用 1 个中袋子装了前面的红色小袋子和 1 个景德镇瓷器(单价 380 元);用 1 个大袋子装了前面的中袋子、白色小袋子和 1 双李宁牌运动鞋(单价 198 元)。

最后“大袋子”中的内容有:{1 双李宁牌运动鞋(单价 198 元)、白色小袋子{2 包韶关香菇(单价 68 元)、3 包韶关红茶(单价 180 元)}、中袋子{1 个景德镇瓷器(单价 380 元)、红色小袋子{2 包婺源特产(单价 7.9 元)、1 张婺源地图(单价 9.9 元)}}},现在要求编程显示李先生放在大袋子中的所有商品信息并计算要支付的总价。

本实例可按安全组合模式设计,其结构图如图 4 所示。


图4 韶关“天街e角”店购物的结构图

程序代码如下:

package composite;
import java.util.ArrayList;
public class ShoppingTest
{public static void main(String[] args){float s=0;Bags BigBag,mediumBag,smallRedBag,smallWhiteBag;Goods sp;BigBag=new Bags("大袋子");mediumBag=new Bags("中袋子");smallRedBag=new Bags("红色小袋子");smallWhiteBag=new Bags("白色小袋子");               sp=new Goods("婺源特产",2,7.9f);smallRedBag.add(sp);sp=new Goods("婺源地图",1,9.9f);smallRedBag.add(sp);       sp=new Goods("韶关香菇",2,68);smallWhiteBag.add(sp);sp=new Goods("韶关红茶",3,180);smallWhiteBag.add(sp);       sp=new Goods("景德镇瓷器",1,380);mediumBag.add(sp);mediumBag.add(smallRedBag);       sp=new Goods("李宁牌运动鞋",1,198);BigBag.add(sp);BigBag.add(smallWhiteBag);BigBag.add(mediumBag);System.out.println("您选购的商品有:");BigBag.show();s=BigBag.calculation();       System.out.println("要支付的总价是:"+s+"元");}
}
//抽象构件:物品
interface Articles
{public float calculation(); //计算public void show();
}
//树叶构件:商品
class Goods implements Articles
{private String name;     //名字private int quantity;    //数量private float unitPrice; //单价public Goods(String name,int quantity,float unitPrice){this.name=name;this.quantity=quantity;this.unitPrice=unitPrice;}   public float calculation(){return quantity*unitPrice; }public void show(){System.out.println(name+"(数量:"+quantity+",单价:"+unitPrice+"元)");}
}
//树枝构件:袋子
class Bags implements Articles
{private String name;     //名字   private ArrayList<Articles> bags=new ArrayList<Articles>();   public Bags(String name){this.name=name;       }public void add(Articles c){bags.add(c);}   public void remove(Articles c){bags.remove(c);}   public Articles getChild(int i){return bags.get(i);}   public float calculation(){float s=0;for(Object obj:bags){s+=((Articles)obj).calculation();}return s;}public void show(){for(Object obj:bags){((Articles)obj).show();}}
}

程序运行结果如下:

您选购的商品有:
李宁牌运动鞋(数量:1,单价:198.0元)
韶关香菇(数量:2,单价:68.0元)
韶关红茶(数量:3,单价:180.0元)
景德镇瓷器(数量:1,单价:380.0元)
婺源特产(数量:2,单价:7.9元)
婺源地图(数量:1,单价:9.9元)
要支付的总价是:1279.7元

组合模式的应用场景

前面分析了组合模式的结构与特点,下面分析它适用的以下应用场景。

  1. 在需要表示一个对象整体与部分的层次结构的场合。
  2. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。

组合模式的扩展

如果对前面介绍的组合模式中的树叶节点和树枝节点进行抽象,也就是说树叶节点和树枝节点还有子节点,这时组合模式就扩展成复杂的组合模式了,如Java AWT/Swing 中的简单组件 JTextComponent 有子类 JTextField、JTextArea,容器组件 Container 也有子类 Window、Panel。复杂的组合模式的结构图如图 5 所示。

组合模式-Composite Pattern相关推荐

  1. 【设计模式】组合模式 Composite Pattern

    树形结构是软件行业很常见的一种结构,几乎随处可见,  比如: HTML 页面中的DOM,产品的分类,通常一些应用或网站的菜单,Windows Form 中的控件继承关系,Android中的View继承 ...

  2. python 设计模式之组合模式Composite Pattern

    #引入一 文件夹对我们来说很熟悉,文件夹里面可以包含文件夹,也可以包含文件. 那么文件夹是个容器,文件夹里面的文件夹也是个容器,文件夹里面的文件是对象. 这是一个树形结构 咱们生活工作中常用的一种结构 ...

  3. 组合模式(Composite Pattern)

    组合模式概述 定义:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构.组合模式让客户端可以统一对待单个对象和组合对象.又被成为"部分-整体"(Part-Whole)模式, ...

  4. 24组合模式(Composite Pattern)

    动机(Motivate):     组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元 ...

  5. C#设计模式——组合模式(Composite Pattern)

    一.概述 在软件开发中,我们往往会遇上类似树形结构的对象体系.即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在.比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点.在设计这 ...

  6. 设计模式:组合模式(Composite Pattern)

    组合模式: 又叫部分整体模式, 它创建了对象组的树形结构,将对象组合成树状结构以表示"整体-部分"的层次关系. JDK中的HashMap就使用了组合模式 public abstra ...

  7. 组合模式测试组合模式(Composite Pattern)

    改章节是一篇关于组合模式测试的帖子 像一个树形结构一样使用基本的对象和自己本身构建一个复杂的对象,称为组合模式. 这类模式很轻易学习以及应用到某个系统中.组合模式属于结构设计模式之一,比拟常用.经典的 ...

  8. 设计模式(17):结构型-组合模式(Composite)(2)

    设计模式(Design pattern) 是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式 ...

  9. 【设计模式自习室】结构型:组合模式 Composite

    前言 <设计模式自习室>系列,顾名思义,本系列文章带你温习常见的设计模式.主要内容有: 该模式的介绍,包括: 引子.意图(大白话解释) 类图.时序图(理论规范) 该模式的代码示例:熟悉该模 ...

最新文章

  1. 小孩学python有意义吗-世界冠军教练告诉你:少儿编程这些坑,能不踩就别踩!...
  2. 可能是最简单易懂的人工智能入门书
  3. C# GDI+ 画坐标(x,y)
  4. 利用spring AOP注解实现日志管理
  5. 双向链表删除节点时间复杂度_「十分钟学算法」删除链表的倒数第N个节点
  6. 【数据库】一篇文章搞懂数据库隔离级别那些事(LBCC,MVCC)
  7. 安卓逆向_15( 一 ) --- JNI 和 NDK
  8. LVS 工作模式以及工作原理
  9. android unable to instantiate activity componentinfo
  10. [数据结构]-循环队列
  11. 前端框架VUE的基础使用
  12. Numpy and Theano broadcasting
  13. 机器学习算法基础5-线回归与岭回归
  14. 126.单词接龙II
  15. (已更新)婚礼类小程序前端界面模板源码
  16. 基本知识 100136
  17. cdr X6 64位32位缩略图补丁包
  18. Python:暴力破解密码
  19. 【STC15系列】STC15软串口输出打印示例程序
  20. sklearn.LabelEncoder解决未见过值问题ValueError y contains previously unseen labels [69]

热门文章

  1. 读书笔记-----跟任何人都聊得来
  2. [转]JQuery Mobile 手机显示页面偏小_se7en3_新浪博客
  3. 智能汽车操作系统哪家强?黑莓QNX领跑,中兴/华为撑起中国方案
  4. 九宫锁屏图案有多少种c语言编程,手机九宫格图案解锁问题,编程高手戳进来!...
  5. 高一被清华姚班录取,高三委拒谷歌 offer,一个重度网瘾少年到理论计算机科学家的蜕变!......
  6. 输入一个整数,判断它能否被3、5、7整除,并输出以下信息之一:
  7. Shader学习2——兰伯特
  8. Javascript实现表单检验(如注册界面)
  9. 萌妹子Python入门指北(二)
  10. 网约车中场战事:曹操出行融资数十亿,谁在觊觎龙头位置?