
C++ 责任链模式讲解和代码示例
责任链是一种行为设计模式, 允许你将请求沿着处理者链进行发送, 直至其中一个处理者对其进行处理。
该模式允许多个对象来对请求进行处理, 而无需让发送者类与具体接收者类相耦合。 链可在运行时由遵循标准处理者接口的任意处理者动态生成。
复杂度:
流行度:
使用示例: 责任链模式在 C++ 程序中并不常见, 因为它仅在代码与对象链打交道时才能发挥作用。
识别方法: 该模式可通过一组对象的行为方法间接调用其他对象的相同方法来识别, 而且所有对象都会遵循相同的接口。
概念示例
本例说明了责任链设计模式的结构并重点回答了下面的问题:
- 它由哪些类组成?
- 这些类扮演了哪些角色?
- 模式中的各个元素会以何种方式相互关联?
main.cc: 概念示例
/** * The Handler interface declares a method for building the chain of handlers. * It also declares a method for executing a request. */ class Handler { public: virtual Handler *SetNext(Handler *handler) = 0; virtual std::string Handle(std::string request) = 0; }; /** * The default chaining behavior can be implemented inside a base handler class. */ class AbstractHandler : public Handler { /** * @var Handler */ private: Handler *next_handler_; public: AbstractHandler() : next_handler_(nullptr) { } Handler *SetNext(Handler *handler) override { this->next_handler_ = handler; // Returning a handler from here will let us link handlers in a convenient // way like this: // $monkey->setNext($squirrel)->setNext($dog); return handler; } std::string Handle(std::string request) override { if (this->next_handler_) { return this->next_handler_->Handle(request); } return {}; } }; /** * All Concrete Handlers either handle a request or pass it to the next handler * in the chain. */ class MonkeyHandler : public AbstractHandler { public: std::string Handle(std::string request) override { if (request == "Banana") { return "Monkey: I'll eat the " + request + ".\n"; } else { return AbstractHandler::Handle(request); } } }; class SquirrelHandler : public AbstractHandler { public: std::string Handle(std::string request) override { if (request == "Nut") { return "Squirrel: I'll eat the " + request + ".\n"; } else { return AbstractHandler::Handle(request); } } }; class DogHandler : public AbstractHandler { public: std::string Handle(std::string request) override { if (request == "MeatBall") { return "Dog: I'll eat the " + request + ".\n"; } else { return AbstractHandler::Handle(request); } } }; /** * The client code is usually suited to work with a single handler. In most * cases, it is not even aware that the handler is part of a chain. */ void ClientCode(Handler &handler) { std::vector<std::string> food = {"Nut", "Banana", "Cup of coffee"}; for (const std::string &f : food) { std::cout << "Client: Who wants a " << f << "?\n"; const std::string result = handler.Handle(f); if (!result.empty()) { std::cout << " " << result; } else { std::cout << " " << f << " was left untouched.\n"; } } } /** * The other part of the client code constructs the actual chain. */ int main() { MonkeyHandler *monkey = new MonkeyHandler; SquirrelHandler *squirrel = new SquirrelHandler; DogHandler *dog = new DogHandler; monkey->SetNext(squirrel)->SetNext(dog); /** * The client should be able to send a request to any handler, not just the * first one in the chain. */ std::cout << "Chain: Monkey > Squirrel > Dog\n\n"; ClientCode(*monkey); std::cout << "\n"; std::cout << "Subchain: Squirrel > Dog\n\n"; ClientCode(*squirrel); delete monkey; delete squirrel; delete dog; return 0; }
Output.txt: 执行结果
Chain: Monkey > Squirrel > Dog Client: Who wants a Nut? Squirrel: I'll eat the Nut. Client: Who wants a Banana? Monkey: I'll eat the Banana. Client: Who wants a Cup of coffee? Cup of coffee was left untouched. Subchain: Squirrel > Dog Client: Who wants a Nut? Squirrel: I'll eat the Nut. Client: Who wants a Banana? Banana was left untouched. Client: Who wants a Cup of coffee? Cup of coffee was left untouched.