Js中的组合模式

定义

是一种将对象组合成树状结构的层次结构模式,用来表示 整体-部分 的关系,使用用户对单个对象和组合对象具有一致的访问性。

详细描述

组合模式是一个树形结构,里面的数据可以是单个对象,也可以n个单个对象组合起来的组合对象。

组合模式主要是用来表示 部分-整体的关系,也就是说组合模式下对于调用者角度来看调用一个对象和调用组合对象没有什么区别,将复杂的组合对象用处理单个对象的方式就可以完成,解耦了客户程序与复杂组合对象的解耦。

因为单个对象就可以表现组合对象,所以要求组合模式中的单个对象和组合对象必须暴露出相同的方法让客户来调用。

示例图

如上图所示当用户需要调用整个对象时,此时因为单个对象和组合对象暴露的调用方法一致,所以用户只需要调用一次最上层的组合对象,组合对象就会将调用逐级往下传递并执行调用,这样用户就可以非常轻松的处理完复杂的组合对象数据。

应用场景

用于想表示部分-整体层次结构,用户可以忽略单个对象与组合对象的不同。
如: 树形结构菜单、文件,文件夹的处理等。

代码实例

宏命令改写
在命令模式中我们写过宏命令的代码(命令模式),此时只需要拿来将命令修改为同样的名字就完成了一个最简单的组合模式:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div><button id="button1">button1</button></div></body><script>const button1 = document.getElementById('button1');const setCommand = (button, command) => {// 调用最顶层对象button.onclick = () => command.execute();};const refresh = {execute() {console.log('刷新功能');},};const add = {execute() {console.log('添加功能');},};const del = {execute() {console.log('删除功能');},};const MenuBarCommand = (receiver) => {return {commandsList: [],// 暴露供用户调用的统一接口execute() {// 调用逐级传递执行this.commandsList.forEach((obj) => obj.execute());},// 收集子对象add(obj) {this.commandsList.push(obj);},};};const macroCommand = MenuBarCommand();macroCommand.add(add);macroCommand.add(del);macroCommand.add(refresh);// 绑定组合对象setCommand(button1, macroCommand);// 点击按钮后打印结果// 添加功能// 删除功能// 刷新功能</script>
</html>

上述代码中组合对象macroCommand 由三个单独对象组合而成,他们都暴漏出相同执行命令的方法execute ,调用者只调用最顶层的组合对象macroCommand就相当于调用了整个组合对象。上面只是最简单的对象组合下面我们看下更复杂对象的组合实例:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div><button id="button1">button1</button></div></body><script>const button1 = document.getElementById('button1');const setCommand = (button, command) => {// 调用最顶层对象button.onclick = () => command.execute();};const MacroCommand = (receiver) => {return {commandsList: [],execute() {this.commandsList.forEach((obj) => obj.execute());},add(obj) {this.commandsList.push(obj);},};};// 定义单个对象const refresh = {execute() {console.log('刷新功能');},};const add = {execute() {console.log('添加功能');},};const del = {execute() {console.log('删除功能');},};const jump = {execute() {console.log('跳转功能');},};const prints = {execute() {console.log('打印功能');},};const back = {execute() {console.log('返回功能');},};// 定义组合对象const macroCommand1 = MacroCommand();macroCommand1.add(refresh);macroCommand1.add(add);// 定义组合对象const macroCommand2 = MacroCommand();macroCommand2.add(del);macroCommand2.add(jump);macroCommand2.add(prints
);// 定义组合对象const macroCommand = MacroCommand();macroCommand.add(macroCommand1);macroCommand.add(macroCommand2);macroCommand.add(back);// 绑定组合对象setCommand(button1, macroCommand);// 点击按钮调用结果// 刷新功能// 添加功能// 删除功能// 跳转功能// 打印功能// 返回功能</script>
</html>

上述组合对象示例图:

上述代码就是更加复杂一些的组合对象macroCommand 它的组成不但包含单个对象还包含了组合对象back 还包含了组合对象macroCommand1和macroCommand2,但是对于调用者来着没有任何区别只需要调用macroCommand对象的execute方法就可以轻松的调用整个组合对象中的每个执行。此时如果需要添加新的执行和组合对象只需要暴露出和原结构相同的execute方法即可(参考在下面文件夹实例),非常易于维护和扩展。

文件处理

文件夹和文件之间的关系,非常适合用组合模式来描述。文件夹里既可以包含文件,又可以 包含其他文件夹,最终可能组合成一棵树。下面看下扫描文件的实例:

class Folder {constructor(name) {this.name = name;this.list = [];}// 扫描scean() {console.log('开始扫描文件夹 -->' + this.name);this.list.forEach((file) => file.scean());}// 添加add(file) {this.list.push(file);}
}class File {constructor(name) {this.name = name;}scean() {console.log('开始扫描文件 -->' + this.name);}// 防止单个对象误操作,添加提示解决透明性带来的安全问题add() {throw new Error('文件下面不能再添加文件');}
}// 定义文件夹
const folder = new Folder('学习资料');
const folder1 = new Folder('JavaScript');
const folder2 = new Folder('jQuery');// 定义文件
const file1 = new File('JavaScript 设计模式与开发实践');
const file2 = new File('精通 jQuery');
const file3 = new File('重构与模式');folder1.add(file1);
folder2.add(file2);
folder.add(folder1);
folder.add(folder2);
folder.add(file3);// 下面将其他文件夹和其下面的文件移动到添加好的文件夹folder中(扩展组合对象中的数据)
const folder3 = new Folder('Nodejs');
const file4 = new File('深入浅出 Node.js');
folder3.add(file4);
const file5 = new File('JavaScript 语言精髓与编程实践');folder.add(folder3);
folder.add(file5);// 最后开始扫描整个文件目录
folder.scean();// 扫描结果
// 开始扫描文件夹 -->学习资料
// 开始扫描文件夹 -->JavaScript
// 开始扫描文件 -->JavaScript 设计模式与开发实践
// 开始扫描文件夹 -->jQuery
// 开始扫描文件 -->精通 jQuery
// 开始扫描文件 -->重构与模式
// 开始扫描文件夹 -->Nodejs
// 开始扫描文件 -->深入浅出 Node.js
// 开始扫描文件 -->JavaScript 语言精髓与编程实践

上述代码更加清晰的展现了组合模式中 部分-整体原则,用户不用区分文件和文件夹的区别,直接调用scean方法就可以完成整个文件目录的扫描。 而当我们想要添加文件数据的时候,只需要直接调用原来的方法添加,不需要改动代码就可以完成。

总结

通过上述实例我们可以看到组合模式表示部分-整体的特性,所以我们在维护这些特性的时候就必须要保持单个对象与组合对象的一致性。

正因为部分与整体的一致性,所以组合模式具有调用非常简单,数据扩展更加灵活的特点。

同时在保持灵活,简单优点的时候因为单个对象和组合对象几乎一样,会使代码不易于阅读,并且由于创建了太多的对象可能会增加系统开销问题。

js中的设计模式之组合模式相关推荐

  1. 每天一个设计模式之组合模式

    作者按:<每天一个设计模式>旨在初步领会设计模式的精髓,目前采用javascript和python两种语言实现.诚然,每种设计模式都有多种实现方式,但此小册只记录最直截了当的实现方式 :) ...

  2. [Head First设计模式]山西面馆中的设计模式——装饰者模式

    原文:[Head First设计模式]山西面馆中的设计模式--装饰者模式 引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里 ...

  3. JS常用的设计模式(7)—— 外观模式

    JS常用的设计模式(7)-- 外观模式 外观模式(门面模式),是一种相对简单而又无处不在的模式.外观模式提供一个高层接口,这个接口使得客户端或子系统更加方便调用. 用一段再简单不过的代码来表示 var ...

  4. 1、【设计模式】组合模式

    java设计模式之组合模式 [学习难度:★★★☆☆,使用频率:★★★★☆]  树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构等等,如何运用面向对象的方式 ...

  5. 详解设计模式:组合模式

    组合模式(Composite Pattern),又叫部分整体模式,是 GoF 的 23 种设计模式中的一种结构型设计模式. 组合模式 是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组 ...

  6. 结构型设计模式之组合模式

    结构型设计模式之组合模式 组合模式 应用场景 优缺点 主要角色 组合模式结构 分类 透明组合模式 创建抽象根节点 创建树枝节点 创建叶子节点 客户端调用 安全组合模式 创建抽象根节点 创建树枝节点 创 ...

  7. java设计模式之组合模式(树形层级)

    java设计模式之组合模式 学习难度:★★★☆☆,使用频率:★★★★☆]  树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构等等,如何运用面向对象的方式来 ...

  8. Java设计模式之组合模式详解

    文章目录 详解Java设计模式之组合模式 案例引入 组合模式 定义 模式类图结构 相关角色 典型代码 案例分析 类图设计 实例代码 结果分析 JavaJDK中的组合模式 透明组合模式 安全组合模式 组 ...

  9. Java设计模式之组合模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

