发布于 2024 年 2 月 26 日,星期一
策略模式是一种设计模式,它允许在运行时选择算法或行为,通过将这些算法或行为封装成独立的策略类,使得它们可以相互替换。在前端开发中,策略模式常用于处理复杂的条件逻辑,避免代码的重复和冗长。通过将不同的策略封装在独立的函数或对象中,可以提高代码的可维护性和可扩展性,同时减少代码的耦合度。这种模式特别适用于需要根据不同条件执行不同操作的场景,如表单验证、数据处理等。使用策略模式,开发者可以轻松地添加、修改或删除策略,而无需修改核心代码,从而实现代码的灵活性和可复用性。
<<<<<<< HEAD:WritingPlan/PublishedArticle/面试官:策略模式有使用过吗?我:没有.......md
=======
系列首发于公众号『非同质前端札记』https://mp.weixin.qq.com/s?__biz=MzkyOTI2MzE0MQ==&mid=2247485576&idx=1&sn=5ddfe93f427f05f5d126dead859d0dc8&chksm=c20d73c2f57afad4bbea380dfa1bcc15367a4cc06bf5dd0603100e8bd7bb317009fa65442cdb&token=1071012447&lang=zh_CN#rd ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
d01511f06d20186737a35f54508e8dd2e2752882:WritingPlan/PublishedArticle/JavaScript程序设计模式小技巧——策略模式,快看快用!!!.md
策略模式:定义一系列的算法,将他们一个个封装,并使他们可相互替换。
/**
*
* @param {*} level 绩效等级
* @param {*} salary 工资基数
* @returns 年终奖金额
*/var calcBonus = function (level, salary) { if (level === "S") { return salary * 4; } else if (level === "A") { return salary * 3; } else if (level === "B") { return salary * 2; }};calcBonus('A', 20000); // 60000calcBonus('B', 8000); // 16000
函数逻辑太多
缺乏弹性
,比如如果我们需要增加一个等级 C,那就必须要去修改 calcBonus 函数。这就违反了开放-封闭原则
。复用性差
。如果后续还要重用这个程序去计算奖金,我们只有去 C,V。var totalS = function (salary) { return salary * 4;};var totalA = function (salary) { return salary * 3;};var totalB = function (salary) { return salary * 2;};var calcBonus = function (level, salary) { if (level === "S") { return totalS(salary); } else if (level === "A") { return totalA(salary); } else if (level === "B") { return totalB(salary); }};calcBonus('A', 20000); // 60000calcBonus('B', 8000); // 16000
将其定义为一系列的算法,将他们每一个封装起来,将不变的部分和变化的部分隔开。
算法的使用方式是不变的,都是根据某个算法获取最后的奖金金额。而在每个算法的内部实现却是不同的,每一个等级对应着不同的计算规则
。在策略模式程序中:最少由两部分组成,一部分是一组策略类,在策略类中封装了具体的算法,并负责具体的计算过程。一部分是环境类 context,接受用户的请求,并将请求委托给某一个策略类。
var strategies = { S: function (salary) { return salary * 4; }, A: function (salary) { return salary * 3; }, B: function (salary) { return salary * 2; },};var calcBonus = function (level, salary) { return strategies[level](salary);}calcBonus('A', 20000); // 60000calcBonus('B', 8000); // 16000
策略模式的实现并不复杂,关键是如何从策略模式的实现背后,找到封装变化,委托和多态性这些思想的价值
。function submit() { let { username, password, tel } = infoForm; if (username === "") { Toast("用户名不能为空"); return false; } if (password.length < 6) { Toast("密码不能少于 6 位"); return false; } if (!/(^1[3|5|8][0-9]{9}$)/.test(tel)) { Toast("手机号码格式不正确"); return false; } // .....}
let infoForm = { username: "我是某某某", password: 'zxcvbnm', tel: 16826384655,};var strategies = { isEmpty: function (val, msg) { if (!val) return msg; }, minLength: function (val, length, msg) { if (val.length < length) return msg; }, isTel: function (val, msg) { if (!/(^1[3|5|8][0-9]{9}$)/.test(val)) return msg; },};var validFn = function () { var validator = new Validator(); let { username, password, tel } = infoForm; validator.add(username, "isEmpty", "用户名不能为空"); validator.add(password, "minLength:6", "密码不能少于 6 位"); validator.add(tel, "isTel", "手机号码格式不正确"); var msg = validator.start(); return msg;};class Validator { constructor() { this.cache = []; } add(attr, rule, msg) { var ruleArr = rule.split(":"); this.cache.push(function () { var strategy = ruleArr.shift(); ruleArr.unshift(attr); ruleArr.push(msg); return strategies[strategy].apply(attr, ruleArr); }); } start() { for (let i = 0; i < this.cache.length; i++) { var msg = this.cache[i](); if (msg) return msg; } }}function submit() { let msg = validFn(); if (msg) { Toast(msg); return false; } console.log('verify success'); // .....}submit();
validator.add(username, [ { strategy: "isEmpty", msg: "用户名不能为空" }, { strategy: 'minLength:6', msg: '密码不能少于 6 位' }]);
let infoForm = { username: "阿斯顿发生的", password: "ss1sdf", tel: 15829485647,};var strategies = { isEmpty: function (val, msg) { if (!val) return msg; }, minLength: function (val, length, msg) { if (val.length < length) return msg; }, isTel: function (val, msg) { if (!/(^1[3|5|8][0-9]{9}$)/.test(val)) return msg; },};var validFn = function () { var validator = new Validator(); let { username, password, tel } = infoForm; validator.add(username, [ { strategy: "isEmpty", msg: "用户名不能为空", }, { strategy: "minLength:6", msg: "密码不能少于 6 位", }, ]); validator.add(password, [ { strategy: "minLength:6", msg: "密码不能少于 6 位", }, ]); validator.add(tel, [ { strategy: "isTel", msg: "手机号码格式不正确", }, ]); var msg = validator.start(); return msg;};class Validator { constructor() { this.cache = []; } add(attr, rules) { for (let i = 0; i < rules.length; i++) { var rule = rules[i]; var ruleArr = rule.strategy.split(":"); var msg = rule.msg; var cacheItem = this.createCacheItem(ruleArr, attr, msg); this.cache.push(cacheItem); } } start() { for (let i = 0; i < this.cache.length; i++) { var msg = this.cache[i](); if (msg) return msg; } } createCacheItem(ruleArr, attr, msg) { return function () { var strategy = ruleArr.shift(); ruleArr.unshift(attr); ruleArr.push(msg); return strategies[strategy].apply(attr, ruleArr); }; }}function submit() { let msg = validFn(); if (msg) { Toast(msg); return false; } console.log("verify success"); // .....}submit();
Context(环境类)
:持有一个 Strategy 类的引用,用一个 ConcreteStrategy 对象来配置Strategy(环境策略类)
:定义了所有支持的算法的公共接口,通常是以一个接口或抽象来实现。Context 使用这个接口来调用其 ConcreteStrategy 定义的算法。ConcreteStrategy(具体策略类)
:以 Strategy 接口实现某种算法<<<<<<< HEAD:WritingPlan/PublishedArticle/面试官:策略模式有使用过吗?我:没有.......md
曾探
大佬的《JavaScript 设计模式与开发实践》。文章仅做个人学习总结=======
曾探
大佬的《JavaScript 设计模式与开发实践》。文章仅做个人学习总结和知识汇总Q:(question)
R:(result)
A:(attention matters)
D:(detail info)
S:(summary)
Ana:(analysis)
T:(tips)
d01511f06d20186737a35f54508e8dd2e2752882:WritingPlan/PublishedArticle/JavaScript程序设计模式小技巧——策略模式,快看快用!!!.md