设计模式 ---- 责任链模式
责任链模式
首先要明白什么是“链”。
在 C++ 中,我们经常会接触到链表。
例如一个单向链表,每个节点都会保存一个指向下一个节点的指针:
Node* next;
当前节点处理完之后,可以通过 next 找到下一个节点。
如果是双向链表,那么节点除了保存下一个节点的指针之外,还会保存一个指向上一个节点的指针:
Node* next;
Node* prev;
责任链模式中的“链”,在某种程度上和这个思想类似:
将多个处理者按照一定顺序连接起来,一个处理者处理不了,就将请求交给下一个处理者。
不过需要注意,责任链模式中的“链”并不一定真的使用 C++ 的链表实现。
这里的“链”更多的是一种对象之间的组织关系。
什么是“责任”?
“责任”可以理解成:
当前对象是否有能力、也是否应该处理这个请求。
责任链上每个节点实际上都承担了一部分“责任”。
这里的“责任”并不是说:
“这个对象一定要处理这个请求。”
而是:
“这个对象有能力处理某一部分请求,如果自己无法处理,就继续向后传递。”
责任链真正的核心
这样就可以把责任链拆成两个非常重要的部分。
1. 责任
每个节点都有自己的处理范围。
例如:(射击游戏)
载具:处理 普通伤害
护盾:处理 贯穿载具 100 伤害
血量:处理 超出贯穿 100 伤害的部分
每个节点只需要关心:
“这个请求是不是我的责任?”
而不需要知道整个系统应该怎么处理。
2. 链
把这些处理者连接起来:
载具 → 护甲 → 徐良
当组长拿到请求时:
请求
↓
载具
↓
能处理?
├─ 是 → 载具承担伤害
└─ 否 → 护盾
↓
能处理?
├─ 是 → 护盾免伤
└─ 否 → 扣血
这就是责任链模式最核心的流程。
为什么不直接使用 if-else?
这里其实有一个很有意思的地方:
为什么不直接写一大堆 if-else?
例如我们完全可以这么写:
if (damage.type == Through)
{
vehicles.Handle();
}
else if (damage <= 100)
{
shield.Handle();
}
else if (damage <= 999)
{
characterHealth.Handle();
}
功能上完全可以实现。
但是问题来了。
假如以后增加:
爆炸伤害
毒气
法术伤害
那么这个 if-else 会越来越长:
if (...)
{
}
else if (...)
{
}
else if (...)
{
}
else if (...)
{
}
else if (...)
{
}
else if (...)
{
}
而且处理规则和具体的处理者全部耦合在了一起。
责任链模式希望解决的就是这个问题:
把“谁来处理请求”的判断,从一个巨大的集中式
if-else中拆出来,让每个处理者只负责自己的责任范围。
于是变成:
请求
↓
Handler A
↓
Handler B
↓
Handler C
↓
Handler D
每个 Handler 只需要知道:
我能处理 → 我处理
我不能处理 → 找下一个
而不需要知道:
下一个到底是谁?
整个系统一共有多少个处理者?
责任链的基本代码结构
可以先定义一个抽象的处理者:
class Handler
{
protected:
Handler* next = nullptr;
public:
void SetNext(Handler* handler)
{
next = handler;
}
virtual void Handle(int days) = 0;
};
然后不同的处理者承担不同的责任。
载具
class Vehicles : public Handler
{
public:
void Handle(int damage) override
{
// handle code;
}
};
护盾
class Shield : public Handler
{
public:
void Handle(int days) override
{
// Shield Handle
}
};
总监
class CharacterHealth : public Handler
{
public:
void Handle(int days) override
{
// character handle;
}
};
最后把它们连接起来:
Vehicles vehicles;
Shield shield;
CharacterHealth characterHealth;
Vehicles.SetNext(&shield);
Shield.SetNext(&characterHealth);
形成:
Vehicles
↓
Shield
↓
CharacterHealth
客户端只需要:
vehicles.Handle(Damgae damgae);
它并不需要知道:
普通伤害应该找谁?
载具处理不了找护盾?
这些都由责任链内部完成。
责任链的核心
虽然上述例子可能并不是很恰当,大概意思就是链条传递责任,外部不需要知道具体内部结构
责任链的核心浓缩成:
责任链模式的核心,就是将多个具有不同处理能力的对象连接起来,让请求沿着这条链依次传递,每个对象判断自己是否能够处理这个请求;能够处理就处理,不能处理就交给下一个对象。
责任链的重点不是“链”,而是“请求的处理者可以动态地传递责任”,从而避免客户端与具体处理者之间产生强耦合。
浙公网安备 33010602011771号