实现一个中间部件对象,也就是可以添加叶子节点的对象,最终这个中间件部件装载在根form对象上.这个中间件的好处是可以按照实际业务需求进行分组.本例中划分了三种业务,分别是名字分组,地址分组和测试分组.本例中还设计了remove按照id删除元素的方法,这样会更加灵活.因为引用类型是公用的,即使前面添加了,后面再删除,最后得到的还是删除后的效果.这样可以不用漫天寻找代码,也不用非要在添加之前注释某段代码,这就是引用类型的优点.策略模式和组合模式之间是没有任何耦合的,我们完全可以在动态装载完form表单后,再根据具体字段绑定策略,至于根据实际需要拆卸某些字段的策略,那就是策略模式自己的事了.

<!DOCTYPE html>
<html><head lang="en"><meta charset="UTF-8"><title>组合+策略模式</title></head><body></body>
</html>
<script type="text/javascript">
//策略类
var strategies = {isNonEmpty: function(value, errorMsg) {if(value === '') {return errorMsg;}},minLength: function(value, length, errorMsg) {if(value.length < length) {return errorMsg;}},isMobile: function(value, errorMsg) {if(!/1[3|5|8][0-9]{9}$/.test(value)) {return errorMsg;}}
};var Validator = function() {this.cache = [];
}Validator.prototype.add = function(dom, rules) {var self = this;for(var i=0; i<rules.length; i++) {(function(rule) {var arr = rule.strategy.split(':');var errorMsg = rule.errorMsg;//将函数都压入数组self.cache.push(function() {//拿出策略字串备用var strategy = arr.shift();//将dom值放在数组头一个arr.unshift(dom.value);//报错信息放在数组最后一个arr.push(errorMsg);return strategies[strategy].apply(dom, arr);})})(rules[i]);}
};Validator.prototype.start = function() {for(var i=0; i<this.cache.length; i++) {var msg = this.cache[i]();if(msg) {return msg;}}
}//继承方法
function extend(newobj, obj) {var F = function() {};F.prototype = obj.prototype;newobj.prototype = new F();newobj.prototype.constructor = newobj;
}//叶子对象
var Field = function(id) {this.id = id;this.divElement;
}Field.prototype.save = function() {sessionStorage.setItem(this.id, this.getValue());console.log(sessionStorage.getItem(this.id));
}
//最终调用子对象的divElement,这个this指向必须是子对象。
//用call函数可以修正this指向。
//以供下面部件对象CompositeFieldSet中使用。
Field.prototype.getDivElement = function() {//这里还要注意divElement必须有个id,在部件对象的容器中作为key值使用。return this.divElement;
}
//子类继承使用
Field.prototype.getValue = function() {throw new Error('you should override this method');
}var InputField = function(label, id, type) {Field.call(this, id);this.input = document.createElement('input');//策略验证类使用name寻找domthis.input.name = id;this.input.type = type;this.label = document.createElement('label');var labelTextNode = document.createTextNode(label);this.label.appendChild(labelTextNode);this.divElement = document.createElement('div');this.divElement.id = id;this.divElement.className = 'input-field';this.divElement.appendChild(this.label);this.divElement.appendChild(this.input);
}extend(InputField, Field);
InputField.prototype.getValue = function() {return this.input.value;
};var SelectField = function(label, id, arr) {Field.call(this, id);this.select = document.createElement('select');for(var i=0; i<arr.length; i++) {var option = document.createElement('option');option.text = arr[i].text;option.value = arr[i].value;this.select.options[i] = option;}this.label = document.createElement('label');var labelTextNode = document.createTextNode(label);this.label.appendChild(labelTextNode);this.divElement = document.createElement('div');this.divElement.id = id;this.divElement.className = 'select-field';this.divElement.appendChild(this.label);this.divElement.appendChild(this.select);
}extend(SelectField, Field);
SelectField.prototype.getValue = function() {return this.select.options[this.select.selectedIndex].value;
}//部件对象:可以按照业务分组表单元素
var CompositeFormSet = function(id, legendText) {//注意这里不是数组了。this.components = {};//legend和fieldset元素在表单元素分组很常用//一个fieldset包含许多legendthis.id = id;this.element = document.createElement('fieldset');this.element.id = id;//dom分组if(legendText) {this.legend = document.createElement('legend');this.legend.appendChild(document.createTextNode(legendText));this.element.appendChild(this.legend);}
}CompositeFormSet.prototype.add = function(child) {//容器内的元素按照id分组。//每个child是一个叶子对象。this.components[child.getDivElement().id] = child;this.element.appendChild(child.getDivElement());
}
//获取这个部件对象,以供下面CompositeForm对象中使用。
CompositeFormSet.prototype.getElement = function() {return this.element;
}CompositeFormSet.prototype.save = function() {console.log(this.components);for(var id in this.components) {//如果容器没有这个元素,直接跳过。if(!this.components.hasOwnProperty(id)) {continue;}this.components[id].save();}
}
//拆卸某个叶子对象
//这样就不用去寻找添加元素的地方注释代码。
CompositeFormSet.prototype.remove = function() {var child;for(var key in this.components) {if(this.components[key]['id'] === id) {child = this.components[key];delete this.components[child.getDivElement().id];this.element.removeChild(child.getDivElement());break;}}
}var CompositeForm = function(id) {this.formComponents = [];this.formElement = document.createElement('form');this.formElement.id = id;this.formElement.onsubmit = function() {return false;}
}CompositeForm.prototype.add = function(child) {this.formComponents.push(child);//添加部件元素//每个child是一个部件对象。this.formElement.appendChild(child.getElement());
}CompositeForm.prototype.save = function() {for(var i=0; i<this.formComponents.length; i++) {this.formComponents[i].save();}
}
//拆掉某个元素
CompositeForm.prototype.remove = function(id) {var child;for(var i=0; i<this.formComponents.length; i++) {if(this.formComponents[i].id === id) {child = this.formComponents[i];this.formComponents.splice(i, 1);this.formElement.removeChild(child.getElement);break;}}
}
//获取最终form对象,以供追加到body下。
CompositeForm.prototype.getFinalElement = function() {var submitButton = document.createElement('input');submitButton.id = 'sub';submitButton.type = 'submit';this.formElement.appendChild(submitButton);return this.formElement;
}//开始组合
var form = new CompositeForm('comtact-form');//造部件:名字分组
var nameFieldSet = new CompositeFormSet('name-fieldset', 'nameArea');
nameFieldSet.add(new InputField('first-name', 'firstName', 'text'));
nameFieldSet.add(new InputField('last-name', 'lastName', 'text'));//造部件:地址分组
var addressFieldSet = new CompositeFormSet('address-fieldset', 'addressArea');
addressFieldSet.add(new SelectField('国家', 'country', [{text:'美国', value:'us'}, {text:'日本', value:'jp'}]));
addressFieldSet.add(new InputField('地址', 'detail', 'text'));
addressFieldSet.add(new InputField('手机号', 'phone', 'text'));//造部件:测试分组
var testFieldSet = new CompositeFormSet('test-fieldset', 'testArea');
testFieldSet.add(new InputField('测试', 'test', 'text'));form.add(nameFieldSet);
form.add(addressFieldSet);
form.add(testFieldSet);//突然有一天,经理让你去掉测试分组,
//并且去掉地址分组中的国家元素。
//但是我并不想去找add的代码到底在哪里
//于是可以从控制台中直接找到id的相关信息,用remove删除就好
addressFieldSet.remove('country');
form.remove('test-fieldset');var formNode = form.getFinalElement();
document.body.appendChild(formNode);var todoFunc = function() {var validator = new Validator();validator.add(formNode.firstName, [{strategy: 'isNonEmpty', errorMsg: 'firstName不能为空'},{strategy: 'minLength:5', errorMsg: 'firstName长度不能少于5位'}]);validator.add(formNode.lastName, [{strategy: 'isNonEmpty', errorMsg: 'lastName不能为空'},{strategy: 'minLength:3', errorMsg: 'lastName长度不能少于3位'}]);validator.add(formNode.detail, [{strategy: 'isNonEmpty', errorMsg: '地址不能为空'},{strategy: 'minLength:10', errorMsg: '地址长度不能少于10位'}]);validator.add(formNode.phone, [{strategy: 'isNonEmpty', errorMsg: '手机号不能为空'},{strategy: 'isMobile', errorMsg: '手机号码格式不正确'}]);var errorMsg = validator.start();return errorMsg;
}document.getElementById('sub').onclick = function() {form.save();var errorMsg = todoFunc();if(errorMsg) {alert(errorMsg);}return false;
}
</script>

设计模式-组合+策略模式相关推荐

  1. 研磨设计模式之 策略模式--转

    http://www.uml.org.cn/sjms/201009092.asp 研磨设计模式之 策略模式   2010-09-09 作者:云飞龙行 来源:云飞龙行的blog   先感谢众多朋友的支持 ...

  2. C++设计模式之策略模式(Strategy)

    Strategy策略模式 作用:定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. UML图: 代码实现 #include <iostream& ...

  3. 面向对象设计模式之策略模式

    面向对象设计模式之策略模式 1.策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 2.抽象鸭子类,鸭子飞行行为在此处类似于算法族 1 package ...

  4. java策略模式详解_Java经典设计模式之策略模式原理与用法详解

    本文实例讲述了Java经典设计模式之策略模式.分享给大家供大家参考,具体如下: 策略模式指:策略模式指将程序中可变部分抽象分离成一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式 ...

  5. 策略设计模式_设计模式之策略模式总结

    再上一篇文章<设计模式之策略模式>中,我们通过模拟鸭子项目,了解了什么是策略模式,怎么使用策略模式.本文将通过鸭子项目的学习,对策略模式进行总结. 策略模式: 分别封装行为接口,实现算法族 ...

  6. JavaScript设计模式之策略模式(学习笔记)

    在网上搜索"为什么MVC不是一种设计模式呢?"其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composi ...

  7. java 策略模式 促销_设计模式之策略模式

    0x01.定义与类型 定义:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化不会影响到使用算法的用户. 从一系列里抽象出不变的部分 策略模式是将可变的部分从程序中抽象分离成算法 ...

  8. Java设计模式之策略模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  9. 橘子学设计模式之策略模式

    策略模式 1.简介 俗话说:条条大路通罗马.在很多情况下,实现某个目标的途径不止一条,例如我们在外出 旅游时可以选择多种不同的出行方式,如骑自行车.坐汽车.坐火车或者坐飞机,可根据实 际情况(目的地. ...

最新文章

  1. mstsc 加密oracle修正,mstsc远程报:这可能是由于CredSSP 加密Oracle修正的两种完美解决方法...
  2. 从零开始编写自己的C#框架(14)——T4模板在逻辑层中的应用(三)
  3. dotNET Core 3.X 使用 Jwt 实现接口认证
  4. appcan php图片上传,appcan文件上传php,asp通用
  5. NLPPython笔记——WordNet
  6. TwentyEleven暗色系主题实现透明
  7. Springboot starter开发之traceId请求日志链路追踪
  8. ipmitool介绍_ipmitool命令行使用详解
  9. mysql mycat 路由规则_Mycat水平拆分之十种分片规则
  10. click Setuptools Integration
  11. CCNA考试题库中英文翻译版及答案10
  12. 怎么用命令提示符打开浏览器_从您当前的命令提示符/终端目录打开文件浏览器...
  13. dos命令远程重启计算机,简单DOS命令实现局域网Windows远程关机
  14. 游戏策划入门(2)——如何写一份项目建议书?
  15. Jenkins集成Sonar(3/3)- 安装SonarQube Scanner进行扫描(离线安装)
  16. ssm+Vue计算机毕业设计学科竞赛赛场安排系统(程序+LW文档)
  17. C语音:for循环实现n个数简单求和
  18. QT::QBitArray
  19. DM368+MT7601U通过wifi可以正常出图
  20. php论坛mybb,MyBB

热门文章

  1. windows系统下Python环境的搭建及Selenium的安装
  2. 1.一些 贪心算法 的简单思维题:
  3. iPhone5或明年下半年发布 配备iOS6和A6芯片
  4. 原创,真正解决iframe高度自适应的问题.兼容各浏览器
  5. StringUtils工具类的常用方法
  6. linux文本编辑器vim的基本使用
  7. 六边形块级元素的绘制
  8. 7. PowerShell -- Provider,数据操作和注册表操作
  9. 从GNOME切换到KDE了
  10. 6.10 docker(三) 终止