当前位置: 首页 > news >正文

【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、应用&#xff1a;表单验证3.1 用策略模式进行表单验证3.2 给某个文本输入框添加多种校验规则 4、策略模式的优缺点 策略模式的定义是&#xff1a;定义一系列的算法&#xff0c;把它们一个个封装起来&#xff0…...

vue面试题:如何保存页面的当前的状态?

如何保存页面的当前的状态&#xff1f; 既然是要保持页面的状态&#xff08;其实也就是组件的状态&#xff09;&#xff0c;那么会出现以下两种情况&#xff1a;组件会被卸载&#xff1a;&#xff08;1&#xff09;将状态存储在LocalStorage / SessionStorage优点&#xff1a;缺…...

Java的编程之旅34——Interger包装类

1.API简介 Java的API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;是一组提供给程序员使用的代码库&#xff0c;用于开发Java应用程序。Java的API包括了各种类和接口&#xff0c;用于处理输入输出、图形用户界面、网络通信、数据库…...

C# Winform画图绘制圆形

一、因为绘制的圆形灯需要根据不同的状态切换颜色,所以就将圆形灯创建为用户控件 二、圆形灯用户控件 1、创建用户控件UCLight 2、设值用户控件大小(30,30)。放一个label标签,AutoSize为false(不自动调整大小),Dock为Fill(填充),textaglign为居中显示。 private Color R…...

Unity(第十六部)声音和视频

声音 1、听声音 创建相机的时候&#xff0c;相机自带Audio Listener 多个相机的时候&#xff0c;我们只保留一个Audio Listener就可以 2、声音源&#xff0c;环境音 添加Audio Source就行中文叫声音源 3、脚本执行的声音 using System.Collections; using System.Collection…...

Linux(CentOS)学习

一、认识Linux 1、如何修改Linux时区 2、配置固定IP 3、重启网络服务 3、小技巧快捷键 4、环境变量设置 5、Linux文件的上传和下载 6、压缩和解压 二、基础命令 1、目录命令 (1、)查看目录内容&#xff08;ls&#xff09; 1、ls //查看当前目录内容 2、- a //显示隐藏内容 3…...

HTML最强入门学习笔记+GitHub小项目源码

HTML学习笔记 GitHub项目链接: 点我跳转GitHub 本博客采用markdown编写&#xff0c;上面这个链接跳转就是采用了html的<a></a>的代码设计的跳转提示~ 1.创建文件可以使用 ! 在VSCode中进行快速补全从而生成一整个HTML结构 HTML组成 <!DOCTYPE html><htm…...

《Spring Security 简易速速上手小册》第4章 授权与角色管理(2024 最新版)

文章目录 4.1 理解授权4.1.1 基础知识详解授权的核心授权策略方法级安全动态权限检查 4.1.2 主要案例&#xff1a;基于角色的页面访问控制案例 Demo 4.1.3 拓展案例 1&#xff1a;自定义投票策略案例 Demo测试自定义投票策略 4.1.4 拓展案例 2&#xff1a;使用方法级安全进行细…...

【java类的使用,及注意事项】

Java类的使用是通过创建对象来调用类的方法和访问类的属性。首先&#xff0c;要在Java中创建一个类&#xff0c;需要使用关键字class&#xff0c;然后给类一个名称&#xff0c;并在代码块中定义类的属性和方法。 例如&#xff0c;下面是一个简单的Java类的示例&#xff1a; p…...

[JSOI2008] 最大数 题解 线段树

[JSOI2008] 最大数 传送门 题目描述 现在请求你维护一个数列&#xff0c;要求提供以下两种操作&#xff1a; 查询操作。 语法&#xff1a;Q L 功能&#xff1a;查询当前数列中末尾 L L L 个数中的最大的数&#xff0c;并输出这个数的值。 限制&#xff1a; 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&#xff1…...

mysql 事务的隔离级别

一、事务的隔离级别要解决的问题&#xff1a; 1&#xff09;脏读&#xff1a;读到了其它事务未提交的数据即脏读&#xff0c;未提交意味着数据有可能会被回滚&#xff0c;也就是最终有可能不会存储到数据库中&#xff0c;即读到了最终不一定存在存在的数据&#xff0c;即为脏读…...

Unity3D 阴影的计算原理详解

前言 阴影是游戏中的重要特效之一&#xff0c;可以增加游戏的真实感和立体感。在Unity3D中&#xff0c;阴影的计算原理主要包括阴影的产生、投影和渲染。 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;希望大家可以点击进来一起交流一下开发经验呀&#xff01; 首…...

【物联网应用案例】从0到N,智慧农业的数据价值

智慧农业全方位渗透到农业的每一个环节&#xff0c;云端解决方案更推动了研究人员、农艺师及农民间的密切协作&#xff0c;为研发企业提供了既经济又具扩展性的完美方案。 据IDC预计&#xff0c;到2036年&#xff0c;农场收集的数据量将增加800%以上&#xff0c;这凸显了农业数…...

文生视频基础1:sora技术报告学习

sora技术报告学习 背景学后理解训练流程技术拆解编码解码扩散模型训练用数据 28号直播交流会后的一些想法自身的一点点想法 参考 原文地址&#xff1a;Video generation models as world simulators 背景 此项目的背景是基于Datawhale的关于sora技术文档的拆解和相关技术讲解…...

Linux第68步_旧字符设备驱动的一般模板

file_operations结构体中的函数就是我们要实现的具体操作函数。 注意&#xff1a; register_chrdev()和 unregister_chrdev()这两个函数是老版本驱动使用的。现在新字符设备驱动已经不再使用这两个函数&#xff0c;而是使用Linux内核推荐的新字符设备驱动API函数。 1、创建C…...

23种设计模式——工厂方法模式

定义&#xff1a; 一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其他子类。 工厂方法通用类图&#xff1a; 这个图更好理解 在工厂方法模式中&#xff0c;抽象产品类Product负责定义产品的共性&#xff0c;实现对事物最抽象的…...

水豚鼠标助手 强大的鼠标美化工具

水豚鼠标助手 水豚鼠标助手是一款 鼠标换肤、屏幕画笔、放大镜、聚光灯、屏幕放大、倒计时功能的强大屏幕演示工具。 软件助手获取 水豚鼠标助手1.0.0 安装教程 第一步&#xff1a;下载后&#xff0c;双击软件安装包 第二步&#xff1a;Windows可能会出现提示弹窗&#xff…...

ArrayList集合源码分析

ArrayList集合源码分析 文章目录 ArrayList集合源码分析一、字段分析二、构造方法分析三、方法分析四、总结 内容如有错误或者其他需要注意的知识点&#xff0c;欢迎指正或者探讨补充&#xff0c;共同进步。 一、字段分析 //默认初始化容量。这里和Vector一样&#xff0c;只是…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...