介绍

组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

在组合模式结构图中包含如下几个角色:

  • Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
  • Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。
  • Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

例子:餐厅菜单的应用

// "抽象构件"
var MenuComponent = function(){
};
MenuComponent.prototype.getName = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.getDescription = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.getPrice = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.isVegetarian = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.print = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.add = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.remove = function(){
throw new Error("This method must be overwritten!");
};
MenuComponent.prototype.getChild = function(){
throw new Error("This method must be overwritten!");
};
// "叶子构件"
var MenuItem = function(sName, sDescription, bVegetarian, nPrice){
MenuComponent.apply(this);
this.sName = sName;
this.sDescription = sDescription;
this.bVegetarian = bVegetarian;
this.nPrice = nPrice;
};
MenuItem.prototype = new MenuComponent();
MenuItem.prototype.getName = function(){
return this.sName;
};
MenuItem.prototype.getDescription = function(){
return this.sDescription;
};
MenuItem.prototype.getPrice = function(){
return this.nPrice;
};
MenuItem.prototype.isVegetarian = function(){
return this.bVegetarian;
};
MenuItem.prototype.print = function(){
console.log(this.getName() + ": " + this.getDescription() + ", " + this.getPrice() + "euros");
};
// "容器构件"
var Menu = function(sName, sDescription){
MenuComponent.apply(this);
this.aMenuComponents = [];
this.sName = sName;
this.sDescription = sDescription;
this.createIterator = function(){
throw new Error("This method must be overwritten!");
};
};
Menu.prototype = new MenuComponent();
Menu.prototype.add = function(oMenuComponent){
this.aMenuComponents.push(oMenuComponent);
};
Menu.prototype.remove = function(oMenuComponent){
var aMenuItems = [];
var nMenuItem = 0;
var nLenMenuItems = this.aMenuComponents.length;
var oItem = null; for(; nMenuItem < nLenMenuItems;){
oItem = this.aMenuComponents[nMenuItem];
if(oItem !== oMenuComponent){
aMenuItems.push(oItem);
}
nMenuItem = nMenuItem + 1;
}
this.aMenuComponents = aMenuItems;
};
Menu.prototype.getChild = function(nIndex){
return this.aMenuComponents[nIndex];
};
Menu.prototype.getName = function(){
return this.sName;
};
Menu.prototype.getDescription = function(){
return this.sDescription;
};
Menu.prototype.print = function(){
console.log(this.getName() + ": " + this.getDescription());
console.log("--------------------------------------------"); var nMenuComponent = 0;
var nLenMenuComponents = this.aMenuComponents.length;
var oMenuComponent = null; for(; nMenuComponent < nLenMenuComponents;){
oMenuComponent = this.aMenuComponents[nMenuComponent];
oMenuComponent.print();
nMenuComponent = nMenuComponent + 1;
}
};
// "指定具体容器"
var DinnerMenu = function(){
Menu.apply(this);
};
DinnerMenu.prototype = new Menu(); var CafeMenu = function(){
Menu.apply(this);
};
CafeMenu.prototype = new Menu(); var PancakeHouseMenu = function(){
Menu.apply(this);
};
PancakeHouseMenu.prototype = new Menu();
// "顶级容器"
var Mattress = function(aMenus){
this.aMenus = aMenus;
};
Mattress.prototype.printMenu = function(){
this.aMenus.print();
};
// 调用
var oPanCakeHouseMenu = new Menu("Pancake House Menu", "Breakfast");
var oDinnerMenu = new Menu("Dinner Menu", "Lunch");
var oCoffeeMenu = new Menu("Cafe Menu", "Dinner");
var oAllMenus = new Menu("ALL MENUS", "All menus combined");
oAllMenus.add(oPanCakeHouseMenu);
oAllMenus.add(oDinnerMenu);
oDinnerMenu.add(new MenuItem("Pasta", "Spaghetti with Marinara Sauce, and a slice of sourdough bread", true, 3.89));
oDinnerMenu.add(oCoffeeMenu);
oCoffeeMenu.add(new MenuItem("Express", "Coffee from machine", false, 0.99));
var oMattress = new Mattress(oAllMenus);
console.log("---------------------------------------------");
oMattress.printMenu();
console.log("---------------------------------------------");

