之前一直都是按照书的结构顺序做总结,觉得好像不是很好,现在试着完全按照自己的理解做总结。例子还是书上的例子。

一:组合模式的作用
在web开发中,主要用于创建嵌套的html结点,使得我们方便的把各种结点连接起来,并且提供简易的操作。
 

二:组合模式的结构

结构就像我们的文件结构一样讲Composite理解为文件夹,Leaf理解为文件就好理解了。

 
三:例子一,创建一个组合的表单
需求:试想着我们想要构建一个表单,但是表单域经常要被产品经理修改,我们怎样才能利用js快速的搭建这个form呢?此外,我们有个功能,就是可以保存用户填写的表单,那么我们一般的做法是手动把一个个表单域保存到cookie中,如何才能通过一个操作就完成所有表单域的保存呢?
 
利用组合模式实现是这样的:
 
思路:创建一个组合表单类CompositeForm,这个类有操作表单域的方法add(),和remove(),传入的参数就是对应的表单域类(InputField,TextareaField等),这样我们就可以很方便的组合表单了。对于保存表单域的功能,我们只要给CompositeForm弄一个save()方法就可以了,这个save()方法就遍历它下面的表单域,自动的保存每个表单域。
 
具体实现:
步骤一:
创建接口,保证表单和表单域都有必须的方法
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var FormItem = new Interface('FormItem', ['save']);
步骤二:
定义组合表单类CompositeForm
var CompositeForm = function(id, method, action) { // implements Composite, FormItem
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) {
Interface.ensureImplements(child, Composite, FormItem);
this.formComponents.push(child);
this.element.appendChild(child.getElement());
}; CompositeForm.prototype.remove = function(child) {
for(var i = , len = this.formComponents.length; i < len; i++) {
if(this.formComponents[i] === child) {
this.formComponents.splice(i, ); // Remove one element from the array at
// position i.
break;
}
}
}; CompositeForm.prototype.getChild = function(i) {
return this.formComponents[i];
}; CompositeForm.prototype.save = function() {
for(var i = , len = this.formComponents.length; i < len; i++) {
this.formComponents[i].save();
}
}; CompositeForm.prototype.getElement = function() {
return this.element;
};
步骤三:
创建Field类,用来派生出表单域的类
var Field = function(id) { // implements Composite, FormItem
this.id = id;
this.element;
}; 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('Unsupported operation on the class Field.');
};
步骤三
创建特定的表单域类
var InputField = function(id, label) { // implements Composite, FormItem
Field.call(this, id); this.input = document.createElement('input');
this.input.id = id; this.label = document.createElement('label');
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode); this.element = document.createElement('div');
this.element.className = 'input-field';
this.element.appendChild(this.label);
this.element.appendChild(this.input);
};
extend(InputField, Field); // Inherit from Field. InputField.prototype.getValue = function() {
return this.input.value;
}; /* TextareaField class. */ var TextareaField = function(id, label) { // implements Composite, FormItem
Field.call(this, id); this.textarea = document.createElement('textarea');
this.textarea.id = id; this.label = document.createElement('label');
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode); this.element = document.createElement('div');
this.element.className = 'input-field';
this.element.appendChild(this.label);
this.element.appendChild(this.textarea);
};
extend(TextareaField, Field); // Inherit from Field. TextareaField.prototype.getValue = function() {
return this.textarea.value;
}; /* SelectField class. */ var SelectField = function(id, label) { // implements Composite, FormItem
Field.call(this, id); this.select = document.createElement('select');
this.select.id = id; this.label = document.createElement('label');
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode); this.element = document.createElement('div');
this.element.className = 'input-field';
this.element.appendChild(this.label);
this.element.appendChild(this.select);
};
extend(SelectField, Field); // Inherit from Field. SelectField.prototype.getValue = function() {
return this.select.options[this.select.selectedIndex].value;
};
步骤四:
使用
var contactForm = new CompositeForm('contact-form', 'POST', 'contact.php');

