策略模式实现 Vue 动态表单验证的方法


Posted in Javascript onSeptember 16, 2019

策略模式(Strategy Pattern)又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。关键是策略的 实现和使用分离

注意:本文可能用到一些编码技巧比如 IIFE(Immediately Invoked Function Expression, 立即调用函数表达式),ES6 的语法 let/const、箭头函数、rest 参数,短路运算符 等,如果还没接触过可以点击链接稍加学习 ~

1. 你曾见过的策略模式

现在电子产品种类繁多,尺寸多种多样,有时候你会忍不住想拆开看看里面啥样(想想小时候拆的玩具车还有遥控器),但是螺丝规格很多,螺丝刀尺寸也不少,如果每碰到一种规格就买一个螺丝刀,家里就得堆满螺丝刀了。所以现在人们都用多功能的螺丝刀套装,螺丝刀把只需要一个,碰到不同规格的螺丝只要换螺丝刀头就行了,很方便,体积也变小很多。

策略模式实现 Vue 动态表单验证的方法

再举个栗子,一辆车的轮胎有很多规格,在泥泞路段开的多的时候可以用泥地胎,在雪地开得多可以用雪地胎,高速公路上开的多的时候使用高性能轮胎,针对不同使用场景更换不同的轮胎即可,不需更换整个车。

这些都是策略模式的实例,螺丝刀/车属于封装上下文,封装和使用不同的螺丝刀头/轮胎,螺丝刀头/轮胎这里就相当于策略,可以根据需求不同来更换不同的使用策略。

在这些场景中,有以下特点:

螺丝刀头/轮胎(策略)之间相互独立,但又可以相互替换;

螺丝刀/车(封装上下文)可以根据需要的不同选用不同的策略;

2. 实例的代码实现

具体的例子我们用编程上的例子来演示,比较好量化。

场景是这样的,某个电商网站希望举办一个活动,通过打折促销来销售库存物品,有的商品满 100 减 30,有的商品满 200 减 80,有的商品直接8折出售(想起被双十一支配的恐惧),这样的逻辑交给我们,我们要怎样去实现呢。

通过判断输入的折扣类型来计算计算商品总价的方式,几个 if-else 就满足了需求,但是这样的做法的缺点也很明显:

priceCalculate 函数随着折扣类型的增多,  if-else 判断语句会变得越来越臃肿;

如果增加了新的折扣类型或者折扣类型的算法有所改变,那么需要更改  priceCalculate 函数的实现,这是违反开放-封闭原则的;

可复用性差,如果在其他的地方也有类似这样的算法,但规则不一样,上述代码不能复用;

我们可以改造一下,将计算折扣的 算法部分提取出来 保存为一个对象,折扣的 类型作为 key ,这样索引的时候 通过对象的键值索引调用具体的算法

这样 算法的实现和算法的使用就被分开了 ,想添加新的算法也变得十分简单:

如果你希望计算算法隐藏起来,那么可以借助 IIFE 使用闭包的方式,这时需要添加增加策略的入口,以方便扩展:

这样算法就被隐藏起来,并且预留了增加策略的入口,便于扩展。

3. 策略模式的通用实现

根据上面的例子提炼一下策略模式,折扣计算方式可以被认为是策略(Strategy),这些策略之间可以相互替代,而具体折扣的计算过程可以被认为是封装上下文(Context),封装上下文可以根据需要选择不同的策略。

主要有下面几个概念:

Context:封装上下文,根据需要调用需要的策略,屏蔽外界对策略的直接调用,只对外提供一个接口,根据需要调用对应的策略;

Strategy:策略,含有具体的算法,其方法的外观相同,因此可以互相代替;

StrategyMap:所有策略的合集,供封装上下文调用;

结构图如下:

策略模式实现 Vue 动态表单验证的方法

下面使用通用化的方法实现一下。

通用实现看起来似乎比较简单,这里分享一下项目实战。

4. 实战中的策略模式

 4.1 表格 formatter

这里举一个 Vue + ElementUI 项目中用到的例子,其他框架的项目原理也类似,和大家分享一下。

Element 的表格控件的 Column 接受一个 formatter 参数,用来格式化内容,其类型为函数,并且还可以接受几个特定参数,像这样: Function(row,column,cellValue,index)

以文件大小转化为例,后端经常会直接传 bit 单位的文件大小,那么前端需要根据后端的数据,根据需求转化为自己需要的单位的文件大小,比如 KB/MB。

首先实现文件计算的算法:

那么在组件中我们可以直接:

代码实例可以参看 codepen - 策略模式实战

运行结果如下图:

策略模式实现 Vue 动态表单验证的方法

4.2 表单验证

除了表格中的 formatter 之外,策略模式也经常用在表单验证的场景,这里举一个 Vue + ElementUI 项目的例子,其他框架同理。

ElementUI 的 Form 表单 具有表单验证功能,用来校验用户输入的表单内容。实际需求中表单验证项一般会比较复杂,所以需要给每个表单项增加 validator 自定义校验方法。

我们可以像官网示例一样把表单验证都写在组件的状态 data 函数中,但是这样就不好复用使用频率比较高的表单验证方法了,这时我们可以结合策略模式和函数柯里化的知识来重构一下。首先我们在项目的工具模块(一般是 utils 文件夹)实现通用的表单验证方法:

然后在 utils/index.js 中增加一个柯里化方法,用来生成表单验证函数:

上面的 formValidateGene 函数接受两个参数,第一个是验证规则,也就是 src/utils/validates.js 文件中提取出来的通用验证规则的方法名,第二个参数是报错的话表单验证的提示信息。

可以看见在使用的时候非常方便,把表单验证方法提取出来作为策略,使用柯里化方法动态选择表单验证方法,从而对策略灵活运用,大大加快开发效率。