相关阅读

Design-Patterns-in-Javascript-Composite

树形结构的处理——组合模式

javaScript 设计模式系列之四:组合模式的更多相关文章

  1. [js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

    所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理, ...

  2. 设计模式系列之组合模式(Composite Pattern)——树形结构的处理

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  3. C#设计模式系列:组合模式(Composite)

    1.组合模式简介 1.1>.定义 组合模式主要用来处理一类具有“容器特征”的对象——即它们在充当对象的同时,又可以作为容器包含其他多个对象. 1.2>.使用频率 中高 2.组合模式结构图 ...

  4. javascript设计模式系列

    javascript设计模式系列   创建型: 1.抽象工厂模式(Abstract Factory) 2.构建者模式(Builder) 3.工厂方法模式(Factory Method) 4.原型模式( ...

  5. [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  6. javascript创建对象的方法--组合模式

    javascript创建对象的方法--组合模式 一.总结 0.作用:解决原型模式对象独有属性创建麻烦的问题 1.组合模式使用普遍:jquery就是用的组合模式,组合模式使用非常普遍 2.组合模式优点: ...

  7. javascript设计模式--策略模式

    javascript策略模式总结 1.什么是策略模式? 策略模式的定义是:定义一系列的算法,把他们独立封装起来,并且可以相互替换. 例如我们需要写一段代码来计算员工的奖金.当绩效为a时,奖金为工资的5 ...

  8. java23种设计模式——八、组合模式

    目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式--四.原型模式 java23种设计模式-- ...

  9. JavaScript 设计模式: 发布者-订阅者模式

    JavaScript 设计模式: 发布者-订阅者模式 发布者-订阅者模式 https://github.com/Kelichao/javascript.basics/issues/22 https:/ ...

随机推荐

  1. 《Java程序设计》第1周学习总结

    1.本周本章学习总结 感觉装环境和基础语言也没什么好总结的,就谈谈我对java的认识. 接触的语言也不多,c语言,python.去年科研立项立了个安卓开发的项.也有去学了一阶段java.由于种种原因没 ...

  2. Swing-JFileChooser的使用

    JFileChooser文件选择器是Swing中经常用到的一个控件.它的使用主要包含以下几个参数: 1.当前路径.也就是它第一次打开时所在的路径,许多软件喜欢设置为桌面. 2.文件过滤器.通过设置文件 ...

  3. 201521123092《java程序设计》第五周学习总结

    1.本周学习总结 #1.1 尝试使用思维导图总结有关多态与接口的知识点. 2.书面作业 #1.代码阅读:Child压缩包内源代码##1.1 com.parent包中Child.java文件能否编译通过 ...

  4. 201521123027 《JAVA程序设计》第二周学习总结

    1.本周学习总结 1.学习使用码云管理程序代码: 2.认识类型(整数.字节.浮点数.字符与布尔)与变量的使用: 3.学习运算符的基本使用以及类型转换的基本规则: 4.学习String类的一些使用方法: ...

  5. 201521123056 《Java程序设计》第1周学习总结

    1. 本周学习总结 java语言结构简单,但功能齐全,同时能够在不同系统平台上编译,但编译的前提是系统要有安装JVM(即java虚拟机),JVM是java实现跨平台的最核心部分.本周还学习了JDK.J ...

  6. 201521123031 《Java程序设计》第一周学习总结

    1. 本周学习总结 a.使用notepad++和eclipse编写程序b.对jav的运行环境jdk.jre有了初步的认识c.学习如何使用码云代码库 2. 书面作业 Q1.为什么java程序可以跨平台运 ...

  7. 201521123081《java程序设计》 第12周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...

  8. 201521123053《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 TCP和UDP两者之间的区别: UDP:1)将数据及源和目的封装成数据包中,不需要建立连接 ...

  9. 201521123118《java程序与设计》第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 1. finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中fi ...

  10. SpringMVC第五篇【方法返回值、数据回显、idea下配置虚拟目录、文件上传】

    Controller方法返回值 Controller方法的返回值其实就几种类型,我们来总结一下-. void String ModelAndView redirect重定向 forward转发 数据回 ...