【Javascript】设计模式之策略模式
文章目录
- 1、使用策略模式计算奖金
- 2、JavaScript 版本的策略模式
- 3、应用:表单验证
- 3.1 用策略模式进行表单验证
- 3.2 给某个文本输入框添加多种校验规则
- 4、策略模式的优缺点
策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
1、使用策略模式计算奖金
假如有个需求:
绩效为 S 的人年终奖有 4 倍工资,绩效为 A 的人年终奖有 3 倍工资,而绩效为 B 的人年终奖是 2 倍工资
1.1 最初代码实现:
var calculateBonus = function (performanceLevel, salary) {if (performanceLevel === 'S') {return salary * 4;}if (performanceLevel === 'A') {return salary * 3;}if (performanceLevel === 'B') {return salary * 2;}
}
console.log(calculateBonus('B', 3000));
console.log(calculateBonus('A', 5000));
缺点:
- calculateBonus 函数,包含了很多 if-else 语句,这些语句需要覆盖所有的逻辑分支
- calculateBonus 函数缺乏弹性,如果增加了一种新的绩效等级 C,或者想把绩效 S 的奖金
系数改为 5,那我们必须深入 calculateBonus 函数的内部实现,这是违反开放封闭原则的 - 算法的复用性差,如果在程序的其他地方需要重用这些计算奖金的算法呢?我们的选择
只有复制和粘贴
1.2 使用组合函数重构代码
使用组合函数来重构代码,我们把各种算法封装到一个个的小函数里面
var performanceS = function (salary) {return salary * 4;
}
var performanceA = function (salary) {return salary * 3;
}
var performanceB = function (salary) {return salary * 2;
}var calculateBonus = function (performanceLevel, salary) {if (performanceLevel === 'S') {return performanceS(salary);}if (performanceLevel === 'A') {return performanceA(salary);}if (performanceLevel === 'B') {return performanceB(salary);}
}console.log(calculateBonus('A', 2000));
问题:calculateBonus 函数有可能越来越庞大,而且在系统变化的时候缺乏弹性
1.3 使用策略模式重构代码
一个基于策略模式的程序至少由两部分组成:
第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。
第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类
// 定义绩效的计算规则
var performanceS = function () { };
performanceS.prototype.calculate = function (salary) {return salary * 4;
}
var performanceA = function () { };
performanceA.prototype.calculate = function (salary) {return salary * 3;
}
var performanceB = function () { };
performanceB.prototype.calculate = function (salary) {return salary * 2;
}// 定义奖金类Bonus
var Bonus = function () {this.salary = null;this.strategy = null;
}
Bonus.prototype.setSalary = function (salary) {this.salary = salary; // 设置员工的原始工资
}
Bonus.prototype.setStrategy = function (strategy) {this.strategy = strategy;// 设置员工绩效等级对应的策略对象
}
Bonus.prototype.getBonus = function () {return this.strategy.calculate(this.salary);// 把计算奖金的操作委托给对应的策略对象
}var bonus = new Bonus();
bonus.setSalary( 10000 );
bonus.setStrategy( new performanceS() ); // 设置策略对象
console.log( bonus.getBonus() ); // 输出:40000
bonus.setStrategy( new performanceA() ); // 设置策略对象
console.log( bonus.getBonus() ); // 输出:30000
2、JavaScript 版本的策略模式
上在 JavaScript 语言中,函数也是对象,所以更简单和直接的做法是把 strategy 直接定义为函数:
var strategies = {"S": function (salary) {return salary * 4;},"A": function (salary) {return salary * 3;},"B": function (salary) {return salary * 2;},
}var calculateBonus = function(level, salary) {return strategies[level](salary);
}console.log(calculateBonus('S', 3000)); // 12000
console.log(calculateBonus('B', 1000)); // 2000
3、应用:表单验证
做如下表单验证:
- 用户名不能为空。
- 密码长度不能少于 6 位。
- 手机号码必须符合格式
3.1 用策略模式进行表单验证
把这些校验逻辑都封装成策略对象:
var strategies = {isNonEmpty: function (value, errorMsg) {// 不为空if (value === '') {return errorMsg;}},minLength: function (value, length, errorMsg) {// 限制最小长度if (value.length < length) {return errorMsg;}},isMobile: function (value, errorMsg) {// 手机号码格式if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {return errorMsg;}},
};
Validator 类的实现:
var Validator = function () {this.cache = []; // 保存校验规则
};
Validator.prototype.add = function (dom, rule, errorMsg) {var ary = rule.split(':'); // 把 strategy 和参数分开this.cache.push(function () {// 把校验的步骤用空函数包装起来,并且放入 cachevar strategy = ary.shift(); // 用户挑选的 strategyary.unshift(dom.value); // 把 input 的 value 添加进参数列表ary.push(errorMsg); // 把 errorMsg 添加进参数列表return strategies[strategy].apply(dom, ary);});
};
Validator.prototype.start = function () {for (var i = 0, validatorFunc; (validatorFunc = this.cache[i++]); ) {var msg = validatorFunc(); // 开始校验,并取得校验后的返回信息if (msg) {// 如果有确切的返回值,说明校验没有通过return msg;}}
};
测试:
var validator = new Validator();
validator.add({ value: '' }, 'isNonEmpty', '用户名不能为空');
validator.add({ value: '1234' }, 'minLength:6', '密码长度不能少于 6 位');
var errorMsg = validator.start();
console.log(errorMsg)
3.2 给某个文本输入框添加多种校验规则
/***********************策略对象**************************/
var strategies = {isNonEmpty: function (value, errorMsg) {if (value === '') {return errorMsg;}},minLength: function (value, length, errorMsg) {if (value.length < length) {return errorMsg;}},isMobile: function (value, errorMsg) {if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {return errorMsg;}},
};
/***********************Validator 类**************************/
var Validator = function () {this.cache = [];
};
Validator.prototype.add = function (dom, rules) {var self = this;for (var i = 0, rule; (rule = rules[i++]); ) {(function (rule) {var strategyAry = rule.strategy.split(':');var errorMsg = rule.errorMsg;self.cache.push(function () {var strategy = strategyAry.shift();strategyAry.unshift(dom.value);strategyAry.push(errorMsg);return strategies[strategy].apply(dom, strategyAry);});})(rule);}
};
Validator.prototype.start = function () {for (var i = 0, validatorFunc; (validatorFunc = this.cache[i++]); ) {var errorMsg = validatorFunc();if (errorMsg) {return errorMsg;}}
};/***********************客户调用代码**************************/
var validataFunc = function () {var validator = new Validator();validator.add({ value: '' }, [{strategy: 'isNonEmpty',errorMsg: '用户名不能为空',},{strategy: 'minLength:6',errorMsg: '用户名长度不能小于 10 位',},]);validator.add({ value: '123' }, [{strategy: 'minLength:6',errorMsg: '密码长度不能小于 6 位',},]);validator.add({ value: '1255555555' }, [{strategy: 'isMobile',errorMsg: '手机号码格式不正确',},]);var errorMsg = validator.start();return errorMsg;
};var errorMsg = validataFunc();
if (errorMsg) {console.warn(errorMsg);return false;
}
4、策略模式的优缺点
优点
- 避免多重条件选择语句
- 策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展
- 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作
缺点:
- 使用策略模式会在程序中增加许多策略类或者策略对象
- 要使用策略模式,必须了解所有的 strategy,必须了解各个 strategy 之间的不同点,这样才能选择一个合适的 strategy
相关文章:
【Javascript】设计模式之策略模式
文章目录 1、使用策略模式计算奖金2、JavaScript 版本的策略模式3、应用:表单验证3.1 用策略模式进行表单验证3.2 给某个文本输入框添加多种校验规则 4、策略模式的优缺点 策略模式的定义是:定义一系列的算法,把它们一个个封装起来࿰…...
vue面试题:如何保存页面的当前的状态?
如何保存页面的当前的状态? 既然是要保持页面的状态(其实也就是组件的状态),那么会出现以下两种情况:组件会被卸载:(1)将状态存储在LocalStorage / SessionStorage优点:缺…...
Java的编程之旅34——Interger包装类
1.API简介 Java的API(Application Programming Interface,应用程序编程接口)是一组提供给程序员使用的代码库,用于开发Java应用程序。Java的API包括了各种类和接口,用于处理输入输出、图形用户界面、网络通信、数据库…...
C# Winform画图绘制圆形
一、因为绘制的圆形灯需要根据不同的状态切换颜色,所以就将圆形灯创建为用户控件 二、圆形灯用户控件 1、创建用户控件UCLight 2、设值用户控件大小(30,30)。放一个label标签,AutoSize为false(不自动调整大小),Dock为Fill(填充),textaglign为居中显示。 private Color R…...
Unity(第十六部)声音和视频
声音 1、听声音 创建相机的时候,相机自带Audio Listener 多个相机的时候,我们只保留一个Audio Listener就可以 2、声音源,环境音 添加Audio Source就行中文叫声音源 3、脚本执行的声音 using System.Collections; using System.Collection…...
Linux(CentOS)学习
一、认识Linux 1、如何修改Linux时区 2、配置固定IP 3、重启网络服务 3、小技巧快捷键 4、环境变量设置 5、Linux文件的上传和下载 6、压缩和解压 二、基础命令 1、目录命令 (1、)查看目录内容(ls) 1、ls //查看当前目录内容 2、- a //显示隐藏内容 3…...
HTML最强入门学习笔记+GitHub小项目源码
HTML学习笔记 GitHub项目链接: 点我跳转GitHub 本博客采用markdown编写,上面这个链接跳转就是采用了html的<a></a>的代码设计的跳转提示~ 1.创建文件可以使用 ! 在VSCode中进行快速补全从而生成一整个HTML结构 HTML组成 <!DOCTYPE html><htm…...
《Spring Security 简易速速上手小册》第4章 授权与角色管理(2024 最新版)
文章目录 4.1 理解授权4.1.1 基础知识详解授权的核心授权策略方法级安全动态权限检查 4.1.2 主要案例:基于角色的页面访问控制案例 Demo 4.1.3 拓展案例 1:自定义投票策略案例 Demo测试自定义投票策略 4.1.4 拓展案例 2:使用方法级安全进行细…...
【java类的使用,及注意事项】
Java类的使用是通过创建对象来调用类的方法和访问类的属性。首先,要在Java中创建一个类,需要使用关键字class,然后给类一个名称,并在代码块中定义类的属性和方法。 例如,下面是一个简单的Java类的示例: p…...
[JSOI2008] 最大数 题解 线段树
[JSOI2008] 最大数 传送门 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 查询操作。 语法:Q L 功能:查询当前数列中末尾 L L L 个数中的最大的数,并输出这个数的值。 限制: L L L 不超过…...
python爬虫之app爬取-charles的使用
专栏系列:http://t.csdnimg.cn/WfCSx 前言 前面介绍的都是爬取 Web 网页的内容。随着移动互联网的发展,越来越多的企业并没有提供 Web 网页端的服务,而是直接开发了 App,更多更全的信息都是通过 App 来展示的。那么针对 App 我们可以爬取吗?当然可以。 App 的爬取相比 …...
神经网络结构——CNN、RNN、LSTM、Transformer !!
文章目录 前言 一、什么是CNN 网络结构 解决问题 工作原理 实际应用 二、什么是RNN 网络结构 解决问题 工作原理 应用场景 三、什么是LSTM 网络结构 解决问题 工作原理 应用场景 四、什么是Transformer 网络结构 解决问题 工作原理 BERT GPT 前言 本文将从什么是CNN࿱…...
mysql 事务的隔离级别
一、事务的隔离级别要解决的问题: 1)脏读:读到了其它事务未提交的数据即脏读,未提交意味着数据有可能会被回滚,也就是最终有可能不会存储到数据库中,即读到了最终不一定存在存在的数据,即为脏读…...
Unity3D 阴影的计算原理详解
前言 阴影是游戏中的重要特效之一,可以增加游戏的真实感和立体感。在Unity3D中,阴影的计算原理主要包括阴影的产生、投影和渲染。 对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀! 首…...
【物联网应用案例】从0到N,智慧农业的数据价值
智慧农业全方位渗透到农业的每一个环节,云端解决方案更推动了研究人员、农艺师及农民间的密切协作,为研发企业提供了既经济又具扩展性的完美方案。 据IDC预计,到2036年,农场收集的数据量将增加800%以上,这凸显了农业数…...
文生视频基础1:sora技术报告学习
sora技术报告学习 背景学后理解训练流程技术拆解编码解码扩散模型训练用数据 28号直播交流会后的一些想法自身的一点点想法 参考 原文地址:Video generation models as world simulators 背景 此项目的背景是基于Datawhale的关于sora技术文档的拆解和相关技术讲解…...
Linux第68步_旧字符设备驱动的一般模板
file_operations结构体中的函数就是我们要实现的具体操作函数。 注意: register_chrdev()和 unregister_chrdev()这两个函数是老版本驱动使用的。现在新字符设备驱动已经不再使用这两个函数,而是使用Linux内核推荐的新字符设备驱动API函数。 1、创建C…...
23种设计模式——工厂方法模式
定义: 一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其他子类。 工厂方法通用类图: 这个图更好理解 在工厂方法模式中,抽象产品类Product负责定义产品的共性,实现对事物最抽象的…...
水豚鼠标助手 强大的鼠标美化工具
水豚鼠标助手 水豚鼠标助手是一款 鼠标换肤、屏幕画笔、放大镜、聚光灯、屏幕放大、倒计时功能的强大屏幕演示工具。 软件助手获取 水豚鼠标助手1.0.0 安装教程 第一步:下载后,双击软件安装包 第二步:Windows可能会出现提示弹窗ÿ…...
ArrayList集合源码分析
ArrayList集合源码分析 文章目录 ArrayList集合源码分析一、字段分析二、构造方法分析三、方法分析四、总结 内容如有错误或者其他需要注意的知识点,欢迎指正或者探讨补充,共同进步。 一、字段分析 //默认初始化容量。这里和Vector一样,只是…...
基于RK3399核心板的智能PCR仪开发:从嵌入式系统到高精度温控
1. 项目概述:当PCR仪遇上高性能核心板在分子生物学实验室里,PCR仪(聚合酶链式反应仪)是当之无愧的“C位”设备。从基础的病原体检测、基因分型,到前沿的基因编辑、高通量测序文库构建,几乎每一个实验环节都…...
增程式电动汽车预测型能量管理策略【附算法】
✨ 长期致力于增程式电动汽车、能量管理策略、车速预测、广义回归神经网络、动态规划研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)基于AIC准则的自…...
工业视觉开发的基石:GenICam 简介
在工业自动化和机器视觉领域,“碎片化”曾是开发者面临的最大痛点。不同品牌的相机使用不同的通信协议、参数定义和 SDK。为了获取一张图像或调节曝光时间,开发者往往需要学习多个厂商的驱动接口。而 GenICam (Generic Interface for Cameras) 标准的出现…...
SSE流式响应:从Reactor Flux到生产级AI聊天的工程实践——5分钟超时、线程隔离、背压处理全解析
大家好,我是程序员小策。 首先给大家去一个例子:凌晨两点,P0 告警炸了。 AI 聊天接口全部超时,用户消息发出去转圈转了 120 秒然后报错。你打开监控一看:Tomcat 线程池满了,200 个工作线程全部卡在"…...
利用 Taotoken 模型广场为你的智能客服场景选择最合适的大模型
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 利用 Taotoken 模型广场为你的智能客服场景选择最合适的大模型 智能客服是当前大模型技术落地最广泛的场景之一。无论是处理售前咨…...
【计算机毕业设计】基于Springboot的高校教师科研管理系统设计与实现+万字文档
博主介绍:✌全网粉丝3W,csdn特邀作者、CSDN新星计划导师、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、…...
洛雪音乐音源终极指南:3步解锁全网无损音乐自由
洛雪音乐音源终极指南:3步解锁全网无损音乐自由 【免费下载链接】lxmusic- lxmusic(洛雪音乐)全网最新最全音源 项目地址: https://gitcode.com/gh_mirrors/lx/lxmusic- 还在为音乐平台会员费烦恼?或是被不同平台的独家版权搞得晕头转向ÿ…...
2026学生背单词软件实测,这5款真心好用不踩坑
过去几年我们团队在帮助不同学段学生提升词汇量时,踩过不少坑:有的工具背词效率还行,但同步一塌糊涂;有的界面酷炫,算法推荐却毫无个性,仿佛在用十年前的技术。市面上背单词软件看似饱和,真正能…...
5步解锁Total War模组制作:用RPFM编辑器从新手到专家的完整指南
5步解锁Total War模组制作:用RPFM编辑器从新手到专家的完整指南 【免费下载链接】rpfm Rusted PackFile Manager (RPFM) is a... reimplementation in Rust and Qt6 of PackFile Manager (PFM), one of the best modding tools for Total War Games. 项目地址: ht…...
CV产线MLOps平台:图像原生处理与硬件感知交付
1. 项目概述:这不是又一个“模型训练平台”,而是一套能真正跑通CV产线的MLOps工作流“Streamline Your Computer Vision Stack with an End-to-End MLOps Platform”——这个标题里藏着三个被太多团队长期忽视的关键事实:第一,“C…...
