【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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/708428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA基础——Maven配置tomcat

配置方案 一、配置maven-tomcat plugin插件&#xff08;只最高支持到tomcat 8&#xff09;~~1.添加镜像源&#xff0c;获取tomcat 8插件配置~~~~1.1 在pom.xml里先添加镜像源~~~~1.2 添加tomcat插件配置~~ 2. 添加tomact官方发布的插件配置&#xff08;无需添加镜像源&#xff…

Python 使用 MyHDL库 实现FPGA板卡仿真验证

要使用 Python 结合 MyHDL 库实现 FPGA 板卡的仿真验证&#xff0c;您可以利用 MyHDL 提供的硬件描述语言和仿真功能来进行 FPGA 设计的验证。下面我将为您介绍一个简单的示例&#xff0c;演示如何使用 MyHDL 库进行 FPGA 设计的仿真验证。 步骤概述 编写 MyHDL 硬件描述&…

本届挑战赛季军方案:基于图网络及LLM AGENT的微服务系统异常检测和根因定位方法

aiboco团队荣获本届挑战赛季军。该团队来自亿阳信通。 方案介绍 本届挑战赛采用开放式赛题&#xff0c;基于建行云龙舟运维平台的稳定性工具和多维监控系统&#xff0c;模拟大型的生活服务APP的生产环境&#xff0c;提供端到端的全链路的日志、指标和调用链数据。参赛队伍在组…

vue中将某个不太规则的json转成对象,或者将对象转成json字符串

vue中将某个不太规则的json转成对象&#xff0c;或者将对象转成json字符串 以我自己做的项目某个不规则的json为例 将json对象转成json字符串&#xff1a; JSON.stringify(jsonData); 将不规则json字符串转成对象并获取对应的属性的值&#xff1a; JSON.parse(jsonData).Name…

云原生精品资料合集(附下载)

云计算是产业数字化转型的关键基础设施,以基础设施资源为中心的云搬迁时代接近尾声&#xff0c;以应用价值为中心的云原生时代已经到&#xff0c;所以IT人员学习云原生正当时&#xff01;最近跟各位大神征集了云原生的教程&#xff0c;行业报告和最佳实践&#xff0c;总有一款适…

蓝桥杯_中断系统

一 中断 中断&#xff0c;即cpu暂停执行当前程序&#xff0c;转而执行另外一段特殊程序&#xff0c;处理结束后。返回之前暂停程序继续执行。 中断向量&#xff0c;中断服务程序的入口地址&#xff0c;每个中断源都对应一个固定的入口地址。 中断服务函数&#xff0c;内核响应中…

【亚马逊云科技】通过Amazon CloudFront(CDN)快速访问资源

文章目录 前言一、应用场景二、【亚马逊云科技】CloudFront&#xff08;CDN&#xff09;的优势三、入门使用总结 前言 前面有篇文章我们介绍了亚马逊云科技的云存储服务。云存储服务主要用于托管资源&#xff0c;而本篇文章要介绍的CDN则是一种对托管资源的快速访问服务&#…

devc++跑酷小游戏3.5.0

本来想搞存档的&#xff0c;失败了&#xff0c;要再学学文件操作的函数。还有一个打印地图的函数&#xff0c;更失败&#xff0c;彻底放弃。最近开学了&#xff0c;游戏不会经常更新&#xff0c;要写作业。昨天写到10点T_T #include<bits/stdc.h> #include<windows.h…

如何在启用Secure Boot的Ubuntu 22.04电脑中安装使用VirtualBox 6.1

我使用的是华为Matebook X Pro笔记本电脑&#xff0c;默认开启了UEFI安全引导&#xff08;UEFI Secure Boot&#xff09;&#xff0c;安装了Windows和Ubuntu双操作系统&#xff0c;平时基本上都是使用Ubuntu 22.04&#xff08;Linux Mint 21.3&#xff09;&#xff0c;使用上也…

Socket网络编程(二)——UDP快速入门

