**定义:**定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。在程序设计中,我们常常遇到类似的情况,例如某个功能会根据不同的情况选择各种可操作,如果单纯的为了实现业务代码,可能会选择if、else 判断,但是当选择的逻辑比较复杂而且各种操作算法也很多的时候,这时候过多的判断条件会使得代码难以阅读和维护,形成一个庞大且复杂的代码段。而策略模式就是为了解决这个情况而出现的。
**举个例子:**某个会员制网购平台的购买打折优惠程序,不同等级的会员的折扣都不相同,白银会员打95折,黄金会员打85折,钻石会员打7折,如果是用普通的业务逻辑来写这段程序是这样的:
var countPrice = function (originalPrice, level) {
if (level === 'silverVip') {
return originalPrice * 0.95
}
if (level === 'goldVip') {
return originalPrice * 0.85
}
if (level === 'diamondVip') {
return originalPrice * 0.7
}
}
countPrice(1000, 'goldVip') // 输出 850
可以看出来,这段代码很简单,而且逻辑也清晰,但是随着这个Vip等级的越来越多而且计算条件的逻辑变得更加复杂的时候,我么就不得不修改这个方法的代码和增加更多的if、else,当多个版本的修改与迭代之后,这段“简单”的代码也变得难以维护和阅读。
现在我们尝试使用策略模式来重写这段代码:
// 定义不同会员的不同算法策略
var silverVip = function () {}
silverVip.prototype.calculator = function(originalPrice){
return originalPrice * 0.95
}
var goldVip = function () {}
goldVip.prototype.calculator = function(originalPrice){
return originalPrice * 0.85
}
var diamondVip= function () {}
diamondVip.prototype.calculator = function(originalPrice){
return originalPrice * 0.7
}
// 定义计算优惠价类
var priceCountor = function(){
this.originalPrice = null
this.levelObj = null
}
priceCountor.prototype.setOriginalPrice = function (originalPrice){ // 将原价set到实例上
this.originalPrice = originalPrice
}
priceCountor.prototype.setLevel = function(levelObj){ // set会员对象(包括了该等级会员的算法)
this.levelObj = levelObj
}
priceCountor.prototype.getPrice = function(){ // 最终统一在实例上调用计算方法
return this.levelObj.calculator(this.originalPrice)
}
// 调用
var customerPay = new priceCountor() // 新建计算客户优惠价实例
customerPay.setLevel(new goldVip()) // 设置等级
customerPay.setOriginalPrice(1000) // 设置原价
customerPay.getPrice() // 输出850
通过使用策略模式的设计重写这个功能,可以看出几个优点:
1、消除了判断的逻辑,如果你需要继续新增各种等级的会员,只需要定义新的等级对象
2、代码的职责更加单一鲜明,会员对象是负责计算这个等级的会员的优惠算法
3、会员的算法可以随时修改,即使该算法很复杂很庞大,也不会影响整个程序逻辑,易于维护和阅读
通过使用策略模式重构代码,我们消除了原程序中大片的条件分支语句。所有的会员算法不会放在原程序中,而是定义成各个策略对象,策略对象中包含了他们各自的算法实现,当我们把策略对象传进去时,都会调用这些策略对象共有的计算方法从而获取不同的计算结果,这就符合了开放-封闭的原则。
小结: 策略模式存优点很多,从上面的例子已经可以看出,通过对象的多态性有效的避免了过多的判断语句;很好的将开放封闭原则应用到这个设计模式上,将独立的功能封闭起来(每个策略对象的算法封装起来),将易于改变的、多变的开放出来(原价originalPrice, 会员对象),使得会员对象易于切换和维护。当然,策略模式的缺点也是有的,需要编写各种策略对象,而且需要观察这些对象的共同点,就像是代码中,每个策略对象都必须要有calculator方法,但是方法的内部实现可以不同,就因为这样,我们就得对每个策略进行分析,需要考虑到他们的实现细节。