核心:定义一些列的算法(逻辑)封装起来,并且它们是平等关系可以相互替换
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的逻辑比较复杂且需要很多场景共用,则该模式的好处将愈发显现。