组合模式(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. JAVA的Hashtable在遍历时的迭代器线程问题

    这篇博客主要讲什么 Hashtable及其内部类的部分源码分析 Hashtable在遍历时的java.util.ConcurrentModificationException异常的来由和解决 单机在内 ...

  2. 深入C#学习系列一:序列化(Serialize)、反序列化(Deserialize)(转)

    序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制.其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方.    .NET框架提供了两种串行化的方式: ...

  3. 面向对象、接口编程的重要性 python 为什么引入接口interface

    面向对象编程的实践 有个产品,其有10个子产品,现在要统计每日消费数据其中8个子产品的消费入账金额算法相同,2个不同; 拓展性差的糟糕的代码 def ConsumptionSum(product): ...

  4. CSS标签内多余内容隐藏

    CSS: <style> .mazey{width:100px;} .nowrap{overflow:hidden;text-overflow:ellipsis;white-space:n ...

  5. jfinal实现上传功能

    首先,jsp页面:由于设置enctype="multipart/form-data",所以form里面的input的值以2进制的方式传过去. <form id="f ...

  6. 【转】hibernate中的映射文件xxx.hbm.xml详解总结

    一.Hibernate映射文件的作用: Hibernate映射文件是Hibernate与数据库进行持久化的桥梁 二,Hibernate映射文件主要内容:     (1).映射内容的定义: Hibern ...

  7. Java 注解入门

    1.什么是注解 注解的语法: @注解名称; 注解的作用: 用来替代 xml 配置文件; 在 Servlet 3.0 中就可以使用注解来代替配置文件; 注解是由框架来读取使用的; 所有的注解都是 Ann ...

  8. python函数回顾:hex()

    描述 hex() 函数用于将10进制整数转换成16进制,以字符串形式表示. 语法 hex 语法: hex(x) 参数说明: x -- 10进制整数 返回值 返回16进制数,以字符串形式表示. 实例 & ...

  9. 启动hadoop集群

    1.配置core-site.xml(每个节点上都要配置) 路径: /usr/local/hadoop-2.7.3/etc/hadoop/core-site.xml 配置项1: name: fs.def ...

  10. mysql执行计划图