首页 > 其他分享 >策略模式

策略模式

时间:2023-06-17 23:22:45浏览次数:30  
标签:function return 策略 rule 校验 value let 模式

行为型:策略模式

定义

 

 

 

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

 

 

 

  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. 策略模式有效避免多重条件选择语句,将算法封装在策略中 

标签:function,return,策略,rule,校验,value,let,模式
From: https://www.cnblogs.com/Leo_wl/p/17488465.html

相关文章

  • mysql5.7密码策略说明
    一、mysql5.7在创建用户设置密码时提示“ERROR1819(HY000):Yourpassworddoesnotsatisfythecurrentpolicyrequirements”createuser'tom'@localhostidentifiedby'123456';ERROR1819(HY000):Yourpassworddoesnotsatisfythecurrentpolicyrequi......
  • 访问者模式(十八)
    相信自己,请一定要相信自己上一章简单介绍了命令模式(十七),如果没有看过,请观看上一章一.访问者模式引用菜鸟教程里面访问者模式介绍:https://www.runoob.com/design-pattern/visitor-pattern.html在访问者模式(VisitorPattern)中,我们使用了一个访问者类,它改变了元素类的执行算......
  • 单例模式(三)
    过气的,终究是过气了上一章简单介绍了UML类图(二),如果没有看过,请观看上一章一.单例模式所谓的单例设计模式,就是采用一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)一.一单例模式介绍引用菜鸟教程里面的......
  • 抽象工厂模式(六)
    过气的,终究是过气了上一章简单介绍了工厂方法模式(五),如果没有看过,请观看上一章一.抽象工厂模式引用菜鸟教程里面的单例模式介绍:https://www.runoob.com/design-pattern/abstract-factory-pattern.html抽象工厂模式(AbstractFactoryPattern)是围绕一个超级工厂创建其他工厂......
  • 工厂模式(四)
    过气的,终究是过气了上一章简单介绍了单例模式(三),如果没有看过,请观看上一章一.工厂模式引用菜鸟教程里面的单例模式介绍:https://www.runoob.com/design-pattern/factory-pattern.html工厂模式(FactoryPattern)是Java中最常用的设计模式之一。这种类型的设计模式属于创建型......
  • 工厂方法模式(五)
    过气的,终究是过气了上一章简单介绍了工厂模式(四),如果没有看过,请观看上一章一.工厂方法模式工厂方法模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一......
  • 设计模式的原则(一)
    相信自己,无论自己到了什么局面,请一定要继续相信自己。新的世界开始了,接下来,老蝴蝶带领大家学习一下设计模式。我们先了解一下设计原则一.设计模式一.一设计原则设计模式常用的七大原则:单一职责原则接口隔离原则依赖倒转(倒置)原则里氏替换原则开闭原则迪米特法则合成复用原则一.......
  • 策略模式(二十五)
    相信自己,请一定要相信自己上一章简单介绍了状态模式(二十四),如果没有看过,请观看上一章一.策略模式引用菜鸟教程里面策略模式介绍:https://www.runoob.com/design-pattern/strategy-pattern.html在策略模式(StrategyPattern)中,一个类的行为或其算法可以在运行时更改。这种类......
  • PHP开发:代码风格、重构和设计模式的实践
    一、代码风格和规范:采用一致的代码风格和规范有助于提高代码的可读性和可维护性。我们将介绍一些常见的PHP代码风格指南,如PSR-12(PHPStandardRecommendation),以及一些静态代码分析工具,如PHPCodeSniffer,可以帮助您自动检测代码规范问题。示例代码风格(使用PSR-12):<?phpnamespaceV......
  • 迭代器模式(Iterator Pattern)
    迭代器模式(IteratorPattern)一、定义提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。二、优缺点优点: 1、它支持以不同的方式遍历一个聚合对象。2、迭代器简化了聚合类。3、在同一个聚合上可以有多个遍历。4、在迭代器模式中,增加新的聚合类和......