在JavaScript中理解组合模式
栏目: JavaScript · 发布时间: 5年前
内容简介:组合模式就是用小的子对象来构建更大的对象, 将对象组合成树形结构, 以表示 “部分-整体” 的层次结构.位于底层最小的对象, 我们在这里称为叶对象, 由叶对象组成的组合对象我们称为分支对象, 位于最顶层的根对象在这里我们也称为分支对象. 不过它们只是结构上呈现出父子关系.组合模式最大的好处可以一致性地对待分支对象和叶对象, 这也就要求了它们有着相同的接口.
组合模式就是用小的子对象来构建更大的对象, 将对象组合成树形结构, 以表示 “部分-整体” 的层次结构.
位于底层最小的对象, 我们在这里称为叶对象, 由叶对象组成的组合对象我们称为分支对象, 位于最顶层的根对象在这里我们也称为分支对象. 不过它们只是结构上呈现出父子关系.
组合模式最大的好处可以一致性地对待分支对象和叶对象, 这也就要求了它们有着相同的接口. 在JavaScript中理解策略模式 中, 我们对员工进行考核, 划分了甲乙丙三个等级. 现在, 公司决定结合等级以资鼓励.
以下所有代码参见compositeMode.
开销的占比
现有考核人员:
考核项目\考核人 | 等级 | 月薪 |
---|---|---|
person_1 | 甲 | 6k |
person_2 | 乙 | 9k |
person_3 | 乙 | 4k |
person_4 | 乙 | 5k |
person_5 | 丙 | 6k |
person_6 | 丙 | 5k |
person_7 | 丙 | 6k |
person_8 | 丙 | 4k |
person_9 | 甲 | 8k |
const persons = [ { scale: '甲', salary: 6000, company: 'JavaScript' }, { scale: '乙', salary: 9000, company: 'JavaScript' }, { scale: '乙', salary: 4000, company: 'JavaScript' }, { scale: '乙', salary: 5000, company: 'JavaScript' }, { scale: '丙', salary: 6000, company: 'JavaScript' }, { scale: '丙', salary: 5000, company: 'JavaScript' }, { scale: '丙', salary: 6000, company: 'JavaScript' }, { scale: '丙', salary: 4000, company: 'JavaScript' }, { scale: '丙', salary: 9000, company: 'JavaScript' }, { scale: '甲', salary: 6000, company: 'JavaScript' }, ] 复制代码
等级与月薪相关, 分别为3倍月薪、2倍月薪、1倍月薪.
等级 | 甲 | 乙 | 丙 |
---|---|---|---|
月薪倍率 | 3 | 2 | 1 |
const scaleMap = { '甲': 3, '乙': 2, '丙': 1 } 复制代码
到底需要拿出多少钱奖励呢? 甲乙丙三组人分别占比多少呢? 针对这样的需求, 我们尝试着用组合模式计算一下.
叶对象与分支对象
上面也提到了, 组合模式中有两类对象. 一个是分支对象, 一个是叶对象. 分支对象是叶对象的集合, 保存着叶对象的引用, 可以操作叶对象(比如添加, 执行). 而叶对象只要暴露接口即可. 现在我们从简单的开始, 造一个生产叶对象的函数.
const leaf = params => { return { ...params, expense() { return scaleMap[params.scale] * params.salary } } } 复制代码
分支对象就稍微麻烦些了, 因为需要管理叶对象.
const branch = params => { return { ...params, members: [], add(item) { this.members.push(item) }, expense() { return this.members.reduce((sum, item) => { return sum + item.expense() }, 0) } } } 复制代码
expense()
的方法不论是在分支对象还是叶对象上, 或者说不清楚是分支对象还是叶对象, 我们都可以得到相应的结果. 在分支对象里, 保存着叶对象的引用, 我们可以对叶对象进行任何操作.
从JSON数据到树形结构
组合模式就是这么简单, 剩下的就是如何 JSON 数据转换成层次分明的结构了.
const convertData = array => { const branchList = []; const branchObjs = []; array.forEach(item => { let leafObj = leaf(item); if (!branchList.includes(item.scale)) { let params = { scale: item.scale } let branchObj = branch(params) branchObjs.push(branchObj) branchList.push(item.scale) } branchObjs.filter(obj => obj.scale == item.scale)[0].add(leafObj); }) return branchObjs; } console.log('branchObjs', convertData(persons)) const scaleA = convertData(persons)[0] const scaleB = convertData(persons)[1] const scaleC = convertData(persons)[2] console.log('甲', scaleA.expense()) console.log('乙', scaleB.expense()) console.log('丙', scaleC.expense()) 复制代码
最终结果展示
如果我们想知道公司的总支出, 也可以把 scaleA, scaleB, scaleC 组合在一起作为公司的一子集.
const company = branch(); company.add(scaleA); company.add(scaleB); company.add(scaleC); company.expense() 复制代码
不难发现, 我们可以随意组装对象而不会影响到其它节点, 任何一个集合或个体都能够单独运行. 我们也可以根据需要去组合更复杂的结构. 但是, 如果通过组合模式创建了太多的对象, 那么这些对象可能会让系统负担不起.
小结
-
组合模式对象形式上至少有两种, 分支对象和叶对象.
-
分支对象和叶对象拥有相同的接口, 且对一组叶对象操作具有同步一致性.
-
组合模式是 HAS-A (聚合)关系, 不是 IS-A.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 如何理解go语言提倡组合,不提倡继承
- js组合模式和寄生组合模式的区别研究
- 组合还是继承,这是一个问题?——由模式谈面向对象的原则之多用组合、少用继承
- Django实现组合搜索
- 组合优于继承
- 迷人的算法-排列组合
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
离心力:互联网历史与数字化未来
[英] 乔尼·赖安(Johnny Ryan) / 段铁铮 / 译言·东西文库/电子工业出版社 / 2018-2-1 / 68.00元
★一部详实、严谨的互联网史著作; ★哈佛、斯坦福等高校学生必读书目; ★《互联网的未来》作者乔纳森·L. 齐特雷恩,《独立报》《爱尔兰时报》等知名作者和国外媒体联合推荐。 【内容简介】 虽然互联网从诞生至今,不过是五六十年,但我们已然有必要整理其丰富的历史。未来的数字世界不仅取决于我 们的设想,也取决于它的发展历程,以及互联网伟大先驱们的理想和信念。 本书作者乔尼· ......一起来看看 《离心力:互联网历史与数字化未来》 这本书的介绍吧!