前端进阶与开发实践Web前端之路

翻滚吧,设计模式之02策略模式笔记

2017-05-12  本文已影响15人  莫闻

问题提出:

  1. 最初的代码实现
var calculateBonus = function(level, salary){
      if(level === "s"){
          return salary*4;    
      }else if(level === "a"){
          return salary*3; 
      }else if(level === "b"){
          return salary*2; 
      }
}
console.log(calculateBonus(10000,"a"));//30000
console.log(calculateBonus(10000,"b"));//20000
//可以使用组合函数进行代码重构
var levelS = function(salary){
    return salary*4;
}
var levelA = function(salary){
    return salary*3;
}
var levelB = function(salary){
    return salary*2;
}

var calculateBonus = function(level, salary){
    if(level == "s"){
        return levelS(salary);
    }else if(level == "a"){
        return levelA(salary);
    }if(level == "b"){
        return levelB(salary);
    }
}
//我们可以看到,将具体的方法进行了分离
//但是这种重构方法的作用感觉很有限,没有解决调本质的问题

  1. 策略类:封装了具体的算法,并负责集体的计算过程。
  2. 环境类:context 接受客户请求,随后吧请求委托给某一个策略类,说明了context中要维持对某个策略对象的引用;

先看一下js模仿传统的面向对象的实现方法

// 策略类
var performaceS = function(){

}
performaceS.prototype.calculate = function(salary){
   return salary*4;
}

var performaceA = function(){

}
performaceA.prototype.calculate = function(salary){
   return salary*4;
}

var performaceB = function(){

}
performaceB.prototype.calculate = function(salary){
   return salary*4;
}


//- 定义奖金了类
var Bouns = function(){
   this.salary = null;//原始工资
   this.strategy = null;//绩效等级对应的策略对象
}
Bonus.prototype.setSalary = function(salary){
   this.salary = salary;//设置员工的原始工资
}
Bonus.prototype.setStrategy = function(strategy) {
   this.strategy = strategy;//设置员工绩效等级对应的策略对象
}
Bonus.prototype.getBonus = function(){
   return this.strategy.calculate (this.salary);/把计算奖金的操作委托给对应策略对象
}
//让我们再来回顾下策略模式的思想:定义一系列的算法,把他们一个个封装起来,并且可以使他们相互替换。
//详细点就是:定义一系列算法,把他们封装成策略类,算法被封装到策略类内部的方法里。
//客户对Context发起请求时,context总是把请求委托给这些策略对象中的某一个进行计算。

var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new perfomaceS());//设置策略类对象
console.log(bonus.getBonus());

bonus.setSalary(20000);
bonus.setStrategy(new performaceA());//设置策略类
console.log(bonus.getBonus());

策略模式js版的正式实现

//策略类(对象)
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);
}
console.log(calculateBonus("S",10000));
//可以看出来将构造函数进行简化,直接采用对象,简化了代码的体积,消除了原来在代码中的大片if语句,如果后期我们有其他需求时(添加一个C类),只需要修改策略类就行了

再来举一个web中很常见的例子,表单提交时我们要进行验证

//html
请输入用户名: <input type="text" name="userName"/ >
请输入密码: <input type="text" name="password"/ >
请输入手机号码: <input type="text" name="phoneNumber"/ >
<button id="btn">提交</button>
//js
var btn = document.getElementById("btn");
//伪代码
btn.onclick = function(){
    if(userName.value === ""){//
        alert("用户名不能为空");
        return false;
    }
    if(password === rexExp){
        alert();
        return false;
    }
    if(phoneNumber === regExp1){
        alert();
        return false;
    }
}
//策略类,封装算法
var strategies = {
    isEmpty:function(value, errMsg){
        if(value.trim() == ''){
            return errMsg
        }
    },
    minLength:function(value, length, errMsg){
        if(value.length < length){
            return errMsg;
        }
    },
    isMobile:function(value,errMsg){
        if(!/(^1[3|5|8][0-9]{9}$)/.test( value ) ){
            return errMsg;
        }
    }
};

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

Validator.prototype.add = function(dom, rule, errMsg) {
    var arr = rule.split(":");
    //r比如数据参数是这样的:egisterForm.userName, 'isNonEmpty', ' 用户名不能为空'
    this.cache.push(function(){//把校验的步骤用空函数包裹起来
        var strategy = arr.shift();//用户挑选的strategy
        arr.push(dom.value);//将input的值传入缓存数组中
        arr.push(errMsg);//将error也添加进数组中
        return strategies[strategy].apply(dom, arr);
    });
}
Validator.prototype.start = function(){
    for(var i = 0,ValidatorFun; ValidatorFun =  this.cache[ i++ ]){
        var msg = ValidatorFun();//开始校验并返回数据
        if(msg){//如果有返回说明没有通过
             return msg;
        }
    }
}

var form = document.getElementById( 'registerForm' );
var validataFunc = function(){
   var validator = new Validator();
   validator.add(form.userName, 'isEmpty', '对象不能为空');
   validator.add( form.password, 'minLength:6', ' 密码长度不能少于 6 位' );
   var errMsg = volidator.start();
    return errMsg;
}
form.onsubmit = function(){
     var errorMsg = validataFunc(); // 如果 errorMsg 有确切的返回值,说明  未通过校验
     if ( errorMsg ){
       alert ( errorMsg );
       return false; // 阻止表单提交
     }
};

参考自javascript设计模式与开发实践

上一篇 下一篇

猜你喜欢

热点阅读