JavaScript设计模式:组合模式原理与实战应用

作者:函数茶馆时间:2026-10-23 17:29:45浏览:638

本文深入解析JavaScript中的组合模式,通过公司组织架构管理的实例,对比传统分类设计与组合模式的差异。详细阐述如何利用统一接口处理叶子节点与容器节点,实现树形结构的透明遍历,并分析该模式在提升代码可扩展性与维护性方面的优缺点及适用场景。

组合模式概述

本文详细解析JavaScript中的组合模式,涵盖其核心原理及具体应用案例,旨在为开发者提供实用的参考指南。

组合模式,亦称部分整体模式,旨在将一组相似对象视为单一对象进行处理。该模式基于树形结构来组合对象,从而清晰地表达部分与整体之间的层次关系。

其定义在于将多个对象组合成树形结构,以表示具有整体-部分关系的层次化机构。该模式确保了对单个对象(叶子对象)和组合对象(容器对象)的操作具有一致性,因此也被称为整体-部分模式。作为一种对象结构型设计模式,它简化了复杂结构的处理。

应用场景与初始设计缺陷

应用场景示例:假设我们需要打印公司的员工架构,且管理岗与开发岗的区别仅在于是否拥有下级员工。下面我们将通过代码实现这一需求。

初始示例代码:


var LEADER = function(name,dept){
  this._name = name || '';  //姓名
  this._dept = dept || '';  //职位
  this._subordinates = [];  //下属
 
  this.add = function(employee){
    this._subordinates.push(employee);
  }
 
  this.remove = function(employee){
    this._subordinates.splice(this._subordinates.indexOf(employee),1);
  }
 
  this.getSubordinates = function(){
    return this._subordinates;
  }
  this.toString = function(){
    console.log('姓名:'+this._name+',职位:'+this._dept)
  }
}
var JAVARD = function(name,dept){
  this._name = name || '';  //姓名
  this._dept = dept || '';  //职位
 
  this.toString = function(){
    console.log('姓名:'+this._name+',职位:'+this._dept)
  }
}
 
var FERD = function(name,dept){
  this._name = name || '';  //姓名
  this._dept = dept || '';  //职位
  this.toString = function(){
    console.log('姓名:'+this._name+',职位:'+this._dept)
  }
}
 
function addData(){
  var CEO = new LEADER('spancer','CEO');
 
  var CTO = new LEADER('zijian','CTO');
 
  var MANAGER = new LEADER('jiang','LEADER');
 
  var JAVA_LEADER = new LEADER('fei','JAVA_LEADER');
  var FE_LEADER = new LEADER('risker','FE_LEADER');
 
  var wh = new FERD('wanghui','FE');
  var si = new FERD('si','FE');
  var amy = new FERD('amy','FE');
 
  var wei = new JAVARD('wei','JAVA');
  var guo = new JAVARD('guo','JAVA');
  var yuan = new JAVARD('yuan','JAVA');
 
  CEO.add(CTO);
 
  CTO.add(MANAGER);
 
  MANAGER.add(JAVA_LEADER);
  MANAGER.add(FE_LEADER);
 
  FE_LEADER.add(wh);
  FE_LEADER.add(si);
  FE_LEADER.add(amy);
 
  JAVA_LEADER.add(wei);
  JAVA_LEADER.add(guo);
  JAVA_LEADER.add(yuan);
  return CEO;
}
var eachEmployee = function(employee){
  for(var employ of employee.getSubordinates()){
    employ.toString();
    if(employ.getSubordinates && employ.getSubordinates().length > 0){
      eachEmployee(employ);
    }
  }
}
 
var CEO = addData();
CEO.toString();
eachEmployee(CEO);
// 姓名:spancer,职位:CEO
// 姓名:zijian,职位:CTO
// 姓名:jiang,职位:LEADER
// 姓名:fei,职位:JAVA_LEADER
// 姓名:wei,职位:JAVA
// 姓名:guo,职位:JAVA
// 姓名:yuan,职位:JAVA
// 姓名:risker,职位:FE_LEADER
// 姓名:wanghui,职位:FE
// 姓名:si,职位:FE
// 姓名:amy,职位:FE

