javascript设计模式之组合模式

介绍

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

组合模式的好处:

  • 1 你可以用同样的方法处理对象的集合与其中的特定子对象。
  • 2 它可以用来把一批子对象组织成树形结构,并且使整棵树都可以被遍历。

正文

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

常见的场景有asp.net里的控件机制(即control里可以包含子control,可以递归操作、添加、删除子control),类似的还有DOM的机制,一个DOM节点可以包含子节点,不管是父节点还是子节点都有添加、删除、遍历子节点的通用功能。所以说组合模式的关键是要有一个抽象类,它既可以表示子元素,又可以表示父元素。

场景

    组合模式场景:   -->公司
-->财务部门
-->张一
-->张二
-->张三 -->销售部门
-->张四
-->张五
-->张六
实际任务是具体落实到人上去实施的,也就是说
只有人才具有具体的方法实现

<!DOCTYPE html>
<html>
<head>
<script src="./commonUtil.js" type="text/javascript" charset="utf-8" ></script> <title>组合模式</title>
</head>
<body>
<script>
/*
组合模式场景: -->公司
-->财务部门
-->张一
-->张二
-->张三 -->销售部门
-->张四
-->张五
-->张六
实际任务是具体落实到人上去实施的,也就是说
只有人才具有具体的方法实现
*/ //定义一个公司
var Orgnazation = function(name){
this.name = name ;
this.departments= []; };
Orgnazation.prototype = {
constructor: Orgnazation,
addDepts : function(childOrgnazation){
this.departments.push(childOrgnazation);
//链式调用
return this;
},
getDepts: function(){
return this.departments;
} }; //定义一个部门
var Department = function(name){
this.name = name ;
this.persons = [];
};
Department.prototype = {
constructor:Department,
addPersons : function (childPerson){
this.persons.push(childPerson);
return this;
},
getPersons: function(){
return this.persons;
}
}; //定义一个人
var Person = function(name){
this.name = name ;
};
Person.prototype ={
constructor:Person,
hardworking:function(name){
document.write(this.name + "....好好上班!");
},
sleeping: function(name){
document.write(this.name + "....好好休息!"); }
}; /*需求:1、实例化上述情景,2、叫张三好好工作*/
var org = new Orgnazation("华为");
var dept1 = new Department("财务部门");
var dept2 = new Department("销售部门");
var p1 = new Person("张1");
var p2 = new Person("张2");
var p3 = new Person("张3");
var p4 = new Person("张4");
var p5 = new Person("张5");
var p6 = new Person("张6"); dept1.addPersons(p1).addPersons(p2).addPersons(p3);
dept2.addPersons(p4).addPersons(p5).addPersons(p6);
org.addDepts(dept1).addDepts(dept2); for(var i =0 , depts = org.getDepts(); i <depts.length ; i ++ ){
for (var j = 0, persons = depts[i].getPersons(); j < persons.length; j++){
if (persons[j].name =="张3") {
persons[j].hardworking();
};
} }
/*
上述方法完全是面向对象的方法,实现的上述需求,如果要给变功能(比如说,财务部全体放假,整个公司好好休息!增加一个新部门,在好好工作。。。。。),怎要动怎么for循环,这样不是我们想要的,如果我们引入组合模式,是不是能解决效果呢? 直接 org.hardworking("华为")
*/ </script> </body>
</html>

组合模式的使用场景:

    1 存在一批组织成某种层次体系的对象
