当前位置: 首页 > 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;只是…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...