本文有我们组内丁武龙分享总结
什么是策略模式
定义
定义一系列的方法,把他们一个个封装成函数,也可把他们作为属性同意封装进一个对象,然后再定义一个方法,该方法可根据参数自动选择执行对应的算法
策略模式主要有两部分构成,一部分是封装不同策略的策略组,另一部分是 Context。通过组合和委托来让 Context 拥有执行策略的能力,从而实现可复用、可扩展和可维护,并且避免大量复制粘贴的工作。
应用场景
一般可用于在实现某一个功能的时候,有很多个方案可选择的情况
在JavaScript中使用策略模式
在理解策略模式之前,我们也来一个例子,根据员工的薪水、绩效等级S,A,B,C来计算年终奖
使用一般方法
var calculation = function( level, salary ){
if ( level === 'S' ){
return salary * 4;
}
if ( level === 'A' ){
return salary * 3;
}
if ( level === 'B' ){
return salary * 2;
}
}
calculation( 'S', 10000 );
上面这段代码暴露了几个问题
- calculation函数包含了很多if-else语句
- calculation函数缺乏弹性,假如还有D等级的话,那么我们需要在calculation 函数内添加判断等级D的if语句
- 算法复用性差,如果在其他的地方也有类似这样的算法的话,但是规则不一样,我们这些代码不能通用
使用组合函数
组合函数是把各种算法封装到一个个的小函数里面,比如等级A的话,封装一个小函数,等级为B的话,也封装一个小函数,以此类推;如下代码:
var A = function(salary) {
return salary * 4;
};
var B = function(salary) {
return salary * 3;
};
var C = function(salary) {
return salary * 2
};
var calculation = function(level,salary) {
if(level === 'A') {
return A(salary);
}
if(level === 'B') {
return B(salary);
}
if(level === 'C') {
return C(salary);
}
};
// 调用如下
console.log(calculation('A',4500)); // 18000
代码看起来有点完善,但是还是有以下问题
- calculation函数有可能会越来越大,比如增加D等级的时候,而且缺乏弹性。
使用策略模式实现
一个基于策略模式的程序至少有两部分组成,第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context,该Context接收客户端的请求,随后把请求委托给某一个策略类。我们先使用传统面向对象来实现
var A = function(){};
A.prototype.calculate = function(salary) {
return salary * 4;
};
var B = function(){};
B.prototype.calculate = function(salary) {
return salary * 3;
};
var C = function(){};
C.prototype.calculate = function(salary) {
return salary * 2;
};
// 奖金类
var Bouns = function(){
this.salary = null; // 原始工资
this.levelObj = null; // 绩效等级对应的策略对象
};
Bouns.prototype.setSalary = function(salary) {
this.salary = salary; // 保存员工的原始工资
};
Bouns.prototype.setlevelObj = function(levelObj){
this.levelObj = levelObj; // 设置员工绩效等级对应的策略对象
};
// 取得奖金数
Bouns.prototype.getBouns = function(){
// 把计算奖金的操作委托给对应的策略对象
return this.levelObj.calculate(this.salary);
};
var bouns = new Bouns();
bouns.setSalary(10000);
bouns.setlevelObj(new A()); // 设置策略对象
console.log(bouns.getBouns()); // 40000
bouns.setlevelObj(new B()); // 设置策略对象
console.log(bouns.getBouns()); // 30000
如上代码使用策略模式,可以看到代码职责更新分明,代码变得更加清晰。
Javascript版本的策略模式
//策略类Strategy
var setSalary = {
'S':function(salary) {
return salary * 4
}
'A':function(salary) {
return salary * 3
}
'B':function(salary) {
return salary * 2
}
'C':function(salary) {
return salary * 1
}
}
//环境类Context
var calculation = function(level , salary){
return setSalary[level](salary)
}
//使用
calculation('S' , 10000)
这样就实现了javascript的策略模式了,可以看出代码更加的简单明了了
策略模式有哪些优缺点
优点:
- 策略模式利用组合,代理等技术和思想,有效的避免很多if条件语句。
- 策略模式提供了开放-封闭原则,使代码更容易理解和扩展。
- 策略模式中的代码可以复用
缺点:
- 增加了许多策略类或者策略对象
- 要使用策略模式,必须了解所有的strategy,违反了最少知识原则
总结
策略模式定义了一系列算法,从概念上来讲这些算法都是做相同的事,只是实现方法不同,它可以用相同的方式调用所有的方法,减少了各类算法类与使用算法之间的耦合
从另一层面上来说,单独定义算法类也方便了单元测试,因为可以通过自己的算法进行单独测试
在实际运用中,不仅可以封装算法,也可以用来封装几乎任何类型的规则,是要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑是要策略模式来处理各种变化。