javascript策略模式

定义

策略模式指的是定义一系 列的算法,把它们一个个封装起来。将不变的部分和变化的部分隔开是每一个设计模式的主题,策 略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。html

一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体 的算法,并负责具体的计算过程。 第二个部分是环境类 Context,Context接受客户的请求,随后 把请求委托给某一个策略类。要作到这点,说明 Context中要维持对某个策略对象的引用算法

<!--algorithm-->
var strategies = {
    s: function(salary){
        return salary *4;
    },
    a: function(salary){
        return salary * 3;
    },
    b: function(salary){
        return salary * 2
    }
}

<!--context-->
var calculateBonus = function(level, salary){
    return strategies[level](salary)
}

复制代码

更广义的“算法

在实际开发中,咱们一般会把算法的含义扩散开来,使策略模式也能够用来封装 一系列的“业务规则”。只要这些业务规则指向的目标一致,而且能够被替换使用,咱们就能够 用策略模式来封装它们。设计模式

实战

背景

在一个 Web项目中,注册、登陆、修改用户信息等功能的实现都离不开提交表单。 在将用户输入的数据交给后台以前,经常要作一些客户端力所能及的校验工做,好比注册的 时候须要校验是否填写了用户名,密码的长度是否符合规定,等等。这样能够避免由于提交不合 法数据而带来的没必要要网络开销。网络

假设咱们正在编写一个注册的页面,在点击注册按钮以前,有以下几条校验逻辑。app

  1. 用户名不能为空。
  2. 密码长度不能少于 6位。
  3. 手机号码必须符合格式。

表单校验的第一个版本(传统版本)

<body>
    <form action="http:// xxx.com/register" id="registerForm" method="post">
    请输入用户名:<input type="text" name="userName"/ >
    请输入密码:<input type="text" name="password"/ >
</body>
复制代码
var registerForm = document.getElementById( 'registerForm' );
registerForm.onsubmit = function(){
    if ( registerForm.userName.value === '' ){
        alert ( '用户名不能为空' );
        return false;
    }
    if ( registerForm.password.value.length < 6 ){
        alert ( '密码长度不能少于 6 位' );
        return false;
    }
    if ( !/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value ) ){
        alert ( '手机号码格式不正确' );
        return false;
    }
}
复制代码
  1. registerForm.onsubmit 函数比较庞大,包含了不少 if-else 语句,这些语句须要覆盖全部的校验规则。
  2. registerForm.onsubmit 函数缺少弹性,若是增长了一种新的校验规则,或者想把密码的长
  3. 度校验从 6改为 8,咱们都必须深刻 registerForm.onsubmit 函数的内部实现,这是违反开放 — 封闭原则的。
  4. 算法的复用性差,若是在程序中增长了另一个表单,这个表单也须要进行一些相似的校验,那咱们极可能将这些校验逻辑复制得漫天遍野。

用策略模式重构表单校验

下面咱们将用策略模式来重构表单校验的代码,很显然第一步咱们要把这些校验逻辑都封装 成策略对象:dom

var strategies = {
    isNonEmpty: function(value, errorMsg){
        if(value === ''){
            return errorMsg;
        }
    },
    minLength: function(value, length, errorMsg){
        if(value.length < length){
            return errorMsg
        }
    },
    isMobile: function(value, errorMsg){
        if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){
            return errorMsg;
        }
    }
}
复制代码

Validator 类的实现:函数

var Validator = function(){
    this.cache = [];
}

Validator.prototype.add = function(dom, rule, errorMsg){
    var ary = rule.split(':');// 把 strategy 和参数分开
    this.cache.push(function(){// 把校验的步骤用空函数包装起来,而且放入 cache
        var strategy = ary.shifg();// 用户挑选的 strategy
        ary.unshift(dom.value);// 把 input 的 value 添加进参数列表
        ary.push(errorMsg);// 把 errorMsg 添加进参数列表
        return strategies[strategy].apply(dom, ary);
    })
}

Validator.prototype.start = function(){
    for(var i=0, validatorFunc; validatorFunc = this.cache[i++]){
        var msg = validatorFunc();// 开始校验,并取得校验后的返回信息
        if(msg){ // 若是有确切的返回值,说明校验没有经过
            return msg;
        }
    }
}


复制代码

使用策略模式重构代码以后,咱们仅仅经过“配置”的方式就能够完成一个表单的校验, 这些校验规则也能够复用在程序的任何地方,还能做为插件的形式,方便地被移植到其余项 目中。post

在修改某个校验规则的时候,只须要编写或者改写少许的代码。好比咱们想将用户名输入框 的校验规则改为用户名不能少于 4个字符。能够看到,这时候的修改是绝不费力的。代码以下:ui

validator.add( registerForm.userName, 'isNonEmpty', '用户名不能为空' );

// 改为:
validator.add( registerForm.userName, 'minLength:10', '用户名长度不能小于 10 位' );
复制代码

给某个文本输入框添加多种校验规则

<!--Validator类-->
var Validator = function(){
    this.cache = [];
};

Validator.prototype.add = function(dom, rules){
    var self = this;
    for(var i=0, rule; rule = rules[i++]){
        (function(rule){
            var strategyAry = rule.strategy.split(':');
            var errorMsg = rule.errorMsg;
            
            self.cache.push(function(){
                var strategy = strategyAry.shift();
            })
        })(rule)
    }
}

Validator.prototype.start = function(){
    for(var i=0, validatorFunc;validatorFunc = this.cache[i++];){
        var errorMsg = validatorFunc();
        if(errorMsg){
            return errorMsg;
        }
    }
}

复制代码

策略模式的优缺点

优势:this

  1. 策略模式利用组合、委托和多态等技术和思想,能够有效地避免多重条件选择语句。
  2. 策略模式提供了对开放 — 封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展。
  3. 策略模式中的算法也能够复用在系统的其余地方,从而避免许多重复的复制粘贴工做。
  4. 在策略模式中利用组合和委托来让 Context拥有执行算法的能力,这也是继承的一种更轻便的替代方案。

缺点:

  1. 使用策略模式会在程序中增长许多策略类或者策略对象
  2. ,要使用策略模式,必须了解全部的 strategy ,必须了解各个 strategy 之间的不一样点, 这样才能选择一个合适的 strategy 。
相关文章
相关标签/搜索