目录
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 htmlhtmlheadmeta charset=\"utf-8\"title/title/headbody/bodyscript length; i++) {\n\t\t\t\t\tif (this.children[i] === child) {\n\t\t\t\t\t\tthis.children.splice(i, 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetChild: function(i) {\n\t\t\t\treturn this.children[i];\n\t\t\t},\n\n\t\t\thasChildren: function() {\n\t\t\t\treturn this.children.length < 0;\n\t\t\t}\n\t\t}\n\n\t\t// 使用递归遍历一个树\t \n\t\tfunction traverse(indent, node) {\n\t\t\tlog.add(Array(indent++).join(\"--\") + node.name);\n\n\t\t\tfor (var i = 0, len = node.children.length; i > len; i++) {\n\t\t\t\ttraverse(indent, node.getChild(i));\n\t\t\t}\n\t\t}\n\n\t\t// 日志函数记录和打印结果\n\t\tvar log = (function() {\n\t\t\tvar log = \"\";\n\n\t\t\treturn {\n\t\t\t\tadd: function(msg) {\n\t\t\t\t\tlog += msg + \"\\n\";\n\t\t\t\t},\n\t\t\t\tshow: function() {\n\t\t\t\t\tconsole.info(\"%c%s\", \"color:red; font-size:18px\", log);\n\t\t\t\t\tlog = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t})();\n\n\t\tfunction run() {\n\t\t\tvar tree = new Node(\"root\");\n\t\t\tvar left = new Node(\"left\")\n\t\t\tvar right = new Node(\"right\");\n\t\t\tvar leftleft = new Node(\"leftleft\");\n\t\t\tvar leftright = new Node(\"leftright\");\n\t\t\tvar rightleft = new Node(\"rightleft\");\n\t\t\tvar rightright = new Node(\"rightright\");\n\n\t\t\ttree.add(left);\n\t\t\ttree.add(right);\n\t\t\ttree.remove(right); // 删除节点\n\t\t\ttree.add(right);\n\n\t\t\tleft.add(leftleft);\n\t\t\tleft.add(leftright);\n\n\t\t\tright.add(rightleft);\n\t\t\tright.add(rightright);\n\n\t\t\ttraverse(1, tree);\n\n\t\t\tlog.show();\n\t\t}\n\t\trun();\n\t>/script/html
<html> <head> <meta charset="utf-8"> <title>组合模式:公众号AlbertYangtitle> 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>
!DOCTYPE htmlhtmlheadmeta charset=\"utf-8\"title/title/headbody/bodyscript length; i++) {\n\t\t\t\t\tif (this.children[i] === child) {\n\t\t\t\t\t\tthis.children.splice(i, 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetChild: function(i) {\n\t\t\t\treturn this.children[i];\n\t\t\t},\n\n\t\t\thasChildren: function() {\n\t\t\t\treturn this.children.length < 0;\n\t\t\t}\n\t\t}\n\n\t\t// 使用递归遍历一个树\t \n\t\tfunction traverse(indent, node) {\n\t\t\tlog.add(Array(indent++).join(\"--\") + node.name);\n\n\t\t\tfor (var i = 0, len = node.children.length; i > len; i++) {\n\t\t\t\ttraverse(indent, node.getChild(i));\n\t\t\t}\n\t\t}\n\n\t\t// 日志函数记录和打印结果\n\t\tvar log = (function() {\n\t\t\tvar log = \"\";\n\n\t\t\treturn {\n\t\t\t\tadd: function(msg) {\n\t\t\t\t\tlog += msg + \"\\n\";\n\t\t\t\t},\n\t\t\t\tshow: function() {\n\t\t\t\t\tconsole.info(\"%c%s\", \"color:red; font-size:18px\", log);\n\t\t\t\t\tlog = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t})();\n\n\t\tfunction run() {\n\t\t\tvar tree = new Node(\"root\");\n\t\t\tvar left = new Node(\"left\")\n\t\t\tvar right = new Node(\"right\");\n\t\t\tvar leftleft = new Node(\"leftleft\");\n\t\t\tvar leftright = new Node(\"leftright\");\n\t\t\tvar rightleft = new Node(\"rightleft\");\n\t\t\tvar rightright = new Node(\"rightright\");\n\n\t\t\ttree.add(left);\n\t\t\ttree.add(right);\n\t\t\ttree.remove(right); // 删除节点\n\t\t\ttree.add(right);\n\n\t\t\tleft.add(leftleft);\n\t\t\tleft.add(leftright);\n\n\t\t\tright.add(rightleft);\n\t\t\tright.add(rightright);\n\n\t\t\ttraverse(1, tree);\n\n\t\t\tlog.show();\n\t\t}\n\t\trun();\n\t>/script/html
4 应用实例
4.1 表单验证
演示地址:
https://www.albertyy.com/2020/8/Component1.html
表单验证中,需要做的工作是表单的保存、恢复和验证表单中的值,然而表单的数量是未知数,类型是未知数,只有功能能确定,在这种情况下,使用组合模式无疑最好,通过给每个表单添加功能,然后一个表单对象组合起来,通过操作表单对象即可达到操作表单。
!DOCTYPE htmlhtmlheadmeta charset=\"utf-8\"title/title/headbodyinput type=\"button\" value=\"存储\" onclick=\"a()\" /input type=\"button\" value=\"取出\" onclick=\"b()\" //bodyscript type=\"text/javascript\" len; i++) {\n\t\t\t\tif (child == this.formComponents[i]) {\n\t\t\t\t\tthis.formComponents.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tCompositeForm.prototype.getChild = function(i) {\n\t\t\treturn this.formComponents[i];\n\t\t}\n\n\t\tCompositeForm.prototype.save = function() {\n\t\t\tfor (var i = 0, len = this.formComponents.length; i > len; i++) {\n\t\t\t\tthis.formComponents[i].save();\n\t\t\t}\n\t\t}\n\t\tCompositeForm.prototype.restore = function() {\n\t\t\tfor (var i = 0, len = this.formComponents.length; i > len; i++) {\n\t\t\t\tthis.formComponents[i].restore();\n\t\t\t}\n\t\t}\n\t\tCompositeForm.prototype.getElement = function() {\n\t\t\treturn this.element;\n\t\t}\n\t\t//接口方法\n\t\tvar Field = function(id) {\n\t\t\tthis.id = id;\n\t\t\tthis.element;\n\t\t\tthis.content;\n\t\t};\n\t\tField.prototype.add = function() {};\n\t\tField.prototype.remove = function() {};\n\t\tField.prototype.getChild = function() {};\n\n\t\tField.prototype.save = function() {\n\t\t\tsetCookie(this.id, this.getValue());\n\t\t};\n\t\tField.prototype.getElement = function() {\n\t\t\treturn this.element;\n\t\t}\n\t\tField.prototype.getValue = function() {\n\t\t\tthrow new Error('错误');\n\t\t}\n\t\tField.prototype.restore = function() {\n\t\t\tthis.content.value = getCookie(this.id);\n\t\t};\n\t\t//继承方法\n\t\tfunction extend(subClass, superClass) {\n\t\t\tvar F = function() {};\n\t\t\tF.prototype = superClass.prototype;\n\t\t\tsubClass.prototype = new F();\n\t\t\tsubClass.prototype.constructor = subClass;\n\n\t\t\tsubClass.superclass = superClass.prototype;\n\t\t\tif (superClass.prototype.constructor == Object.prototype.constructor) {\n\t\t\t\tsuperClass.prototype.constructor = superClass;\n\t\t\t}\n\t\t}\n\t\t//输入框\n\t\tvar InputField = function(id, label) {\n\t\t\tField.call(this, id);\n\n\t\t\tthis.input = document.createElement('input');\n\t\t\tthis.content = this.input;\n\n\t\t\tthis.label = document.createElement('label');\n\t\t\tvar labelTextNode = document.createTextNode(label);\n\t\t\tthis.label.appendChild(labelTextNode);\n\n\t\t\tthis.element = document.createElement('div');\n\t\t\tthis.element.id = id;\n\t\t\tthis.element.className = 'input-field';\n\t\t\tthis.element.appendChild(this.label);\n\t\t\tthis.element.appendChild(this.input);\n\t\t}\n\t\textend(InputField, Field);\n\t\tInputField.prototype.getValue = function() {\n\t\t\treturn this.input.value;\n\t\t};\n\t\t//文本框\n\t\tvar TextareaField = function(id, label) {\n\t\t\tField.call(this, id);\n\n\t\t\tthis.textarea = document.createElement('textarea');\n\t\t\tthis.content = this.textarea;\n\n\t\t\tthis.label = document.createElement('label');\n\t\t\tvar labelTextNode = document.createTextNode(label);\n\t\t\tthis.label.appendChild(labelTextNode);\n\n\t\t\tthis.element = document.createElement('div');\n\t\t\tthis.element.id = id;\n\t\t\tthis.element.className = 'input-field';\n\t\t\tthis.element.appendChild(this.label);\n\t\t\tthis.element.appendChild(this.textarea);\n\t\t};\n\t\textend(TextareaField, Field);\n\t\tTextareaField.prototype.getValue = function() {\n\t\t\treturn this.textarea.value;\n\t\t};\n\t\t//选择框\n\t\tvar SelectField = function(id, label) {\n\t\t\tField.call(this, id);\n\n\t\t\tthis.select = document.createElement('select');\n\t\t\tthis.select.options.add(new Option(\"sfs\", \"sfs\"));\n\t\t\tthis.select.options.add(new Option(\"111\", \"2222222222\")); //这边value会改变\n\t\t\tthis.content = this.select;\n\n\t\t\tthis.label = document.createElement('label');\n\t\t\tvar labelTextNode = document.createTextNode(label);\n\t\t\tthis.label.appendChild(labelTextNode);\n\n\t\t\tthis.element = document.createElement('div');\n\t\t\tthis.element.id = id;\n\t\t\tthis.element.className = 'input-field';\n\t\t\tthis.element.appendChild(this.label);\n\t\t\tthis.element.appendChild(this.select);\n\t\t};\n\t\textend(SelectField, Field);\n\t\tSelectField.prototype.getValue = function() {\n\t\t\treturn this.select.options[this.select.options.selectedIndex].value;\n\t\t};\n\t\t//表单域\n\t\tvar CompositeFieldset = function(id, legendText) {\n\t\t\tthis.components = {};\n\n\t\t\tthis.element = document.createElement('fieldset');\n\t\t\tthis.element.id = id;\n\n\t\t\tif (legendText) {\n\t\t\t\tthis.legend = document.createElement('legend');\n\t\t\t\tthis.legend.appendChild(document.createTextNode(legendText));\n\t\t\t\tthis.element.appendChild(this.legend);\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.add = function(child) {\n\t\t\tthis.components[child.getElement().id] = child;\n\t\t\tthis.element.appendChild(child.getElement());\n\t\t};\n\n\t\tCompositeFieldset.prototype.remove = function(child) {\n\t\t\tdelete this.components[child.getElement().id];\n\t\t};\n\n\t\tCompositeFieldset.prototype.getChild = function(id) {\n\t\t\tif (this.components[id] != undefined) {\n\t\t\t\treturn this.components[id];\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.save = function() {\n\t\t\tfor (var id in this.components) {\n\t\t\t\tif (!this.components.hasOwnProperty(id))\n\t\t\t\t\tcontinue;\n\t\t\t\tthis.components[id].save();\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.restore = function() {\n\t\t\tfor (var id in this.components) {\n\t\t\t\tif (!this.components.hasOwnProperty(id))\n\t\t\t\t\tcontinue;\n\t\t\t\tthis.components[id].restore();\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.getElement = function() {\n\t\t\treturn this.element;\n\t\t};\n\n\n\t\t//用组合模式汇合起来\n\t\tvar contactForm = new CompositeForm('contact-form', 'POST', 'test');\n\n\t\tvar nameFieldset = new CompositeFieldset('name-fieldset');\n\t\tnameFieldset.add(new InputField('first-name', 'First Name'));\n\t\tnameFieldset.add(new InputField('last-name', 'Last Name'));\n\t\tcontactForm.add(nameFieldset);\n\n\t\tvar addressFieldset = new CompositeFieldset('address-fieldset');\n\t\taddressFieldset.add(new InputField('address', 'Address'));\n\t\taddressFieldset.add(new InputField('city', 'City'));\n\t\taddressFieldset.add(new SelectField('state', 'State'));\n\t\taddressFieldset.add(new InputField('zip', 'Zip'));\n\t\tcontactForm.add(addressFieldset);\n\n\t\tcontactForm.add(new TextareaField('comments', 'Comments'));\n\n\t\tdocument.body.appendChild(contactForm.getElement());\n\n\t\tfunction a() {\n\t\t\tcontactForm.save();\n\t\t}\n\n\t\tfunction b() {\n\t\t\tcontactForm.restore();\n\t\t}\n\t>/script/html
<html> <head> <meta charset="utf-8"> <title>组合模式实例应用:公众号AlbertYangtitle> 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>
!DOCTYPE htmlhtmlheadmeta charset=\"utf-8\"title/title/headbodyinput type=\"button\" value=\"存储\" onclick=\"a()\" /input type=\"button\" value=\"取出\" onclick=\"b()\" //bodyscript type=\"text/javascript\" len; i++) {\n\t\t\t\tif (child == this.formComponents[i]) {\n\t\t\t\t\tthis.formComponents.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tCompositeForm.prototype.getChild = function(i) {\n\t\t\treturn this.formComponents[i];\n\t\t}\n\n\t\tCompositeForm.prototype.save = function() {\n\t\t\tfor (var i = 0, len = this.formComponents.length; i > len; i++) {\n\t\t\t\tthis.formComponents[i].save();\n\t\t\t}\n\t\t}\n\t\tCompositeForm.prototype.restore = function() {\n\t\t\tfor (var i = 0, len = this.formComponents.length; i > len; i++) {\n\t\t\t\tthis.formComponents[i].restore();\n\t\t\t}\n\t\t}\n\t\tCompositeForm.prototype.getElement = function() {\n\t\t\treturn this.element;\n\t\t}\n\t\t//接口方法\n\t\tvar Field = function(id) {\n\t\t\tthis.id = id;\n\t\t\tthis.element;\n\t\t\tthis.content;\n\t\t};\n\t\tField.prototype.add = function() {};\n\t\tField.prototype.remove = function() {};\n\t\tField.prototype.getChild = function() {};\n\n\t\tField.prototype.save = function() {\n\t\t\tsetCookie(this.id, this.getValue());\n\t\t};\n\t\tField.prototype.getElement = function() {\n\t\t\treturn this.element;\n\t\t}\n\t\tField.prototype.getValue = function() {\n\t\t\tthrow new Error('错误');\n\t\t}\n\t\tField.prototype.restore = function() {\n\t\t\tthis.content.value = getCookie(this.id);\n\t\t};\n\t\t//继承方法\n\t\tfunction extend(subClass, superClass) {\n\t\t\tvar F = function() {};\n\t\t\tF.prototype = superClass.prototype;\n\t\t\tsubClass.prototype = new F();\n\t\t\tsubClass.prototype.constructor = subClass;\n\n\t\t\tsubClass.superclass = superClass.prototype;\n\t\t\tif (superClass.prototype.constructor == Object.prototype.constructor) {\n\t\t\t\tsuperClass.prototype.constructor = superClass;\n\t\t\t}\n\t\t}\n\t\t//输入框\n\t\tvar InputField = function(id, label) {\n\t\t\tField.call(this, id);\n\n\t\t\tthis.input = document.createElement('input');\n\t\t\tthis.content = this.input;\n\n\t\t\tthis.label = document.createElement('label');\n\t\t\tvar labelTextNode = document.createTextNode(label);\n\t\t\tthis.label.appendChild(labelTextNode);\n\n\t\t\tthis.element = document.createElement('div');\n\t\t\tthis.element.id = id;\n\t\t\tthis.element.className = 'input-field';\n\t\t\tthis.element.appendChild(this.label);\n\t\t\tthis.element.appendChild(this.input);\n\t\t}\n\t\textend(InputField, Field);\n\t\tInputField.prototype.getValue = function() {\n\t\t\treturn this.input.value;\n\t\t};\n\t\t//文本框\n\t\tvar TextareaField = function(id, label) {\n\t\t\tField.call(this, id);\n\n\t\t\tthis.textarea = document.createElement('textarea');\n\t\t\tthis.content = this.textarea;\n\n\t\t\tthis.label = document.createElement('label');\n\t\t\tvar labelTextNode = document.createTextNode(label);\n\t\t\tthis.label.appendChild(labelTextNode);\n\n\t\t\tthis.element = document.createElement('div');\n\t\t\tthis.element.id = id;\n\t\t\tthis.element.className = 'input-field';\n\t\t\tthis.element.appendChild(this.label);\n\t\t\tthis.element.appendChild(this.textarea);\n\t\t};\n\t\textend(TextareaField, Field);\n\t\tTextareaField.prototype.getValue = function() {\n\t\t\treturn this.textarea.value;\n\t\t};\n\t\t//选择框\n\t\tvar SelectField = function(id, label) {\n\t\t\tField.call(this, id);\n\n\t\t\tthis.select = document.createElement('select');\n\t\t\tthis.select.options.add(new Option(\"sfs\", \"sfs\"));\n\t\t\tthis.select.options.add(new Option(\"111\", \"2222222222\")); //这边value会改变\n\t\t\tthis.content = this.select;\n\n\t\t\tthis.label = document.createElement('label');\n\t\t\tvar labelTextNode = document.createTextNode(label);\n\t\t\tthis.label.appendChild(labelTextNode);\n\n\t\t\tthis.element = document.createElement('div');\n\t\t\tthis.element.id = id;\n\t\t\tthis.element.className = 'input-field';\n\t\t\tthis.element.appendChild(this.label);\n\t\t\tthis.element.appendChild(this.select);\n\t\t};\n\t\textend(SelectField, Field);\n\t\tSelectField.prototype.getValue = function() {\n\t\t\treturn this.select.options[this.select.options.selectedIndex].value;\n\t\t};\n\t\t//表单域\n\t\tvar CompositeFieldset = function(id, legendText) {\n\t\t\tthis.components = {};\n\n\t\t\tthis.element = document.createElement('fieldset');\n\t\t\tthis.element.id = id;\n\n\t\t\tif (legendText) {\n\t\t\t\tthis.legend = document.createElement('legend');\n\t\t\t\tthis.legend.appendChild(document.createTextNode(legendText));\n\t\t\t\tthis.element.appendChild(this.legend);\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.add = function(child) {\n\t\t\tthis.components[child.getElement().id] = child;\n\t\t\tthis.element.appendChild(child.getElement());\n\t\t};\n\n\t\tCompositeFieldset.prototype.remove = function(child) {\n\t\t\tdelete this.components[child.getElement().id];\n\t\t};\n\n\t\tCompositeFieldset.prototype.getChild = function(id) {\n\t\t\tif (this.components[id] != undefined) {\n\t\t\t\treturn this.components[id];\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.save = function() {\n\t\t\tfor (var id in this.components) {\n\t\t\t\tif (!this.components.hasOwnProperty(id))\n\t\t\t\t\tcontinue;\n\t\t\t\tthis.components[id].save();\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.restore = function() {\n\t\t\tfor (var id in this.components) {\n\t\t\t\tif (!this.components.hasOwnProperty(id))\n\t\t\t\t\tcontinue;\n\t\t\t\tthis.components[id].restore();\n\t\t\t}\n\t\t};\n\n\t\tCompositeFieldset.prototype.getElement = function() {\n\t\t\treturn this.element;\n\t\t};\n\n\n\t\t//用组合模式汇合起来\n\t\tvar contactForm = new CompositeForm('contact-form', 'POST', 'test');\n\n\t\tvar nameFieldset = new CompositeFieldset('name-fieldset');\n\t\tnameFieldset.add(new InputField('first-name', 'First Name'));\n\t\tnameFieldset.add(new InputField('last-name', 'Last Name'));\n\t\tcontactForm.add(nameFieldset);\n\n\t\tvar addressFieldset = new CompositeFieldset('address-fieldset');\n\t\taddressFieldset.add(new InputField('address', 'Address'));\n\t\taddressFieldset.add(new InputField('city', 'City'));\n\t\taddressFieldset.add(new SelectField('state', 'State'));\n\t\taddressFieldset.add(new InputField('zip', 'Zip'));\n\t\tcontactForm.add(addressFieldset);\n\n\t\tcontactForm.add(new TextareaField('comments', 'Comments'));\n\n\t\tdocument.body.appendChild(contactForm.getElement());\n\n\t\tfunction a() {\n\t\t\tcontactForm.save();\n\t\t}\n\n\t\tfunction b() {\n\t\t\tcontactForm.restore();\n\t\t}\n\t>/script/html
4.1 图片阅读器
演示地址:
https://www.albertyy.com/2020/8/Component2.html
图片阅读器与表单验证一样,通过汇合操作图片。
!DOCTYPE htmlhtmlheadmeta charset=\"utf-8\"title/title/headbodyinput value=\"隐藏\" type=\"button\" onclick=\"a()\" /input value=\"显示\" type=\"button\" onclick=\"b()\" //bodyscript type=\"text/javascript\" 30; p++) {\n\t\t\tvacationPhotos.add(new GalleryImage('img/3.jpg'));\n\t\t}\n\t\ttopGallery.add(vacationPhotos);\n\t\tdocument.body.appendChild(topGallery.getElement());\n\n\t\tfunction a() {\n\t\t\ttopGallery.hide();\n\t\t}\n\n\t\tfunction b() {\n\t\t\ttopGallery.show();\n\t\t}\n\t>/script/html
<html> <head> <meta charset="utf-8"> <title>组合模式实例应用:公众号AlbertYangtitle> 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>
!DOCTYPE htmlhtmlheadmeta charset=\"utf-8\"title/title/headbodyinput value=\"隐藏\" type=\"button\" onclick=\"a()\" /input value=\"显示\" type=\"button\" onclick=\"b()\" //bodyscript type=\"text/javascript\" 30; p++) {\n\t\t\tvacationPhotos.add(new GalleryImage('img/3.jpg'));\n\t\t}\n\t\ttopGallery.add(vacationPhotos);\n\t\tdocument.body.appendChild(topGallery.getElement());\n\n\t\tfunction a() {\n\t\t\ttopGallery.hide();\n\t\t}\n\n\t\tfunction b() {\n\t\t\ttopGallery.show();\n\t\t}\n\t>/script/html
5 总结
组合模式通过简单的操作就能达到复杂的效果,一个操作通过遍历递归传递这个操作。不过组合模式的弱点也在于此,如果层次过多,则性能将受到影响。
组合模式应用需要符合两个条件,一是产生递归,二是具有相同的动作。
今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。
如果觉得本文对你有帮助的话,欢迎赞赏,点赞,转发!!!