分支语句优化--策略模式
发表日期:2019-01-25
在很多业务场景中,完成一项任务时,往往可以有多种不同的方式,比如我们很多商品有不同的促销方式,比如满百减10,满200返40,满三减一等等,每一种方式我们称其为一种策略。每种策略事实上都是一种针对处理相同业务的不同算法,每种算法都是相互独立的,是可以相互替代的,所以策略模式就是:
定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的调用者而变化。策略模式是一种对象行为型模式。
进一步了解5
在项目开发中,有很多需求都是使用不同的算法来实现同一种需求,比如查找、排序、表单校验等。这里我以前端更为常见的表单校验来举例。我们常用的方法是硬编码在一个公共类中,如有多种校验行为,可以将对应的校验算法写到工具类中,每一种算法对外提供一个方法以供调用。下面是在我们火车票、酒店H5项目中有关校验的写法,我们将校验方法与其他工具方法放在了工具类中同一级。
当然也可以将这些校验算法封装在一个统一的方法中,通过if…else…等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的校验方式,需要修改封装算法工具类的源代码;更换查找算法,也需要修改调用端的代码。
其实我们在利用某些动画库写动效时,一定会见到类似如下的写法:
animate({width: '200px'}, 1000, 'linear')其中,第三个参数可选不同的缓动算法,比如linear、easeout等,算法复杂的处理过程对调用者隐藏,这是一个很典型的策略模式应用。
模式实例
我们希望表单校验的调用也可以如此优雅,下面是一个表单正则校验策略对象。
// 表单正则验证策略对象
var Inputstrategy = function() {
var strategy = {
// 是否为空
notNull: function(value) {
return /\s+/.test(value) ? '请输入内容' : ''
},
// 是否是个数字
number: function(value) {
return /^[0-9]+(\.[0-9]+)?$/.test(value) ? '' : '请输入数字'
},
// 是否是本地电话
phone: function(value) {
return /^\d{3}\-\d{8}$|^\d{4}\-\d{7}$/.test(value) ? '' : '请输入正确的电话号'
}
}
return {
// 验证接口type算法value表单值
check: function (type, value) {
// 去除首尾空白符
value = value.replace(/^\s+|\s+$/g, '');
return strategy[type] ? strategy[type](value) : '没有该类型的检测方法'
},
// 添加策略
addStrategy: function (type, fn) {
strategy[type] = fn
}
}
}()可以看到这个策略类除了导出一个check方法做校验,还导出了一个添加策略的方法addStrategy,这样即可实现策略方法的临时性修改,而不需要修改策略对象内部的代码。
Inputstrategy.ckeck('nickname', 'xxxxxxxx')如此的调用方式更加清晰可读,算法实现类中也不再臃肿无序。
小结
策略模式主要优点在于对“开闭原则”的完美支持,在不修改原有系统的基础上可以更换算法或者增加新的算法,它很好地管理算法族,提高了代码的复用性,是一种替换继承,避免多重条件转移语句的实现方式;其缺点在于客户端必须知道所有的策略类,并理解其区别,增加了用户对策略类使用的成本,同时在一定程度上增加了系统中类的个数,可能会存在很多策略类。
对于分支语句优化,一共有三种模式涉及。分别为工厂方法模式、状态模式和策略模式。对于工厂方法模式,它是一种创建型模式,他的最终目的是创建对象。而状态模式和策略模式都是行为型模式,在状态模式中,其核心是对状态的控制来决定不同的行为表现,所以状态之间通常是不可替代的,否则将产生不同的行为结果。而策略模式核心是算法,往往每种算法要处理的业务逻辑相同,因此他们可以相互替换,当然策略类也不必关心调用者的环境,因为同一种策略模式最终产出的结果是一定的。
参考文献
JavaScript设计模式 张容铭
最后更新于