目录

1 什么是组合模式

2 主要参与者

3 代码实现

4 应用实例

4.1 表单验证

4.1 图片阅读器

5 总结


1 什么是组合模式

组合模式允许创建具有属性的对象,这些对象是原始项目或对象集合。集合中的每个项目本身可以容纳其他集合,创建深度嵌套结构。

树型控件是复合模式的一个完美例子。树的节点要么包含一个单独的对象(叶子节点),要么包含一组对象(节点的子树)。组合模式用于简单化,一致化对单组件和复合组件的使用;其实它就是一棵树。

组合模式能对于工作能起到简化作用,组合对象实现某一操作时,通过递归,向下传递到所有的组成对象,在存在大批对象时,假如页面的包含许多拥有同样功能的对象,只需要操作组合对象即可达到目标。在存在着某种的层次结构,并且其中的一部分要实现某些操作,即可使用组合模式。

组合模式中的所有节点都共享一组通用的属性和方法,它既支持单个对象,也支持对象集合。这种共同的接口极大地促进了递归算法的设计和构建,这种算法可以对复合集合中的每个对象进行迭代。

实例场景:

1 自然界中的各种树,树长在大地人,树头(树根),即是入口点,这棵树头向上生长,即有自己的叶子,又有自己的子树枝,某树枝还有自己的叶子,跟子树枝。

2  操作系统目录结构、公司部门组织架构、国家省市县等,像这么看起来复杂的现象,都可以使用组合模式,即部分-整体模式来操作。

2 主要参与者

参与该模式的对象有:

Component :声明组成中对象的接口。

Leaf :代表构图中的叶子对象,一个叶子没有子对象。

Composite :表示组成中的分支(或子树),维护一个子组件的集合。

3 代码实现

在下边的代码中,Node(节点)对象创建了一个树状结构。每个节点都有一个名字和4个方法:add、remove、getChild和hasChildren。这些方法被添加到Node的原型中。这减少了对内存的要求,因为这些方法现在被所有节点共享。Node是完全递归的,不需要单独的Component或Leaf对象。

通过向父节点添加节点来构建一个小型的复合树。一旦完成,我们调用traverse,它将遍历树中的每个节点,并显示其名称和深度(通过缩进显示)。日志函数用来记录和显示结果。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>组合模式:公众号AlbertYang</title></head><body></body><script>var Node = function(name) {this.children = [];this.name = name;}Node.prototype = {add: function(child) {this.children.push(child);},remove: function(child) {var length = this.children.length;for (var i = 0; i < length; i++) {if (this.children[i] === child) {this.children.splice(i, 1);return;}}},getChild: function(i) {return this.children[i];},hasChildren: function() {return this.children.length > 0;}}// 使用递归遍历一个树     function traverse(indent, node) {log.add(Array(indent++).join("--") + node.name);for (var i = 0, len = node.children.length; i < len; i++) {traverse(indent, node.getChild(i));}}// 日志函数记录和打印结果var log = (function() {var log = "";return {add: function(msg) {log += msg + "\n";},show: function() {console.info("%c%s", "color:red; font-size:18px", log);log = "";}}})();function run() {var tree = new Node("root");var left = new Node("left")var right = new Node("right");var leftleft = new Node("leftleft");var leftright = new Node("leftright");var rightleft = new Node("rightleft");var rightright = new Node("rightright");tree.add(left);tree.add(right);tree.remove(right); // 删除节点tree.add(right);left.add(leftleft);left.add(leftright);right.add(rightleft);right.add(rightright);traverse(1, tree);log.show();}run();</script>
</html>

4 应用实例

4.1 表单验证

演示地址:https://www.albertyy.com/2020/8/Component1.html

