介绍

组合模式(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. 团队作业8——第二次项目冲刺(Beta阶段)--5.19 first day

    团队作业8--第二次项目冲刺(Beta阶段)--5.19 Day one: 会议照片 项目进展 由于今天是Beta版本项目冲刺的第一天,所以没有昨天已完成任务.以下是今日具体的任务安排. 队员 今日计 ...

  2. 201521123019 《Java程序设计》第8周学习总结

    1. 本章学习总结 2. 书面作业 一.List中指定元素的删除(题目4-1) for (int i = list.size()-1; i >=0; i--) {//从最后一个元素开始删除 if ...

  3. [转载]Eclipse自定义快捷键导出和导入方法

    背景: 以前做C/C++开发,习惯了Visual Studio这个强大的IDE,转到安卓开发后,用到蛋疼的Eclipse,实在不习惯,而且以前总觉得VS不流畅,现在才知道VS很好,才知道什么是真正的& ...

  4. 201521123113《Java程序设计》第13周学习总结

    1. 本周学习总结 2. 书面作业 Q1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 返回的结果 ...

  5. 201521123020《java程序设计》第十周学习总结

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

  6. 来自projecteuler.net网站的练习题2

    0.题目如下: Each new term in the Fibonacci sequence is generated by adding the previous two terms. By st ...

  7. 中文转unicode,中文转bytes,unicode转bytes java实现

    utf-8 utf-8格式的中文由三位字节组成. UTF-8的编码规则很简单,只有二条: 1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码.因此对于英语字母,UTF-8编 ...

  8. 【DDD】领域驱动设计实践 —— UI层实现

    前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...

  9. ArrayList 和 LinkedList 的实现与区别

    (转载请标明出处) 1.ArrayLis t的实现 2.LinkedLis t的实现 3.ArrayList 和 LinkedList 的区别 ArrayList 的实现: 1.MyArrayList ...

  10. js 倒计时(服务器时间同步)

    首先说一下,为什么要服务器时间同步, 因为服务器时间和本地电脑时间存在一定的时间差.有些对时效性要求非常高的应用,例如时时彩开奖,是不能容忍这种时间差存在的. 方案1:每次倒计时去服务端请求时间 // ...