在物件導向程式設計裡,责任链模式(),是一种行为型软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。还存在往该处理链的末尾添加新的处理对象的机制。
结构
在上面的UML类图中,Sender类不直接提及到特定的接收者类。Sender转而提及到了Handler接口,通过它来处理一个请求(handler.handleRequest()),这使得Sender独立于处理这个请求的接收者。Receiver1、Receiver2和Receiver3类实现了Handler接口,它们要么处理要么转发一个请求(依赖于运行时条件)。
UML序列图展示了运行时交互:在这个例子中,Sender对象调用handleRequest()于receiver1对象之上(它具有类型Handler)。receiver1转发这个请求至receiver2,它接着转发这个请求至receiver3,它处理了这个请求。
代码示例
C++
《设计模式》书中早于C++98的例子的C++23实现:
import std;
using std::shared_ptr;
enum class Topic: char {
NO_HELP_TOPIC = 0,
PRINT = 1,
PAPER_ORIENTATION = 2,
APPLICATION = 3,
// more topics
};
// Abstract handler
// defines an interface for handling requests.
class HelpHandler {
private:
HelpHandler* successor;
Topic topic;
public:
explicit HelpHandler(HelpHandler* h = nullptr, Topic t = Topic::NO_HELP_TOPIC):
successor{h}, topic{t} {}
nodiscard
virtual bool hasHelp() const noexcept {
return topic != Topic::NO_HELP_TOPIC;
}
virtual void setHandler(HelpHandler*, Topic) = 0;
virtual void handleHelp() const {
std::println("HelpHandler::handleHelp called");
// (optional) implements the successor link.
if (!successor) {
successor->handleHelp();
}
}
virtual ~HelpHandler() = default;
HelpHandler(const HelpHandler&) = delete;
HelpHandler& operator=(const HelpHandler&) = delete;
};
class Widget : public HelpHandler {
private:
Widget* parent;
protected:
explicit Widget(Widget* w, Topic t = Topic::NO_HELP_TOPIC):
HelpHandler(w, t), parent{w} {
parent = w;
}
public:
Widget(const Widget&) = delete;
Widget& operator=(const Widget&) = delete;
};
// Concrete handler
// handles requests it is responsible for.
class Button : public Widget {
public:
explicit Button(shared_ptr h, Topic t = NO_HELP_TOPIC):
Widget(h.get(), t) {}
virtual void handleHelp() const {
// if the Concrete handler can handle the request, it does so; otherwise it forwards the request to its successor.
std::println("Button::handleHelp called");
if (hasHelp()) {
// handles requests it is responsible for.
} else {
// can access its successor.
HelpHandler::handleHelp();
}
}
};
// Concrete handler
class Dialog : public Widget {
public:
explicit Dialog(shared_ptr h, Topic t = Topic::NO_HELP_TOPIC):
Widget(nullptr) {
setHandler(h.get(), t);
}
virtual void handleHelp()const {
std::println("Dialog::handleHelp called");
// Widget operations that Dialog overrides...
if (hasHelp()) {
// offer help on the dialog
} else {
HelpHandler::handleHelp();
}
}
};
class Application : public HelpHandler {
public:
explicit Application(Topic t):
HelpHandler(nullptr, t) {}
virtual void handleHelp() const {
std::println("Application::handleHelp called");
// show a list of help topics
}
};
int main(int argc, char* argv[]) {
shared_ptr application = std::make_shared(Topic::APPLICATION_TOPIC);
shared_ptr dialog = std::make_shared(application, Topic::PRINT_TOPIC);
shared_ptr button = std::make_shared(dialog, Topic::PAPER_ORIENTATION_TOPIC);
button->handleHelp();
return 0;
}
Python
下面是Python的例子:
from abc import ABC, abstractmethod
class Handler(ABC):
def __init__(self, successor=None):
self.successor = successor
@abstractmethod
def __call__(self): pass
topic_list = [
'Application topic', 'Print topic',
'Paper orientation topic']
class HelpHandler(Handler):
def __init__(self, topic, *args):
assert topic in topic_list
self.topic = topic
super().__init__(*args)
def __call__(self, topic):
if self.topic == topic:
print(f"Help with {topic}")
elif self.successor is None:
print(f"No help with {topic}")
else:
self.successor(topic)
class Application():
def __init__(self, handler=None):
self.handler = handler
def handle_help(self, topic):
if self.handler is not None:
self.handler(topic)
class Widget():
def __init__(self, parent, handler=None):
self.parent = parent
self.handler = handler
def handle_help(self, topic):
if self.handler is not None:
self.handler(topic)
def draw(self): pass
class Dialog(Widget): pass
class Button(Widget): pass
def demo():
chain = HelpHandler(topic_list[0])
application = Application(chain)
chain = HelpHandler(topic_list[1], chain)
dialog = Dialog(None, chain)
chain = HelpHandler(topic_list[2], chain)
button = Button(dialog, chain)
button.handle_help(topic_list[2])
button.handle_help(topic_list[1])
button.handle_help(topic_list[0])
button.handle_help('No such topic')
其执行:
>> demo()
Help with Paper orientation topic
Help with Print topic
Help with Application topic
No help with No such topic
Java
下面是Java的日志类(logging)例子演示了该模式。 每一个logging handler首先决定是否需要在该层做处理,然后将控制传递到下一个logging handler。程序的输出是:
Writting to stdout: Entering function y.
Writting to stdout: Step1 completed.
Sending via e-mail: Step1 completed.
Writting to stdout: An error has occurred.
Sending via e-mail: An error has occurred.
Writing to stderr: An error has occurred.
注意:该例子不是日志类的推荐实现方式。
同时,需要注意的是,通常在责任链模式的实现中,如果在某一层已经处理了这个logger,那么这个logger就不会传递下去。在我们这个例子中,消息会一直传递到最底层不管它是否已经被处理。
import java.util.*;
abstract class Logger {
public static int ERR = 3;
public static int NOTICE = 5;
public static int DEBUG = 7;
protected int mask;
// The next element in the chain of responsibility
protected Logger next;
public Logger setNext(Logger l) {
next = l;
return this;
}
public final void message( String msg, int priority) {
if (priority
参见
*修饰模式
*适配器模式
引用
外部链接
- Article "[https://web.archive.org/web/20110608001551/http://www.javaworld.com/javaworld/jw-08-2004/jw-0816-chain.html The Chain of Responsibility pattern's pitfalls and improvements]" by Michael Xinsheng Huang
- Article "[https://web.archive.org/web/20111020000843/http://www.javaworld.com/javaworld/jw-08-2003/jw-0829-designpatterns.html Follow the Chain of Responsibility]" by David Geary
- Article "[https://web.archive.org/web/20120305185518/http://www.developer.com/java/other/article.php/631261 Pattern Summaries: Chain of Responsibility]" by Mark Grand
- [http://dofactory.com/Patterns/PatternChain.aspx CoR overview]
- [https://web.archive.org/web/20080220175113/http://www.allapplabs.com/java_design_patterns/chain_of_responsibility_pattern.htm Behavioral Patterns - Chain of Responsibility Pattern]
- [https://web.archive.org/web/20110818180059/http://c2.com/cgi/wiki?ChainOfResponsibilityPattern Descriptions from Portland Pattern Repository]
- [https://web.archive.org/web/20080517011147/http://jakarta.apache.org/commons/chain Apache Jakarta Commons Chain]
评论 (0)