2 希望对这批对象或其中的一部分对象实施一个操作。
组合模式的特点:
1 组合模式中只有两种类型对象:组合对象、叶子对象
2 这两种类型都实现同一批接口
3 一般我们会在组合对象中调用其方法并隐式调用"下级对象"的方法(这里我们一般采用递归的形式去做)
*/ /*
组合模式场景: -->公司
-->北京分公司
-->财务部门
-->张一
-->张二
-->张三 -->销售部门
-->张四
-->张五
-->张六
-->南京分公司
-->开发部门
-->张7
-->张8
-->张9 -->法务部门
-->张10
-->张11
-->张12 实际任务是具体落实到人上去实施的,也就是说
只有人才具有具体的方法实现

<!DOCTYPE html>
<html>
<head>
<script src="./commonUtil.js" type="text/javascript" charset="utf-8" ></script> <title>组合模式2</title>
</head>
<body>
<script> /*
组合模式的使用场景:
1 存在一批组织成某种层次体系的对象
2 希望对这批对象或其中的一部分对象实施一个操作。
组合模式的特点:
1 组合模式中只有两种类型对象:组合对象、叶子对象
2 这两种类型都实现同一批接口
3 一般我们会在组合对象中调用其方法并隐式调用"下级对象"的方法(这里我们一般采用递归的形式去做)
*/ /*
组合模式场景: -->公司
-->北京分公司
-->财务部门
-->张一
-->张二
-->张三 -->销售部门
-->张四
-->张五
-->张六
-->南京分公司
-->开发部门
-->张7
-->张8
-->张9 -->法务部门
-->张10
-->张11
-->张12 实际任务是具体落实到人上去实施的,也就是说
只有人才具有具体的方法实现
*/ //定义接口
var CompositeInterface = new XGP.Interface("CompositeInterface", ["addChild","getChild"]);
var LeafInterface = new XGP.Interface("LeafInterface", ["hardworking","sleeping"]); // 首先建立组合对象
var Composite = function(name){
this.name = name ;
this.type = "Composite"; //说明对象的类型为(组合对象)
this.children = []; //承装孩子的数组
}; //建立叶子对象
var Leaf = function(name){
this.name = name ;
this.type = "Leaf";
}; //实现同一批接口
Composite.prototype = {
constructor: Composite,
addChild:function(child){
this.children.push(child);
return this;
}, //难点!!!!
getChild:function(name){
//接收叶子对象
var elments =[]; var pushLeaf = function(item){
if(item.type ==="Composite"){
item.children.each(arguments.callee);//看是否是Composite还是Leaf;
}else{
elments.push(item);//直接添加到叶子对象集合
}
}); if (name && this.name !== name) {//根据name ,让name下的Compsite的所有Leaf去执行操作
this.children.each(function(item){
//如果是2级节点名称---北京分公司,南京分公司
if (item.name === name && item.type =="Composite") {
item.children.each(pushLeaf); };
//如果是3级,4级。。。。N级
if (item.name !== name && item.type =="Composite") {
item.children.each(arguments.callee);
}; //如果传递的就是叶子节点
if (item.name == name && item.type =="Leaf") {
elments.push(item);
};
}); }else{//不传名字,则整个公司的所有类型的leaf 类型执行操作
//Array.prototype.each()方法----添加到commomUtil.js
this.children.each(pushLeaf); //直接抽取到pushLeaf函数中
};
},
hardworking: function(name){
//对于Composite类型的对象,要先获得其下面所有的Leaf对象
var leafObjects = this.getChild(name);
for (var i = 0; i < leafObjects.length; i++) {
leafObjects[i].hardworking();
};
},
sleeping: function(){
//对于Composite类型的对象,要先获得其下面所有的Leaf对象
var leafObjects = this.getChild(name);
for (var i = 0; i < leafObjects.length; i++) {
leafObjects[i].sleeping();
};
} }; Leaf.prototype = {
constructor: Leaf,
addChild:function(child){
throw new Error("this method is disable...");
},
getChild:function(name){
if(this.name = name ){
return this;
};
return null;
},
hardworking: function(){
document.write(this.name + "....好好上班!"); },
sleeping: function(){
document.write(this.name + "....好好休息!");
} }; //测试数据
var org = new CompositeInterface("华为");
var suborg1 = new CompositeInterface("北京分公司");
var suborg2 = new CompositeInterface("南京分公司");
var dept1 = new CompositeInterface("财务部门");
var dept2 = new CompositeInterface("销售部门");
var dept3 = new CompositeInterface("开发部门");
var dept4 = new CompositeInterface("法务部门");
var p1 = new Leaf("张1");
var p2 = new Leaf("张2");
var p3 = new Leaf("张3");
var p4 = new Leaf("张4");
var p5 = new Leaf("张5");
var p6 = new Leaf("张6");
var p7 = new Leaf("张7");
var p8 = new Leaf("张8");
var p9 = new Leaf("张9");
var p10 = new Leaf("张10");
var p11 = new Leaf("张11");
var p12 = new Leaf("张12"); dept1.addChild(p1).addChild(p2).addChild(p3);
dept2.addChild(p4).addChild(p5).addChild(p6);
dept3.addChild(p7).addChild(p8).addChild(p9);
dept2.addChild(p10).addChild(p11).addChild(p12);
suborg1.addChild(dept1).addChild(dept2);
suborg2.addChild(dept3).addChild(dept4);
org.addChild(suborg1).addChild(suborg2);
//让公司整个员工都去努力工作
org.hardworking();
document.write("<Br>--------------------<Br>");
org.hardworking("北京分公司");
document.write("<Br>--------------------<Br>");
org.hardworking("南京分公司");
document.write("<Br>--------------------<Br>");
org.hardworking("法务部门");
document.write("<Br>--------------------<Br>");
org.hardworking("张5");
</script> </body>
</html>

