组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

  • 透明方式,也就是说在Commponent中声明所有用来管理子对象的方法,其中包括Add、Remove等。这样实现Commponent接口的所有子类都具备了Add和Remove。这样做的好处就是叶节点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但问题也很明显,因为Leaf类本身不具备Add()、Remove()方法的功能,所以实现它是没有意义的。
  • 安全方式,也就是在Component接口中不去声明Add和Remove方法,那么子类的Leaf也就不需要去实现它,而是在Composite声明所有用来管理子类对象的方法,不过由于不够透明,所以树叶和树枝类将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。

透明式的组合模式类图:

安全式组合模式的类图:

组合模式中涉及到三个角色:

  • 抽象构件(Component)角色:这是一个抽象角色,上面实现中Graphics充当这个角色,它给参加组合的对象定义出了公共的接口及默认行为,可以用来管理所有的子对象(在透明式的组合模式是这样的)。在安全式的组合模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝结构对象给出。
  • 树叶构件(Leaf)角色:树叶对象时没有下级子对象的对象,上面实现中Line和Circle充当这个角色,定义出参加组合的原始对象的行为
  • 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象,上面实现中ComplexGraphics充当这个角色,树枝对象给出所有管理子对象的方法实现,如Add、Remove等。

组合模式的使用场景

在以下情况下应该考虑使用组合模式:

  1. 需要表示一个对象整体或部分的层次结构。
  2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

C#组合模式:

namespace 组合模式
{
class Program
{
static void Main(string[] args)
{
ConcreteCompany root = new ConcreteCompany("北京总公司");
root.Add(new HRDepartment("总公司人力资源部"));
root.Add(new FinanceDepartment("总公司财务部")); ConcreteCompany comp = new ConcreteCompany("上海华东分公司");
comp.Add(new HRDepartment("华东分公司人力资源部"));
comp.Add(new FinanceDepartment("华东分公司财务部"));
root.Add(comp); ConcreteCompany comp1 = new ConcreteCompany("南京办事处");
comp1.Add(new HRDepartment("南京办事处人力资源部"));
comp1.Add(new FinanceDepartment("南京办事处财务部"));
comp.Add(comp1); ConcreteCompany comp2 = new ConcreteCompany("杭州办事处");
comp2.Add(new HRDepartment("杭州办事处人力资源部"));
comp2.Add(new FinanceDepartment("杭州办事处财务部"));
comp.Add(comp2); Console.WriteLine("\n结构图:"); root.Display(1); Console.WriteLine("\n职责:"); root.LineOfDuty(); Console.Read();
}
} abstract class Company
{
protected string name; public Company(string name)
{
this.name = name;
} public abstract void Add(Company c);//增加
public abstract void Remove(Company c);//移除
public abstract void Display(int depth);//显示
public abstract void LineOfDuty();//履行职责 } class ConcreteCompany : Company
{
private List<Company> children = new List<Company>(); public ConcreteCompany(string name)
: base(name)
{ } public override void Add(Company c)
{
children.Add(c);
} public override void Remove(Company c)
{
children.Remove(c);
} public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name); foreach (Company component in children)
{
component.Display(depth + 2);
}
} //履行职责
public override void LineOfDuty()
{
foreach (Company component in children)
{
component.LineOfDuty();
}
} } //人力资源部
class HRDepartment : Company
{
public HRDepartment(string name)
: base(name)
{ } public override void Add(Company c)
{
} public override void Remove(Company c)
{
} public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
} public override void LineOfDuty()
{
Console.WriteLine("{0} 员工招聘培训管理", name);
}
} //财务部
class FinanceDepartment : Company
{
public FinanceDepartment(string name)
: base(name)
{ } public override void Add(Company c)
{
} public override void Remove(Company c)
{
} public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
} public override void LineOfDuty()
{
Console.WriteLine("{0} 公司财务收支管理", name);
} }
}

js组合模式:

<html>
<body>
<button id="button">按我</button>
</body>
<script>
var MacroCommand = function(){
return{
commandsList:[],
add:function(command){
this.commandsList.push(command);
},
execute:function(){
for(var i=0,command;command=this.commandsList[i++];){
command.execute();
}
}
}
}; var openAcCommand = {
execute:function(){
console.log('打开空调');
}
}; /*****************家里的电视和音响是连接在一起的,所以可以用一个宏命令来组合打开电视和打开音响的命令********************/ var openTvCommand = {
execute:function(){
console.log('打开电视');
}
}; var openSoundCommand = {
execute:function(){
console.log('打开音响');
}
}; var macroCommand1 = MacroCommand();
macroCommand1.add(openTvCommand);
macroCommand1.add(openSoundCommand); /***********关门、打开电脑和登录QQ的命令**************/ var closeDoorCommand = {
execute:function(){
console.log('关门');
}
}; var openPcCommand = {
execute:function(){
console.log('开电脑');
}
}; var openQQCommand = {
execute:function(){
console.log('登录QQ');
}
}; var macroCommand2 = MacroCommand();
macroCommand2.add(closeDoorCommand);
macroCommand2.add(openPcCommand);
macroCommand2.add(openQQCommand); /******************现在把所有的命令组合成一个“超级命令”*********************/ var macroCommand = MacroCommand();
macroCommand.add(openAcCommand);
macroCommand.add(macroCommand1);
macroCommand.add(macroCommand2); /**************最后给遥控器绑定“超级命令”**********************/ var setCommand = (function(command){
document.getElementById('button').onclick = function(){
command.execute();
}
})(macroCommand); </script>
</html>

javascript中实现组合模式的难点在于要保证组合对象和叶对象对象拥有同样的方法,这通常需要用鸭子类型的思想对它们进行接口检查。

