JavaScript形而上的策略模式
什么是策略模式?
先看代码片段1。
// 代码片段1
var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new performanceS());
console.log('bounsS' ,bonus.getBonus());
// => 40000
bonus.setStrategy(new performanceA());
console.log('bounsA',bonus.getBonus());
// => 30000
bonus
是一个对象,而对象自带上下文。
这个对象在运行的不同阶段,通过setStrategy
设置了不同的参数,导致同样的bonus.getBonus()
输出结果不同。
所以策略模式是指,定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
下面的代码片段2是代码片段1的定义。
// 代码片段2
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 () {
return this.strategy.calculate(this.salary);
};
改进的策略模式
同样的bonus.getBonus()
,却输出结果不同。
当业务变得复杂,这会导致代码难以预测。
我们稍微改进一下,让对象初始化时接收一个策略对象,并且设置策略属性不可修改。
// 代码片段3
var bonusFactory = function(strategy){
this.salary = null;
Object.defineProperty(this, 'strategy',{
value: strategy,
writable: false,
configurable:false,
})
};
bonusFactory.prototype.setSalary = function (salary) {
this.salary = salary;
};
bonusFactory.prototype.getBonus = function () {
return this.strategy.calculate(this.salary);
};
var bonusS = new bonusFactory(new performanceS());
bonusS.setSalary(10000);
bonusS.strategy = 11;
console.log('bonusS', bonusS.getBonus());
var bonusA = new bonusFactory(new performanceA());
bonusA.setSalary(10000);
console.log('bonusA', bonusA.getBonus());
策略模式的函数式写法
这里使用了名为ramda
的函数式工具库。
var R = require('ramda');
var salaryS = function(salary) {
return salary * 4;
};
var salaryA = function(salary) {
return salary * 3;
};
var salaryB = function(salary) {
return salary * 2;
};
var getBonus = function(salary, strategy){
return strategy(salary);
};
var getBonusFacotry = R.curry(getBonus);
var getBonusS = getBonusFacotry(R.__, salaryS);
var getBonusA = getBonusFacotry(R.__, salaryA);
var getBonusB = getBonusFacotry(R.__, salaryB);
var getBouns1000 = getBonusFacotry(1000, R.__);
console.log('封装奖金计算方式的策略');
console.log(getBonusS(1000));
console.log(getBonusA(1000));
console.log(getBonusB(1000));
console.log('封装奖金数目的策略');
console.log(getBouns1000(salaryS));
console.log(getBouns1000(salaryA));
console.log(getBouns1000(salaryB));
可以看到函数式写法更加灵活和简洁。
合乎自然而生生不息。。。