新生代农民工需要懂的策略设计模式

开发 前端
俗话说,凡事讲策略。讲策略的时候,我们往往会考虑每种情况的成本。策略同样可体现在我们的代码之中,合理利用策略模式重构逻辑复杂的代码,会使项目工程更易维护和扩展。

[[418571]]

本文转载自微信公众号「DYBOY」,作者DYBOY 。转载本文请联系DYBOY公众号。

俗话说,凡事讲策略。讲策略的时候,我们往往会考虑每种情况的成本。策略同样可体现在我们的代码之中,合理利用策略模式重构逻辑复杂的代码,会使项目工程更易维护和扩展。

这几天朋友圈被“新生代农民工”刷屏了,看到有这样一张截图:

新生代农民工正名

代码里写了约 30 个 if else 逻辑,从程序语义以及程序效率理论上是会有一定的影响,最主要的是可能会被其他“新生代农民工”嘲笑。

一位经验老道的民工则会用一手 switch case 或策略模式来重构代码,那么什么是策略模式呐?

一、定义

策略:为实现一定的战略任务,根据形势发展而制定的行动方针和斗争方式。

策略模式:一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。

在常见的前端游戏奖励激励交互中,常常会涉及到不同分数会展示不同的动效,这其实就是一种条件策略。

二、优缺点

优点:

  • 隔离算法的实现与使用
  • 运行时可切换算法
  • 用组合代替继承
  • 易扩展,符合开闭原则,无需修改上下文即可引入新策略

缺点:

  • 需要暴露所有的策略接口,用于区分策略差异
  • 如果逻辑条件简单,使用策略模式会增加代码冗余度

三、实现

策略模式指的是定义了一系例算法,把它们每个都封装起来。将不变的部分和变化的部分隔离开来是设计模式中的一个重要思想,策略模式则是将算法和使用算法两部分的实现拆开,降低耦合度。

基于策略模式的程序至少有两部分组成:策略类和环境类(Context)。

策略类封装了具体的算法,并负责具体的计算过程,可以理解为“执行者”。

环境类(Context)接受客户的请求,然后将请求委托给一个策略类,可以理解为“调度者”。

四、表单验证中的策略模式

在Web项目中,常见的表单有注册、登陆、修改用户信息等涉及到表单的功能,与此同时我们会在表单提交的时候,做一些例的前端输入框值的条件校验工作。

由于输入框中用户的输入是任意的,校验的规则相对比较复杂,如果不使用设计模式,我们的代码中可能就会写出较多的 if else 判断逻辑,从可阅读性和可维护性来说,确实不是很好。

接下来我们将从前端Web项目中常见的表单验证功能,逐步认识策略设计模式。

4.1 初级的表单验证