组合对象可以拥有子节点,叶对象下面就没有子节点,所以我们也许会发生一些误操作,比如试图往叶对象中添加子节点,解决方案通常是给叶对象叶增加add方法,并且在调用这个方法时,抛出一个异常来及时提醒客户,代码如下:

var MacroCommand = function(){
return{
commandsList:[],
add:function(command){
this.commandsList.push(command);
},
execute:function(){
for(var i=0,command;command=this.commandsList[i++];){
command.execute();
}
}
}
}; var openTvCommand = {
execute:function(){
console.log('打开电视');
},
add:function(){
throw new Error('叶对象不能添加子节点');
}
}; var macroCommand = MacroCommand(); macroCommand.add(openTvCommand);
openTvCommand.add(macroCommand); //Uncaugth Error:叶对象不能添加子节点

js组合模式的更多相关文章

  1. javascript设计模式(张容铭) 第14章 超值午餐-组合模式 学习笔记

    JS 组合模式更常用于创建表单上,比如注册页面可能有不同的表单提交模块.对于这些需求我们只需要有基本的个体,然后通过一定的组合即可实现,比如下面这个页面样式(如图14-2所示),我们来用组合模式实现. ...

  2. js架构设计模式——你对MVC、MVP、MVVM 三种组合模式分别有什么样的理解?

    你对MVC.MVP.MVVM 三种组合模式分别有什么样的理解? MVC(Model-View-Controller)MVP(Model-View-Presenter)MVVM(Model-View-V ...

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

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

  4. js设计模式(六)---组合模式

    组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构.除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性.基本图例 1.组合模式 ...

  5. JS设计模式(7)组合模式

    什么是组合模式? 定义:1.将对象组合成树形结构以表示"部分-整体"的层次结构.2.组合模式使得用户对单个对象和组合对象的使用具有一致性.3.无须关心对象有多少层,调用时只需在根部 ...

  6. js设计模式-组合模式

    组合模式是一种专为创建web上的动态用户界面而量身定制的模式.使用这种模式,可以用一条命令在多个对象上激发复杂的或递归的行为.这可以简化粘合性代码,使其更容易维护,而那些复杂行为则被委托给各个对象. ...

  7. JS常用的设计模式(13)——组合模式

    组合模式又叫部分-整体模式,它将所有对象组合成树形结构.使得用户只需要操作最上层的接口,就可以对所有成员做相同的操作. 一个再好不过的例子就是jquery对象,大家都知道1个jquery对象其实是一组 ...

  8. js设计模式(4)---组合模式

    0.前言 今天是建党节,新疆那边又开始了闹腾.作为立志成为码农的我,现在已经从一个大愤青淡化为一个小愤青,对这些国家民生大事不在血气喷发,转而把经历发泄在技术问题上面,因而在扯一篇随笔吧,把无处发泄的 ...

  9. JS设计模式——9.组合模式

    组合模式概述 组合模式是一种专为创建Web上的动态用户界面量身定制的模式.使用这种模式可以用一条命令在多个对象上激发复杂的递归的行为. 它可以用来把一批子对象组织成树形结构,并且使整棵树都可被遍历.所 ...

随机推荐

  1. NetCore

    正确理解DTO.值对象和POCO https://www.cnblogs.com/redmoon/archive/2015/04/29/4467485.html ASP.NET Core 配置系统 h ...

  2. Linux下Solr的安装和配置

    一.安装 1.需要的安装包:apache-tomcat-7.0.47.tar.gz.solr-4.10.3.tgz.tgz(jdk自行安装) 2.解压tomcat并创建solr文件夹 [root@lo ...

  3. 参数Slave_IO_Running和Slave_SQL_Running的状态值解析

     Slave_SQL_Running: No mysql同步故障解决方法 2010-02-21 16:31:30 标签:mysql 双机 同步 数据库 休闲 原创作品,允许转载,转载时请务必以超链接形 ...

  4. 解决github访问慢和clone慢解决方案

    在http://tool.chinaz.com/dns/ 这个网站输入github.com 打开cmd ping各个服务器ip地址,看看哪个比较好 windows下C:\Windows\System3 ...

  5. 4.4 使用STM32控制MC20进行GPS帧数据解析

    需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...

  6. python数据之间的转换和关系

    首先数据类型在我看来分为两类: 容器类:能存储数据,例如:元祖.列表.集合.字符串. 原子类:单纯保存数值,例如:整数.浮点数.复数. 容器类与容器类之间,一般都可以进行两两之间的转化. 原子类与原子 ...

  7. 利用FFmpeg将RTSP转码成RTMP发布在RED5

    安装jdk,并设置环境  from:http://www.w3c.com.cn/%E5%88%A9%E7%94%A8ffmpeg%E5%B0%86-ipcamera-%E7%9A%84rtsp%E8% ...

  8. iOS 视图控制器转场动画/页面切换效果/跳转动画 学习

    一 学习 在 UINavigationController 中 push 和 pop 的转场效果  (基于iOS7 以上的转场方式) 经过学习了解到,重点分三块: (1)pushAnimation:  ...

  9. token的生成和应用

    token的生成和应用 接口特点汇总: 1.因为是非开放性的,所以所有的接口都是封闭的,只对公司内部的产品有效: 2.因为是非开放性的,所以OAuth那套协议是行不通的,因为没有中间用户的授权过程: ...

  10. UNIX 系统常用管理命令

    一. 引言 UNIX系统作为一种强大的多用户分时操作系统,在越来越多的场合受到了应用,同时,对UNIX的系统管理的要求也随之越来越多,但目前的书籍对UNIX系统管理命令介绍的并不是很多.本文主要是针对 ...