zoukankan      html  css  js  c++  java
  • 设计模式(10)[JS版]-JavaScript如何实现组合模式???

    目录

    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 html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>组合模式:公众号AlbertYang</title>
    	</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 + "
    ";
    				},
    				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>
    

    4 应用实例

    4.1 表单验证

        演示地址:https://www.albertyy.com/2020/8/Component1.html

        表单验证中,需要做的工作是表单的保存、恢复和验证表单中的值,然而表单的数量是未知数,类型是未知数,只有功能能确定,在这种情况下,使用组合模式无疑最好,通过给每个表单添加功能,然后一个表单对象组合起来,通过操作表单对象即可达到操作表单。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>组合模式实例应用:公众号AlbertYang</title>
    	</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>
    

    4.1 图片阅读器

      演示地址:https://www.albertyy.com/2020/8/Component2.html

      图片阅读器与表单验证基本一样,通过汇合操作图片。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>组合模式实例应用:公众号AlbertYang</title>
    	</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>
    

    5 总结

    组合模式通过简单的操作就能达到复杂的效果,一个操作通过遍历递归传递这个操作。不过组合模式的弱点也在于此,如果层次过多,则性能将受到影响。

    组合模式应用需要符合两个条件,一是产生递归,二是具有相同的动作。

    今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎点赞,评论,转发!!!

  • 相关阅读:
    SqlCeConnectionBeginTransaction 方法
    父子继承窗体,子窗体视图无法正常打开,解决办法
    Windows Mobile 如何和模拟器关联有用的URL
    Windows Mobile 6.5.3 Developer Tool Kit
    通过Eclipse import导入项目,並重新命名Project
    【杂】Oracle使用记录:分区表及执行计划
    实践 2-0 selenium使用的一些总结
    实践2-1 python连接Oracle数据库
    【杂】word文件加密和压缩加密
    【杂】HIVE使用记录:回收站及从回收站恢复分区表
  • 原文地址:https://www.cnblogs.com/yangxianyang/p/13675544.html
Copyright © 2011-2022 走看看