目录
一、问题背景
在 VC/MFC 开发中,消息处理机制是核心部分之一。VC 是基于消息和事件驱动的框架,消息的处理流程通常是通过链式传递的方式进行的。例如,一个 `WM_COMMAND` 消息的处理流程可能如下:
(1)MDI 主窗口(CMDIFrameWnd) 收到命令消息 `WM_COMMAND`,其 ID 为 `ID_×××`。
(2)MDI 主窗口 将消息传递给当前活动的 MDI 子窗口(CMDIChildWnd)。
(3)MDI 子窗口 将消息交给其子窗口 View 处理。
(4)View 检查自己的消息映射表(Message Map)。
(5)如果 View 没有处理该消息的程序,则将消息传递给其对应的 Document 对象。
(6)Document 检查自己的消息映射表,如果没有处理程序,则将消息传递给其 DocumentTemplate 处理。
(7)如果消息在 Document 中仍未得到处理,则消息返回给 View。
(8)View 将消息传回给 MDI 子窗口。
(9)MDI 子窗口 将消息传递给 CWinApp 对象,CWinApp 为所有无主的消息提供了默认处理。
这种链式处理策略使得消息的发送者无需知道消息最终由哪个对象处理,只需将消息传递给链中的第一个对象即可。这种设计模式正是 Chain of Responsibility(责任链)模式 的典型应用。
二、模式选择
Chain of Responsibility 模式的核心思想是将多个处理对象连接成一条链,请求沿着链传递,直到某个对象处理它为止。这种模式的主要优点在于:
(1)降低耦合性:请求的发送者无需知道具体的处理者,只需将请求传递给链中的第一个对象。
(2)动态处理:可以在运行时动态地调整链中的处理对象。
(3)灵活性:可以灵活地增加或删除处理对象。
Chain of Responsibility 模式的典型结构图如下:
在 Chain of Responsibility 模式中,每个 `ConcreteHandler` 对象都维护一个指向其后继者的引用。当一个请求到来时,`ConcreteHandler` 会先检查自己是否能处理该请求。如果不能,则将请求传递给后继者。
三、代码实现
下面我们将通过一个完整的 C++ 代码示例来展示如何实现 Chain of Responsibility 模式。
代码片段 1:Handle.h
// Handle.h
#ifndef _HANDLE_H_
#define _HANDLE_H_
class Handle {
public:
virtual ~Handle();
virtual void HandleRequest() = 0; // 处理请求的接口
void SetSuccessor(Handle* succ); // 设置后继者
Handle* GetSuccessor(); // 获取后继者
protected:
Handle();
Handle(Handle* succ);
private:
Handle* _succ; // 后继者对象
};
// ConcreteHandleA 类
class ConcreteHandleA : public Handle {
public:
ConcreteHandleA();
~ConcreteHandleA();
ConcreteHandleA(Handle* succ);
void HandleRequest(); // 处理请求的具体实现
protected:
private:
};
// ConcreteHandleB 类
class ConcreteHandleB : public Handle {
public:
ConcreteHandleB();
~ConcreteHandleB();
ConcreteHandleB(Handle* succ);
void HandleRequest(); // 处理请求的具体实现
protected:
private:
};
#endif //~_HANDLE_H_
代码片段 2:Handle.cpp
// Handle.cpp
#include "Handle.h"
#include <iostream>
using namespace std;
// Handle 类的实现
Handle::Handle() {
_succ = nullptr; // 初始化后继者为空
}
Handle::~Handle() {
delete _succ; // 释放后继者对象
}
Handle::Handle(Handle* succ) {
_succ = succ; // 设置后继者
}
void Handle::SetSuccessor(Handle* succ) {
_succ = succ; // 设置后继者
}
Handle* Handle::GetSuccessor() {
return _succ; // 获取后继者
}
void Handle::HandleRequest() {
// 默认实现为空
}
// ConcreteHandleA 类的实现
ConcreteHandleA::ConcreteHandleA() {
// 构造函数
}
ConcreteHandleA::~ConcreteHandleA() {
// 析构函数
}
ConcreteHandleA::ConcreteHandleA(Handle* succ) : Handle(succ) {
// 构造函数
}
void ConcreteHandleA::HandleRequest() {
if (this->GetSuccessor() != nullptr) {
cout << "ConcreteHandleA 我把处理权给后继节点....." << endl;
this->GetSuccessor()->HandleRequest(); // 将请求传递给后继者
} else {
cout << "ConcreteHandleA 没有后继了,我必须自己处理...." << endl;
}
}
// ConcreteHandleB 类的实现
ConcreteHandleB::ConcreteHandleB() {
// 构造函数
}
ConcreteHandleB::~ConcreteHandleB() {
// 析构函数
}
ConcreteHandleB::ConcreteHandleB(Handle* succ) : Handle(succ) {
// 构造函数
}
void ConcreteHandleB::HandleRequest() {
if (this->GetSuccessor() != nullptr) {
cout << "ConcreteHandleB 我把处理权给后继节点....." << endl;
this->GetSuccessor()->HandleRequest(); // 将请求传递给后继者
} else {
cout << "ConcreteHandleB 没有后继了,我必须自己处理...." << endl;
}
}
代码片段 3:main.cpp
// main.cpp
#include "Handle.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
// 创建责任链中的处理对象
Handle* h1 = new ConcreteHandleA();
Handle* h2 = new ConcreteHandleB();
// 设置责任链的顺序
h1->SetSuccessor(h2);
// 处理请求
h1->HandleRequest();
// 释放内存
delete h1;
delete h2;
return 0;
}
代码说明
(1)Handle 类:`Handle` 是抽象基类,定义了处理请求的接口 `HandleRequest`,并提供了设置和获取后继者的方法。
(2)ConcreteHandleA 和 ConcreteHandleB:这两个类是具体的处理者,实现了 `HandleRequest` 方法。如果它们无法处理请求,则将请求传递给后继者。
(3)责任链的构建:在 `main.cpp` 中,我们创建了两个处理对象 `h1` 和 `h2`,并通过 `SetSuccessor` 方法将它们连接成一条链。当请求到来时,`h1` 会先尝试处理请求,如果无法处理,则将请求传递给 `h2`。
运行结果
程序的输出如下:
ConcreteHandleA 我把处理权给后继节点.....
ConcreteHandleB 没有后继了,我必须自己处理....
四、总结讨论
Chain of Responsibility 模式的最大优点在于它降低了系统的耦合性。请求的发送者无需知道具体的处理者,只需将请求传递给责任链中的第一个对象即可。这种设计模式非常适合以下场景:
(1)多级处理:当请求需要经过多个对象处理时,可以使用责任链模式。
(2)动态处理:可以在运行时动态地调整责任链中的处理对象。
(3)解耦:请求的发送者和处理者之间完全解耦,系统更加灵活。
Chain of Responsibility 模式通过将多个处理对象连接成一条链,使得请求可以沿着链传递,直到某个对象处理它为止。这种模式不仅降低了系统的耦合性,还提高了系统的灵活性和可扩展性。在实际开发中,责任链模式可以广泛应用于消息处理、事件处理等场景。