组合模式是操劳过度的JavaScript程序员的福音。。。。。。
因为,使用组合模式可以使用一条命令就(递归的)实现复杂的行为。
而这些行为是通过被委托给各个对象来实现的,就好像你只需要点亮树尖上的一盏灯,然后整个树上的灯就会依照你的代码依次被点亮。
组合对象的结构
组合对象中存在两种类型的对象:叶子对象和组合对象。叶子对象是组合模式中最基本的元素,也是所有操作最终被实现的地方。组合对象则由其他组合对象和叶子对象构成。
使用组合模式
使用组合模式的条件:
1、存在一批组织称某种层次体系的对象。
2、希望对这批对象全体或一部分实施某一个操作。
组合模式就是为了对一批对象进行操作的模式,它将对象组合成一颗树的样子,并且将命令从上向下进行传递。
栗子:表单验证
目标:创建一个有保存、恢复、验证功能的表单。
要求:表单中元素的内容和数目都是动态生成的,在编程过程中无法得知。
设计方案:
第一步:
实现过程中,我们会要求顶层的对象根据代码递归的调用子对象上的方法。例如,如果我们调用topForm.save(),那么整个域的代码都会进行保存。但是实际上,真正执行了保存操作的是叶子结点(input/select/textarea)。
第二步:创建动态表单,实现save和validate
组合节点:
(如下代码中用到的接口模式代码见:http://blog.csdn.net/u014328357/article/details/70145306)
// 定义两个接口
var Composite = new Interface('Composite',['add','remove','getChild']);
var FormItem = new Interface('FormItem',['save']);
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){
Interface.ensureImplements(child,Composite,FormItem);
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(this.formComponents[i] === child){
this.formComponents.splice(i,1);
break;
}
}
}
在对save方法的实现中我们很容易就发现了组合模式的工作方法:遍历子对象,并对它们调用同样的方法。
叶子结点:
var Field = function(id){
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 super class Field');
};
这个对象将被作为‘父类’,由不同的叶子对象继承。下面给出inputField的代码:
var InputField = function(id,label){
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);
InputField.prototype.getValue = function(){
return this.input.value;
}
根据input的代码,我们可以仿照写出select和textarea的代码。
汇总
这部分体现了组合模式的优势所在,无论有多少个表单,对整个组合对象执行操作只需要调用一个函数即可。
var contactForm = new CompositeForm('contact-form','POST','contact.php');
contactForm.add(new InputField('firstName','First Name'));
contactForm.add(new InputField('lastName','Last Name'));
contactForm.add(new InputField('address','Address'));
contactForm.add(new InputField('city','City'));
contactForm.add(new SelectField('state','State',stateArray));
......
addEvent(window,'unload',contactForm.save);//一个函数即可保存所有表单内容
在此基础上,我们可以为FormItem接口添加其他操作,或者向层次体系中添加新的类(也就是向组合模式的树上添加新的节点)。
组合模式的弊端:
有遍历操作,可能会影响性能。