• 策略模式——多重if-else解决方案


    概念

    大量的 if 判断操作,逻辑比较复杂,并且处理起来相对麻烦。可以采用策略模式来优化分支代码。
    策略模式 💤:是一种行为设计模式,它允许你在运行时根据不同情况选择不同的算法或行为。
    设计模式 🤌:就是提前第一次了解全过程,第二次直接规划不必要的坑。
    我们在写代码亦是如此,一定也遇到过许多类似的场景。随着程序员经验的增加,我们对于这些常见场景的处理越来越得心应手,甚至总结出了针对性的“套路”,下次遇到此类问题直接运用“套路”解决,省心又省力。这些在软件开发过程中逐渐积累下来的“套路”就是设计模式。

    设计模式的目标之一就是提高代码的可复用性、可扩展性和可维护性

    例:

    const game = (name) => {
      if (name === "原s") {
        console.log("启动!");
      } else if (name === "xx精英") {
        console.log("我先成盒了你们加油!");
      } else if (name === "云顶yy") {
        console.log("这就是我们之间的羁绊!");
      } else if (name === "王者zz") {
        console.log("我再也不买皮肤了!");
      } else {
        console.log("我啥也没玩");
      }
    };
    game("原s"); // 启动!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    简单优化一下写法:

    const game = (name) => {
      let obj = {
        原s: "启动!",
        xx精英: "我先成盒了你们加油!",
        云顶yy: "这就是我们之间的羁绊!",
        王者zz: "我再也不买皮肤了!",
      };
      if (obj[name]) {
        console.log(obj[name]);
      } else {
        console.log("我啥也没玩");
      }
    };
    game("原s"); // 启动!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这种写法只是参考了策略模式的思路,将逻辑封装到一个对象中。这种方式使得这个对象能够独立出来,只需专注于维护这个对象本身即可。如果要是每个方法都不同,那该如何去写呢?接着往下看

    const game = (name) => {
      let obj = {
        原s: () => {
          console.log("启动!");
        },
        xx精英: () => {
          console.log("我先成盒了你们加油!");
        },
        云顶yy: () => {
          console.log("这就是我们之间的羁绊!");
        },
        王者zz: () => {
          console.log("我再也不买皮肤了!");
        },
      };
      if (obj[name]) {
        obj[name]();
      } else {
        console.log("我啥也没玩");
      }
    };
    
    game("原s"); // 启动!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这种写法就是将对象中的处理逻辑单独封装成一个函数,让他内部自己处理自己所用到的逻辑。

    下面这种写法代码更加灵活和可扩展,也是我比较推荐的写法。

    const strategies = {
      原s: () => console.log("启动!"),
      xx精英: () => console.log("我先成盒了你们加油!"),
      云顶yy: () => console.log("这就是我们之间的羁绊!"),
      王者zz: () => console.log("我再也不买皮肤了!"),
    };
    
    function executeStrategy(name) {
      if (strategies[name]) {
        strategies[name]();
      } else {
        console.log("我啥也没玩");
      }
    }
    
    executeStrategy("原s");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这个例子里面,我们可以将游戏名作为参数传递给函数,而不是在函数内部定义多个条件。这样,我们就可以将函数封装成一个可复用的策略,以便在将来添加更多的游戏名称。

    1. 案例

    下面看一下使用场景,比如我们需要做一个 from 表单验证,需要验证手机号和密码

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>表单title>
        <script src="./src/index.js">script>
      head>
    
      <body>
        <form id="login-form" action="" method="post">
          <label for="account">手机号label>
          <input type="number" id="account" name="account" />
          <label for="password">密码label>
          <input type="password" id="password" name="password" />
          <button id="login">登录button>
        form>
        <script>
          let loginForm = document.getElementById("login-form");
    
          loginForm.onsubmit = function (e) {
            e.preventDefault();
            let account = document.getElementById("account").value;
            let pwd = document.getElementById("password").value;
    
            if (account === null || account === "") {
              console.log("手机号不能为空");
              return false;
            }
            if (pwd === null || pwd === "") {
              console.log("密码不能为空");
              return false;
            }
            if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(account)) {
              console.log("手机号格式错误");
              return false;
            }
            if (pwd.length < 6) {
              console.log("密码不能小于六位");
              return false;
            }
    
            // 模拟ajax请求
            setTimeout(() => {
              console.log("登录成功!");
            }, 1000);
          };
        script>
      body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    在这里可以发现问题也是很明显的,如果你想说他能跑起来吗?他也能跑起来,但是里面的 if 语句到处都是,每次新增一种校验,需要整体去调整这个 loginForm.onsubmit 代码,复用性也很差,只能手动矫正

    2. 优化

    先将此方法抽离出来

    let obj = {
      isNonEmpty: function (value, errorMsg) {
        if (value === "" || value === null) {
          return errorMsg;
        }
      },
      isMobile: function (value, errorMsg) {
        // 手机号码正则
        if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(value)) {
          return errorMsg;
        }
      },
      minLength: function (value, errorMsg) {
        if (value.length < length) {
          return errorMsg;
        }
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    修改 Context 内容部分

    let loginForm = document.getElementById("loginForm");
    
    loginForm.onsubmit = function (e) {
      e.preventDefault();
      let phone = strategies.isMobile(account, "手机号格式错误");
      let pwdMinLength = strategies.minLength(pwd, "密码不能小于六位");
      let error = accountIsMobile || pwdMinLength;
      if (error) {
        console.log(error);
        return false;
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    完整代码如下

    <div>
      <form id="loginform" action="" method="post">
        <label for="account">手机号label>
        <input type="number" id="account" name="account" />
        <label for="password">密码label>
        <input type="password" id="password" name="password" />
        <button id="login">登录button>
      form>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    let account = ""; // 这里的变量需要初始化一下,不然无法获取到value
    let pwd = "";
    
    let loginForm = document.getElementById("loginform");
    let strategies = {
      isNonEmpty: function (value, errorMsg) {
        if (value === "" || value === null) {
          return errorMsg;
        }
      },
      isMobile: function (value, errorMsg) {
        // 手机号码格式
        if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(value)) {
          return errorMsg;
        }
      },
      minLength: function (value, length, errorMsg) {
        console.log(value);
        if (value.length < length) {
          return errorMsg;
        }
      },
    };
    
    loginForm.addEventListener("submit", (e) => {
      account = document.getElementById("account").value;
      pwd = document.getElementById("password").value;
      e.preventDefault();
      let phonenull = strategies.isNonEmpty(account, "手机号不能为空");
      let phone = strategies.isMobile(account, "手机号格式错误");
      let pwdMinLength = strategies.minLength(pwd, 6, "密码不能小于六位");
      let error = phonenull || phone || pwdMinLength;
      if (error) {
        console.log(error);
        return false;
      } else {
        console.log("提交成功!");
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    嵌入式linux系统中设备树基础知识
    数据结构与算法(四)--队列
    gpg: no valid OpenPGP data found.
    KY37 小白鼠排队
    SpringMVC应用
    spring boot 返回文件流
    E 排队(排列组合)[牛客小*白月赛61]
    进程控制(跑路人笔记)
    10. Spring源码篇之BeanPostProcessor
    Python 数据可视化:Matplotlib库的使用
  • 原文地址:https://blog.csdn.net/nanchen_J/article/details/133854250