组合模式:用于处理一批具有树形结构的对象的模式。
如:
-> 公司
-> 财务部门
-> 张一
-> 张二
-> 张三
-> 销售部门
-> 张四
-> 张五
-> 张六
对于以上的树形结构,我们要对这批对象或其中一部分对象实施一个操作,可以不采用设计模式来完成,但是存在一个问题,假如需求发生变化,需要增加一个新的层级结构,那么程序的可维护性和可扩展性会很差,那么我们可以用组合模式来解决这个问题。
观察以上的树形结构,是不是和文件目录结构很像?在文件目录结构中,只存在两种对象:文件夹和文件。那么“公司”和“部门”其实都相当于文件夹,张一、张二 等相当于文件,组合模式就是利用这一特点来处理树形结构的。
组合模式的特点:
1、组合模式中只有两种类型的对象:组合对象(文件夹)、叶子对象(文件);
2、这两种类型都实现同一批接口;
3、一般我们会在组合对象中调用其方法并隐式的调用“下级对象”的方法(一般采用 递归)
// 建立接口
var CompositeInterface = new JG.Interface('CompositeInterface', ['addChild', 'getChild']);
var LeafInterface = new JG.Interface('LeafInterface', ['hardworking', 'sleeping']);
// 组合对象
var Composite = function(name){
this.name = name;
this.type = 'Composite';
this.children = [];
};
Composite.prototype = {
constructor : Composite,
addChild : function(child){
this.children.push(child);
return this; // 链式编程
},
getChild : function(name){
// 这个方法是关键
// 接收叶子对象的数组
var elements = [];
var pushLeaf = function(item){
if (item.type === 'Composite') {
item.children.forEach(arguments.callee);
}else if (item.type === 'Leaf') {
elements.push(item);
}
}
if (name && this.name !== name) {
this.children.forEach(function(item){
if (item.name === name && item.type === 'Composite') {
item.children.forEach(pushLeaf);
}
if (item.name !== name && item.type === 'Composite') {
item.children.forEach(arguments.callee);
}
if (item.name === name && item.type === 'Leaf') {
elements.push(item);
}
});
}else{// 如果没有传递name,则获得所有的Leaf(叶子类型)对象
this.children.forEach(pushLeaf);
}
return elements;
},
hardworking : function(name){
// 得到所有的Leaf(叶子类型)对象
var childObjects = this.getChild(name);
for (var i = 0; i < childObjects.length; i++) {
childObjects[i].hardworking();
}
},
sleeping : function(name){
// 得到所有的Leaf(叶子类型)对象
var childObjects = this.getChild(name);
for (var i = 0; i < childObjects.length; i++) {
childObjects[i].sleeping();
}
}
};
// 叶子对象
var Leaf = function(name){
this.name = name;
this.type = 'Leaf';
};
Leaf.prototype = {
constructor : Leaf,
addChild : function(child){
throw new Error('the final child addChild method is disabled...');
},
getChild : function(name){
if (this.name === name) {
return this;
}
return null;
},
hardworking : function(name){
document.write(this.name + '...努力工作!<br>');
},
sleeping : function(name){
document.write(this.name + '...努力睡觉!<br>');
}
};
// 测试
// 创建一批叶子对象
var z1 = new Leaf('张一');
var z2 = new Leaf('张二');
var z3 = new Leaf('张三');
var z4 = new Leaf('张四');
var z5 = new Leaf('张五');
var z6 = new Leaf('张六');
// 创建组合对象(部门)
var dept1 = new Composite('财务部门');
var dept2 = new Composite('销售部门');
// 为部门添加员工
dept1.addChild(z1).addChild(z2).addChild(z3);
dept2.addChild(z4).addChild(z5).addChild(z6);
// 创建组合对象(公司)
var org = new Composite('中国有限公司');
// 为公司添加部门
org.addChild(dept1).addChild(dept2);
// 获得全部员工
var arr = org.getChild();
arr.forEach(function(item){
document.write(item.name + '<br>');
});
/*
结果:
张一
张二
张三
张四
张五
张六
*/
// 让销售部门的所有员工努力工作
org.hardworking('销售部门');
/*
结果:
张四...努力工作!
张五...努力工作!
张六...努力工作!
*/
// 让财务部门的所有员工努力睡觉
org.sleeping('财务部门');
/*
结果:
张一...努力睡觉!
张二...努力睡觉!
张三...努力睡觉!
*/