策略模式

  • What: 定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换(相互替换主要针对静态语言,对于js弱类型语言则不是很重要)
  • where: 验证表单;运动函数;
  • when:
  • who:
  • why: 优点:解决代码量、开放封闭(需要增加if else判断、缺乏弹性)(扩展性)、复用行性;缺点:必须了解所有策略才可以选择
  • how: 将算法的使用和算法的实现分离出来(可以体现出多态性)

eq1: 基于策略模式的编写方式:

  1. 策略类:封装具体算法;
  2. 环境类:接受客户请求,把请求委托给某一个策略;

eq2: 箭头函数

  1. 箭头函数没有prototype属性;
  2. 没能作为构造器;
  3. 不能作为函数生成器;

eq3:不建议使用prototype和箭头函数结合,影响this指向问题

简单版实现

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

var performanceA = function() {};
performanceA.prototype.calculate = function(salary) {
    return salary * 3;
};

var performanceB = function() {};
performanceB.prototype.calculate = function(salary) {
    return salary * 2;
};

var Bonus = 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() {
    if (!this.strategy) {
        throw new Error('strategy is undefined');
    }
    return this.strategy.calculate(this.salary);
};

var bonus = new Bonus();
bonus.setSalary(1000);
bonus.setStrategy(new performanceS());
console.log(bonus.getBonus());
bonus.setStrategy(new performanceB());
console.log(bonus.getBonus());

基于js语言

var strategies = {
    'S': (salary) => 4 * salary,
    'A': (salary) => 3 * salary,
    'B': (salary) => 2 * salary
};
var calculateBonus = (level, salary) => {
    return strategies[level] && strategies[level](salary);
};
console.log(calculateBonus('S', 1000));
console.log(calculateBonus('B', 1000));

应用实例:

表单验证

/**
 * 表单校验
 */

// 没有解决非必传字段的校验

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

var Validate = function() {
    this.cache = [];
};
Validate.prototype.add = function(value, 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(value); // 向数组头部插入
                strategyAry.push(errorMsg); // 向数组尾部插图
                return strategies[strategy].apply(value, strategyAry); // apply(this, [参数]) 对于不同策略参数个数不同,使用apply解决参数个数问题
            });
        })(rule);
    }
};
Validate.prototype.start = function() {
    for(var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
        var msg = validatorFunc();
        if (msg) {
            return msg;
        }
    }
};


var registerForm = {
    userName: 'xiaoming',
    password: '123456',
    phoneNumber: '13333333333'
};
var validateFunc = function() {
    var validate = new Validate();
    validate.add(registerForm.userName, [{
        strategy: 'isNonEmpty',
        errorMsg: 'userName is empty!'
    }, {
        strategy: 'minLength:10',
        errorMsg: 'userName is less than 10!'
    }]);
    validate.add(registerForm.password, [{
        strategy: 'minLength:6',
        errorMsg: 'userName is less than 10!'
    }]);
    validate.add(registerForm.phoneNumber, [{
        strategy: 'isMobile',
        errorMsg: 'fill in phone number!'
    }]);

    var errorMsg = validate.start();
    return errorMsg;
};
console.log(validateFunc());

运动

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
            position: absolute;
            background: blue;
            width: 50px;
            height: 50px;
            left: 0;
            top: 0;
        }

    </style>
</head>

<body>
    <div class="box" id="box"></div>

</body>
<script>
    var tween = {
        Linear: (t, b, c, d) => c * t / d + b,
        easeIn: (t, b, c, d) => c * (t /= d) * t + b,
        strongEaseIn: (t, b, c, d) => c * (t /= d) * t * t * t * t + b,
        strongEaseOut: (t, b, c, d) => c * ((t /= d - 1) * t * t * t * t + 1) + b,
        sineaseIn: (t, b, c, d) => c * (t /= d) * t * t + b,
        sineaseOut: (t, b, c, d) => c * ((t /= d - 1) * t * t + 1) + b
    };

    var Animate = function(dom) {
        this.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];
        this.propertyName = propertyName;
        this.endPos = endPos;
        this.duration = duration;
        this.easing = tween[easing];

        var self = this;
        var timeId = setInterval(function() {
            if(self.step() === false) {
                clearInterval(timeId);
            }
        }, 10);
    };
    Animate.prototype.step = function() {
        var t = +new Date();
        if (t >= this.startTime + this.duration) {
            this.update(this.endPos);
            return false;
        }
        var pos = this.easing(t-this.startTime, this.startPos, this.endPos-this.startPos, this.duration);
        this.update(pos);
    };

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

    var dom = document.querySelector('#box');
    var animate = new Animate(dom);
    animate.start('left', 200, 500, 'sineaseOut');

</script>

</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值