关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

JavaScript如何实现组合模式???

发布时间:2020-08-08 10:01:00

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 + "\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>

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 总结

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

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


相关阅读

云备份有哪些主要优点?初步认识什么是云备份?大数据采集与数据采集有什么区别?数据采集的定义是什么?云存储技术之集群存储云存储的相关性能要求关于“云”的相关基础认识云主机与虚拟主机有什么区别?IDC机房监控设备服务标准IDC机房服务维护内容IDC基本业务产品常识服务器的访问的速度由哪些因素决定?《手机卡顿 - 办法新招》关于服务器托管有些什么功能?服务器托管应该注意哪些事项?服务器的托管有哪些优势?服务器租用和服务器托管的相关基础知识三级分销中薪金报酬计划之矩阵制的缺陷三级分销商城搭建时需要掌握的技术Hadoop主要有下面几个优点云计算的数据组织结构云计算的部署模型关于块存储的特性及其优缺点面向对象存储(OOS)的特点及适合应用的类型云计算的三种类型云计算中文件系统操作和namespace的关系关于云计算的优势对于Namenode和Datanode的划分关于Hadoop HDFS的设计思想关于云服务的优缺点云服务的特点及其市场价值云计算的主要特征云服务的好处有哪些?什么是对象存储对象?云存储有哪些特点?云存储系统所具有的几大优势云数据库具有一些什么特性?关于云服务器的特点有哪些?云服务器的架构体系及其优势云南RTK网络应用常见的问题及解决办法关于前端开发的优化问题阿里云域名转入失败常见问题及处理方法关于云计算的概念计算机网络技术基础知识云计算的优点和缺点服务器搭建计算机网络安全常见的危险因素有哪些?什么是内容分发网络(CDN)?云南服务器搭建和数据备份,恢复云南云服务器的三大作用人工智能AI初认识云计算服务的6个优势云南服务器托管有哪些注意事项Tomcat的特点云计算的三个优点选取小程序服务商时的注意事项不同数据库的不同区别什么是VPS主机它的优势是什么?你知道5G的优点和缺点吗?云南三级分销商城开发的目的和对企业的价值云南网站优化的3个方面和网页的优化我们晋级拉!!!云南网站链接维护的具体方法云南网站应该如何做优化云南网站维护的主要内容云南云服务器和虚拟主机的操作区别云服务器部署和注意点云南服务网器托管应该选择怎样的机房云南虚拟建设网站主机的优点和缺点云服务器和物理服务器的区别云服务器有哪些优势C# List用法 List介绍C#和Java有什么不同PHP的优点和缺点智慧新餐饮和传统餐饮的区别云数据库对比传统数据库有哪些优点裸金属服务器是什么它的作用是什么白盒测试的特点js中添加scriptjs中[]、{}、()的用法和区别php 字符串的整型转换ipa如何安装到苹果手机邓白氏码是什么?iOS开发者账号到期续费教程在C#中有哪些引用类型和值类型小程序搭建时需要准备些什么云数据库对比传统数据库的优势什么样的企业适合SEMjs中的常见错误C#数据类型转换字符串与数值之间的转换C#的几种循环遍历方式物联网是什么它和互联网又有什么区别?云南网站建设时应该注意些什么云计算是什么?它能干些什么?展望未来5G会给我们的生活带来哪些影响C#常见的几种报错类别C#的学习流程有哪些dedecms 绑定二级域名的正确方法SEM是什么它和SEO之间是什么关系?云南新餐饮料模式是如何运行的?云南网站建设初期应该注意哪些问题
/template/Home/Zkeys/PC/Static