表单验证中,需要做的工作是表单的保存、恢复和验证表单中的值,然而表单的数量是未知数,类型是未知数,只有功能能确定,在这种情况下,使用组合模式无疑最好,通过给每个表单添加功能,然后一个表单对象组合起来,通过操作表单对象即可达到操作表单。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>组合模式实例应用:公众号AlbertYang</title></head><body><input type="button" value="存储" onclick="a()" /><input type="button" value="取出" onclick="b()" /></body><script type="text/javascript">//存储的值  var value_content = {};function setCookie(name, value) {value_content[name] = value;}function getCookie(name) {return value_content[name];}//表单组合对象var CompositeForm = function(id, method, action) {this.formComponents = [];this.element = document.createElement('form');this.element.id = id;this.element.method = method || 'POST';this.element.action = action || '#';}CompositeForm.prototype.add = function(child) {this.formComponents.push(child);this.element.appendChild(child.getElement());}CompositeForm.prototype.remove = function(child) {for (var i = 0, len = this.formComponents.length; i < len; i++) {if (child == this.formComponents[i]) {this.formComponents.splice(i, 1);break;}}}CompositeForm.prototype.getChild = function(i) {return this.formComponents[i];}CompositeForm.prototype.save = function() {for (var i = 0, len = this.formComponents.length; i < len; i++) {this.formComponents[i].save();}}CompositeForm.prototype.restore = function() {for (var i = 0, len = this.formComponents.length; i < len; i++) {this.formComponents[i].restore();}}CompositeForm.prototype.getElement = function() {return this.element;}//接口方法var Field = function(id) {this.id = id;this.element;this.content;};Field.prototype.add = function() {};Field.prototype.remove = function() {};Field.prototype.getChild = function() {};Field.prototype.save = function() {setCookie(this.id, this.getValue());};Field.prototype.getElement = function() {return this.element;}Field.prototype.getValue = function() {throw new Error('错误');}Field.prototype.restore = function() {this.content.value = getCookie(this.id);};//继承方法function extend(subClass, superClass) {var F = function() {};F.prototype = superClass.prototype;subClass.prototype = new F();subClass.prototype.constructor = subClass;subClass.superclass = superClass.prototype;if (superClass.prototype.constructor == Object.prototype.constructor) {superClass.prototype.constructor = superClass;}}//输入框var InputField = function(id, label) {Field.call(this, id);this.input = document.createElement('input');this.content = this.input;this.label = document.createElement('label');var labelTextNode = document.createTextNode(label);this.label.appendChild(labelTextNode);this.element = document.createElement('div');this.element.id = id;this.element.className = 'input-field';this.element.appendChild(this.label);this.element.appendChild(this.input);}extend(InputField, Field);InputField.prototype.getValue = function() {return this.input.value;};//文本框var TextareaField = function(id, label) {Field.call(this, id);this.textarea = document.createElement('textarea');this.content = this.textarea;this.label = document.createElement('label');var labelTextNode = document.createTextNode(label);this.label.appendChild(labelTextNode);this.element = document.createElement('div');this.element.id = id;this.element.className = 'input-field';this.element.appendChild(this.label);this.element.appendChild(this.textarea);};extend(TextareaField, Field);TextareaField.prototype.getValue = function() {return this.textarea.value;};//选择框var SelectField = function(id, label) {Field.call(this, id);this.select = document.createElement('select');this.select.options.add(new Option("sfs", "sfs"));this.select.options.add(new Option("111", "2222222222")); //这边value会改变this.content = this.select;this.label = document.createElement('label');var labelTextNode = document.createTextNode(label);this.label.appendChild(labelTextNode);this.element = document.createElement('div');this.element.id = id;this.element.className = 'input-field';this.element.appendChild(this.label);this.element.appendChild(this.select);};extend(SelectField, Field);SelectField.prototype.getValue = function() {return this.select.options[this.select.options.selectedIndex].value;};//表单域var CompositeFieldset = function(id, legendText) {this.components = {};this.element = document.createElement('fieldset');this.element.id = id;if (legendText) {this.legend = document.createElement('legend');this.legend.appendChild(document.createTextNode(legendText));this.element.appendChild(this.legend);}};CompositeFieldset.prototype.add = function(child) {this.components[child.getElement().id] = child;this.element.appendChild(child.getElement());};CompositeFieldset.prototype.remove = function(child) {delete this.components[child.getElement().id];};CompositeFieldset.prototype.getChild = function(id) {if (this.components[id] != undefined) {return this.components[id];} else {return null;}};CompositeFieldset.prototype.save = function() {for (var id in this.components) {if (!this.components.hasOwnProperty(id))continue;this.components[id].save();}};CompositeFieldset.prototype.restore = function() {for (var id in this.components) {if (!this.components.hasOwnProperty(id))continue;this.components[id].restore();}};CompositeFieldset.prototype.getElement = function() {return this.element;};//用组合模式汇合起来var contactForm = new CompositeForm('contact-form', 'POST', 'test');var nameFieldset = new CompositeFieldset('name-fieldset');nameFieldset.add(new InputField('first-name', 'First Name'));nameFieldset.add(new InputField('last-name', 'Last Name'));contactForm.add(nameFieldset);var addressFieldset = new CompositeFieldset('address-fieldset');addressFieldset.add(new InputField('address', 'Address'));addressFieldset.add(new InputField('city', 'City'));addressFieldset.add(new SelectField('state', 'State'));addressFieldset.add(new InputField('zip', 'Zip'));contactForm.add(addressFieldset);contactForm.add(new TextareaField('comments', 'Comments'));document.body.appendChild(contactForm.getElement());function a() {contactForm.save();}function b() {contactForm.restore();}</script>
</html>

