天天日报丨结构型:策略模式
发布时间:2023-03-27 11:06:51 来源:博客园
定义定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。算法:就是写的逻辑可以是你任何一个功能函数的逻辑封装:就是把某一功能点对应的逻辑给抽出来可替换:建立在封装的基础上,这些独立的算法可以很方便的替换通俗的理解就是,把你的算法(逻辑)封装到不同的策略中,在不同的策略中是互相独立的,这样我们封装的每一个算法是可以很方便的复用。

策略模式主要解决在有多种情况下,使用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,如写一个很简单的表单的校验

                    
姓名:
密码:
确认密码:
手机号:
<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>

只是4个字段,我们用了 6个if判断来做相关的逻辑校验。

仔细观察发现很多校验的逻辑是一致的,所以我们可以把他封装起来,用策略模式修改成如下

                    
姓名:
密码:
确认密码:
手机号:
<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>

下次我们增加其他的字段也只是增加规则而已,而不会去修改判断的业务逻辑。

小结将一个个算法封装起来,提高代码复用率,减少代码冗余

策略模式可看作为if/else判断的另一种表现形式,在达到相同目的的同时,极大的减少了代码量以及代码维护成本

策略模式有效避免多重条件选择语句,将算法封装在策略中

标签:

x 广告
金融
x 广告

Copyright ©  2015-2022 热讯租赁网版权所有  备案号:豫ICP备20005723号-6   联系邮箱:29 59 11 57 8@qq.com