接上篇命令模式来继续看下js设计模式中另一种常用的模式,策略模式。策略模式也是js开发中常用的一种实例,不要被这么略显深邃的名字给迷惑了。接下来我们慢慢看一下。
一、基本概念与使用场景:
基本概念:定义一系列方法,封装起来使他们可以相互替换。也就是将策略封装在策略类中,当发起请求时管理类将请求委托给对应策略类。
概括而言,就是讲对应不同情况的策略(即不同的处理方法)专门分装在一个对象中,即策略对象里面包含所有的策略。事件请求不直接请求该策略对象,而是有个管理对象来处理请求转发给策略对象的不同接口,这里其实也可以认为涉及到代理模式的概念,不过要申明一点,任何的设计模式都不是单一独立存在的,一种解决方案涉及到两种或者多种的设计模式也是很正常的现象。不要去强行区分到底属于哪种设计模式。 主要目的是为了避免太多的逻辑判断语句的出现,解耦业务逻辑和算法策略。
使用场景:适用于业务逻辑中重复比较多依赖参数或者标识来区分不同的处理的场景。例如react中一个新建某个订单的页面中,存在很多的渲染input等。
二、实例:
假设我们现在有这样一个需求:需要根据form表单元素的不同类型,当点击的时候输出对应的表单元素类型。
分析一下其实很简单,不外乎这下面的几种做法:。
1、简单粗暴流、每个元素都绑定一个事件,依次处理就好:
1 /** 2 * 每个元素绑定一个事件,分别去输出 3 */ 4 btn1.onClick(function(){ 5 console.log('btn1 type') 6 }) 7 //n多个 8 btnN.onClick(function(){ 9 console.log('btnN type') 10 })
2、上面的代码太糟心了,例如10个input就要写10个事件来绑定。可以绑定在同一个事件上,通过判断来处理
1)给各个表单绑定事件,点击的时候将type属性带过去(这个就略过了)
2)针对性的处理事件,用if-else或者switch来判断
1 /** 2 * 非策略模式 3 * 根据入参的不同,调用不同的方法,输出对应结果 4 */ 5 var renderDom = function(type){ 6 if(type == 'text'){ 7 console.log('this is method for text') 8 }else if(type == 'radio'){ 9 console.log('this is method for radio') 10 }else if(type == 'checkbox'){ 11 console.log('this is method for checkbox') 12 }else { 13 console.log('this is method for default') 14 } 15 //也可能这么写 16 switch(type){ 17 case 'text': 18 console.log('this is method for text') 19 break; 20 case 'radio': 21 console.log('this is method for radio') 22 /** 23 * 余下的省略 24 * */ 25 } 26 }
3、上面这种写法引入了那么多的逻辑判断,当有更改的时候就需要跟进不同的方法里进行修改了。还是有点麻烦。这时候就可以用策略模式来做了:
1 /** 2 * 针对不同情况的策略算法封装在策略类fucs中, 3 * 从调用事件中去除繁琐的if或者switch逻辑判断。达到解耦的目的 4 * 加入后面再增加‘select’的选项增加对应的方法即可 5 */ 6 var funcs = { 7 text:function(){ 8 console.log('this is method for text') 9 }, 10 radio:function(){ 11 console.log('this is method for radio') 12 }, 13 checkbox:function(){ 14 console.log('this is method for checkbox') 15 }, 16 default:function(){ 17 console.log('this is method for default') 18 } 19 } 20 21 var renderDom = function(type){ 22 /** 23 * 只需要根据不同的入参,自行匹配策略类中的接口即可。 24 */ 25 return (funcs[type] || funcs['default'])() 26 } 27 renderDom('checkbox')
简单说下策略模式的思路:
1)所谓的策略对象就是funcs对象,里面的不同属性接口对应的方法就是策略。与逻辑判断分离开,如果有不同的情况的出现,对应的增加属性接口即可。
2)renderDom方法就是对应的管理类了,只需要根据不同的type,去调用funcs不同的方法就好了。如果有改动,这里不需要修改,为了健壮性考虑,如果type没有对应的接口,那就调用默认的default对应接口。
3)调用事件,就保持不变。将tyoe类型传过去就好了。
这样来看,将可变的策略部分封装成了一个对象,不再需要逻辑判断只需要调用策略类对应的接口就行,这样无论从性能,可读性,可扩展性上来讲都比逻辑判好的不是一点半点。
至此策略模式也介绍结束了。可能我们在原来写代码的过程中多多少少的都用到过,只不过没有明确的名称观念罢了。说开了,设计模式也就是为了解决问题而产生的一种思路,没有听起来那么的高大上。切勿为了使用设计模式而强行引入,也切勿不同情况坚持使用某一种设计模式。不要被形式总之快速高效的解决问题才是我们的唯一目的。
参考文章:JavaScript设计模式与开发实践