策略模式
定义
指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
组成
一个基于策略模式的程序有以下组成部分:
- 抽象策略角色: 通常由一个接口或者抽象类实现
- 具体策略角色:包装了相关的算法和行为
- 环境角色:持有一个策略类的引用,最终给客户端调用
应用场景
- 针对同一类型问题的多种处理方式,在运行时动态选择具体要执行的行为
- 在不同情况下需要使用不同的策略(算法),或者在未来还可能新增其它方式来实现
- 隐藏具体策略(算法)的实现细节,彼此完全独立
代码实现
1 .使用面向对象的思想实现策略模式:
// 定义抽象策略角色
var Calculator = function(num1, num2){
this.num1 = num1;
this.num2 = num2;
};
Calculator.prototype.caculate = function() {};
// 定义具体策略角色(加法)
var Add = function(num1, num2){
Calculator.call(this, num1, num2);
};
inheritPrototype(Add, Calculator); // 寄生组合式继承
Add.prototype.caculate = function() {
console.log("num1 + num2 = " + (this.num1 + this.num2));
};
// 定义具体策略角色(减法)
var Sub = function(num1, num2){
Calculator.call(this, num1, num2);
};
inheritPrototype(Sub, Calculator);
Sub.prototype.caculate = function() {
console.log("num1 - num2 = " + (this.num1 - this.num2));
};
// 定义具体策略角色(乘法)
var Mul = function(num1, num2){
Calculator.call(this, num1, num2);
};
inheritPrototype(Mul, Calculator);
Mul.prototype.caculate = function() {
console.log("num1 * num2 = " + (this.num1 * this.num2));
};
// 定义具体策略角色(除法)
var Div = function(num1, num2){
Calculator.call(this, num1, num2);
};
inheritPrototype(Div, Calculator);
Div.prototype.caculate = function() {
console.log("num1 / num2 = " + (this.num1 / this.num2));
};
// 定义环境角色,负责和具体的策略交互,持有一个策略类的引用
var Environment = function(strategy) {
this.strategy = strategy;
}
Environment.prototype.caculateRes = function(){
return this.strategy.caculate();
}
var addMethod = new Environment(new Add(10, 5));
var subMethod = new Environment(new Sub(10, 5));
var mulMethod = new Environment(new Mul(10, 5));
var divMethod = new Environment(new Div(10, 5));
addMethod.caculateRes() // 打印结果 15
subMethod.caculateRes() // 打印结果 5
mulMethod.caculateRes() // 打印结果 50
divMethod.caculateRes() // 打印结果 2
如果需要增加新的计算方法,只需增加具体的策略实现即可,具有良好的扩展性。
2.使用Javascript版本的策略模式
// 策略对象
var calculate = function() {
// 内部实现算法
var strategy = {
add: function(num1, num2){
return num1 + num2;
},
sub: function(num1, num2) {
return num1 - num2;
},
mul: function(num1, num2) {
return num1 * num2;
},
div: function(num1, num2) {
return num1 / num2;
}
}
// 策略算法调用
return {
calculateRes: function(type, value) {
return strategy[type] ? strategy[type](...value) : "计算方法不存在"
},
}
}();
console.log("num1 + num2 = " + calculate.calculateRes('add', [10,5])) // 15
console.log("num1 - num2 = " + calculate.calculateRes('sub', [10,5])) // 5
console.log("num1 * num2 = " + calculate.calculateRes('mul', [10,5])) // 20
console.log("num1 / num2 = " + calculate.calculateRes('div', [10,5])) // 2
需要增加计算方式,只需在 strategy 增加对应的算法即可。
总结
策略模式最主要的特色就是创建了一系列策略算法,每组算法处理的业务都是相同的,只是处理过程或者处理结果不一样,所以它们又是可以相互替换的。这解决了算法和使用者之间的耦合。在测试层面上,由于每组算法是相互独立的,该模式更方便我们对每组算法执行单元测试,以保证算法的质量。