Паттерн Mediator (Посредник)

Название и классификация паттерна

Посредник — паттерн поведения объектов.

Назначение

Паттерн Mediator определяет объект, инкапсулирующий взаимодействие множества объектов. Mediator делает систему слабосвязанной, избавляя объекты от необходимости ссылаться друг на друга, что позволяет изменять взаимодействие между ними независимо.

Паттерн Mediator вводит Посредника для развязывания множества взаимодействующих объектов.

Мотивация

Объектно-ориентированное проектирование способствует распределению некоторого поведения между объектами. Но при этом в получившейся структуре объектов может возникнуть много связей или (в худшем случае) каждому объекту придется иметь информацию обо всех остальных.

Несмотря на то что разбиение системы на множество объектов в общем случае повышает степень повторного использования, однако изобилие взаимосвязей приводит к обратному эффекту. Если взаимосвязей слишком много, тогда существенно изменить поведение системы практически невозможно, поскольку оно распределено между многими объектами.

Рассмотрим реализацию диалоговых окон в графическом интерфейсе пользователя в виде виджетов: кнопки,меню, поля ввода и т. д. Как правило между разными виджетами в диалоговом окне существуют зависимости. Например, если одно из полей ввода пустое, то определенная кнопка недоступна. При выборе из списка может измениться содержимое поля ввода. И наоборот, ввод текста в некоторое поле может автоматически привести к выбору одного или нескольких элементов списка. Если в поле ввода присутствует какой-то текст, то могут быть активированы кнопки, позволяющие произвести определенное действие над этим текстом, например изменить либо удалить его.

В разных диалоговых окнах зависимости между виджетами могут быть различными. Поэтому, несмотря на то что во всех окнах встречаются однотипные виджеты, просто взять и повторно использовать готовые классы виджетов не удастся, придется производить настройку с целью учета зависимостей, что трудоемко, ибо участвующих классов много.

Всех этих проблем можно избежать, если инкапсулировать коллективное поведение в отдельном объекте-посреднике, отвечающем за координацию взаимодействий между группой объектов. Он избавляет входящие в группу объекты от необходимости явно ссылаться друг на друга. Все объекты располагают информацией только о посреднике, поэтому количество взаимосвязей сокращается.

Пример паттерна Mediator. Башня управления полетами в аэропорту хорошо демонстрирует этот паттерн. Пилоты взлетающих или идущих на посадку самолетов в районе аэропорта общаются с башней вместо непосредственного общения друг с другом. Башня определяет, кто и в каком порядке будет садиться или взлетать. Важно отметить, что башня контролирует самолеты только в районе аэродрома, а не на протяжении всего полета.

Применимость

Имеются объекты, связи между которыми сложны и четко определены. Получающиеся при этом взаимозависимости не структурированы и трудны для понимания.

Нельзя повторно использовать объект, поскольку он обменивается информацией со многими другими объектами.

Поведение, распределенное между несколькими классами, должно поддаваться настройке без порождения множества подклассов.

UML-диаграмма классов паттерна Mediator Структура паттерна Посредник показана на рис. 68.

UML-диаграмма паттерна Итератор

Рис. 68. UML-диаграмма паттерна Итератор

Участники

Mediator — Посредник: определяет интерфейс для обмена информацией с объектами Colleague.

ConcreteMediator — конкретный Посредник:

  • • реализует кооперативное поведение, координируя действия объектов Colleague;
  • • владеет информацией о коллегах и подсчитывает их.

Классы Colleague — коллеги:

  • • каждый класс Colleague «знает» о своем объекте Mediator;
  • • все коллеги обмениваются информацией только с Посредником, так как при его отсутствии им пришлось бы общаться между собой напрямую.

Отношения

Коллеги посылают запросы Посреднику и получают запросы от него. Посредник реализует кооперативное поведение путем переадресации каждого запроса подходящему коллеге (или нескольким коллегам).

Достоинства и недостатки

Снижает число порождаемых подклассов. Посредник локализует поведение, которое в противном случае пришлось бы распределять между несколькими объектами. Для изменения поведения нужно породить подклассы только от класса Посредника Mediator, классы коллег Colleague можно использовать повторно без каких бы то ни было изменений.

Устраняет связанность между коллегами. Посредник обеспечивает слабую связанность коллег. Изменять классы Colleague и Mediator можно независимо друг от друга.

Упрощает протоколы взаимодействия объектов. Посредник заменяет дисциплину взаимодействия «все со всеми» дисциплиной «один со всеми», что проще для понимания, сопровождения и расширения.

Абстрагирует способ кооперирования объектов, что позволяет сосредоточиться именно на взаимодействии объектов, а не на их индивидуальном поведении.

Централизует управление. Паттерн Посредник переносит сложность взаимодействия в класс-посредник. Поскольку Посредник инкапсулирует протоколы, то он может быть сложнее отдельных коллег. В результате сам Посредник становится монолитом, который трудно сопровождать.

Использование паттерна Mediator

Определите совокупность взаимодействующих объектов, связанность между которыми нужно уменьшить.

Инкапсулируйте все взаимодействия в абстракцию нового класса.