最新文章

  1. 权限组件(10):三级菜单的展示和增删改查
  2. Scrapy爬虫(6)爬取银行理财产品并存入MongoDB(共12w+数据)
  3. c++名字查找和作用域的一个例子的感想
  4. 不要打2岁内和6岁后的孩子 父母必看
  5. EntityFramework进阶——CodeFirst数据库迁移
  6. mysql sequence java_MySQL增加Sequence管理功能
  7. “滚蛋吧”扎克伯格!
  8. linux 编程 调度,Linux的进程线程及调度
  9. struct 和typedef struct的区别
  10. shp格式文件出带审图号的地图
  11. 高德地图集成之基础定位
  12. 系统建模uml语言(用例图、实现类图、状态图、顺序图、活动图、组件图、部署图、详细类图、uml文档设计)
  13. 以后有面试官问你「密码学」,你就把这篇文章扔给他
  14. 解决WIN10本地账号绑定微软账号后无法解绑的方法
  15. 电商如何抢占“双十一”?试试自动化仓库机器人 | 行业
  16. python 网络编程 day02
  17. 多线程写法 与老虎机的制作
  18. JS原生获取class对象(getElementsByClassName)
  19. pyecharts1.7.1实现地图可视化(空间数据可视化)
  20. HowTo如何制作一个文字冒险游戏-里篇(1)

热门文章

  1. TinyHTTPd 编译及 HTTP 浅析
  2. 神州无线AC、三层交换机、无线AP连接方法
  3. 证券量化交易平台-接入业务:SpringBoot 集成Apama
  4. 基于Qt的局域网即时通信系统设计与实现(提供各种版本的源代码)
  5. windows XP 开机网络连接慢 的解决方法
  6. 开源堡垒机是什么?开源堡垒机的优缺点是什么?
  7. 大数据离线集群数据迁移实战项目
  8. java截取数组_JS Array.slice 截取数组的实现方法
  9. 大数据Spark必读书目
  10. csdn学习业务 --- 技能树建议