前言
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着一个链条传递,直到有一个对象处理它为止。这个模式的关键是将请求的发送者与接收者解耦,使得多个对象都有机会处理请求,而发送者不需要知道哪个对象最终处理了请求。
在软件开发中,经常会遇到这样的问题:一个请求可能需要多个对象处理,但我们不希望请求者与处理者之间存在强耦合关系。传统的处理方式是通过在发送者中引入条件语句(如if-else)来判断由哪个对象处理请求,但这种方式的缺点在于:
- 代码的可维护性和可扩展性差。
- 发送者需要了解所有可能的处理者,这违背了“开闭原则”。
为了解决上述问题,责任链模式应运而生。
责任链模式的核心思想是:将多个处理对象连成一条链,并将请求沿着这条链传递,直到某个对象处理该请求。每个处理对象都包含一个指向下一个处理对象的引用,这样请求在未被处理时,可以沿着链传递到下一个对象。
场景
现在有个业务场景,针对一个商品需要打不同的标签,例如:商品上架不超过 30天 需要打上 New标签、折扣商品需带上 折扣标签等。
普通版
function createTag(tag) {
if (tag.tagType === 1) {
console.log("特性标签");
} else if (tag.tagType === 2) {
console.log("New 标签");
} else if (tag.tagType === 3) {
console.log("折扣标签");
} else if (tag.tagType === 4) {
console.log("属性标签");
}
}
createTag({ tagType: 1 });
聪明的小伙伴,发现上述代码已经违反了设计模式的 单一职责原则 和 开放封闭原则。下面我们用责任链
责任链0.1版
function porpertypeLabel(tag) {
if (tag.tagType !== 1) return "next";
console.log("特性标签");
}
function newLabel(tag) {
if (tag.tagType !== 2) return "next";
console.log("New 标签");
}
function discountLabel(tag) {
if (tag.tagType !== 3) return "next";
console.log("折扣标签");
}
function attributeLabel(tag) {
if (tag.tagType !== 4) return "next";
console.log("属性标签");
}
function chain(tag) {
let arr = [porpertypeLabel, newLabel, discountLabel, attributeLabel],
length = arr.length;
while (length--) {
if (arr[length](tag) !== "next") {
break;
}
}
}
chain({ tagType: 1 });
责任链0.2版
基于 0.1 版本,如果后期又新增了 XLabel、YLabel 等,我们则需要修改 chain 函数, 违背了 开放封闭原则。下面我们将 Chain 抽离成独立的类,提供 add 方法实现动态添加。
function porpertypeLabel(tag) {
if (tag.tagType !== 1) return "next";
console.log("特性标签");
}
function newLabel(tag) {
if (tag.tagType !== 2) return "next";
console.log("New 标签");
}
function discountLabel(tag) {
if (tag.tagType !== 3) return "next";
console.log("折扣标签");
}
function attributeLabel(tag) {
if (tag.tagType !== 4) return "next";
console.log("属性标签");
}
function Chain() {
this.queue = [];
}
Chain.prototype.add = function (handler) {
this.queue.push(handler);
};
Chain.prototype.end = function (tag) {
let length = this.queue.length;
while (length--) {
if (this.queue[length](tag) !== "next") {
break;
}
}
};
const chain = new Chain();
chain.add(porpertypeLabel);
chain.add(newLabel);
chain.add(discountLabel);
chain.add(attributeLabel);
chain.end({ tagType: 1 });
责任链最终版
0.2 版本的 add 需要逐个添加不同的标签 handler 代码比较冗余,我们通过 链式调用 进行优化。
Chain.prototype.add = function (handler) {
this.queue.push(handler);
return this;
};
我们将 Chain 上的 add 方法,返回当前实例对象。使用如下:
const chain = new Chain();
chain.add(porpertypeLabel).add(newLabel).add(discountLabel).add(attributeLabel).end({ tagType: 3 });
总结
在后面看到 if …… else 的语句时,我们在心里需要想一下是不是可以使用 责任链设计模式 来实现。