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

概念

大量的 if 判断操作,逻辑比较复杂,并且处理起来相对麻烦。可以采用策略模式来优化分支代码。
策略模式 💤 :是一种行为设计模式,它允许你在运行时根据不同情况选择不同的算法或行为。
设计模式 🤌 :就是提前第一次了解全过程,第二次直接规划不必要的坑。

我们在写代码亦是如此,一定也遇到过许多类似的场景。随着程序员经验的增加,我们对于这些常见场景的处理越来越得心应手,甚至总结出了针对性的"套路",下次遇到此类问题直接运用"套路"解决,省心又省力。这些在软件开发过程中逐渐积累下来的"套路"就是设计模式。

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

例:

js 复制代码
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"); // 启动!

简单优化一下写法:

js 复制代码
const game = (name) => {
  let obj = {
    原s: "启动!",
    xx精英: "我先成盒了你们加油!",
    云顶yy: "这就是我们之间的羁绊!",
    王者zz: "我再也不买皮肤了!",
  };
  if (obj[name]) {
    console.log(obj[name]);
  } else {
    console.log("我啥也没玩");
  }
};
game("原s"); // 启动!

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

js 复制代码
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"); // 启动!

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

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

js 复制代码
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. 案例

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

html 复制代码
<!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>

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

2. 优化

先将此方法抽离出来

js 复制代码
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;
    }
  },
};

修改 Context 内容部分

js 复制代码
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;
  }
};

完整代码如下

html 复制代码
<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>
js 复制代码
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("提交成功!");
  }
});
相关推荐
花海少爷11 分钟前
第十章 JavaScript的应用课后习题
开发语言·javascript·ecmascript
Amd79415 分钟前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You24 分钟前
09 —— Webpack搭建开发环境
前端·webpack·node.js
狸克先生35 分钟前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互
sinat_3842410938 分钟前
在有网络连接的机器上打包 electron 及其依赖项,在没有网络连接的机器上安装这些离线包
javascript·arcgis·electron
baiduopenmap1 小时前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish1 小时前
小程序webview我爱死你了 小程序webview和H5通讯
前端
小牛itbull1 小时前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
菜牙买菜1 小时前
让安卓也能玩出Element-Plus的表格效果
前端
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript