使用 职责链模式 来优化代码吧

290 阅读5分钟

今天的这篇文章主要是讲 代码优化 层面,我个人认为,代码的质量体现了一个人的编码能力,也是一个项目是否能够快速迭代的关键因素之一。代码写得好,下班回家早

今天我们使用 职责链 模式来优化我们的代码

职责链模式

职责链模式:使多个对象都有机会处理请求,从而避免请求的 发送者接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

职责链模式的名字非常形象,一系列可能会处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇到一个可以处理它的对象, 我们把这些对象称为节点, 如下图所示:

image.png

现实中的职责链模式

在以前坐公交车需要售票员的时候,如果在早高峰的时候,你上车的时候,需要找到售票员,因为人太多,不太好找,所以你拿着硬币去递给你的下一个人,如果他遇到了售票员,结束传递,如果不是,则继续往下传递,直到遇见售票员

image.png

可以很容易的发现,职责链模式的最大优点:请求发送者只需要知道链中的第 一个节点,从而弱化了发送者和一组接收者之间的强联系。 如果不使用职责链模式,那么在公交车上,我就得先搞清楚谁是售票员,才能把硬币递给他

实际开发中的职责链模式

1. 售卖手机的电商网站

假设我们负责一个售卖手机的电商网站,经过分别交纳 500 元定金和 200 元定金的两轮预定后(订单已在此时生成),现在已经到了正式购买的阶段

公司针对支付过定金的用户有一定的优惠政策。 在正式购买后,已经支付过 500 元定金的用户会收到 100 元的商城优惠券,200 元定金的用户可以收到 50 元的优惠券,而之前没有支付定金 的用户只能进入普通购买模式,也就是没有优惠券,且在库存有限的情况下不一定保证能买到

Untitled-2023-03-29-1524.png

如果在开发过程中,我们一般都会这样定义字段

  1. orderType:表示订单类型(定金用户或者普通购买用户),code 的值为 1 的时候是 500 元定金用户,为 2 的时候是 200 元定金用户,为 3 的时候是普通购买用户。

  2. pay:表示用户是否已经支付定金,值为 true 或者 false, 虽然用户已经下过 500 元定金的订单,但如果他一直没有支付定金,现在只能降级进入普通购买模式。

  3. stock:表示当前用于普通购买的手机库存数量,已经支付过 500 元或者 200 元定金的用户不受此限制。

下面我们把这个流程写成代码:

普通写法

code.png

虽然这个代码运行良好,但是这个已经 order 方法已经非常巨大了,且难以理解,维护起来有一定的难度,如果再增加其他条件,代码理解会更加的困难

🚀 职责链模式优化

现在我们采用 职责链模式 重构这段代码,先把 500 元订单、200 元订单以及普通购买分成 3 个函数。

接下来把 orderType、pay、stock 这 3 个字段当作参数传递给 500 元订单函数,如果该函数不符合处理条件,则把这个请求传递给后面的 200 元订单函数,如果 200 元订单函数依然不能处理该请求,则继续传递请求给普通购买函数

代码如下:

code.png

是不是感觉逻辑变得更加的清晰了,就像一根链条依次执行,直到可以结束为止,即遇到终结条件为止;这种模式的好处是, 如果想要加一个 300 元的订单逻辑,可以很容易的加上一个 chainOrder300,而不必修改其他代码,切合了开放封闭原则

用 AOP 实现职责链

在之前的职责链实现中,我们利用了一个 Chain 类 来把普通函数包装成职责链的节点。其实利用 JavaScript 的函数式特性,有一种更加方便的方法来创建职责链。代码如下

code.png

2. 验证密码格式🐝

验证密码是很常见的需求,比如我们验证一个密码长度在 8, 16 位之间,类型是必须要有 大写英文,小写英文,数字 组成

你有可能写下如下代码

let regs = [/\w{6,9}/,/[a-zA-Z0-9]/];

let password1 = '123'
let password2 = 'Abcdef123'
let r1 =  regs.every(reg=>reg.test(password1)) // false
let r2 =  regs.every(reg=>reg.test(password2)) // true

当然没有问题,但是如果验证密码需要多处用到,但是每次的要求都不一样,亦或者进行自定义的报错,这种简单写法的局限性就出来了,我们使用 职责链模式 进行扩展

我们定义一个 passwordChecker 类,其中的 rules 属性用来存放校验器,check 方法使用校验器校验密码

code.png

接下来我们定义校验器

1.长度校验器

code.png

  1. 类型校验器

code.png

校验结果

code.png

这样虽然说代码量增加了,但是可扩展性增强了,代码结构变的更加清晰,如果以后想要扩展,可以直接在校验类中添加方法

总结

代码优化就像是锦上添花,是在实现原有功能的基础上,进行的有目的优化,代码是给机器运行的,但更多的是给人看的,完成功能最基本的要求,在此基础上使用优化手段。
设计模式是先有的设计,是前辈们不断在实践中总结,最终形成的一种可复用模式,今天的职责链模式目的是代码更加强壮,可读性更强