当前位置:
首页 > temp > JavaScript教程 >
-
行为型:策略模式
定义
定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。
- 算法:就是写的逻辑可以是你任何一个功能函数的逻辑
- 封装:就是把某一功能点对应的逻辑给抽出来
- 可替换:建立在封装的基础上,这些独立的算法可以很方便的替换
通俗的理解就是,把你的算法(逻辑)封装到不同的策略中,在不同的策略中是互相独立的,这样我们封装的每一个算法是可以很方便的复用。
策略模式主要解决在有多种情况下,使用if...else
所带来的复杂和难以维护。
它的优点是算法可以自由切换,同时可以避免多重if...else
判断,且具有良好的扩展性。
回到目录
看一个真实场景--最简单的策略模式
我们有一个根据不同的类型返回不同价格的一个方法
|
function getPrice (type) { |
|
if (type === 1) { |
|
// code 或许每个分支要处理很多逻辑 |
|
} |
|
if (type === 2) { |
|
// code |
|
} |
|
if (type === 3) { |
|
// code |
|
} |
|
if (type === 4) { |
|
// code |
|
} |
|
if (type === 5) { |
|
// code |
|
} |
|
if (type === 6) { |
|
// code |
|
} |
|
if (type === 7) { |
|
// code |
|
} |
|
} |
从代码上看确实没有什么问题,但是如果需要增加一种新的类型,我们就会一个if判断,导致这个方法可能会过于庞大,后期不太好维护。
其次代码每次都是从上往下走,可能存在前面某个判断出现问题(如某个 && 的判断变量null 之类),导致后面的代码没有走,所以这种影响还是挺大的。
用了这么多if-else
,我们的目的是什么?是不是就是为了把传进来的参数的值-对应的处理函数
,这个映射关系给明确下来?在 JS 中我们可以通过对象映射的形式来做,如下代码
|
/* |
|
1、把 if else 的代码快优化为一个一个的映射 |
|
2、把if else 里面的逻辑抽离成一个独立的函数,这样方便其他模块或者分支使用 |
|
*/ |
|
function getPrice (type) { |
|
const actionMap = { |
|
'1': action1, |
|
'2': action2, |
|
'3': action3, |
|
'4': action4, |
|
'5': action5, |
|
'6': action6, |
|
'7': action7, |
|
} |
|
const params = {} |
|
return actionMap[type](params) |
|
} |
这种代码结构变得易读、易维护。
这就是最简单的策略模式
回到目录
模拟表单校验逻辑
如果不把逻辑封装起来,那么我们在判断的时候会写很多的if else,如写一个很简单的表单的校验
|
|
|
<html lang="en"> |
|
|
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"> |
|
<meta content="yes" name="apple-mobile-web-app-capable"> |
|
<meta content="black" name="apple-mobile-web-app-status-bar-style"> |
|
<meta content="telephone=no,email=no" name="format-detection"> |
|
<meta name="App-Config" content="fullscreen=yes,useHistoryState=yes,transition=yes"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
<title></title> |
|
<link href="css/style.css" rel="stylesheet"> |
|
</head> |
|
|
|
<body> |
|
<div> |
|
<form action="" id="form"> |
|
姓名:<input type="text" id="username"><br> |
|
密码:<input type="password" id="password1"><br> |
|
确认密码:<input type="password" id="password2"><br> |
|
手机号:<input type="text" id="phone"><br> |
|
<input type="submit" value="提交"> |
|
</form> |
|
</div> |
|
|
|
<script> |
|
function getValue (id) { |
|
return document.getElementById(id).value; |
|
} |
|
var formData = document.getElementById('form') |
|
formData.onsubmit = function () { |
|
var name = getValue('username'); |
|
var pwd1 = getValue('password1'); |
|
var pwd2 = getValue('password2'); |
|
var tel = getValue('phone'); |
|
if (name.replace(/(^\s*)|(\s*$)/g, "") === "") { |
|
alert('用户名不能为空') |
|
return false |
|
} |
|
if (pwd1.replace(/(^\s*)|(\s*$)/g, "") === "") { |
|
alert('密码不能为空') |
|
return false |
|
} |
|
if (pwd2.replace(/(^\s*)|(\s*$)/g, "") === "") { |
|
alert('确认密码不能为空') |
|
return false |
|
} |
|
if (pwd2 !== pwd1) { |
|
alert('确认密码与原密码不相同!') |
|
return false |
|
} |
|
if (tel.replace(/(^\s*)|(\s*$)/g, "") === "") { |
|
alert('手机号码不能为空') |
|
return false |
|
} |
|
if (!/^1[3,4,5,7,8,9][0-9]\d{8}$/.test(tel)) { |
|
alert('手机号码格式不正确') |
|
return false |
|
} |
|
alert('注册成功') |
|
} |
|
</script> |
|
</body> |
|
|
|
</html> |
只是4个字段,我们用了 6个if判断来做相关的逻辑校验。
仔细观察发现很多校验的逻辑是一致的,所以我们可以把他封装起来,用策略模式修改成如下
|
|
|
<html lang="en"> |
|
|
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"> |
|
<meta content="yes" name="apple-mobile-web-app-capable"> |
|
<meta content="black" name="apple-mobile-web-app-status-bar-style"> |
|
<meta content="telephone=no,email=no" name="format-detection"> |
|
<meta name="App-Config" content="fullscreen=yes,useHistoryState=yes,transition=yes"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
<title></title> |
|
<link href="css/style.css" rel="stylesheet"> |
|
</head> |
|
|
|
<body> |
|
<div> |
|
<form action="" id="form"> |
|
姓名:<input type="text" id="username"><br> |
|
密码:<input type="password" id="password1"><br> |
|
确认密码:<input type="password" id="password2"><br> |
|
手机号:<input type="text" id="phone"><br> |
|
<input type="submit" value="提交"> |
|
</form> |
|
</div> |
|
|
|
<script> |
|
let formData = document.getElementById('form') |
|
function getValue(id) { |
|
return document.getElementById(id).value; |
|
} |
|
function Validate() { } |
|
Validate.prototype.rules = { |
|
// 是否手机号 |
|
isMobile: function (str) { |
|
let rule = /^1[3,4,5,7,8,9][0-9]\d{8}$/; |
|
return rule.test(str); |
|
}, |
|
// 是否必填 |
|
isRequired: function (str) { |
|
// 除去首尾空格 |
|
let value = str.replace(/(^\s*)|(\s*$)/g, ""); |
|
return value !== ""; |
|
}, |
|
// 最小长度 |
|
minLength: function (str, length) { |
|
let strLength = str.length; |
|
return strLength >= length; |
|
}, |
|
// 是否相等 |
|
isEqual: function (...args) { |
|
let equal = args.every(function (value) { |
|
return value === args[0]; |
|
}) |
|
return equal; |
|
} |
|
} |
|
|
|
Validate.prototype.test = function (rules) { |
|
let _this = this; |
|
let valid; // 保存校验结果 |
|
for (let key in rules) { // 遍历校验规则对象 |
|
for (let i = 0; i < rules[key].length; i++) { // 遍历每一个字段的校验规则 |
|
let ruleName = rules[key][i].rule; // 获取每一个校验规则的规则名 |
|
let value = rules[key][i].value; // 获取每一个校验规则的校验值 |
|
if (!Array.isArray(value)) { // 统一校验值为数组类型 |
|
value = new Array(value) |
|
} |
|
let result = _this.rules[ruleName].apply(this, value); // 调用校验规则方法进行校验 |
|
if (!result) { // 如果校验不通过,就获取校验结果信息,并立即跳出循环不再执行,节约消耗 |
|
valid = { |
|
errValue: key, |
|
errMsg: rules[key][i].message |
|
} |
|
break; |
|
} |
|
} |
|
if (valid) { // 如果有了校验结果,代表存在不通过的字段,则立即停止循环,节约消耗 |
|
break; |
|
} |
|
} |
|
return valid; // 把校验结果反悔出去 |
|
} |
|
|
|
formData.onsubmit = function () { |
|
event.preventDefault() |
|
let validator = new Validate(); |
|
let result = validator.test({ |
|
'username': [{ rule: 'isRequired', value: this.username.value, message: '用户名不能为空!' }], |
|
'password1': [ |
|
{ rule: 'isRequired', value: this.password1.value, message: '密码不能为空!' }, |
|
{ rule: 'minLength', value: [this.password1.value, 6], message: '密码长度不能小于6个字符!' } |
|
], |
|
'password2': [ |
|
{ rule: 'isRequired', value: this.password2.value, message: '确认密码不能为空!' }, |
|
{ rule: 'minLength', value: [this.password2.value, 6], message: '确认密码长度不能小于6个字符!' }, |
|
{ rule: 'isEqual', value: [this.password2.value, this.password1.value], message: '确认密码与原密码不相同!' } |
|
], |
|
'isMobile': [ |
|
{ rule: 'isRequired', value: this.phone.value, message: '手机号不能为空!' }, |
|
{ rule: 'isMobile', value: this.phone.value, message: '手机号格式不正确!' } |
|
] |
|
}) |
|
|
|
if (result) { |
|
console.log(result); |
|
} else { |
|
console.log('校验通过'); |
|
} |
|
} |
|
</script> |
|
</body> |
|
|
|
</html> |
下次我们增加其他的字段也只是增加规则而已,而不会去修改判断的业务逻辑。
回到目录
小结
- 将一个个算法封装起来,提高代码复用率,减少代码冗余
-
策略模式可看作为
if/else
判断的另一种表现形式,在达到相同目的的同时,极大的减少了代码量以及代码维护成本 - 策略模式有效避免多重条件选择语句,将算法封装在策略中
如果您觉得阅读本文对您有帮助,请点一下推荐按钮,您的推荐将是我最大的写作动力,欢迎各位转载!
出处:https://www.cnblogs.com/longbensong/p/17260684.html
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数