上述简单Demo用于遍历输出公司组织架构。由于研发(rd)与领导(leader)职能不同,我们将技术与管理分为两类。然而,这种设计存在显著缺陷:

首先,可扩展性较差。若新增职位,归类时是新增类别还是归入现有类目均难以确定。其次,当某一行为发生变化时,需逐一修改leader类和rd类,这违反了开闭原则。

组合模式实现方案

接下来,我们使用组合模式重新实现该功能:


var Employee = function(name, dept){
  this._name = name || '';  //姓名
  this._dept = dept || '';  //职位
  this._subordinates = [];  //下属
 
  this.add = function(employee){
    this._subordinates.push(employee);
  }
 
  this.remove = function(employee){
    this._subordinates.splice(this._subordinates.indexOf(employee),1);
  }
 
  this.getSubordinates = function(){
    return this._subordinates;
  }
  this.toString = function(){
    console.log('姓名:'+this._name+',职位:'+this._dept)
  }
}
 
function addData(){
  var CEO = new Employee('spancer','CEO');
 
  var CTO = new Employee('zijian','CTO');
 
  var LEADER = new Employee('jiang','LEADER');
 
  var JAVA_LEADER = new Employee('fei','JAVA_LEADER');
  var FE_LEADER = new Employee('risker','FE_LEADER');
 
  var wh = new Employee('wanghui','FE');
  var si = new Employee('si','FE');
  var amy = new Employee('amy','FE');
 
  var wei = new Employee('wei','JAVA');
  var guo = new Employee('guo','JAVA');
  var yuan = new Employee('yuan','JAVA');
 
  CEO.add(CTO);
 
  CTO.add(LEADER);
 
  LEADER.add(JAVA_LEADER);
  LEADER.add(FE_LEADER);
 
  FE_LEADER.add(wh);
  FE_LEADER.add(si);
  FE_LEADER.add(amy);
 
  JAVA_LEADER.add(wei);
  JAVA_LEADER.add(guo);
  JAVA_LEADER.add(yuan);
  return CEO;
}
var eachEmployee = function(employee){
  for(var employ of employee.getSubordinates()){
    employ.toString();
    if(employ.getSubordinates().length > 0){
      eachEmployee(employ);
    }
  }
}
 
var CEO = addData();
CEO.toString();
eachEmployee(CEO);
// 姓名:spancer,职位:CEO
// 姓名:zijian,职位:CTO
// 姓名:jiang,职位:LEADER
// 姓名:fei,职位:JAVA_LEADER
// 姓名:wei,职位:JAVA
// 姓名:guo,职位:JAVA
// 姓名:yuan,职位:JAVA
// 姓名:risker,职位:FE_LEADER
// 姓名:wanghui,职位:FE
// 姓名:si,职位:FE
// 姓名:amy,职位:FE

对比两段代码可知,我们使用统一的Employee类替代了原有的leader和rd类,这正是组合模式的核心所在:

通过定义一个抽象类(如Employee),它既能代表leader也能代表rd。在添加或打印操作时,基于Employee类进行处理,无需关心具体角色,从而实现统一处理。

模式优缺点与适用场景分析

组合模式总结:

优点包括: * 能够清晰定义具有层次关系的复杂对象,使客户端在开发过程中无需关注层次差异。 * 全局修改时,仅需修改一处代码即可生效。

缺点包括: * 难以对生成结果进行严格限制。例如,在第一个例子中,所有rd都没有下级员工属性及对应方法,但组合模式无法强制约束这一点。因此使用时需注意这些潜在约束。

适用场景: * 在面向对象语言开发的系统中,需要处理树形结构时。 * 在具有整体与部分的结构中,希望忽略二者差异,使客户端能够一致对待它们时。

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

作者最新文章