JavaScript职责链模式与开发实践(下)

news/2024/10/18 18:27:38/

前言

作为一个前端切图仔,少有和各类设计模式打交道。但这不影响我们学习设计模式的思维,来提升我们的代码水平。

本章通过讲解职责链模式,希望能够让你对设计模式更一步的学习。

本章学习内容👇

  • 灵活可拆分的职责链模式

灵活可拆分的职责链模式

在上一章,《JavaScript职责链模式与开发实践(中)》

我们将大段的条件判断函数拆分为了三个小函数,并用职责链模式模式串联起来了这些模块。虽然解决了大量使用条件分支的语句,但这依然还存在一些问题:

function orderMember(seniorMember, price) {if (seniorMember) {return orderSeniorMember(price)} else {return price * 0.95}
}

可以看到,在职责链的传递上非常僵硬,链上的下一段函数直接被耦合在了业务函数之中。这是违反开放-封闭原则OCP,Open Closed Principle)是所有面向对象原则的核心。如果以后我们的会员还要再分钻石会员以及大会员等等就意味着必须改动这些业务函数内部。这会扰乱我们之前所构建的链条,就像在已经创建好的数组我们去改变其中每一个元素的顺序而导致整个数组偏移的后果。

接下来, 我们通过对职责链节点进行一层工厂化包装来解决这个问题👇

首先,我们先解除之前三个函数节点的耦合。并在需要传递给下一层请求时,我们通过返回一个字符串nextSuccessor表示。

​
function orderNormal(userType, seniorMember, stock, price) {if (userType === 0) {if (stock > 0) {console.log(price * 0.99)} else {console.log(false)}} else {return 'nextSuccessor'; //向职责链后继节点传递请求}
}
​
function orderMember(userType, seniorMember, stock, price) {if (seniorMember == 0) {return 'nextSuccessor'; //向职责链后继节点传递请求} else {console.log(price * 0.95)}
}
​
function orderSeniorMember(userType, seniorMember, stock, price) {if (userType === 1 && seniorMember == 1) {console.log(price * 0.91)}
}
​

接着, 我们定义一个构造函数Chain,使它接受一个函数作为该节点运行的函数,同时他还拥有俩个属性和方法:

  • fn当前的运行节点函数
  • successor下一个节点
  • Chain.prototype.setNextSuccessor指定在链中的下一个节点
  • Chain.prototype.passRequest传递请求给某个节点
let Chain = function (fn) {this.fn = fn;this.successor = null;
};
Chain.prototype.setNextSuccessor = function (successor) {return this.successor = successor;
};
Chain.prototype.passRequest = function () {var ret = this.fn.apply(this, arguments);if (ret === 'nextSuccessor') {return this.successor && this.successor.passRequest.apply(this.successor, arguments);}return ret;
};

然后, 我们通过这个工厂实例化包装下我们的节点,并测试运行。

var chainOrderSenior = new Chain(orderSeniorMember);
var chainOrderMember = new Chain(orderMember);
var chainOrderNormal = new Chain(orderNormal);
​
chainOrderMember.setNextSuccessor(chainOrderSenior);
chainOrderNormal.setNextSuccessor(chainOrderMember);
​
chainOrderNormal.passRequest(1, false, 1, 100)

控制台输出

95

完成🤩。这样下次我们需要追加新的会员等级或者其他条件时,只需要设置在对应节点设置后继节点即可。

\


http://www.ppmy.cn/news/11165.html

相关文章

(十六)一篇文章学会Java的常用API

目录 前言: 一、Object:toStringequals 二、StringBuilder 三、Math 四、System 五、BigDecimal 前言: API的主要目的是提供应用程序与开发人员以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。提供API所定义的功能的软件称作此API的实…

【Redis】缓存穿透问题及其解决方案

【Redis】缓存穿透问题及其解决方案 文章目录【Redis】缓存穿透问题及其解决方案1. 缓存穿透概念及原因2. 解决方案2.1 缓存空对象2.1.1 缓存空对象的优缺点2.1.2 改进代码2.2 布隆过滤2.2.1 布隆过滤的优缺点1. 缓存穿透概念及原因 缓存穿透:客户端请求的数据在 缓…

软件著作权申请注意事项

​软著申请需要哪些材料 ①企业申请:企业营业执照副本复印件(加盖公章)、身份证复印件(正反面)。 个人申请:个人身份证复印件。 ②软件设计/使用说明书文档一份 文档可根据要求提供,可以是软件…

互联网摸鱼日报(2023-01-11)

互联网摸鱼日报(2023-01-11) InfoQ 热门话题 下一个十年,我们需要一款什么样的分析型数据库? VS Code有多么不安全:一个扩展就可能导致公司GitHub中的所有代码被擦除? OpenJDK提议Galahad项目合并GraalV…

Cesium 点击获取/拾取(PICK)的不同用法

Cesium 拾取有多个方法,下面就分别说明一下几种常用方法都是做什么用的,在什么场景下使用。 1. viewer.scene.pick 通过坐标位置,拾取 Entity 、 Primitive、3D-Tiles(Cesium3DTileFeature)对象。 例如获取 Entity …

【VUE2-02】vue2的指令和vue2的缺点

文章目录一、vue条件渲染 v-if二、vue循环渲染 v-for三、vue的事件 v-on四、vue的双向绑定 v-model五、VUE2的缺点5.1 vue底层原理解决方案在上节 【VUE2-01】vue2的起步,中写hello world!例子的时候使用了一个指令 v-bind绑定元素属性一、vue条件渲染 v-if v-if控…

无需离开 Visual Studio 即可编写 Markdown

当您想要格式化代码但又不想牺牲易读性时,Markdown 是一个很好的解决方案。GitHub 将其用于自述文件,我们将其用作 Visual Studio 文档的标准。之前收到了不少来自开发者的反馈,大家希望在 Visual Studio 中使用 Markdown 编辑器。在最近的 V…

CSS知识点大全

目录 CSS Step1.我的第一个CSS程序 Step2.CSS编写的位置 内联样式表 内部样式表 外部样式表