Читайте также:
|
|
безопасного с точки зрения типов способа передачи параметров, поэтому упаковывать и распаковывать их приходится вручную. Очевидно, что это не так безопасно, как прямой вызов операции.
Чтобы решить проблему передачи параметров, допустимо использовать отдельные объекты-запросы, в которых инкапсулированы параметры запроса. Класс Request может представлять некоторые запросы явно, а их новые типы описываются в подклассах. Подкласс может определить другие параметры. Обработчик должен иметь информацию о типе запроса (какой именно подкласс Request используется), чтобы разобрать эти параметры. Для идентификации запроса в классе Request можно определить функцию доступа, которая возвращает идентификатор класса. Вместо этого получатель мог бы воспользоваться информацией о типе, доступной во время выполнения, если язык программирования поддерживает такую возможность. Приведем пример функции диспетчеризации, в которой используются объекты для идентификации запросов. Операция GetKind, указанная в базовом классе Request, определяет вид запроса:
void Handler::HandleRequest (Request* theRequest) { switch (theRequest->GetKind()) { case Help:
// привести аргумент к походящему типу
HandleHelp((HelpRequest*) theRequest);
break;
case Print:
HandlePrint((PrintRequest*) theRequest);
//
break; default: break;
j
Подклассы могут расширить схему диспетчеризации, переопределив операцию HandleRequest. Подкласс обрабатывает лишь те запросы, в которых заинтересован, а остальные отправляет родительскому классу. В этом случае подкласс именно расширяет, а не замещает операцию HandleRequest. Подкласс ExtendedHandler расширяет операцию HandleRequest, определенную в классе Handler, следующим образом:
classs ЖМвшЙеййагйИет • public; НатйНет { ршШМс:
void ExtendedHandler::HandleRequest (Request* theRequest) { switch (theRequest->GetKind()) {
Паттерн Clhamoftespnsibility
case Preview:
// обработать запрос Preview break;
default:
// дать классу Handler возможность обработать
// остальные запросы
Handler::HandleRequest (theRequest);
а автоматическое перенаправление запросов в языке Smalltalk. С этой целью можно использовать механизм doesNotUnderstand. Сообщения, не имеющие соответствующих методов, перехватываются реализацией doesNotUnderstand, которая может быть замещена для перенаправления сообщения объекту-преемнику. Поэтому осуществлять перенаправление вручную необязательно. Класс обрабатывает только запросы, в которых заинтересован, и ожидает, что механизм doesNotUnderstand выполнит все остальное.
Пример кода
В следующем примере иллюстрируется, как с помощью цепочки обязанностей можно обработать запросы к описанной выше системе оперативной справки. Запрос на получение справки - это явная операция. Мы воспользуемся уже имеющимися в иерархии виджетов ссылками для перемещения запросов по цепочке от одного виджета к другому и определим в классе Handler отдельную ссылку, чтобы можно было передать запрос включенным в цепочку объектам, не являющимся вид-жетами.
Класс HelpHandler определяет интерфейс для обработки запросов на получение справки. В нем хранится раздел справки (по умолчанию пустой) и ссылка на преемника в цепочке обработчиков. Основной операцией является HandleHelp, которая замещается в подклассах. HasHelp - это вспомогательная операция, проверяющая, ассоциирован ли с объектом какой-нибудь раздел:
typedef int Topic;
const Topic NO_HELP_TOPIC = -1;
class HelpHandler { public:
HelpHandler (HelpHandler* = 0, Topic = NO_HELP_TOPIC);
virtual bool HasHelpO;
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, который, в свою очередь, является подклассом HelpHandler, так как со всеми элементами пользовательского интерфейса может быть ассоциирована справочная информация. (Можно было, конечно, построить реализацию и на основе подмешиваемого класса.)
class Widget: public HelpHandler { protected:
Widget(Widget* parent, Topic t = NO_HELP_TOPIC); private:
Widget* _parent;
Widget::Widget (Widget* w, Topic t)
_parent = w; \
HelpHandler(w, t) {
В нашем примере первым обработчиком в цепочке является кнопка. Класс Button - это подкласс Widget. Конструктор класса Button принимает два параметра - ссылку на виджет, в котором он находится, и раздел справки:
class Button: public Widget { public:
Button (Widget* d, Topic t = NO_HELP_TOPIC);
virtual void HandleHelp ();
// операции класса Widget, которые Button замещает...
Реализация HandleHelp в классе Button сначала проверяет, есть ли для
кнопки справочная информация. Если разработчик не определил ее, то запрос отправляется преемнику с помощью операции HandleHelp класса HelpHandler. Если же информация есть, то кнопка ее отображает и поиск заканчивается:
Button::Button (Widget* h, Topic t): Widget(h, t) { }
void Button::HandleHelp () { if (HasHelp()) {
// предложить справку по кнопке х else {
HelpHandler:: HandleHelp();
Дата добавления: 2015-09-11; просмотров: 69 | Поможем написать вашу работу | Нарушение авторских прав |