设计模式中的组合模式在JavaScript程序构建中的使用


Posted in Javascript onMay 18, 2016

定义

组合,顾名思义是指用包含多个部件的对象创建单一实体。 这个单一实体将用作所有这些部件的访问点,虽然这大大简化了操作,但也可能具有相当的欺骗性,因为没有哪种隐性方式明确表明该组合包含多少部件。
组合模式的目标是解耦客户程序与复杂元素内部架构,使得客户程序对待所有子元素都一视同仁。

每个子节点都可以使复杂的存在,对于父节点来说,不需要知道子节点的复杂性或者实现子节点的复杂性,只需要关注子节点的特定方法,便可以使用子节点。简化了父和子之间的关系。

对于子节点来说也是一样的,过多的接口暴露有时候也是一种滥用,同时也减少了对外部的依赖。

示例
我们最好使用例证解说组合。 在下图中,您可以看到两种不同类型的对象: 容器和库是组合,图像是叶片。 组合可承载子项,但一般不会实施更多行为。 叶片包含绝大多数行为,但不能承载子项,至少在传统的组合示例中不可以。

设计模式中的组合模式在JavaScript程序构建中的使用

此示例创建图片库,将其作为组合模式示例。 只有三个层次: 专辑、库和图像。 专辑和库将作为组合,图像是叶片,如上面那张图所示。这是一种比组合本身需求更加明确的结构,但对于本示例而言,将这些层次仅限制为组合或叶片很有意义。 标准组合不会限制哪些结构层次可以具有叶片,也不会限制叶片数量。

要开始操作,应首先创建用于专辑和库的 GalleryComposite“类”。 请注意,我正在使用 jQuery 执行 DOM 操作以简化过程。

var GalleryComposite = function (heading, id) {
  this.children = [];

  this.element = $('<div id="' + id + '" class="composite-gallery"></div>')
  .append('<h2>' + heading + '</h2>');
}

GalleryComposite.prototype = {
  add: function (child) {
    this.children.push(child);
    this.element.append(child.getElement());
  },

  remove: function (child) {
    for (var node, i = 0; node = this.getChild(i); i++) {
      if (node == child) {
        this.children.splice(i, 1);
        this.element.detach(child.getElement());
        return true;
      }

      if (node.remove(child)) {
        return true;
      }
    }

    return false;
  },

  getChild: function (i) {
    return this.children[i];
  },

  hide: function () {
    for (var node, i = 0; node = this.getChild(i); i++) {
      node.hide();
    }

    this.element.hide(0);
  },

  show: function () {
    for (var node, i = 0; node = this.getChild(i); i++) {
      node.show();
    }

    this.element.show(0);
  },

  getElement: function () {
    return this.element;
  }
}

这个位置有点棘手,能否允许我再更多的解释一下? 我们同时使用 add, remove, 和getChild getChild 方法构建这一组合。 本示例不会实际使用 remove 和 getChild,但它们对于创建动态组合非常有用。 hide, show, 和getElement 方法则用来操纵 DOM。 该组合旨在作为库的 表示在页面上向用户展示。 该组合可通过 hide 和 show控制这些库元素。 如果在专辑上调用 hide,则整个专辑将消失,或者您也可以只在单一图像上调用它,这样只有该图像会消失。

现在,创建一个 GalleryImage类。 请注意,它使用的方法与 GalleryComposite完全相同。 换句话说,它们实现同一接口,不同的是该图像是叶片,因此不会实际对子项相关方法执行任何操作,就像不具有任何子项一样。 必须使用同一接口运行该组合,因为组合元素不知道自身添加的是另一个组合元素还是叶片,因此如果尝试在其子项上调用这些方法,则需要运行完全正常,没有任何错误。

var GalleryImage = function (src, id) {
  this.children = [];

  this.element = $('<img />')
  .attr('id', id)
  .attr('src', src);
}

GalleryImage.prototype = {
  // Due to this being a leaf, it doesn't use these methods,
  // but must implement them to count as implementing the
  // Composite interface
  add: function () { },

  remove: function () { },

  getChild: function () { },

  hide: function () {
    this.element.hide(0);
  },

  show: function () {
    this.element.show(0);
  },

  getElement: function () {
    return this.element;
  }
}

鉴于您已经构建了对象原型,您现已能够进行使用。 从下面您可以看到实际构建图像库的代码。

var container = new GalleryComposite('', 'allgalleries');
var gallery1 = new GalleryComposite('Gallery 1', 'gallery1');
var gallery2 = new GalleryComposite('Gallery 2', 'gallery2');
var image1 = new GalleryImage('image1.jpg', 'img1');
var image2 = new GalleryImage('image2.jpg', 'img2');
var image3 = new GalleryImage('image3.jpg', 'img3');
var image4 = new GalleryImage('image4.jpg', 'img4');

gallery1.add(image1);
gallery1.add(image2);

gallery2.add(image3);
gallery2.add(image4);

container.add(gallery1);
container.add(gallery2);

// Make sure to add the top container to the body,
// otherwise it'll never show up.
container.getElement().appendTo('body');
container.show();

