设计模式之职责链(chain of responsibility)---对象行为型模式
1.意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
2.适用性
1)有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定
2)你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3)可处理一个请求的对象集合应被动态指定。
3.结构(如图1)
一个典型的对象结构可能如下图所示:
4.参与者
*Handler
---定义一个处理请求的接口.
---(可选) 实现后继者.
*ConcreteHander
---处理它所负责的请求.
---可访问他的后继者.
---如果可处理该请求,就处理之; 否则将它转发给他的后继者.
* Client
---向链上的具体处理这( ConcreteHander) 对象提交该请求.
5.协作
当客户提交一个请求时,请求沿着链直至有一个ConcreteHander对象负责处理它.
6.代码及示例:
//本例实现一个文档的帮助系统,帮助沿着职责链上传.
class HelpHandler {
public:
HelpHandler(HelpHandler* s) : _successor(s) { }
virtual void HandleHelp();
private:
HelpHandler* _successor;
};
void HelpHandler::HandleHelp () {
if (_successor) {
_successor->HandleHelp();
}
}
class Request {
public:
int GetKind();
};
class HelpRequest : public Request {
};
class PrintRequest : public Request {
};
class Handler {
public:
virtual void HandleRequest(Request* theRequest);
void HandleHelp(HelpRequest*);
void HandlePrint(PrintRequest*);
};
const int Help = 1;
const int Print = 2;
const int Preview = 2;
void Handler::HandleRequest (Request* theRequest) {
switch (theRequest->GetKind()) {
case Help:
// cast argument to appropriate type
HandleHelp((HelpRequest*) theRequest);
break;
case Print:
HandlePrint((PrintRequest*) theRequest);
// ...
break;
default:
// ...
break;
}
}
class ExtendedHandler : public Handler {
public:
virtual void HandleRequest(Request* theRequest);
// ...
};
void ExtendedHandler::HandleRequest (Request* theRequest) {
switch (theRequest->GetKind()) {
case Preview:
// handle the Preview request
break;
default:
// let Handler handle other requests
Handler::HandleRequest(theRequest);
}
}
#include"defs.H"
class Application;
class Dialog;
class HelpHandler;
typedef int Topic;
const Topic NO_HELP_TOPIC = -1;
class HelpHandler {
public:
HelpHandler(HelpHandler* = 0, Topic = NO_HELP_TOPIC);
virtual bool HasHelp();
virtual void SetHandler(HelpHandler*, Topic);
virtual void HandleHelp();
private:
HelpHandler* _successor;
Topic _topic;
};
HelpHandler::HelpHandler (
HelpHandler* h, Topic t
) : _successor(h), _topic(t) { }
bool HelpHandler::HasHelp () {
return _topic != NO_HELP_TOPIC;
}
void HelpHandler::HandleHelp () {
if (_successor != 0) {
_successor->HandleHelp();
}
}
class Widget : public HelpHandler {
protected:
Widget(Widget* parent, Topic t = NO_HELP_TOPIC);
private:
Widget* _parent;
};
Widget::Widget (Widget* w, Topic t) : HelpHandler(w, t) {
_parent = w;
}
class Button : public Widget {
public:
Button(Widget* d, Topic t = NO_HELP_TOPIC);
virtual void HandleHelp();
// Widget operations that Button overrides...
};
Button::Button (Widget* h, Topic t) : Widget(h, t) { }
void Button::HandleHelp () {
if (HasHelp()) {
// offer help on the button
} else {
HelpHandler::HandleHelp();
}
}
class Dialog : public Widget {
public:
Dialog(HelpHandler* h, Topic t = NO_HELP_TOPIC);
virtual void HandleHelp();
// Widget operations that Dialog overrides...
// ...
};
Dialog::Dialog (HelpHandler* h, Topic t) : Widget(0) {
SetHandler(h, t);
}
void Dialog::HandleHelp () {
if (HasHelp()) {
// offer help on the dialog
} else {
HelpHandler::HandleHelp();
}
}
class Application : public HelpHandler {
public:
Application(Topic t) : HelpHandler(0, t) { }
virtual void HandleHelp();
// application-specific operations...
};
void Application::HandleHelp () {
// show a list of help topics
}
void dummy () {
const Topic PRINT_TOPIC = 1;
const Topic PAPER_ORIENTATION_TOPIC = 2;
const Topic APPLICATION_TOPIC = 3;
Application* application = new Application(APPLICATION_TOPIC);
Dialog* dialog = new Dialog(application, PRINT_TOPIC);
Button* button = new Button(dialog, PAPER_ORIENTATION_TOPIC);
button->HandleHelp();
}
.