行为型模式--职责链
1、意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
2、结构

3、参与者
Handler:定义一个处理请求的接口。实现后继链(可选)。
ConcreteHandler:处理它所负责的请求;可访问它的后继者;如果可处理改请求,就处理之,否则将该请求转发给它的后继者。
Client:向链上的具体处理者对象(ConcreteHandler)提交请求。
4、适用性
在以下条件下使用职责链(Responsibility):
有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
可处理一个请求的对象集合应被动态指定。
5、代码示例
// HelpHandler类定义了处理帮助请求的接口。它维护一个帮助主题(缺省值为空), // 并保持对帮助处理对象链中它的后继者的引用。关键的操作是HandleHelp,它可被子类重定义。 // HasHelp是一个辅助操作,用于检查是否有一个相关的帮助主题。 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(); } }
// 所有的窗口组件都是Widget抽象类的子类。Widget是HelpHandler的子类, // 因为所有的用户界面元素都可有相关的帮助。(我们也可以使用另一种基于混入类的实现方式) 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; }
// 在我们的例子中,按钮是链上的第一个处理者。Button类是widget类的子类。 // Button构造函数有两个参数:对包含它的窗口组件的引用和其自身的帮助主题。 class Button : public widget { public: Button(Widget* d, Topic t = NO_HELP_TOPIC); virtual void HandleHelp(); //Widget operations that Button overrides... }; // Button版本的HandleHelp的首先测试检查其自身是否有帮助主题。如果开发者没有定义一个帮助主题, // 就用HelpHandler中的HandleHelp操作将该请求转发给它的后继者。如果有帮助主题,那么就显示它,并且搜索结束。 Button::Button (widget* h, Topic t):Widget(h,t){} void Button::HandleHelp () { if (HasHelp()) { // offer help on the button } else { HelpHandler::HandleHelp(); } }
// Dialog实现了一个类似的策略,只不过它的后继者不是一个窗口组件而是任意的帮助请求处理对象。 // 在我们的应用中这个后继者将是Application的一个实例。 class Dialog : public widget { public: Dialog(HelpHandler* h, Topic t = NO_HELP_TOPIC); virtual void HandleHelp(); // Widgeet 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(); } }
// 在链的末端是Application的一个实例。该应用不是一个窗口组件,因此Application不是HelpHandler的直接子类。 // 当一个帮助请求传递到这一层时,该应用可提供关于该应用的一般性的信息,或者它可以提供一系列不同的帮助主题。 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 }
// 下面的代码创建并连接这些对象。此处的对话框涉及打印,因此这些对象被赋给与打印相关的主题。 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); // 我们可对链上的任意对象调用HandleHelp以触发相应的帮助请求。要从按钮对象开始搜索,只需对它调用HandleHelp // 在这种情况下,按钮会立即处理该请求。注意任何HelpHandler类都可作为Dialog的后继者。 // 此外,它的后继者可以被动态地改变。因此不管对话框被用在何处,你都可以得到它正确的与上下文相关的帮助信息。 button->HandleHelp();
6、总结
职责链模式降低了对象之间的耦合程度,请求的发送方并不知道最终处理请求的是哪一个对象,它只需指派自己的后继处理者,由后继者去进行交付或处理请求。
职责链模式可以灵活地指派请求,当前请求的接收者的后继者可以被动态地指派和调整。
职责链的链式结构由客户建立和维护,客户负责指定后继者,而链式结构中的对象负责处理(也可以丢弃该请求不处理,那么该请求将在此终止)或继续传递请求。
本文来自博客园,作者:流翎,转载请注明原文链接:https://www.cnblogs.com/hjx168/p/16219354.html

浙公网安备 33010602011771号