JavaScript 设计模式 之 组合模式
组合模式是一种专门为创建 Web 上的动态用户界面而量身定制的模式, 使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为 。这可以简化粘合性代码,使其更容易维护,而那些复杂行为则被委托给各个对象。
组合模式的好处:
- 可以用同样的方法处理对象的集合与其中的特定子对象
- 可以用来把一批子对象组织成树形结构,并且使整棵树都可以被遍历
/*
* 场景模拟:
* -> 公司
* -> 财务部门
* -> 张一
* -> 张二
* -> 张三
* -> 销售部门
* -> 张四
* -> 张五
* -> 张六
*
* 实际的任务具体是落实到人上去实施的 也就是说只有人才具有具体的方法实现
*
*/
const Org = function(name) {
this.name = name;
this.depts = [];
}
Org.prototype = {
constructor: Org,
addDepts: function(child) {
this.depts.push(child);
return this; // 链式调用
},
getDepts: function(){
return this.depts;
}
}
const Dept = function(name) {
this.name = name;
this.persons = [];
}
Dept.prototype = {
constructor: Dept,
addPersons: function(child) {
this.persons.push(child);
return this; // 链式调用
},
getPersons: function(){
return this.persons;
}
}
const Person = function(name) {
this.name = name;
}
Person.prototype = {
constructor: Person,
hardworking: function() {
document.write(this.name + '...努力工作!');
},
sleeping: function() {
document.write(this.name + '...努力睡觉!');
}
}
const p1 = new Person('张 1');
const p2 = new Person('张 2');
const p3 = new Person('张 3');
const p4 = new Person('张 4');
const p5 = new Person('张 5');
const p6 = new Person('张 6');
const dept1 = new Dept('开发部门');
dept1.addPersons(p1).addPersons(p2).addPersons(p3);
const dept2 = new Dept('销售部门');
dept2.addPersons(p4).addPersons(p5).addPersons(p6);
const org = new Org('bjsxt');
org.addDepts(dept1).addDepts(dept2);
// 需求: 具体的让一个人(张 3)去努力工作
for(let i = 0 ,depts = org.getDepts(); i<depts.length;i++ ){
for(let j = 0 ,persons = depts[i].getPersons(); j < persons.length ; j++){
if(persons[j].name === '张 6'){
persons[j].hardworking();
}
}
}
使用组合模式
/**
* 组合模式应用的场景和特点:
* 场景:
* 1.存在一批组织成某种层次体系的对象
* 2.希望对这批对象或其中的一部分对象实施一个操作
*
* 应用特点:
* 1.组合模式中只有两种类型对象:组合对象、叶子对象
* 2.这两种类型都实现同一批接口
* 3.一般我们会在组合对象中调用其方法并隐式调用"下级对象"的方法(这里我们一般采用递归的形式去做)
*
*/
/*
* 场景模拟:
* -> 公司
* -> 北京分公司
* -> 财务部门
* -> 张 1
* -> 张 2
* -> 张 3
* -> 销售部门
* -> 张 4
* -> 张 5
* -> 张 6
* -> 长沙分公司
* -> 财务部门
* -> 张 7
* -> 张 8
* -> 张 9
* -> 销售部门
* -> 张 10
* -> 张 11
* -> 张 12
*
* 实际的任务具体是落实到人上去实施的 也就是说只有人才具有具体的方法实现
*
*/
const CompositeInterface = new BH.Interface('CompositeInterface' , ['addChild','getChild']);
const LeafInterface = new BH.Interface('LeafInterface' , ['hardworking','sleeping']);
const 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) {
// 接受叶子对象类型的数组
const elements = [] ;
// 判断对象是否为 Leaf 类型的,如果是,直接加到 elements 数组中;不是,继续递归调用
const pushLeaf = function(item){
if(item.type === 'Composite'){
item.children.each(arguments.callee);
} else if(item.type === 'Leaf'){
elements.push(item);
}
};
// 根据 name 让指定 name 下的所有的类型为 Leaf 的对象去执行操作
if(name && this.name !== name){
this.children.each(function(item){
// 如果传递的 name 是 2 级节点名称
if(item.name === name && item.type === 'Composite'){
item.children.each(pushLeaf);
}
// 如果传递的 name 是 3 级节、4 级、5 级...N 级
if(item.name !== name && item.type === 'Composite'){
item.children.each(arguments.callee);
}
// 如果传递的 name 是叶子节点的时候
if(item.name === name && item.type === 'Leaf'){
elements.push(item);
}
});
}
// 不传递 name 让整个公司所有类型为 Leaf 的对象去执行操作
else {
this.children.each(pushLeaf);
}
return elements ;
},
hardworking: function(name) {
//得到所有的 Leaf 类型的对象数组
const leafObjects = this.getChild(name);
for(let i = 0 ; i < leafObjects.length; i ++){
leafObjects[i].hardworking();
}
},
sleeping: function(name) {
//得到所有的 Leaf 类型的对象数组
const leafObjects = this.getChild(name);
for(let i = 0 ; i < leafObjects.length; i ++){
leafObjects[i].sleeping();
}
}
}
const Leaf = function(name) {
this.name = name;
this.type = "leaf"; // 说明对象的类型(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Android CAS 和 AQS
下一篇: Covenant 利用分析
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论