组合模式就是指在页面表现中,通过一条指令而达到在多个对象中的复杂的递归行为,就是通过控制一个对象,不过该对象复杂的递归下去又是很多复杂的对象,同时控制对象的行为。这样简化代码,可维护,复杂的对象的行为委托给一个对象。
组合模式确实能对于工作能起到简化作用,组合对象实现某一操作时,通过递归,向下传递到所有的组成对象,在存在大批对象时,假如页面的包含许多拥有同样功能的对象,只需要操作组合对象即可达到目标。在存在存在着某种的层次结构,并且其中的一部分要实现某些操作,即可使用组合模式。
下面是组合模式书上的例子,展示了表单验证与图片阅读器。
表单验证中,需要做的工作是表单的保存、恢复和验证表单中的值,然而表单的数量是未知数,类型是未知数,只有功能能确定的情况下,使用组合模式无疑最好,通过给每个表单添加功能,然后一个表单对象组合起来,通过操作表单对象即可达到操作表单。
图片阅读器与表单验证基本一样,通过汇合操作图片。
<!DOCTYPE HTML>
<html>
<head>
<style>
</style>
</head>
<body>
<input value="存储" type="button" οnclick="a()" />
<input value="取出" type="button" οnclick="b()" />
<input value="隐藏" type="button" οnclick="c()" />
<input value="显示" type="button" οnclick="d()" />
</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');
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'));
var stateArray=[];
contactForm.add(new SelectField('state','State',stateArray));
contactForm.add(new InputField('zip','Zip'));
contactForm.add(new TextareaField('comments','Comments'));
contactForm.save(); */
//用组合模式汇合起来
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();
}
//图片库
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/abc1.jpg'));
topGallery.add(new GalleryImage('img/abc2.jpg'));
topGallery.add(new GalleryImage('img/abc3.jpg'));
var vacationPhotos=new DynamicGallery('vacation-photos');
for(var p=0;p<30;p++){
vacationPhotos.add(new GalleryImage('img/abc3.jpg'));
}
topGallery.add(vacationPhotos);
document.body.appendChild(topGallery.getElement());
function c(){
topGallery.hide();
}
function d(){
topGallery.show();
}
</script>
</html>
组合模式通过简单的操作就能达到复杂的效果,一个操作通过遍历递归传递这个操作。不过组合模式的弱点也在于此,如果层次过多,则性能将受到影响。
组合模式应用场所 应用在对一批对象具有相同的动作的情况下适用,并产生递归的条件下。即是符合两个条件,一是产生递归,二是具有相同的动作。