策略模式

  1. 策略模式
    1. 一个表单验证的例子
      1. 通常我们的做的简单表单验证
    2. 策略模式简介
    3. 使用策略模式构建的表单校验
  2. 史诗级的表单验证
  3. 优缺点
  4. 思考

策略模式

一个表单验证的例子

给一个html页面,带一个form表单

<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>
    var loginForm = document.getElementById('login-form');

    loginForm.onsubmit = function (e) {
        e.preventDefault();  
        var account = document.getElementById("account").value;
        var pwd = document.getElementById("password").value;

        if(account===null||account===''){
            alert('手机号不能为空');
            return false;
        }
        if(pwd===null||pwd===''){
            alert('密码不能为空');
            return false;
        }
        if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(account)) {
            alert('手机号格式错误');
            return false;
        }
        if(pwd.length<6){
            alert('密码不能小于六位');
            return false;
        }
        // 发送请求
    }
</script>

通常我们都是想,直接用if else来解决各种表单的验证,但是这样做的问题是,每次新加一个验证规则都要找到onsubmit函数,添加if判断,而且还要知道对应的字段名,麻烦就算了,最重要的是逻辑不能复用,如果有多个地方用到这个表单判断又要重写,这时候用到策略模式,一个策略就像一个诸葛亮的精囊妙计

策略模式简介

  • 意图: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
  • 方式:创建一个策略对象和一个context,context的行为会随着不同的策略对象有不同的表现
  • 解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

使用策略模式构建的表单校验

// 策略对象
const strategy = {
    isNoEmpty: (val) => {
        if(val === null || var == '') {
            return '不能为空'
        }
    },
    isPhoneNum: (val) => {
        if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(account)) {
            return '手机号格式错误'
        }
    },
    length: (val, len) => {
        if (val.length > len) {
            return '不能小于六位'
        }
    }
 }

// 上下文
const context = (formRule) => {
    if(let i = 0; i < formRule.length; i++) {
        const item = formRule[i]
        const res = strategy[item.type](item.val)
        if(res) res
    }
}

/**
class validator {
    constructor() {
        this.strategy = null
        this.formRule =null 
    }
    // 设置策略对象
    setStrategy(val) {
        this.startegy = val
    }
    // 设置规则
    setFormRule() {
        this.formRule = val
    }
    // 验证,相对于context
    validate() {
        if(let i = 0; i < formRule.length; i++) {
        const item = formRule[i]
        const res = strategy[item.type](item.val)
        if(res) res
    }
    }
}
*/

// 提交
function subimit() {
    const form =  [
        {type: 'isNoEmpty', val:account },
        {type: 'isNoEmpty', val:pwd },
        {type: 'isPhoneNum', val:account },
        {type: 'length', val:pwd },
    ] // 简化的表单数据

    // 验证
    if(!context(form)) return

    /**
    // 验证
    const validator = new context()
    validator.setStrategy(strategy)
    validator.setFormrule(form)
    if(!validator.validate()) return
    */
    // 发起请求...

}

这里用的就是策略模式,定义了一个策略对象,和一个context控制执行,可以很方便的实现逻辑复用

史诗级的表单验证

相关库 async-validator,可以找相关源码了解,同样是用了了策略模式。

优缺点

优点:

  1. 把相互独立的代码块封装在一处,方便以后管理扩展
  2. 优于继承,继承的算法是封装在类里的,在算法多的情况下,会衍生很多不同的类,而类里面算法和使用者耦合也会增加维护难度
  3. 优化繁重的if else,提升代码简洁度

缺点:

  1. 选择算法时,必须了解全部算法的使用方法,才能选择合适的方法,违反最小知识原则
  2. 算法间相互独立,如果有共同部分无法实现共享

思考

  • 在哪些场景下适用,哪些场景不适用?
  • 跟状态模式有什么不一样?

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1249118795@qq.com