在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,如果用组合模式来实现会很方便。

组合模式的定义与特点

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

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;

其主要缺点是:

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
  2. 不容易限制容器中的构件;
  3. 不容易用继承的方法来增加构件的新功能;

组合模式的结构与实现

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

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的树状图

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

  1. package composite;
  2. import java.util.ArrayList;
  3. public class CompositePattern
  4. {
  5. public static void main(String[] args)
  6. {
  7. Component c0=new Composite();
  8. Component c1=new Composite();
  9. Component leaf1=new Leaf("1");
  10. Component leaf2=new Leaf("2");
  11. Component leaf3=new Leaf("3");
  12. c0.add(leaf1);
  13. c0.add(c1);
  14. c1.add(leaf2);
  15. c1.add(leaf3);
  16. c0.operation();
  17. }
  18. }
  19. //抽象构件
  20. interface Component
  21. {
  22. public void add(Component c);
  23. public void remove(Component c);
  24. public Component getChild(int i);
  25. public void operation();
  26. }
  27. //树叶构件
  28. class Leaf implements Component
  29. {
  30. private String name;
  31. public Leaf(String name)
  32. {
  33. this.name=name;
  34. }
  35. public void add(Component c){ }
  36. public void remove(Component c){ }
  37. public Component getChild(int i)
  38. {
  39. return null;
  40. }
  41. public void operation()
  42. {
  43. System.out.println("树叶"+name+":被访问!");
  44. }
  45. }
  46. //树枝构件
  47. class Composite implements Component
  48. {
  49. private ArrayList<Component> children=new ArrayList<Component>();
  50. public void add(Component c)
  51. {
  52. children.add(c);
  53. }
  54. public void remove(Component c)
  55. {
  56. children.remove(c);
  57. }
  58. public Component getChild(int i)
  59. {
  60. return children.get(i);
  61. }
  62. public void operation()
  63. {
  64. for(Object obj:children)
  65. {
  66. ((Component)obj).operation();
  67. }
  68. }
  69. }

程序运行结果如下:

树叶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角”店购物的结构图

程序代码如下:

  1. package composite;
  2. import java.util.ArrayList;
  3. public class ShoppingTest
  4. {
  5. public static void main(String[] args)
  6. {
  7. float s=0;
  8. Bags BigBag,mediumBag,smallRedBag,smallWhiteBag;
  9. Goods sp;
  10. BigBag=new Bags("大袋子");
  11. mediumBag=new Bags("中袋子");
  12. smallRedBag=new Bags("红色小袋子");
  13. smallWhiteBag=new Bags("白色小袋子");
  14. sp=new Goods("婺源特产",2,7.9f);
  15. smallRedBag.add(sp);
  16. sp=new Goods("婺源地图",1,9.9f);
  17. smallRedBag.add(sp);
  18. sp=new Goods("韶关香菇",2,68);
  19. smallWhiteBag.add(sp);
  20. sp=new Goods("韶关红茶",3,180);
  21. smallWhiteBag.add(sp);
  22. sp=new Goods("景德镇瓷器",1,380);
  23. mediumBag.add(sp);
  24. mediumBag.add(smallRedBag);
  25. sp=new Goods("李宁牌运动鞋",1,198);
  26. BigBag.add(sp);
  27. BigBag.add(smallWhiteBag);
  28. BigBag.add(mediumBag);
  29. System.out.println("您选购的商品有:");
  30. BigBag.show();
  31. s=BigBag.calculation();
  32. System.out.println("要支付的总价是:"+s+"元");
  33. }
  34. }
  35. //抽象构件:物品
  36. interface Articles
  37. {
  38. public float calculation(); //计算
  39. public void show();
  40. }
  41. //树叶构件:商品
  42. class Goods implements Articles
  43. {
  44. private String name; //名字
  45. private int quantity; //数量
  46. private float unitPrice; //单价
  47. public Goods(String name,int quantity,float unitPrice)
  48. {
  49. this.name=name;
  50. this.quantity=quantity;
  51. this.unitPrice=unitPrice;
  52. }
  53. public float calculation()
  54. {
  55. return quantity*unitPrice;
  56. }
  57. public void show()
  58. {
  59. System.out.println(name+"(数量:"+quantity+",单价:"+unitPrice+"元)");
  60. }
  61. }
  62. //树枝构件:袋子
  63. class Bags implements Articles
  64. {
  65. private String name; //名字
  66. private ArrayList<Articles> bags=new ArrayList<Articles>();
  67. public Bags(String name)
  68. {
  69. this.name=name;
  70. }
  71. public void add(Articles c)
  72. {
  73. bags.add(c);
  74. }
  75. public void remove(Articles c)
  76. {
  77. bags.remove(c);
  78. }
  79. public Articles getChild(int i)
  80. {
  81. return bags.get(i);
  82. }
  83. public float calculation()
  84. {
  85. float s=0;
  86. for(Object obj:bags)
  87. {
  88. s+=((Articles)obj).calculation();
  89. }
  90. return s;
  91. }
  92. public void show()
  93. {
  94. for(Object obj:bags)
  95. {
  96. ((Articles)obj).show();
  97. }
  98. }
  99. }

程序运行结果如下:

您选购的商品有:
李宁牌运动鞋(数量: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 所示。

图5 复杂的组合模式的结构图

组合模式_Java设计模式-组合模式相关推荐

  1. java 行为模式_java设计模式--行为模式

    前言 行为模式是描述多个类与对象之间通过协作共同完成单个对象无法单独完成的任务. 行为模式分为: 类行为模式通过集成在类之间分派行为 对象行为模式通过组合或聚合在对象之间分配行为 行为模式: 模板方法 ...

  2. java模板方法模式_JAVA 设计模式 模板方法模式

    定义 模板方法模式 (Template Method) 定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成. 模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 模 ...

  3. java原始模型模式_java设计模式--原始模型模式

    简介 原始模型模式属于对象的创建模式.通过一个原型对象来指明要创建对象的类型,然后用复制原型对象的方法来创建出更多同类型的对象. Java所有的类都是从java.lang.Object类继承来的,Ob ...

  4. java 备忘录模式_java设计模式--备忘录模式

    备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象外保存这个状态,这样以后可将此对象恢复成原来的状态. 就拿单机游戏举例,玩游戏打boss前我们通常都会存档,避免打boss时失误死 ...

  5. java设计模式 组合_JAVA 设计模式 组合模式

    用途组合模式 (Component) 将对象组合成树形结构以表示"部分-整体"的层次结构. 组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模式. 结构 ...

  6. java 类的合成_Java设计模式-合成模式

    合成模式有时也叫组合模式,对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性.掌握组合模式的重点是要理解清楚 "部分/ ...

  7. java设计模式建造_java设计模式-建造者模式

    建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创造不同的表示. 建造者模式将一个产品的内部表象和产品的生成过程分割开来,建造对象的时候只需要指定需要建造的类型,而不必了解具体的 ...

  8. java的visitor模式_java设计模式(二十一)访问者模式(Visitor)

    介绍 访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问者模式是一种对象行为型模式. 简单来 ...

  9. Java创新型模式_java设计模式--创建型模式(一)

    2016-04-24 10:10:34 创建型模式:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 注意:工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂 ...

最新文章

  1. 第08讲:解析无所不能的正则表达式
  2. Shiro安全框架入门篇
  3. .net的retrofit--WebApiClient底层篇
  4. python 渗透框架_Python渗透测试框架:PytheM
  5. 5006.c++类中使用static变量bug
  6. 数据库操作update,和insert为什么会有int的返回值
  7. 空间点到空间直线的垂点计算
  8. 【光纤传输特性】图文并茂,你该了解这些
  9. 智能家居控制系统制作技术_智能家居控制系统是什么_智能家居控制系统的由来-装修攻略...
  10. ansible 001 __ 小斌文档 | ansible介绍和安装
  11. 精准医学: 应用脑脊液游离DNA全基因组甲基化测序筛选小儿髓母细 胞瘤早期诊断与预后监测的可靠生物标志物|液体活检专题
  12. 解决No EPCS layout data --- looking for section [EPCS-xxxxx]
  13. 三十、非谓语动词_作状语
  14. 手机端的多图片剪辑上传支持手势支持预览
  15. 怎么将PDF转换成Excel表格呢?
  16. 3ds Max 实验十二 材质的种类
  17. 2004十大网络流行语”已评出 做人要厚道排第一
  18. vsm什么意思_VSM通用图标和基本概念解释.ppt
  19. matlab 计算半波宽,半导体激光器半高宽(FWHM)计算(包含matlab仿真程序).docx
  20. [C#] 折腾海康威视的人体测温 模组

热门文章

  1. 【设计模式】学习笔记8:命令模式
  2. 剔除数组中的相同元素
  3. 使用ubuntu系统中遇到的问题及解决方案
  4. 深度优先搜索——First Step(洛谷 P3654)
  5. Java-Hashmap
  6. oracle11g异机备份,tsm oracle11g rac环境异机恢复报错(或者搭建dg)
  7. python中json如何存放字节数组中_测试面试题集锦(四)| Linux 与 Python 编程篇(附答案)...
  8. 数据3分钟丨Snowflake获“2021 DBMS”;OceanBase社区版3.1.2正式发布
  9. “我的国产数据库之路”征文活动——专访优秀作者彭冲
  10. 2020年12月国产数据库排行:榜首TiDB 2.7亿融资再破纪录;openGauss晋级十强!