核心:定义一些列的算法(逻辑)封装起来,并且它们是平等关系可以相互替换
js中的策略模式关键字:策略和业务分离
(一)基本实现
常见代码:
function playGame(gameName){
let str;
if(gameName == 'footBall'){
str = '不喜欢玩足球'
}else if(method == 'basketball'){
str = '不喜欢玩蓝球'
}else if(method == 'pingpang'){
str = '不喜欢玩乒乓'
}else if(method == 'swing'){
str = '好啊,我最喜欢游泳了'
}
alert(str)
}
策略模式优化
let gameStrategies = {
'footBall': function(){
return '不喜欢玩足球'
},
'basketball': function(){
return '不喜欢玩蓝球'
},
'pingpang': function(){
return '不喜欢玩乒乓'
},
'swing': function(){
return '好啊,我最喜欢游泳了'
}
}
function playGame_1(gameName){
let str;
str = gameStrategies(gameName)
alert(str)
}
将策略单独提取出来封装,和业务代码分离。这样需要修改策略不需要去业务代码里面查找,而提取出来的策略也可以被多个业务代码复用。
(二)场景案例
//策略模式实现表单判断
let formStrategies = {
isNonEmpty: function(val,errorMsg){
if(val == ''){
return errorMsg
}
},
minLength: function(val,length,errorMsg){
if(val.length < length){
return errorMsg
}
},
isMobile: function(val,errorMsg){
if(!/(^1[3|5|8][0-9]{9}$)/.test(val)){
return errorMsg
}
}
}
registerForm.onsubmit = function(){
let userNameErrorMsg = formStrategies.isNonEmpty(registerForm.userName,'用户名不能为空')
let pwdErrorMsg = formStrategies.minLength(registerForm.pwd,'密码长度不能少于6位')
let telErrorMsg = formStrategies.isMobile(registerForm.tel,'手机格式不正确')
if(userNameErrorMsg){
alert(userNameErrorMsg)
}else if(pwdErrorMsg){
alert(pwdErrorMsg)
}else if(telErrorMsg){
alert(telErrorMsg)
}
}
这里可以继续优化
//start--------实现一个可配置策略的验证类
function Validator(){
this.rules = [] //待验证规则队列
}
Validator.prototype.add = function(rule,dom,errorMsg){
let _rule = rule.split(':') //把策略和参数分开,比如minLength:6
this.rules.push(function(){
let strategy = _rule.shift() //策略字符串
_rule.unshift(dom.value)
_rule.push(errorMsg)
return formStrategies[strategy].apply(dom,_rule)
})
}
Validator.prototype.start = function(){
for(let i = 0,validatorFunc;validatorFunc = this.rules[i++];){
let msg = validatorFunc()
if(msg)return msg
}
}
//end-----------
let validataFunc = function(){
let validator = new Validator()
validator.add(registerForm.userName,'isNonEmpty','用户名不能为空')
validator.add(registerForm.pwd,'minLength','密码长度不能少于6位')
validator.add(registerForm.tel,'isMobile','手机格式不正确')
let errorMsg = validator.start()
return errorMsg
}
registerForm.onsubmit = function(){
let errorMsg = validataFunc()
if(errorMsg){
alert(errorMsg)
return
}
}
(三)场景案例
//上午返回'上午好';中午返回'中午';下午返回'下午好';晚上返回'晚上好';凌晨返回'凌晨了,请马上休息'
function say(){
var hour = new Date().getHours()
if(hour > 6 && hour < 12){
return '上午好'
}else if(hour >= 12 && hour <= 13){
return '中午好'
}else if(hour > 13 && hour <18){
return '下午好'
}else if(hour >= 18 && hour < 24){
return '晚上好'
}else{
return '凌晨了,请马上休息'
}
}
//策略模式
//语言策略
var say_words = {
morning : function(){
return '上午好'
},
noon : function(){
return '中午好'
},
afternoon : function(){
return '下午好'
},
night : function(){
return '晚上好'
},
beforeDawn : function(){
return '凌晨了,请马上休息'
}
}
//时间策略
var say_times = {
time6_12 : function(hour){
return hour > 6 && hour < 12
},
time12_13 : function(hour){
return hour >= 12 && hour <= 13
},
time13_18 : function(hour){
return hour > 13 && hour <18
},
time18_24 : function(hour){
return hour >= 18 && hour < 24
},
time0_6 : function(hour){
return hour >= 0 && hour <= 6
},
}
function say1(){
var hour = new Date().getHours()
if(say_times.time6_12){
return say_words.morning()
}else if(say_times.time12_13){
return say_words.noon()
}else if(say_times.time13_18){
return say_words.afternoon()
}else if(say_times.time18_24){
return say_words.night()
}else{
return say_words.beforeDawn()
}
}
//继续优化
function say2(){
var hour = new Date().getHours()
//策略模式和多态思想结合
function doSayByStrategies(arr){
for(var i in arr){
if(say_times[i](hour)){
return arr[i]()
}
}
}
return doSayByStrategies({
time6_12:say_words.morning,
time12_13:say_words.noon,
time18_24:say_words.night
})
}
这个例子其实并不是一个好例子,因为使用策略模式显得比直接使用if else语句更加繁琐,这个例子中如果say_words和say_times的逻辑比较复杂且需要很多场景共用,则该模式的好处将愈发显现。