代码实例可以参看 codesandbox - 策略模式表单验证实战

运行结果:

策略模式实现 Vue 动态表单验证的方法

5. 策略模式的优缺点

策略模式将算法的 实现和使用拆分 ,这个特点带来了很多优点:

策略之间相互独立,但 策略可以自由切换 ,这个策略模式的特点给策略模式带来很多灵活性,也提高了策略的复用率;

如果不采用策略模式,那么在选策略时一般会采用多重的条件判断,采用策略模式可以 避免多重条件判断 ,增加可维护性;

可扩展性好,策略可以很方便的进行扩展;

策略模式的缺点:

策略相互独立,因此一些复杂的算法逻辑 无法共享 ,造成一些资源浪费;

如果用户想采用什么策略,必须了解策略的实现,因此 所有策略都需向外暴露 ,这是违背迪米特法则/最少知识原则的,也增加了用户对策略对象的使用成本。

6. 策略模式的适用场景

那么应该在什么场景下使用策略模式呢:

多个算法 只在行为上稍有不同 的场景,这时可以使用策略模式来动态选择算法;

算法 需要自由切换 的场景;

有时 需要多重条件判断 ,那么可以使用策略模式来规避多重条件判断的情况;

7. 其他相关模式

7.1 策略模式和模板方法模式

策略模式和模板方法模式的作用比较类似,但是结构和实现方式有点不一样。

策略模式让我们在程序运行的时候动态地指定要使用的算法;

模板方法模式是在子类定义的时候就已经确定了使用的算法;

7.2 策略模式和享元模式

总结

 以上所述是小编给大家介绍的策略模式实现 Vue 动态表单验证的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
某页码显示的helper 少量调整,另附js版
Sep 12 Javascript
js对象之JS入门之Array对象操作小结
Jan 09 Javascript
javascript面向对象入门基础详细介绍
Sep 05 Javascript
JavaScript中判断整字类型最简洁的实现方法
Nov 08 Javascript
无刷新上传文件并返回自定义值
Jun 11 Javascript
谈谈JavaScript异步函数发展历程
Sep 29 Javascript
js实现选项卡内容切换以及折叠和展开效果【推荐】
Jan 08 Javascript
JavaScript编程设计模式之构造器模式实例分析
Oct 25 Javascript
Vue工程模板文件 webpack打包配置方法
Dec 26 Javascript
Vue动态组件与异步组件实例详解
Feb 23 Javascript
微信小程序网络层封装的实现(promise, 登录锁)
May 08 Javascript
微信小程序获取用户信息并保存登录状态详解
May 10 Javascript
jQuery设置下拉框显示与隐藏效果的方法分析
Sep 15 #jQuery
Vue实现滑动拼图验证码功能
Sep 15 #Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
Sep 15 #Javascript
解决layui调用自定义方法提示未定义的问题
Sep 14 #Javascript
layui使用label标签的方法
Sep 14 #Javascript
使用layui定义一个模块并使用的例子
Sep 14 #Javascript
基于Layui自定义模块的使用方法详解
Sep 14 #Javascript
You might like
php基础知识:类与对象(5) static
2006/12/13 PHP
Php Ctemplate引擎开发相关内容
2012/03/03 PHP
PHP输出日历表代码实例
2015/03/27 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
2016/01/05 PHP
深入理解PHP 数组之count 函数
2016/06/13 PHP
Yii全局函数用法示例
2017/01/22 PHP
YII框架页面缓存操作示例
2019/04/29 PHP
JAVASCRIPT下判断IE与FF的比较简单的方式
2008/10/17 Javascript
js遍历td tr等html元素
2012/12/13 Javascript
键盘上一张下一张兼容IE/google/firefox等浏览器
2014/01/28 Javascript
用js闭包的方法实现多点标注冒泡示例
2014/05/29 Javascript
完美兼容各大浏览器的jQuery仿新浪图文淡入淡出间歇滚动特效
2014/11/12 Javascript
javascript日期计算实例分析
2015/06/29 Javascript
jQuery实现简单下拉导航效果
2015/09/07 Javascript
JS递归遍历对象获得Value值方法技巧
2016/06/14 Javascript
jQuery Tags Input Plugin(添加/删除标签插件)详解
2016/06/20 Javascript
Bootstrap table的使用方法
2016/11/02 Javascript
微信小程序左滑动显示菜单功能的实现
2018/06/14 Javascript
swiper4实现移动端导航切换
2020/10/16 Javascript
关于ligerui子页面关闭后,父页面刷新,重新加载的方法
2019/09/27 Javascript
[38:30]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第一场2
2014/05/24 DOTA
[01:55]2014DOTA2国际邀请赛快报:国土生病 紧急去医院治疗
2014/07/10 DOTA
Django 路由系统URLconf的使用
2018/10/11 Python
django-rest-framework 自定义swagger过程详解
2019/07/18 Python
全面解析HTML5中的标准属性与自定义属性
2016/02/18 HTML / CSS
英国邮购活的植物主要供应商:Gardening Direct
2019/01/28 全球购物
如何写出高性能的JSP和Servlet
2013/01/22 面试题
施工班组长岗位职责
2014/01/05 职场文书
自我鉴定注意事项
2014/01/19 职场文书
《中华少年》教学反思
2014/02/15 职场文书
2014年综治宣传月活动总结
2014/04/28 职场文书
2014幼儿园大班工作总结
2014/11/10 职场文书
毕业生自荐信范文
2015/03/05 职场文书
2015夏季作息时间调整通知
2015/04/24 职场文书
义卖募捐活动总结
2015/05/09 职场文书
求职信:求职应该注意的问题
2019/04/24 职场文书