设计模式—策略模式

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换,策略模式的目的就是将算法的使用与算法的实现分离开来。
首先我们来看一个情景:很多公司的年终奖是根据员工的绩效来进行发放,绩效为S的人,年终奖有4倍工资,绩效为A的人有3倍工资,绩效为B的人有2倍工资。我们怎么用代码来实现这个问题呢?
很简单粗暴的会想到:

var calculateBonus = function (performacceLevel, salary) {
    if (performacceLevel === "S") {
        return salary * 4;
    }
    if (performacceLevel === "A") {
        return salary * 3;
    }
    if (performacceLevel === "B") {
        return salary * 2;
    }
};

这段的代码存在什么问题呢?
过多的if-else,函数缺乏弹性,如果我们现在又增加一种绩效C,那么我们该怎么办,我们只有手动去改我们的代码,这也就违反了我们所说的开闭原则。
下面我们利用策略模式来对这段代码进行重构:
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个是环境类Context,Context接受客户的请求后,随后把请求委托给某一个策略类。再说明白点就是,Context把客户发起的请求,委托给了一个策略类new出来的一个策略对象。

// 定义三种策略类
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 (stratrgy) {
    this.strategy = stratrgy;
};
Bonus.prototype.getBonus = function () {
    return this.strategy.calculate(this.salary);
};
var bonus = new Bonus();
bonus.setSalary(20000);  
bonus.setStrategy(new PerformanceS());
console.log(bonus.getBonus());    // 80000

bonus.setStrategy(new PerformanceA());
console.log(bonus.getBonus());    // 60000

这种方式是仿造传统面向对象语言实现的,利用js的特性,函数就是对象,所以我们可以将策略类定义为一个对象,PerformanceS,PerformanceA,PerformanceB设置为该对象的方法,就有如下代码:

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("B", 20000));   // 40000

下面来看策略模式的两个具体应用:
编写一个动画运动,其中tween为策略类对象,其中的每一种方法,代表其每一种策略

// 策略类
var tween = {
    linear: function (useTime, originPos, targetPos, allTime) {
        return targetPos * useTime / allTime + originPos; 
    },
    easeIn: function (useTime, originPos, targetPos, allTime) {
        return targetPos * (useTime /= allTime) * useTime + originPos; 
    },
    strongEaseIn: function (useTime, originPos, targetPos, allTime) {
        return targetPos * (useTime /= allTime) * useTime * useTime * useTime * useTime + originPos; 
    },
    strongEaseOut: function (useTime, originPos, targetPos, allTime) {
        return targetPos * ((useTime = useTime / allTime - 1) * useTime * useTime * useTime * useTime + 1) + originPos; 
    },
    sineaseIn: function (useTime, originPos, targetPos, allTime) {
        return targetPos * (useTime /= allTime) * useTime * useTime + originPos;
    },
};
// 运动类,easing可以采取不同的策略
var Animate = function (dom) {
    this.dom = dom;
    this.startTime = 0;
    this.startPos = 0;
    this.endPos = 0;
    this.propertyName = null;     // 节点需要被改变的css属性名
    this.easing = null;           // 运动算法
    this.duration = null;
};
Animate.prototype.start = function (propertyName, targetPos, duration, easing) {
    this.startTime = +(new Date());
    this.startPos = this.dom.getBoundingClientRect()[propertyName];
    this.endPos = targetPos;
    this.duration = duration;
    this.easing = tween[easing];
    this.propertyName = propertyName;

    var self = this,
        timeId = setInterval(function () {
            if (self.step() === false) {
                clearInterval(timeId);
                timeId = null;
            }
        }, 20);
};
Animate.prototype.step = function () {
    var time = +(new Date()),
        pos;
    if (time >= this.startTime + this.duration) {
        this.update(this.endPos);
        return false;
    }
    pos = this.easing(time - this.startTime, this.startPos, this.endPos - this.startPos, this.duration);
    this.update(pos);
};
Animate.prototype.update = function (pos) {
    pos = pos | 0;
    this.dom.style[this.propertyName] = pos + "px";
};
// 测试代码
var div = document.getElementById("div"),
    animate = new Animate(div);
animate.start("left", 500, 1000, "easeIn");
// html代码
<div id="div" style="position: absolute;height:100px;width:100px;background:red;"></div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值