contactForm.add(new InputField('first-name', 'First Name'));
contactForm.add(new InputField('last-name', 'Last Name'));
contactForm.add(new InputField('address', 'Address'));
contactForm.add(new InputField('city', 'City'));
contactForm.add(new SelectField('state', 'State', stateArray)); // var stateArray =
[{'al', 'Alabama'}, ...]
contactForm.add(new InputField('zip', 'Zip'));
contactForm.add(new TextareaField('comments', 'Comments')); addEvent(window, 'unload', contactForm.save);
点评:注意CompositeForm里面有formComponents这个属性,里面包含的是每一个表单域的对象,这样的话当我们要用到他们的时候就不用操作DOM来获取了。save()这个方法可以看一下,具体做法就是遍历表单的组件,逐一调用它们的save()方法。由于表单的结构要求,表单域不能嵌套form元素,所以这个例子还不能很好的诠释组合模式,最好情况下组合模式的组合程度是很高的。步骤四中的使用方法中,我们可以发现表单的动态创建是很简单的,保存方法的使用也是很简单,只要操作最contactForm这个变量就可以了。
书上还有一个对这个表单的扩展,这里就不展开了。
四:例子二,Image gallery
下面来看一个更好的例子:
需求:我们要创建一个图片集,图片集里面有图片集和图片,图片集下面又有图片集和图片。
思路:创建一个DynamicGallery类,这个类有add()、remove()等方法。add()方法可以传入DynamicGallery类和GalleryImage类。
 
实现:
步骤一:创建接口,保证上面提到的两个类符合要求
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var GalleryItem = new Interface('GalleryItem', ['hide', 'show']);
步骤二:创建DynamicGallery类
var DynamicGallery = function(id) { // implements Composite, GalleryItem
this.children = []; this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'dynamic-gallery';
} DynamicGallery.prototype = { // Implement the Composite interface. add: function(child) {
Interface.ensureImplements(child, Composite, GalleryItem);
this.children.push(child);
this.element.appendChild(child.getElement());
},
remove: function(child) {
for(var node, i = ; node = this.getChild(i); i++) {
if(node == child) {
this.formComponents[i].splice(i, );
break;
}
}
this.element.removeChild(child.getElement());
},
getChild: function(i) {
return this.children[i];
}, // Implement the GalleryItem interface. hide: function() {
for(var node, i = ; node = this.getChild(i); i++) {
node.hide();
}
this.element.style.display = 'none';
},
show: function() {
this.element.style.display = 'block';
for(var node, i = ; node = this.getChild(i); i++) {
node.show();
}
}, // Helper methods. getElement: function() {
return this.element;
}
};
第三步:创建GalleryImage类
var GalleryImage = function(src) { // implements Composite, GalleryItem
this.element = document.createElement('img');
this.element.className = 'gallery-image';
this.element.src = src;
} GalleryImage.prototype = { // Implement the Composite interface. add: function() {}, // This is a leaf node, so we don't
remove: function() {}, // implement these methods, we just
getChild: function() {}, // define them. // Implement the GalleryItem interface. hide: function() {
this.element.style.display = 'none';
},
show: function() {
this.element.style.display = ''; // Restore the display attribute to its
// previous setting.
}, // Helper methods. getElement: function() {
return this.element;
}
};
第四步:使用
var topGallery = new DynamicGallery('top-gallery');

topGallery.add(new GalleryImage('/img/image-1.jpg'));
topGallery.add(new GalleryImage('/img/image-2.jpg'));
topGallery.add(new GalleryImage('/img/image-3.jpg')); var vacationPhotos = new DynamicGallery('vacation-photos'); for(var i = ; i < ; i++) {
vacationPhotos.add(new GalleryImage('/img/vac/image-' + i + '.jpg'));
} topGallery.add(vacationPhotos);
topGallery.show(); // Show the main gallery,
vacationPhotos.hide(); // but hide the vacation gallery.
总结:在这个例子中,我们就可以把DynamicGallery当作是上面那个结构图的Composite,GalleryImage当作是Leaf来理解了。DynamicGallery的add方法可以添加DynamicGallery,这样我们就可以创造出不同的结构了
 