Создайте экземпляр этого нового класса. Объекты-коллеги для взаимодействия друг с другом используют только этот объект.

Найдите правильный баланс между принципом слабой связанности и принципом распределения ответственности.

Будьте внимательны и не создавайте объект-«контроллер» вместо объекта-посредника.

Реализация паттерна Mediator

В этом примере объект диалогового окна функционирует в качестве Посредника. Виджеты диалогового окна ничего не знают о своих соседях. Всякий раз, когда происходит взаимодействие с пользователем, виджет в Widget::changed() «делегирует» это событие Посреднику mediator- >widgetChanged(this).

FileSelectionDialog:: widgetChanged() инкапсулирует все коллективное поведение для диалогового окна (служит центром взаимодействия). Пользователь может выбрать «взаимодействие» с полем редактирования Filter, списком Directories, списком Files или полем редактирования Selection.

#include

class FileSelectionDialog;

class Widget

{

public:

Widget(FileSelectionDialog "“mediator, char *name)

{

_mediator = mediator; strcpy(_name, name);

}

virtual void changed(); virtual void updateWidget() = 0; virtual void queryWidget() = 0; protected: char_name[20]; private:

FileSelectionDialog *_mediator;

class List: public Widget

{

public:

List(FileSelectionDialog *dir, char *name): Widget(dir, name){} void queryWidget()

{

cout << " " << _name << " list queried" << endl;

}

void updateWidget()

{

cout << " " << _name << " list updated" << endl;

}

};

class Edit: public Widget

{

public:

Edit(FileSelectionDialog *dir, char *name): Widget(dir, name){} void queryWidget()

{

cout << " " << _name << " edit queried" << endl;

}

void updateWidget()

{

cout << " " << _name << " edit updated" << endl;

}

};

class FileSelectionDialog

{

public:

enum Widgets

{

FilterEdit, DirList, File List, SelectionEdit

};

FileSelectionDialog()

{

_components[FilterEdit] = new Edit(this, "filter"); _components[DirList] = new List(this, "dir"); _components[FileList] = new List(this, "file"); _components[SelectionEdit| = new Edit(this, "selection");

}

virtual ~FileSelectionDialog(); void handleEvent(int which)

{

_components[which|->changed();

}

virtual void widgetChanged(Widget TheChangedWidget)

{

if (theChangedWidget == _components[FilterEdit])

{

_components[FilterEdit]->queryWidget();

_componentsf DirList] ->updateWidget(); _components[FileList]->updateWidget(); _components[SelectionEdit|->updateWidget();

}

else if (theChangedWidget == _components[DirList])

{

_components[DirList]->queryWidget();

_components[FileList]->updateWidget();

_components[ FilterEdit]->updateWidget(); _components[SelectionEdit]->updateWidget();

}

else if (theChangedWidget == _components[FileList])

{

_components[FileList]->queryWidget();

_components[SelectionEdit|->updateWidget();

}

else if (theChangedWidget == _components[SelectionEdit])

{

_components[SelectionEdit]->queryWidget(); cout << " file opened" << endl;

}

}

private:

Widget *_components[4|;

};

FileSelectionDialog::~FileSelectionDialog()

{

for (int i = 0; i < 3; i++) delete _components[i];

}

void Widget::changed()

{

_mediator->widgetChanged(this);

}

int main()

{

FileSelectionDialog fileDialog; int i;

cout << "Exitf0|, Filterfl], Dir[2], File[3|, Selection[4|: cin >> i;

while (i)

{

fileDialog.handleEvent(i - 1);

cout << "Exit[0], Filter[l], Dir[2], File[3], Selection[4]: cin >> i;

}

}

Результаты вывода программы:

Exit[0], Filterf 11, Dir[2|, File[3|, Selectionf4|: 1 filter edit queried dir list updated file list updated selection edit updated

Exit[0], Filter! 1], Dir[2|, File[3|, Selection[4|: 2 dir list queried file list updated filter edit updated selection edit updated

Exit[0], Filterfl], Dir[2], File[3], Selection[4]: 3 file list queried selection edit updated

Exit[0], Filter! 1], Dir[2], File[3], Selection[4]: 4 selection edit queried file opened

Exit[0], Filter! 1], Dir[2], File[3], Selection[4|: 3 file list queried selection edit updated

Особенности паттерна Mediator

Chain of Responsibility передает запрос отправителя по цепочке потенциальных получателей. Command номинально определяет связь — «оправитель—получатель» с помощью подкласса. В Mediator отправитель и получатель ссылаются друг на друга косвенно, через объект-посредник. В паттерне Observer связь между отправителем и получателем слабее, при этом число получателей может конфигурироваться во время выполнения.

Mediators Observer являются конкурирующими паттернами. Если Observer распределяет взаимодействие с помощью объектов «Наблюдатель» и «Субъект», то Mediator использует объект-посредник для инкапсуляции взаимодействия между другими объектами. Легче сделать повторно используемыми Наблюдателей и Субъектов, чем Посредников.

Mediator может использовать Observer для динамической регистрации коллег и их взаимодействия с Посредником.

 
< Пред   СОДЕРЖАНИЕ     След >