组合模式之利:
简单的操作也能产生复杂的结果,只需对最顶层的对象执行操作,让每一个子对象自己传递这个操作即可。这对于那些再三执行的操作尤其有用。

在组合模式中,各个对象之间的耦合非常松散。只要它们实现了同样的接口那么改变它们的位置或互换它们只是举手之劳。着促进了代码的重用,也有利于代码重构。

每当对顶层组合对象执行一个操作时,实际上是在对整个结构进行深度优先的搜索以查找节点,而创建组合对象的程序员对这些细节一无所知。在这个层次体系中添加、删除和查找节点都非常容易。

组合模式之弊:
组合对象的易用性可能掩盖了它所支持的每一种操作的代价。由于组合对象调用的任何操作都会被传递到它的所有子对象如果这个层次体系很大的话,系统的性能将会受到影响。组合模式的正常运作需要用到某种形式的接口。

组合对象和节点类被用作HTML元素的包装工具时,组合对象必须遵守HTML的使用规则。例如,表格就很难转化为一个组合对象。

接口检查越严格,组合对象类也就越可靠。

Javascript 相关文章推荐
escape编码与unescape解码汉字出现乱码的解决方法
Jul 02 Javascript
JavaScript设计模式之观察者模式(发布者-订阅者模式)
Sep 24 Javascript
原生js实现移动开发轮播图、相册滑动特效
Apr 17 Javascript
jQuery网页右侧广告跟随滚动代码分享
Apr 20 Javascript
基于JavaScript实现跳转提示页面
Sep 24 Javascript
AngularJS控制器之间的通信方式详解
Nov 03 Javascript
Vue2.x中的父组件传递数据至子组件的方法
May 01 Javascript
详谈vue+webpack解决css引用图片打包后找不到资源文件的问题
Mar 06 Javascript
基于Vue 2.0 监听文本框内容变化及ref的使用说明介绍
Aug 24 Javascript
详解vue数组遍历方法forEach和map的原理解析和实际应用
Nov 15 Javascript
vue单文件组件lint error自动fix与styleLint报错自动fix详解
Jan 08 Javascript
使用koa2创建web项目的方法步骤
Mar 12 Javascript
easyui window refresh 刷新两次的解决方法(推荐)
May 18 #Javascript
详解JavaScript设计模式开发中的桥接模式使用
May 18 #Javascript
jquery解析XML及获取XML节点名称的实现代码
May 18 #Javascript
Jquery跨域获得Json的简单实例
May 18 #Javascript
jQuery 获取跨域XML(RSS)数据的相关总结分析
May 18 #Javascript
jQuery使用ajax跨域获取数据的简单实例
May 18 #Javascript
JQuery 的跨域方法推荐_可跨任何网站
May 18 #Javascript
You might like
smarty section简介与用法分析
2008/10/03 PHP
三个类概括PHP的五种设计模式
2012/09/05 PHP
php反射应用示例
2014/02/25 PHP
从零开始学YII2框架(二)通过 Composer 安装扩展插件
2014/08/20 PHP
Joomla使用Apache重写模式的方法
2016/05/04 PHP
PHP类型约束用法示例
2016/09/28 PHP
PHP字典树(Trie树)定义与实现方法示例
2017/10/09 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
innerText和innerHTML 一些问题分析
2009/05/18 Javascript
Exitjs获取DataView中图片文件名
2009/11/26 Javascript
javaScript 关闭浏览器 (不弹出提示框)
2010/01/31 Javascript
深入理解JavaScript高级之词法作用域和作用域链
2013/12/10 Javascript
iframe里面的元素触发父窗口元素事件的jquery代码
2014/10/19 Javascript
微信小程序  简单实例(阅读器)的实例开发
2016/09/29 Javascript
Bootstrap基本组件学习笔记之按钮组(8)
2016/12/07 Javascript
Angular.Js中ng-include指令的使用与实现
2017/05/07 Javascript
Vue.js学习笔记之常用模板语法详解
2017/07/25 Javascript
vue-cli常用设置总结
2018/02/24 Javascript
jQuery实现模糊搜索功能的方法分析
2018/06/29 jQuery
详解React 的几种条件渲染以及选择
2018/10/23 Javascript
JavaScript数组常用的增删改查与其他属性详解
2020/10/13 Javascript
[01:04:31]DOTA2-DPC中国联赛定级赛 iG vs Magma BO3第二场 1月8日
2021/03/11 DOTA
python 开发的三种运行模式详细介绍
2017/01/18 Python
浅析Python四种数据类型
2018/09/26 Python
Django 自动生成api接口文档教程
2019/11/19 Python
Python print不能立即打印的解决方式
2020/02/19 Python
Python错误的处理方法
2020/06/23 Python
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
艺术系应届生的自我评价
2013/10/19 职场文书
生产文员岗位职责
2014/04/05 职场文书
校优秀毕业生主要事迹
2014/05/26 职场文书
班级出游活动计划书
2014/08/15 职场文书
会计学习心得体会
2014/09/09 职场文书
给客户的感谢信
2015/01/21 职场文书
2016年12月份红领巾广播稿
2015/12/21 职场文书
python中24小时制转换为12小时制的方法
2021/06/18 Python