JavaScript 设计模式 之 组合模式

发布于 2024-08-31 09:52:58 字数 4661 浏览 11 评论 0

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

组合模式的好处:

  1. 可以用同样的方法处理对象的集合与其中的特定子对象
  2. 可以用来把一批子对象组织成树形结构,并且使整棵树都可以被遍历
 /*
 * 场景模拟:
 *  -> 公司 
 *			-> 财务部门
 *						-> 张一
 *						-> 张二
 *						-> 张三
 *			-> 销售部门
 *						-> 张四
 *						-> 张五
 *						-> 张六
 *	
 *		实际的任务具体是落实到人上去实施的 也就是说只有人才具有具体的方法实现
 *			
 */	
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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

清音悠歌

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

謌踐踏愛綪

文章 0 评论 0

开始看清了

文章 0 评论 0

高速公鹿

文章 0 评论 0

alipaysp_PLnULTzf66

文章 0 评论 0

热情消退

文章 0 评论 0

白色月光

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文