JavaScript设计模式之策略模式
《JavaScript设计模式与开发实践》读书笔记。这本书挺好的,推荐。
俗话说,条条大路通罗马。在现实生活中,我们可以采用很多方法实现同一个目标。比如我们先定个小目标,先挣它一个亿。我们可以根据具体的实际情况来完成这个目标。
如果你是个富二代,可以接手家族生意,分分钟挣它一个亿。
如果你是个官二代,可以......(你懂的)。
如果你是个屌丝,可以......别做梦了,好好撸码。
策略模式的定义
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
举个例子:表单校验
在一个Web项目中,注册、登录等功能的实现都离不开表单提交。表单校验也是前端常常需要做的事。假设我们正在编写一个注册的页面,在点击提交按钮之前,有如下几条校验逻辑:
用户名不可为空,不允许以空白字符命名,用户名长度不能小于2位。
密码长度不能小于6位。
正确的手机号码格式。
也许,一开始我们会这么写:
<html>
<head>
<title>策略模式-校验表单</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body>
<form id = "registerForm" method="post" action="http://xxxx.com/api/register">
用户名:<input type="text" name="userName">
密码:<input type="text" name="password">
手机号码:<input type="text" name="phoneNumber">
<button type="submit">提交</button>
</form>
<script type="text/javascript">
var registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
if (registerForm.userName.value === '') {
alert('用户名不可为空');
return false;
}
if (registerForm.userName.value === '') {
alert('用户名不可为空');
return false;
}
if (registerForm.userName.value.trim() === '') {
alert('用户名不允许以空白字符命名');
return false;
}
if (registerForm.userName.value.trim().length < 2) {
alert('用户名用户名长度不能小于2位');
return false;
}
if (registerForm.password.value.trim().length < 6) {
alert('密码长度不能小于6位');
return false;
}
if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(registerForm.phoneNumber.value)) {
alert('请输入正确的手机号码格式');
return errorMsg;
}
}
</script>
</body>
</html>
这是一种很常见的编码方式,但它有很明显的缺点:
registerForm.onsubmit 函数比较庞大,包含了很多if语句,这些语句要覆盖所有的校验规则。
若校验规则有变,不得不深入到registerForm.onsubmit 函数的内部实现,违反开放-封闭原则。
算法的复用性差。
下面,让我们来用策略模式重构表单校验
策略模式:表单校验
<html>
<head>
<title>策略模式-校验表单</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body>
<form id = "registerForm" method="post" action="http://xxxx.com/api/register">
用户名:<input type="text" name="userName">
密码:<input type="text" name="password">
手机号码:<input type="text" name="phoneNumber">
<button type="submit">提交</button>
</form>
<script type="text/javascript">
// 策略对象
var strategies = {
isNoEmpty: function (value, errorMsg) {
if (value === '') {
return errorMsg;
}
},
isNoSpace: function (value, errorMsg) {
if (value.trim() === '') {
return errorMsg;
}
},
minLength: function (value, length, errorMsg) {
if (value.trim().length < length) {
return errorMsg;
}
},
maxLength: function (value, length, errorMsg) {
if (value.length > length) {
return errorMsg;
}
},
isMobile: function (value, errorMsg) {
if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(value)) {
return errorMsg;
}
}
}
// 验证类
var Validator = function() {
this.cache = [];
}
Validator.prototype.add = function(dom, rules) {
var self = this;
for(var i = 0, rule; rule = rules[i++];) {
(function(rule) {
var strategyAry = rule.strategy.split(':');
var errorMsg = rule.errorMsg;
self.cache.push(function() {
var strategy = strategyAry.shift();
strategyAry.unshift(dom.value);
strategyAry.push(errorMsg);
return strategies[strategy].apply(dom, strategyAry);
})
})(rule)
}
};
Validator.prototype.start = function() {
for(var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
var errorMsg = validatorFunc();
if (errorMsg) {
return errorMsg;
}
}
};
// 调用代码
var registerForm = document.getElementById('registerForm');
var validataFunc = function() {
var validator = new Validator();
validator.add(registerForm.userName, [{
strategy: 'isNoEmpty',
errorMsg: '用户名不可为空'
}, {
strategy: 'isNoSpace',
errorMsg: '不允许以空白字符命名'
}, {
strategy: 'minLength:2',
errorMsg: '用户名长度不能小于2位'
}]);
validator.add(registerForm.password, [ {
strategy: 'minLength:6',
errorMsg: '密码长度不能小于6位'
}]);
validator.add(registerForm.phoneNumber, [{
strategy: 'isMobile',
errorMsg: '请输入正确的手机号码格式'
}]);
var errorMsg = validator.start();
return errorMsg;
}
registerForm.onsubmit = function() {
var errorMsg = validataFunc();
if (errorMsg) {
alert(errorMsg);
return false;
}
}
</script>
</body>
</html>
策略模式优缺点
策略模式是一种常用且有效的设计模式。
策略模式可以有效避免多重条件选择语句。
策略模式提供了对开放-封装原则的完美支持,将方法封装在独立的strategy中,使得它们易于切换,易于理解,易于扩展。
复用性高。
当然,策略模式也有一些缺点
增加了许多策略类或者策略对象。
要使用策略模式,必须了解所有的strategy,违反了最少知识原则。
至此,回家咯~
本文转载于:猿2048→https://www.mk2048.com/blog/blog.php?id=h2aacc1b2ib
原文地址:https://www.cnblogs.com/homehtml/p/12929474.html
- 程序员你为什么这么累【续】:编码习惯-函数编写建议
- 那些年,我们一起碰到过的骗局
- Spring Security (五) 动手实现一个IP_Login
- 史上最全Linux提权后获取敏感信息方法
- Spring Security (四) 核心过滤器源码分析
- Spring Security (三) 核心配置解读
- Spring Cloud配置中心获取不到最新配置信息的问题
- 总是听别人说响应式布局,原来这么简单
- Spring Cloud Zuul重试机制探秘
- Eureka中RetryableClientQuarantineRefreshPercentage参数探秘
- Edgware.RC1中ZuulFallbackProvider的改进
- JPA的多表复杂查询:详细篇
- 尝试使用Memcached遇到的狗血问题
- Enumerable#Zip 实现一下
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- JavaScript 技术篇-js检测原生对象类型实例演示,js的3种对象类型
- Python 技术篇-利用pyqt5库读取剪切板已复制数据的格式类型实例演示,python判断复制文件的文件类型
- 第36期:二叉树的遍历(小白必看)
- Python 技术篇-index()字符串倒叙匹配获取索引,字符串切片反向输出,逆向输出字符串
- JavaScript 技术篇-navigator.permissions读取chrome剪切板权限获取不生效原因:只有在https协议下使用有效。手动设置chrome页面剪切板读取权限方法
- 生产prometheus-operator 监控二进制kubernetes
- Excel 技术篇-跨页签统计某一区域下符合条件值的数量方法,COUNTIF函数、数量统计公式的用法实例演示
- Oracle 数据库用户锁定与解锁,用户锁定最大密码失败次数设置方法,ORA-28000: the account is locked问题解决方法
- TypeScript 注意事项
- Linux下MySQL数据库的备份与还原,mysql快速导入导出数据库实例演示,解决mysql大数据量数据库导出慢的问题
- 前端如何分片上传文件?
- PL/SQL 工具远程连接Oracle数据库方法,plsql免安装oracle客户端直接配置oci实战演示
- Python 技巧篇-官方网站打不开的情况下通过官方获取最新python安装包方法
- MySQL 技术篇- linux下mysql数据库利用binlog文件进行数据回滚实例演示,binlog恢复数据库的两种方式
- Oracle 数据库表空间不足拓展方法实例演示,表空间剩余大小查看,通过新增表空间文件拓展表空间,表空间文件路径查看