设计模式之开闭原则:对修改关闭,对扩展开放

3,450 阅读3分钟
  • 底层模块的变更,必然有高层模块的耦合,开闭原则就是减少变更的扩展性

通俗的意思就是说,在开发过程中,在前期设计就必须做好相对应的扩展

  • 在修改代码时必须要尽量少动原有的代码,最好不要修改老的代码,这就是对修改关闭
  • 那么如何处理新的需求呢?这里就涉及到代码的前期涉及了,尽量做到的是新增函数,只对新需求做扩展

这里举一个栗子:

这里有个表单:

<div id="loginForm">
    <input type="text" class="username" id="username" placeholder="username"><br>
    <input type="text" class="pwd" id="pwd" placeholder="pwd"><br>
    <button onclick="checkLogin()">提交</button>
</div>

一般做前端校验的方法可能就会是这个样子:

  • 写一个公共的校验方法来对表单中的每个输入项进行校验
  • 取出 input 表单中的每个值,依次根据指定的校验规则,来校验前端输入的内容
  • 如果出现错误的话,就会对这个输入错误的数据进行提醒

比如下面这样的方式:

function checkLogin() {

    let username = document.querySelector("#username").value;
    if (!username) {
        alert("username must not be null");
    }

    let pwd = document.querySelector("#pwd").value;
    if (!pwd) {
        alert("pwd must not be null");
    }
}

这样就会面临下面的问题:

  • 如果校验规则有变动的话,就需要对原来的代码进行修改
  • 如果需求有变动,比如在原来的表单中新增了一个 input 输入框的话,就还需要修改原来的这个校验的代码
  • 一般来说,修改代码都有可能对原来的代码造成一定的问题,修改就有可能出错

对修改关闭

这是一个非常重要的原则,对原来已有的代码最好不做修改

那么我们在这里该这么做呢?看这样的修改:

  1. 在 html 中添加一个 input 输入框自身的自定义属性 data-validate 用来标识这个 input 输入框对应的校验函数名
<div id="loginForm">
    <input type="text" class="username" data-validate="checkUsername" id="username" placeholder="username"><br>
    <input type="text" class="pwd" data-validate="checkPwd" id="pwd" placeholder="pwd"><br>
    <button onclick="checkLoginForm()">提交</button>
</div>
  1. 写通用函数,专门负责这个表单的校验,获取所有的 input 输入框,拿到对应的校验函数,并调用对应的挂载在 window 上的校验函数
function checkLoginForm() {
    // 表单
    let form = document.querySelector("#loginForm");
    // 表单中input
    let ipts = form.querySelectorAll("input");
    // 获取input中的校验函数名,并调用对应的函数
    for (let i = 0; i < ipts.length; i++) {
        let input = ipts[i];
        let validate = input.dataset.validate;
        let validateFn = window[validate];
        if (validateFn) {
            let rst = !validateFn(input.value);
            if (rst) {
                return false;
            }
        } else {
            alert(`当前没有这个${validate}校验函数`);
        }
    }

}
  1. 这样以后的扩展就可以单独写对应的校验函数就ok,无需再去修改原来的 checkLoginForm 函数,同时校验函数还可以复用。
function checkUsername(username) {
    if (!username) {
        alert("username must not be null");
    }
}
  1. data-validate="checkUsername" 属性值对应的就是通用的校验函数名称,减少对原有代码的修改和侵入。