![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zMzYTOzITMxITMwgDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
組合模式的使用場景:
1、存在一批組織成某種層次體系的對象
2、希望對這批對象或其中的一部分對象實施一個操作。
組合模式的特點:
1、組合模式中隻有兩種類型對象:組合對象、葉子對象
2、這兩種類型都實作同一批接口
3、一般我們會在組合對象中調用其方法并隐式調用"下級對象"的方法(這裡我們一般采用遞歸的形式去做)
/**
* 組合模式應用的場景和特點:
場景:
1、存在一批組織成某種層次體系的對象那個
2、希望對這批對象或其中的一個部分對象實施一個操作
應用特點:
1、組合模式中隻有兩種類型對象:組合對象、葉子對象
2、這兩種類型都實作同一批接口
3、一般我們會在組合對象中調用其方法并瘾式調用‘下級對象’的方法(這裡我們一般采用遞歸的形勢去做)
* 場景模拟:
* -> 公司
* -> 北京分公司
* -> 财務部門
* -> 張1
* -> 張2
* -> 張3
* -> 銷售部門
* -> 張4
* -> 張5
* -> 張6
-> 上海分公司
* -> 财務部門
* -> 張7
* -> 張8
* -> 張9
* -> 銷售部門
* -> 張10
* -> 張11
* -> 張12
*
*實際的任務具體是落實到人上去實施的 也就是說隻有人才具有具體的方法實作
*
*/
//這兩個類型必須實作同一個接口
//添加方法和取得方法
var CompositeInterface = new Fan.Interface('CompositeInterface',['addChild','getChild']);
//努力工作和努力睡覺
var LeafInterface = new Fan.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 = [];
//判斷對象是否為Leaf類型的
var pushLeaf = function(item){
if(item.type === 'Composite'){
item.children.each(arguments.callee);
}else if(item.type === 'Leaf'){
elements.push(item);
}
};
if(name && this.name !== name){ //根據name傳值,指定name下的所有類型leaf對象去執行操作
this.children.each(function(item){
//如果傳入的name是二級子節點名稱
if(this.name === name && item.type === 'Composite'){
item.children.each(pushLeaf);
}
//如果傳遞的name是三級節點或者是N級
if(this.name !== name && item.type === 'Composite'){
item.children.each(arguments.callee);
}
//如果傳遞的name是葉子節點
if(this.name === name && item.type === 'Leaf'){
elements.push(item);
}
})
}else{ //不傳name,讓整個公司所有類型為Leaf的對象去執行操作
//org.hardworking();沒有傳值,就周遊公司所有部門
this.children.each(pushLeaf);
}
return elements;
},
hardworking : function(name){
//得到所有的Leaf類型的對象數組
var leafObject = this.getChild(name);
for(var i=0; i<leafObject.length; i++){
leafObject[i].hardworking();
}
},
sleeping : function(name){
var leafObject = this.getChild(name);
for(var i=0; i<leafObject.length; i++){
leafObject[i].sleeping();
}
}
}
//葉子對象
var Leaf = function(name){
this.name = name;
this.type = 'Leaf';
};
Leaf.prototype = {
constructor : Leaf,
//葉子節點方法無法再調用下一級
addChild : function(child){
throw new Error('不能被使用');
},
getChild : function(name){
if(this.name == name){
return this;
}
return name;
},
hardworking : function(name){
console.log(this.name + '努力工作...');
},
sleeping : function(name){
console.log(this.name + '努力睡覺...');
}
}
//測試資料
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');
var dept1 = new Composite('北京開發部門');
dept1.addChild(p1).addChild(p2).addChild(p3);
var dept2 = new Composite('北京銷售部門');
dept2.addChild(p4).addChild(p5).addChild(p6);
var dept3 = new Composite('上海開發部門');
dept3.addChild(p7).addChild(p8).addChild(p9);
var dept4 = new Composite('上海銷售部門');
dept4.addChild(p10).addChild(p11).addChild(p12);
var org1 = new Composite('北京分公司');
org1.addChild(dept1).addChild(dept2);
var org2 = new Composite('上海分公司');
org2.addChild(dept3).addChild(dept4);
var org = new Composite('深圳總部');
org.addChild(org1).addChild(org2);
org.hardworking('張7');