JS设计模式-策略模式
发布于 4 年前 作者 myfirebug 6036 次浏览 来自 分享

定义 定义一系列的算法,把他们一个个封装起来,并且使他们可以互相替换。 优点

    • 策略模式利用组合,委托和多态等技术思想,可以避免多重条件语句。
    • 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的stragety中,使得它们易于切换,理解和扩展。
    • 策略模式中算法也可以在其他地方复用,避免冗余代码。 缺点
  1. 使用策略模式会增加许多策略类或者策略对象。
  2. 要使用stragety,必须要了解所有stragety的细节。此时stragety向客户暴露了其实现,这是有违最少知识原则的。

1.使用策略计算评分内容

假设有如下需求:总评分为5分,评分为1分显示非常差,评分为2显示差,评分为3显示一般,评分为4显示好,评分为5显示非常好。你可能会很自觉写出如下代码:

function getStarText(level) {
    if (level = 1) {
        return '非常差'
    } else if (level = 2) {
        return '差'
    } else if (level = 3) {
        return '一般'
    } else if (level = 4) {
        return '好'
    } else if (level = 5) {
        return '非常好'
    }
}
console.log(getStarText(2)); // 非常差

使用策略实现

let strategies = {
    level1: function (level) {
        return '非常差'
    },
    level2: function (level) {
        return '差'
    },
    level3: function (level) {
        return '一般'
    },
    level4: function (level) {
        return '好'
    },
    level5: function (level) {
        return '非常好'
    }
}
function getStarText(level) {
    return strategies['level' + level] ? strategies['level' + level](level) : '一般'
}
console.log(getStarText(4)); // 非常差

2.使用策略模式实现表单校验 表单验证是一个很常见的功能需求,假设你需要为一个网站编写注册模块。用户需要输入用户、密码、手机号码点击注册 按钮进行注册,在向后端发送请求,需要在前端校验合法法:用户名不能为空,密码不能为空,手机号码不能为空且手机号码必须符合正确的格式。 html代码如下:

<form id="js_register">
    <p>用户名:<input type="text" name="username"></p>
    <p>密 码:<input type="text" name="password"></p>
    <p>手机号码:<input type="text" name="phone"></p>
    <button>提交</button>
</form>

可能我们很容易就写出了以下代码:

var registerForm = document.getElementById('js_register');
registerForm.onsubmit = function() {
    if (registerForm.username.value === '') {
        alert('用户名不能为空');
        return false;
    }
    if (registerForm.password.value === '') {
        alert('密码不能为空');
        return false;
    }
    if (registerForm.phone.value === '') {
        alert('手机号码不能为空');
        return false;
    }
    if (!/^1[3|5|8][0-9]{9}$/.test(registerForm.phone.value)) {
        alert('手机号码格式不正确');
        return false;
    }
}

缺点: 1.registerForm.onsubmit函数比较庞大,包含了很多if-esle语句。 2.registerForm.onsubmit 函数缺乏弹性,如果增加了一种新的校验规则,我们都必须深入registerForm.onsubmit 函数的内部实现,这是违反开放-封闭原则的。 3.算法的复用性差,如果在程序中还有一个登录表单,这个表单也需要进行一些类似的校验,那么我们很可能随处都可见这些校验逻辑规则的复制。 下面,我们使用策略模式来实现表单校验:

// 封装策略对象
let rules = {
    required: function (value, message) {
        if (value === '') {
            return message
        }
    },
    isMobile: function (value, message) {
        if (!/^1[3|5|8][0-9]{9}$/.test(value)) {
            return message
        }
    }
}

// 校验规则
function Validate() {
    this.rules = [];
}

Validate.prototype = {
    constructor: Validate,
    add: function (element, rule) {
        let _self = this;
        for (let i = 0; i < rule.length; i++) {
            (function (rule) {
                let array = rule.type.split(':'),
                    error = rule.message;
                _self.rules.push(function () {
                    // 取出用户指定的stragety
                    let stragety = array.shift();
                    // 将input的value放到参数列表最前面
                    array.unshift(element.value);
                    // 将errMsg放到参数列表最后面
                    array.push(error);
                    return rules[stragety].apply(element, array);
                })
            })(rule[i]);
        }
    },
    start: function () {
        for (let i = 0; i < this.rules.length; i++) {
            let message = this.rules[i]();
            if (message) {
                return message
            }
        }
    }
}

let registerForm = document.getElementById('js_register'),
    validates = function () {
        let validate = new Validate();
        validate.add(registerForm.username, [
            {type: 'required', message: '用户名不能为空'}
        ]);
        validate.add(registerForm.password, [
            {type: 'required', message: '密码不能为空'}
        ]);
        validate.add(registerForm.phone, [
            {type: 'required', message: '手机号码不能为空'},
            {type: 'isMobile', message: '手机号码格式不正确'}
        ]);
        let message = validate.start();
        return message
    };
validates();
registerForm.onsubmit = function () {
    let message = validates();
    if (message) {
        alert(message);
        return false
    }
}
1 回复

状态模式和策略模式有点相似,有没有想过具体区别。提个小意见,文章尽可能代码为辅,因为看大篇幅代码是个很累的事情。

回到顶部