在很久很久以前,我的表单验证可能是这么写的:

  1. var username = $('#nuserame').val(); 
  2. var password = $('#password').val(); 
  3.  
  4. if (!username) { 
  5.     alert('用户名不能为空'); 
  6. else if (username.length < 5) { 
  7.     alert('用户名长度需要大于等于5'); 
  8. else if (username.length < 13) { 
  9.     alert('用户名长度需要小于13'); 
  10. else if (!(/[a-z]+/i.test(username))) { 
  11.     alert('用户名只能包含英文大小写字符'
  12. else { 
  13.     regeister(username); 
  14.  
  15. // password的验证同上 

写法似乎有些不忍直视,不过能用!

4.2 基于策略模式的表单验证

换个思路,结合策略模式的思想,实现一个专用于值校验的 Validator 类,Validator 是一个调度着,也就是策略模式中的环境类。

然后我们在验证目标字段值 targetValue 的时候其用法大致如下:

  1. Validator.addRules(targetValue, ['isNonEmpty''minLength:5''maxLength:12']).valid(); 

校验器会返回判断结果 result 字段,以及语义话的提示 msg 字段:

  1. return { 
  2.     result: false
  3.     msg: '不能为空' 

4.2.1 Validator

根据上述需求,Validator的实现如下:

  1. const formatResult = (isPass: boolean = false, errMsg: string = "") => { 
  2.   return { 
  3.     result: isPass, 
  4.     msg: errMsg, 
  5.   }; 
  6. }; 
  7.  
  8. const ValidStrategies = { 
  9.   isNonEmpty: function (val: string = "") { 
  10.     if (!val) return formatResult(false"内容不能为空"); 
  11.   }, 
  12.   minLength: function (val: string = "", length: string | number = 0) { 
  13.     console.log(val, length); 
  14.     if (typeof length === "string") length = parseInt(length); 
  15.     if (val.length < length) 
  16.       return formatResult(false, `内容长度不能小于${length}`); 
  17.   }, 
  18.   maxLength: function (val: string = "", length: string | number = 0) { 
  19.     if (typeof length === "string") length = parseInt(length); 
  20.     if (val.length > length) 
  21.       return formatResult(false, `内容长度不能大于${length}`); 
  22.   }, 
  23.   defaultfunction () { 
  24.     return formatResult(true); 
  25.   }, 
  26. }; 
  27.  
  28. /** 
  29.  * 验证器 
  30.  * 策略模式 —— 环境类,负责调度算法 
  31.  */ 
  32. class Validator { 
  33.   // 存储规则 
  34.   private _ruleExecuters: Array<any>; 
  35.  
  36.   constructor() { 
  37.     this._ruleExecuters = []; 
  38.   } 
  39.  
  40.   /** 
  41.    * addRules 
  42.    * 添加校验规则 
  43.    */ 
  44.   public addRules(value: string = "", rules: Array<string>) { 
  45.     this._ruleExecuters = []; 
  46.     rules.forEach((rule) => { 
  47.       const args = rule.split(":"); 
  48.       const functionName = args.shift() || "default"
  49.       // 忽略下这里的断言类型👀 
  50.       const ruleFunc = ValidStrategies[ 
  51.         functionName as "isNonEmpty" | "minLength" | "maxLength" | "default" 
  52.       ].bind(this, value); 
  53.       this._ruleExecuters.push({ 
  54.         func: ruleFunc, 
  55.         args, 
  56.       }); 
  57.     }); 
  58.     return this; 
  59.   } 
  60.  
  61.   /** 
  62.    * valid 
  63.    */ 
  64.   public valid() { 
  65.     for (let i = 0; i < this._ruleExecuters.length; i++) { 
  66.       const res = this._ruleExecuters[i].func.apply( 
  67.         this, 
  68.         this._ruleExecuters[i].args 
  69.       ); 
  70.       if (res && !res.result) { 
  71.         return res; 
  72.       } 
  73.     } 
  74.     return formatResult(true); 
  75.   } 
  76.  
  77. export default new Validator(); 
  1. const res = Validator.addRules("123", [ 
  2.     "isNonEmpty"
  3.     "minLength:5"
  4.     "maxLength:12"
  5.   ]).valid(); 
  6.   console.log("res:", res); 

执行结果

这样在验证表单值的时候,我们就可以直接调用 Validator 验证值的合法性。

与此同时,还可以通过扩展策略类(对象)ValidStrategies 中的验证算法来扩展校验器的能力。

五、表驱动法

策略模式节省逻辑判断的特性让我联想到了之前看过的一个概念“表驱动法”,或者叫“查表法”,这里引用下百度百科的解释:

表驱动方法出于特定的目的来使用表,程序员们经常谈到“表驱动”方法,但是课本中却从未提到过什么是"表驱动"方法。表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if 或 Case)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,表就变得越来越富有吸引力了。

举个例子,假设我们想要获取当前是星期几,代码可能是这样的:

  1. function getDay() { 
  2.   const day = (new Date()).getDay(); 
  3.   switch (day) { 
  4.     case 0: 
  5.       return '星期日'
  6.     case 1: 
  7.       return '星期一'
  8.     // ... 
  9.     case 6: 
  10.       return '星期六'
  11.     default
  12.       return ''
  13.   } 

如果是初次编程的同学还可能会有 if else 条件语句来判断返回值,代码就会显得比较冗余。

借助表驱动发法的思想,这里我们是可以有优化空间的,表驱动发法的写法如下:

  1. const days = ['星期日''星期一''星期二''星期三''星期四''星期五''星期六']; 
  2. function getDay2() { 
  3.   return days[(new Date()).getDay()]; 

当然上述只是一个非常简单的??,大家在编码过程中只需要主要点,如有涉及类似场景,请用这种方式去编码,体验更愉悦!

六、总结

策略设计模式让各种算法的代码、内部数据和依赖关系与其他代码隔离开来。不同客户端可通过一个简单接口执行算法,并能在运行时进行切换。 

当然在设计实现程序功能的时候,如果需要使用策略设计模式,也更需要我们的工程师有一个功能全局把控的能力,才能更好将依赖关系拆分,抽象化,以此才能凸显“新生代”民工的不同!

责任编辑:武晓燕 来源: DYBOY
相关推荐

2021-08-19 15:27:47

新生代农民工软件信息技术

2021-08-18 07:37:02

程序员农民工人力

2021-08-18 10:49:55

程序员新生代农民工收入

2021-08-17 15:13:12

码农编程开发

2021-08-23 13:29:44

码农编程开发

2021-08-19 06:03:07

新生代农民工数据分析码农

2021-08-23 14:59:58

技术资讯

2012-12-19 09:54:17

2010-04-15 17:52:58

微软农民工社区学习中心

2009-07-01 16:48:43

JAVA程序员

2011-09-14 09:31:45

2022-03-22 12:12:37

智能建造建筑机器人人工智能

2009-04-13 09:37:42

IT新生代创业

2012-11-27 15:06:50

IT面试

2022-04-29 08:00:51

V8垃圾回收

2009-11-16 15:55:19

博科资讯代理

2012-05-03 10:33:32

欧朋

2021-09-02 07:31:59

农民工 996 国家

2022-03-22 13:58:33

人工智能建筑机器人农民工
点赞
收藏

51CTO技术栈公众号