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

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

Рассмотрим реализацию диалоговых окон в графическом интерфейсе пользователя. Здесь располагается ряд элементов управления: кнопки, меню, поля ввода и т.д., как показано на рисунке.

 

 

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

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

Так, класс МенеджерНастроек может служить посредником между элементами управления в диалоговом окне. Объект этого класса знает обо всех элементах в окне и координирует взаимодействие между ними, то есть выполняет функции центра коммуникаций.

 

 

На диаграмме взаимодействий показано, как объекты кооперируются друг с другом, реагируя на изменение выбранного элемента списка:

 

 

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

1) список информирует распорядителя о происшедших в нем изменениях;

2) распорядитель получает от списка данные о выбранном элементе;

3) распорядитель извлекает из этих данных текст и передает полю ввода;

4) распорядитель формирует на основе данных эскиз для образца и передает ему этот эскиз;

5) распорядитель может выполнить и другие действия, связанные, например, с изменением доступности кнопок и других элементов управления.

Обратите внимание на то, как распорядитель осуществляет посредничество между списком и полем ввода. Элементы управления общаются друг с другом не напрямую, а через распорядителя. Им вообще не нужно владеть информацией друг о друге, они осведомлены лишь о существовании распорядителя. Поскольку поведение локализовано в одном классе, то его несложно модифицировать или сделать совершенно другим путем расширения или замены этого класса. Абстракцию МенеджерНастроек можно было бы интегрировать в библиотеку классов так, как показано на диаграмме (здесь ей присвоено имя PreferencesDialogDirector):

 

 

DialogDirector – это абстрактный класс, который определяет поведение диалогового окна в целом. Клиенты вызывают его операцию ShowDialog для отображения окна на экране. Для оповещения распорядителя об изменениях элементы управления вызывают его операцию ControlChanged, передавая себя в качестве параметра. Подклассы DialogDirector замещают операцию ControlChanged для обработки этих вызовов.

Общая структура решения.

 

 

Типичная структура объектов:

 

 

Mediator (DialogDirector) – посредник: определяет интерфейс для обмена информацией с объектами Соlleague.

ConcreteMediator (PreferencesDialogDirector) – конкретный посредник: реализует кооперативное поведение, координируя действия объектов Colleague; владеет информацией о конкретных коллегах.

Colleague (Control) – класс-коллега: объявляет интерфейс, характерный для сотрудничающих объектов, поддерживает указатель на объект-посредник.

ConcreteColleague (ListBox, TextBox) – конкретные объекты-коллеги: каждый из них знает о своем объекте Mediator, благодаря указателю, поддерживаемому предком; все коллеги обмениваются информацией только с Посредником, не обращаясь напрямую друг к другу.

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

Применимость. Используйте паттерн Посредник, когда:

Результаты. У паттерна Посредник есть следующие достоинства и недостатки:

Особенности реализации:

- избавление от абстрактного класса Mediator: если коллеги работают только с одним посредником, то нет необходимости определять абстрактный класс Mediator. Обеспечиваемая классом Mediator абстракция позволяет коллегам работать с разными подклассами класса Mediator и наоборот;

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

Родственные паттерны.

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

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