4.1 图片阅读器

演示地址:https://www.albertyy.com/2020/8/Component2.html

图片阅读器与表单验证基本一样,通过汇合操作图片。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>组合模式实例应用:公众号AlbertYang</title></head><body><input value="隐藏" type="button" onclick="a()" /><input value="显示" type="button" onclick="b()" /></body><script type="text/javascript">//图片库var DynamicGallery = function(id) {this.children = [];this.element = document.createElement('div');this.element.id = id;this.element.className = 'dynamic-gallery';};DynamicGallery.prototype = {add: function(child) {this.children.push(child);this.element.appendChild(child.getElement());},remove: function(child) {for (var node, i = 0; node = this.getChild(i); i++) {if (node == child) {this.children.splice(i, 1);break;}}this.element.removeChild(chld.getElement());},getChild: function(i) {return this.children[i];},hide: function() {for (var i = 0, node; node = this.getChild(i); i++) {node.hide();}this.element.style.display = 'none';},show: function() {this.element.style.display = 'block';for (var i = 0, node; node = this.getChild(i); i++) {node.show();}},getElement: function() {return this.element;}};//单个图片var GalleryImage = function(src) {this.element = document.createElement('img');this.element.className = 'gallery-image';this.element.src = src;};GalleryImage.prototype = {add: function() {},remove: function() {},getChild: function() {},hide: function() {this.element.style.display = 'none';},show: function() {this.element.style.display = '';},getElement: function() {return this.element;}};//汇合起来var topGallery = new DynamicGallery('top-gallery');topGallery.add(new GalleryImage('img/1.jpg'));topGallery.add(new GalleryImage('img/2.jpg'));topGallery.add(new GalleryImage('img/3.jpg'));var vacationPhotos = new DynamicGallery('vacation-photos');for (var p = 0; p < 30; p++) {vacationPhotos.add(new GalleryImage('img/3.jpg'));}topGallery.add(vacationPhotos);document.body.appendChild(topGallery.getElement());function a() {topGallery.hide();}function b() {topGallery.show();}</script>
</html>

5 总结

组合模式通过简单的操作就能达到复杂的效果,一个操作通过遍历递归传递这个操作。不过组合模式的弱点也在于此,如果层次过多,则性能将受到影响。

组合模式应用需要符合两个条件,一是产生递归,二是具有相同的动作。

今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎点赞,评论,转发!!!

