JavaScript设计模式与开发实践---读书笔记(5) 策略模式

策略模式的定义是:定义一系列的算法,把它们一个个封转起来,并且使它们可以相互替换。

JavaScript版本的策略模式:

奖金系统:

var strategies = {
        "S": function(salary){
            return salary*4;
        },
        "A": function(salary){
            return salary*3;
        },
        "B": function(salary){
            return salary*2;
        }
    };

    var calculateBonus = function(level,salary){
        return strategies[level](salary);
    };

    console.log(calculateBonus('S',20000));//输出:80000
    console.log(calculateBonus('A',10000));//输出:30000

使用策略模式实现缓动动画:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>小球运动策略模式</title>
    <style>
        #div{
            position: absolute;
            background: blue;
            width:50px;
            height: 50px;
        }
    </style>
</head>
<body>
    <div id="div">我是小球</div>
</body>
</html>
<script>
    var tween = {
        linear: function(t,b,c,d){
            return c*t/d+b;
        },
        easeIn: function(t,b,c,d){
            return c*(t/=d)*t+b;
        },
        strongEaseIn: function(t,b,c,d){
            return c*(t/=d)*t*t*t*t+b;
        },
        strongEaseOut: function(t,b,c,d){
            return c*((t=t/d-1)*t*t*t*t+1)+b;
        },
        sineaseIn: function(t,b,c,d){
            return c*(t/=d)*t*t+b;
        },
        sineaseOut: function(t,b,c,d){
            return c*((t=t/d-1)*t*t+1)+b;
        }
    };

    var Animate = function(dom){
        this.dom = dom;//进行运动的dom节点
        this.startTime = 0;//动画开始时间
        this.startPos = 0;
        this.endPos = 0;
        this.propertyName = null;
        this.easing = null;
        this.duration = null;
    };

    Animate.prototype.start = function(propertyName,endPos,duration,easing){    //启动这个动画
        this.startTime = +new Date;
        this.startPos = this.dom.getBoundingClientRect()[propertyName];//dom初始节点位置
        this.propertyName = propertyName;//dom节点需要被改变的CSS属性名
        this.endPos = endPos;//dom节点目标位置
        this.duration = duration;//动画持续事件
        this.easing = tween[easing];//缓动算法

        var self = this;
        var timeId = setInterval(function(){
            if(self.step()===false){
                clearInterval(timeId);
            }
        },19)
    };

    Animate.prototype.step = function(){  //代表小球运动的每一帧要做的事情
        var t = +new Date;
        if(t>=this.startTime+this.duration){//修正小球位置
            this.update(this.endPos);//更新小球的CSS属性值
            return false;
        }
        var pos = this.easing(t-this.startTime,this.startPos,this.endPos-this.startPos,this.duration);
        this.update(pos);//更新小球的CSS属性值
    };

    Animate.prototype.update = function(pos){
        this.dom.style[this.propertyName] = pos+'px';
    };

    var div = document.getElementById('div');
    var animate = new Animate(div);
    animate.start('left',500,1000,'strongEaseOut');
    //animate.start('top',1500,500,'strongEaseIn');
</script>

策略模式指的是定义一系列的算法,并且把它们封装起来。
表单验证:

校验逻辑:

  • 用户名不能为空
  • 密码长度不能少于6位
  • 手机号码必须符合格式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>策略模式表单验证</title>
</head>
<body>
    <form action="" id="registerForm" method="post">
        请输入用户名:<input type="text" name="userName">
        请输入密码:<input type="text" name="password">
        请输入手机号码:<input type="text" name="phoneNumber">
        <button>提交</button>
    </form>
</body>
</html>
<script>
    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,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();
                    strategyAry.unshift(dom.value);
                    strategyAry.push(errorMsg);
                    return strategies[strategy].apply(dom,strategyAry);
                });
            })(rule)
        }
    };

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

    //用户调用代码
    var registerForm = document.getElementById('registerForm');
    var validataFunc = function(){
        var validator = new validator();//创建一个validator对象
        validator.add(registerForm.userName,[{
            strategy:'isNonEmpty',
            errorMsg:'用户名不能为空'
        },{
            strategy:'minLength:6',
            errorMsg:'用户名长度不能小于6位'
        }]);
        validator.add(registerForm.password,[{
            strategy:'minLength:6',
            errorMsg:'密码长度不能小于6位'
        }]);
        validator.add(registerForm.phoneNumber,[{
            strategy:'isMobile',
            errorMsg:'手机号码格式不正确'
        }]);

        var errorMsg = validator.start();
        return errorMsg;
    };

    registerForm.onsubmit = function(){
        var errorMsg = validataFunc();
        if(errorMsg){
            alert(errorMsg);
            return false;
        }
    };

</script>

策略模式的一些优点:
策略模式利用组合、委托和多态等技术思想,可以有效地避免多重条件选择语句。

策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的startegy中,使得它们易于切换,易于理解,易于扩展。

策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制性粘贴工作。

在策略模式中利用组合和委托让Context拥有执行算法的能力,这也是继承的一种更轻便的替代方案。

 

在JavaScript语言的策略模式中,策略类往往被函数所代替,这时策略模式就是一种"隐形"的模式。

 

posted @ 2016-10-07 21:17  cmy1025  阅读(144)  评论(0编辑  收藏  举报