总结

组合模式的使用场景非常明确:

你想表示对象的部分-整体层次结构时;

你希望用户忽略组合对象和单个对象的不同,用户将统一地使用组合结构中的所有对象(方法)

另外该模式经常和装饰者一起使用,它们通常有一个公共的父类(也就是原型),因此装饰必须支持具有add、remove、getChild操作的 component接口。

参考: https://github.com/tcorral/Design-Patterns-in-Javascript/blob/master/Composite/index.html

http://www.cnblogs.com/TomXu/archive/2012/04/12/2435530.html

版权声明:本文为小平果原创文章,转载请注明:http://blog.csdn.net/i10630226

JavaScript设计模式之----组合模式的更多相关文章

  1. 再起航,我的学习笔记之JavaScript设计模式15(组合模式)

    组合模式 组合模式(Composite): 又称部分-整体模式,将对象组合成树形结构以表示"部分整体"的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 如果有一个 ...

  2. JavaScript设计模式(5)-组合模式

    组合模式 1. 适合使用组合模式的条件: 存在一批组织成某种层次体系的对象,如树形结构(具体的结构在开发期间可能无法得知) 希望对这批对象或其中的一部分对象实施一个相同的操作 2. 注意点: 组合对象 ...

  3. JavaScript设计模式-14.组合模式实现

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. JavaScript设计模式-13.组合模式

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. 从ES6重新认识JavaScript设计模式(三): 建造者模式

    1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示. 建造者模式的特点是分步构建一个复杂的对象,可以用不同组合或顺序建造出不 ...

  6. C#设计模式(10)——组合模式(Composite Pattern)

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

  7. c++设计模式15 --组合模式

    今天研究了一下设计模式15 组合模式 本人是菜鸟一枚,所以一开始完全不懂组合究竟是什么意思.先上图一张,树形结构图: 文档说,如果想做出这样的结构,通常考虑组合模式.那是为什么呢?现在让我们看一下组合 ...

  8. 乐在其中设计模式(C#) - 组合模式(Composite Pattern)

    原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...

  9. C#设计模式(10)——组合模式(Composite Pattern)(转)

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

随机推荐

  1. 飞思卡尔IMX6处理器的GPIO配置方式

    在linux或android系统中,假如我们要配置飞思卡尔IMX6处理器的GPIO管脚,比如是GPIO_19这个管脚,那么要像这样: [cpp] view plaincopy #define  MX6 ...

  2. C语言之linux内核实现位数高低位互换

    linux内核实在是博大精深,有很多优秀的算法,我之前在工作中就遇到过位数高低位交换的问题,那时候对于C语言还不是很熟练,想了很久才写出来.最近在看内核的时候看到有内核的工程师实现了这样的算法,和我之 ...

  3. C# 如何合并Excel工作表

    文档合并.拆分是实现文档管理的一种有效方式.在工作中,我们可能会遇到需要将多个文档合并的情况,那如何来实现呢,本文将进一步介绍.关于拆分Excel工作表,可参见这篇文章--C#如何拆分EXCEL工作表 ...

  4. 二叉树(LeetCode) C++相关知识代码 系列1

    0.二叉树最大深度 原题目:Given a binary tree, find its minimum depth.The minimum depth is the number of nodes a ...

  5. Course3-Python文件I/O

    1. 读取键盘输入 Python提供了两个内置函数从标准输入读入一行文本,默认的标准输入是键盘.如下: 1). raw_input. raw_input([prompt]) 函数从标准输入读取一个行, ...

  6. jsonp学习

    使用 JSONP 实现跨域通信:http://www.ibm.com/developerworks/cn/web/wa-aj-jsonp1/

  7. Spring Security简明实践及相关国际化处理

    别人的都是最佳实践,因为我目前的设置没有按照参考文档推荐,还是采用DelegatingFilterProxy,所以我只能说简明实践.先贴我的applicationContext-security.xm ...

  8. DELETE_FAILED_INTERNAL_ERROR Error while Installing APK

    真是Android2.3的特殊版本问题,问题原因是android2.3的instant run的测试版安装方式有所特别,解决办法有2: 1.手动adb install 安装包 2.把Instant r ...

  9. Socket.io文字直播聊天室的简单代码

    直接上代码吧,被注释掉的主要是调试代码,和技术选型的测试代码 var app = require('express')(); var server = require('http').Server(a ...

  10. Ocelot中文文档-不支持

    Ocelot不支持一下几点... 分块编码 - Ocelot将始终获取body大小并返回Content-Length头. 如果这不适合你的场景,只能表示抱歉! 转发host头 - 您发给Ocelot的 ...