面试官:说说你对策略模式的理解?应用场景?

开发 前端
策略模式(Strategy Pattern)指的是定义一系列的算法,把它们一个个封装起来,目的就是将算法的使用与算法的实现分离开来。

[[433203]]

一、策略模式是什么

策略模式(Strategy Pattern)指的是定义一系列的算法,把它们一个个封装起来,目的就是将算法的使用与算法的实现分离开来

一个基于策略模式的程序至少由两部分组成:

策略类,策略类封装了具体的算法,并负责具体的计算过程

环境类Context,Context 接受客户的请求,随后 把请求委托给某一个策略类

二、使用

举个例子,公司的年终奖是根据员工的工资和绩效来考核的,绩效为A的人,年终奖为工资的4倍,绩效为B的人,年终奖为工资的3倍,绩效为C的人,年终奖为工资的2倍

若使用if来实现,代码则如下:

  1. var calculateBouns = function(salary,level) { 
  2.     if(level === 'A') { 
  3.         return salary * 4; 
  4.     } 
  5.     if(level === 'B') { 
  6.         return salary * 3; 
  7.     } 
  8.     if(level === 'C') { 
  9.         return salary * 2; 
  10.     } 
  11. }; 
  12. // 调用如下: 
  13. console.log(calculateBouns(4000,'A')); // 16000 
  14. console.log(calculateBouns(2500,'B')); // 7500 

从上述可有看到,函数内部包含过多if...else,并且后续改正的时候,需要在函数内部添加逻辑,违反了开放封闭原则

而如果使用策略模式,就是先定义一系列算法,把它们一个个封装起来,将不变的部分和变化的部分隔开,如下:

  1. var obj = { 
  2.         "A"function(salary) { 
  3.             return salary * 4; 
  4.         }, 
  5.         "B" : function(salary) { 
  6.             return salary * 3; 
  7.         }, 
  8.         "C" : function(salary) { 
  9.             return salary * 2; 
  10.         }  
  11. }; 
  12. var calculateBouns =function(level,salary) { 
  13.     return obj[level](salary); 
  14. }; 
  15. console.log(calculateBouns('A',10000)); // 40000 

上述代码中,obj对应的是策略类,而calculateBouns对应上下通信类

又比如实现一个表单校验的代码,常常会像如下写法:

  1. var registerForm = document.getElementById("registerForm"); 
  2. registerForm.onsubmit = function(){ 
  3.     if(registerForm.userName.value === '') { 
  4.         alert('用户名不能为空'); 
  5.         return
  6.     } 
  7.     if(registerForm.password.value.length < 6) { 
  8.         alert("密码的长度不能小于6位"); 
  9.         return
  10.     } 
  11.     if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) { 
  12.         alert("手机号码格式不正确"); 
  13.         return
  14.     } 

上述代码包含多处if语句,并且违反了开放封闭原则,如果应用中还有其他的表单,需要重复编写代码

此处也可以使用策略模式进行重构校验,第一步确定不变的内容,即策略规则对象,如下:

  1. var strategy = { 
  2.     isNotEmpty: function(value,errorMsg) { 
  3.         if(value === '') { 
  4.             return errorMsg; 
  5.         } 
  6.     }, 
  7.     // 限制最小长度 
  8.     minLength: function(value,length,errorMsg) { 
  9.         if(value.length < length) { 
  10.             return errorMsg; 
  11.         } 
  12.     }, 
  13.     // 手机号码格式 
  14.     mobileFormat: function(value,errorMsg) { 
  15.         if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) { 
  16.             return errorMsg; 
  17.         } 
  18.     }  
  19. }; 

然后找出变的地方,作为环境类context,负责接收用户的要求并委托给策略规则对象,如下Validator类:

  1. var Validator = function(){ 
  2.         this.cache = [];  // 保存效验规则 
  3. }; 
  4. Validator.prototype.add = function(dom,rule,errorMsg) { 
  5.     var str = rule.split(":"); 
  6.     this.cache.push(function(){ 
  7.         // str 返回的是 minLength:6  
  8.         var strategy = str.shift(); 
  9.         str.unshift(dom.value); // 把input的value添加进参数列表 
  10.         str.push(errorMsg);  // 把errorMsg添加进参数列表 
  11.         return strategys[strategy].apply(dom,str); 
  12.     }); 
  13. }; 
  14. Validator.prototype.start = function(){ 
  15.     for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) { 
  16.         var msg = validatorFunc(); // 开始效验 并取得效验后的返回信息 
  17.         if(msg) { 
  18.             return msg; 
  19.         } 
  20.     } 
  21. }; 

通过validator.add方法添加校验规则和错误信息提示,使用如下:

  1. var validateFunc = function(){ 
  2.     var validator = new Validator(); // 创建一个Validator对象 
  3.     /* 添加一些效验规则 */ 
  4.     validator.add(registerForm.userName,'isNotEmpty','用户名不能为空'); 
  5.     validator.add(registerForm.password,'minLength:6','密码长度不能小于6位'); 
  6.     validator.add(registerForm.userName,'mobileFormat','手机号码格式不正确'); 
  7.  
  8.     var errorMsg = validator.start(); // 获得效验结果 
  9.     return errorMsg; // 返回效验结果 
  10. }; 
  11. var registerForm = document.getElementById("registerForm"); 
  12. registerForm.onsubmit = function(){ 
  13.     var errorMsg = validateFunc(); 
  14.     if(errorMsg){ 
  15.         alert(errorMsg); 
  16.         return false
  17.     } 

上述通过策略模式完成表单的验证,并且可以随时调用,在修改表单验证规则的时候,也非常方便,通过传递参数即可调用

三、应用场景

从上面可以看到,使用策略模式的优点有如下:

  • 策略模式利用组合,委托等技术和思想,有效的避免很多if条件语句
  • 策略模式提供了开放-封闭原则,使代码更容易理解和扩展
  • 策略模式中的代码可以复用

策略模式不仅仅用来封装算法,在实际开发中,通常会把算法的含义扩散开来,使策略模式也可以用来封装 一系列的“业务规则”

只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们

参考文献

https://segmentfault.com/a/1190000021883055

https://juejin.cn/post/6844903504109109262 

https://juejin.cn/post/6844903751225081864

 

责任编辑:武晓燕 来源: JS每日一题
相关推荐

2021-11-10 07:47:49

组合模式场景

2021-11-03 14:10:28

工厂模式场景

2021-11-05 07:47:56

代理模式对象

2021-11-09 08:51:13

模式命令面试

2021-11-11 16:37:05

模板模式方法

2021-11-22 23:50:59

责任链模式场景

2021-09-16 07:52:18

算法应用场景

2021-08-16 08:33:26

git

2021-05-31 10:35:34

TCPWebSocket协议

2021-09-29 07:24:20

场景数据

2021-09-06 10:51:27

TypeScriptJavaScript

2021-09-28 07:12:09

测试路径

2021-07-07 08:36:45

React应用场景

2021-07-12 08:35:24

组件应用场景

2021-10-09 10:25:41

排序应用场景

2021-09-08 07:49:34

TypeScript 泛型场景

2021-10-08 09:59:32

冒泡排序场景

2021-09-10 06:50:03

TypeScript装饰器应用

2021-10-13 18:01:33

快速排序场景

2021-10-18 07:51:39

回溯算法面试
点赞
收藏

51CTO技术栈公众号