目录 UDP相关概念UDP是什么为什么不可靠UDP能做什么UDP包最大长度 UDP单播、广播、多播概念1. 单播、广播、多播模型图2. ip地址分类3. 子网掩码的作用&#xff1a;4. 广播地址5. 网段划分6. 变长子网掩码 UDP核心APIAPI-DatagramSocketDatagramSocket构造方法DatagramSocket常…

Debezium发布历史158

原文地址&#xff1a; https://debezium.io/blog/2023/08/29/debezium-2-4-beta1-released/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Debezium 2.4.0.Beta1 Released August 29, 2023 by Chris Cranford …

6.5 共享数据

本节介绍Android的四大组件之一ContentProvider的基本概念和常见用法&#xff1a;首先说明如何使用内容提供器封装内部数据的外部访问接口&#xff0c;然后阐述如何使用内容解析器通过外部接口操作内部数据&#xff0c;最后叙述如何利用内容解析器读写联系人信息&#xff0c;以…

10_Vue

文章目录 Vue快速入门Vue的指令Vue的插值表达式V指令v-bind&#xff08;单向绑定&#xff09;v-model&#xff08;双向绑定&#xff09;v-on&#xff08;事件监听&#xff09;v-for&#xff08;循环&#xff09;v-text、v-htmlv-show&#xff08;显示/隐藏&#xff09;v-if&…

学习加密(三)spring boot 使用RSA非对称加密,前后端传递参数加解密

1.前面一篇是AES对称加密写了一个demo,为了后面的两者结合使用,今天去了解学习了下RSA非对称加密. 2.这是百度百科对(对称加密丶非对称加密)的解释: (1)对称加密算法在加密和解密时使用的是同一个秘钥。 (2)非对称加密算法需要两个密钥来进行加密和解密&#xff0c;这两个秘钥…

了解GPT:ChatGPT的终极指南

在人工智能&#xff08;AI&#xff09;的世界里&#xff0c;有一颗冉冉升起的新星正在革命性地改变我们与机器的交互方式&#xff1a;ChatGPT。在本文中&#xff0c;我们将深入研究什么是ChatGPT&#xff0c;为什么底层技术GPT如此强大&#xff0c;以及它是如何实现其卓越功能的…

excel导出标准化

虽然标题叫标准化&#xff0c;只不过是我自己的习惯&#xff0c;当一件事情变得流程标准化之后&#xff0c;开发程序就会飞快&#xff0c;开发评估工作总是 搞个1~2天&#xff0c;实则前端后端一起开发&#xff0c;1个小时就可以搞定。 1 前端 const exportXls async () >…

C++重点---STL简介

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、STL简介 STL&#xff08;Standard Template Library&#xff09;是C标准库中的一个重要组成部分&#xff0c;它提供了…

iOS中卡顿产生的主要原因及优化思路

卡顿本质上是一个UI体验上的问题&#xff0c;而UI的渲染及显示&#xff0c;主要涉及CPU和GPU两个层面。若 CPUGPU渲染耗时超过16.7ms&#xff0c;就会在屏幕vsync信号到来时无法更新屏幕内容&#xff0c;进而导致卡顿。 iOS中UI渲染主要包含Layout->Draw->Prepare->Co…

MySQL5.7.44版本压缩包在Win11系统快速安装

一.背景 主要还是为了公司的带徒弟任务。我自己也喜欢MySQL的绿色版本。 1.软件版本说明 MySQL版本&#xff1a;5.7.44 压缩包版本&#xff0c;相当于绿色版。当然&#xff0c;你也可以使用window系统的Installer版本去安装。 操作系统&#xff1a;Win11家庭版 二.MySQL软…

electron-release-server部署electron自动更新服务器记录

目录 一、前言 环境 二、步骤 1、下载上传electron-release-server到服务器 2、宝塔新建node项目网站 3、安装依赖 ①npm install ②安装并配置postgres数据库 ③修改项目配置文件 ④启动项目 ⑤修改postgres的认证方式 ⑥Cannot find where you keep your Bower p…