设计模式(10)[JS版]-JavaScript如何实现组合模式???相关推荐

  1. 设计模式(7)[JS版]-JavaScript设计模式之原型模式如何实现???

    目录 1.什么是原型模式 2 参与者 3 实例讲解 4 使用 Object.create实现原型模式 4.1 Object.create()的用法 4.2 用 Object.create实现继承 4. ...

  2. 设计模式(9)[JS版]-JavaScript设计模式之如何实现桥接模式???

    目录 1 什么是桥接模式 2 参与者 3 实例讲解 4 总结 1 什么是桥接模式 Bridge模式允许两个组件,即客户端和服务一起工作,每个组件都有自己的接口.Bridge是一种高级架构模式,它的主要 ...

  3. 设计模式(6)[JS版]-JavaScript如何实现抽象工厂模式?

    目录 1 学习目标 2 什么是抽象工厂模式? 3 抽象工厂模式作用 4 工厂模式参与者 5 代码实现 1 学习目标 通过本篇文章的学习,你应当掌握以下知识: 1 知道什么是抽象工厂模式? 2 掌握抽象 ...

  4. 23种设计模式C++源码与UML实现--组合模式

    组合模式 Composite模式也叫做组合模式,是构造型的设计模式之一.通过递归的手段构造树形的对象结构,并可以通过一个对象来访问整个对象树. Component树形结构的节点抽象 为所有的对象定义统 ...

  5. 《Head First设计模式》第九章(2)组合模式

    组合模式 ​ 基于前一篇迭代模式的案例进行需求更新,餐厅的菜单管理系统需要有煎饼屋菜单和披萨菜单.现在希望在披萨菜单中能够加上一份餐后甜点的子菜单. 在迭代模式中,披萨菜单是用数组维护的,我们需要让披 ...

  6. Head First设计模式读书笔记八 第九章下 组合模式

    之前的总结链接: https://blog.csdn.net/u011109881/article/details/58710579 对比headFirst书中的例子,我觉得书中的组合模式的例子比上面 ...

  7. 设计模式学习笔记(九)——Composite组合模式

    Composite组合模式主要是应对这样的问题:一类具有"容器特征"的对象--即他们在充当对象的同时,又是其他对象的容器的情况.在编写时我们常常会造成:客户代码过多地依赖于对象容器 ...

  8. Android开发用到的几种常用设计模式浅谈(一):组合模式

    1:应用场景 Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类.组合模式 ...

  9. 头像上传html js版,javascript头像上传代码实例

    上传头像: 相关关键词: ondragover(拖动元素在投放区内移动) ondrop (元素放在投放区触发但是要去处理浏览器默认事件的影响:ondragenter.ondragover) dataT ...

最新文章

  1. Setting Up Hadoop NameNode High Availability
  2. c语言图形界代码,求个用最简单的的代码来实现图形界面…
  3. _variant_t和_bstr_t
  4. openresty配置部署
  5. asp.net(c#)将彩色图片变灰阶图片
  6. jquery获取java对象的属性_jQuery - 获得内容和属性
  7. PHP curl 直接获取请求变量,不直接输出
  8. CMake 手册详解(十八)
  9. 【转载】文件上传命令rz和下载命令sz的安装
  10. 从OpenStack到OpenInfra
  11. java 工作一年的简历
  12. BOOST升压有源功率因数校正
  13. 复制粘贴之后出现问号怎么办_CAD图形文字复制粘贴以后出现变化该怎么办?
  14. fNIRS–EEG监测人脑活动和氧合作用的研究进展
  15. 浅析cv::cuda::threshold函数的实现
  16. python 在屏幕上点击特定按钮或图像
  17. 【Mysql】调优必知的sql访问方式
  18. 我收藏的短线操作技巧
  19. 工业网关BL110实现西门子S7-200SMART PLC接入OPC UA 云平台
  20. 机器学习——Kmeans聚类算法

热门文章

  1. 中小团队落地配置中心详解
  2. matplotlib之pyplot模块——绘制箱线图(盒须图)boxplot()(一)基本参数
  3. autojs 手游 脚本UI demo【仅供学习交流】
  4. C++ 一文解决 数据库ODB 安装/调试/使用的问题
  5. linux 备份iphone,备份苹果硬盘的数据
  6. 【DP】AGC012B Splatter Painting
  7. python生成ppt图表_使用Python从Excel到PowerPoint的图表
  8. Mybatis层次结构图
  9. 新浪大赚,阿里吃亏------剖析阿里巴巴入股新浪微博
  10. csp认证考试准备Day-3