《javascript设计模式》笔记之第九章:组合模式的更多相关文章

  1. 设计模式之第22章-组合模式(Java实现)

    设计模式之第22章-组合模式(Java实现) “鱼哥,有没有什么模式是用来处理树形的“部分与整体”的层次结构的啊.”“当然”“没有?”“有啊.别急,一会人就到了.” 组合模式之自我介绍 “请问你是?怎 ...

  2. Javascript设计模式理论与实战:组合模式

    我们平时开发过程中,一定会遇到这种情况:同时处理简单对象和由简单对象组成的复杂对象,这些简单对象和复杂对象会组合成树形结构,在客户端对其处理的时候要保持一致性.比如电商网站中的产品订单,每一张产品订单 ...

  3. Javascript设计模式笔记

    Javascript是越来越厉害了,一统前后端开发.于是最近把设计模式又看了一遍,顺便做了个笔记,以方便自己和他人共同学习. 笔记连载详见:http://www.meteorcn.net/wordpr ...

  4. 第9章 组合模式(Composite Pattern)

    原文 第9章 组合模式(Composite Pattern) 概述: 组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理 ...

  5. 设计模式之第17章-备忘录模式(Java实现)

    设计模式之第17章-备忘录模式(Java实现) 好男人就是我,我就是曾小贤.最近陈赫和张子萱事件闹得那是一个沸沸扬扬.想想曾经每年都有爱情公寓陪伴的我现如今过年没有了爱情公寓总是感觉缺少点什么.不知道 ...

  6. 设计模式之第9章-原型模式(Java实现)

    设计模式之第9章-原型模式(Java实现) “快到春节了,终于快放假了,天天上班好累的说.”“确实啊,最近加班比较严重,项目快到交付了啊.”“话说一到过节,就收到铺天盖地的短信轰炸,你说发短信就发吧, ...

  7. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第九章:贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第九章:贴图 代码工程地址: https://github.com/j ...

  8. .NET设计模式(11):组合模式(Composite Pattern)(转)

    概述 组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦. 意图 将对 ...

  9. Java 设计模式系列(九)组合模式

    Java 设计模式系列(九)组合模式 将对象组合成树形结构以表示"部分-整体"的层次结构.组合模式使得用户对单个对象的使用具有一致性. 一.组合模式结构 Component: 抽象 ...

  10. 设计模式之第7章-外观模式(Java实现)

    设计模式之第7章-外观模式(Java实现) “鱼哥,知道怎么把大象装进冰箱里面么?”(作者按:这么简单的问题还想考我,早了几百年吧.)“把大象装进冰箱里,一共需要三步:第一步,把冰箱门打开:第二步,把 ...

随机推荐

  1. Qt属性系统(Qt Property System)

    Qt提供了巧妙的属性系统,它与某些编译器支持的属性系统相似.然而,作为平台和编译器无关的库,Qt不能够依赖于那些非标准的编译器特性,比如__property 或者 [property].Qt的解决方案 ...

  2. 使用google浏览器模拟手机终端的方法

    谷歌Chrome浏览器,可以很方便地用来当移动终端模拟器.在Windows的[开始]-->[运行]中输入以下命令,启动谷歌浏览器,即可模拟相应手机的浏览器去访问3G手机网页,前提:将先前开启的谷 ...

  3. MySQL 数据底部出现总计字样 第二种办法 纵向合并 20161103

    上次在博客http://www.cnblogs.com/Mr-Cxy/p/5923375.html 我们使用了group by with rollup 函数 field自定义排序 来实现添加底部总计字 ...

  4. 洛谷 P2285 [HNOI2004]打鼹鼠

    题目描述 鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的.根据这个特点阿牛编写了一个打鼹鼠的游戏:在一个n*n的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气. ...

  5. WPF TextBox PreviewTextInput handle IME (chinese)

    今天调试自己写的WPF的Behavior, 是关于TextBox只能输入数据或者小数点的. 发现有个问题, 就是英文IME下字母等等都能过滤, 但是一旦切换到中文输入法, 就会发现在OnPreview ...

  6. python基础知识-字符串

    字符串: 赋值方法 a = 'name' a = str('name') 字符串的方法: #!/usr/bin/env python class str(object): ""&q ...

  7. AI-Info-Micron-Insight:通往完全自主之路

    ylbtech-AI-Info-Micron-Insight:通往完全自主之路 1.返回顶部 1. 通往完全自主之路 自动驾驶汽车正在从未来梦想演变为当代现实,随着技术成熟,个人和公共交通将永远转变. ...

  8. border-radius实现圆弧阴影效果

    1 原理 利用border-radius实现一个圆弧边的矩形,并添加box-shadow,然后放在目标元素的下方 demo: html <div class="demo1"& ...

  9. 【VS工程设置】 编译动态库,命令行添加参数,不使用预编译头,指定该项目链接 哪种 运行库

    编译动态库 注意: 动态库: [目标文件扩展] => .dll + [配置类型] => 动态库(.dll) 静态库: [目标文件扩展] => .lib + [ 配置类型]=> ...

  10. 网络工具 NetCat

    http://netcat.sourceforge.net/ windows 版本 https://joncraton.org/blog/46/netcat-for-windows/ https:// ...