行为型:策略模式

定义

  定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。
 

  1. 算法:就是写的逻辑可以是你任何一个功能函数的逻辑
  2. 封装:就是把某一功能点对应的逻辑给抽出来
  3. 可替换:建立在封装的基础上,这些独立的算法可以很方便的替换
通俗的理解就是,把你的算法(逻辑)封装到不同的策略中,在不同的策略中是互相独立的,这样我们封装的每一个算法是可以很方便的复用。

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

<!DOCTYPE html>
<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判断来做相关的逻辑校验。

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

<!DOCTYPE html>
<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>

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

小结

  1. 将一个个算法封装起来,提高代码复用率,减少代码冗余
  2. 策略模式可看作为if/else判断的另一种表现形式,在达到相同目的的同时,极大的减少了代码量以及代码维护成本

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

原文链接:https://www.cnblogs.com/longbensong/p/17260684.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:行为型:策略模式 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • JavaScript中exec函数用法实例分析

    JavaScript中exec函数用法实例分析 介绍 exec 方法是 JavaScript 正则表达式对象的一个方法,用于在字符串中查找指定的正则表达式,并返回匹配结果。 该方法返回一个数组,数组的第一个元素是匹配到的字符串,后面的元素则是与正则表达式的每个括号匹配的子字符的数组。如果没有匹配到,则返回 null。 在本篇文章中,我们将通过两个例子来一步步…

    JavaScript 2023年6月10日
    00
  • JavaScript requestAnimationFrame动画详解

    下面是详细讲解“JavaScript requestAnimationFrame动画详解”的完整攻略。 一、什么是requestAnimationFrame requestAnimationFrame是一个用于浏览器动画渲染的API,它可以被用来优化动画循环的性能。相较于使用setTimeout或setInterval方法,使用requestAnimatio…

    JavaScript 2023年6月10日
    00
  • JS中创建函数的三种方式及区别

    下面为您详细讲解JS中创建函数的三种方式及区别的完整攻略。 一、函数定义方式 函数定义是最常见的创建函数的方式,语法如下: function functionName(param1, param2, …) { // 函数体 return value; } 该方式创建的函数可以被整个作用域访问到,包括其内部的变量和函数。下面是一个示例: function …

    JavaScript 2023年5月27日
    00
  • 代码生成器 document.write()

    代码生成器 document.write() 是一种 JavaScript 方法,可以在 HTML 文档中动态生成内容。在本文中,将详细讲解使用 document.write() 方法来生成 HTML 代码的完整攻略。 使用 document.write() 语法 document.write(HTMLcode) 参数 HTMLcode : 必需。要写入 H…

    JavaScript 2023年5月28日
    00
  • javascript与java有什么关系(区别与相似)

    JavaScript和Java这两个词看起来很相似,但它们是两个完全不同的编程语言。在这篇文章中,我们将讨论JavaScript和Java之间的区别和相似之处。 区别 语法不同 JavaScript和Java有完全不同的语法。JavaScript语法更为简单,而Java则需要更多的代码和结构。JavaScript采用的是弱类型变量,因此在声明变量并定义其类型…

    JavaScript 2023年5月27日
    00
  • 关于UTF-8的客户端用AJAX方式获取GB2312的服务器端乱码问题的解决办法

    关于UTF-8的客户端用AJAX方式获取GB2312的服务器端乱码问题的解决办法,需要考虑以下几个方面: 了解什么是字符编码 字符编码是计算机在处理文本时采用的一种方式,用数字来代表各种字符,包括数字、字母、符号、汉字等等。字符编码的常见表示方式包括 ASCII、GB2312、GBK、UTF-8 等。 理解客户端与服务器端的字符编码要求 客户端和服务器端在处…

    JavaScript 2023年5月19日
    00
  • js严格模式总结(分享)

    JS严格模式总结(分享) JS严格模式,也叫做严格模式,是ES5中定义的一种JS运行的模式。它可以让代码在更加安全的环境下运行,且更加严格地执行代码。本文将为您详细讲解JS严格模式的使用、注意事项以及相关示例。 使用严格模式的方法 使用严格模式只需要在JS代码的开头添加’use strict’;即可,例如: ‘use strict’; function fo…

    JavaScript 2023年6月10日
    00
  • DOM基础教程之使用DOM控制表单

    下面是对“DOM基础教程之使用DOM控制表单”的详细讲解: 基础概念 DOM (Document Object Model) 是文档对象模型的缩写,它是一种描述 HTML 文档结构的方式,可以通过 JavaScript 代码来操作 HTML 页面。 表单是 HTML 中常见的一种交互方式,用户可以通过表单向服务器提交数据,表单中的各个元素都是可以使用 DOM…

    JavaScript 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部