Шаблон проектирования Цепочка обязанностей (Chain of responsibility)

Итак, рассмотрим второй шаблон проектирования.

В чем суть — класс получает задачу на исполнение и если может, то выполняет ее сам, если же нет, передает по цепочке следующему классу, если он есть.

Перейдем от слов к коду. Рассмотрим этот шаблон на примере андроид.

Предположим у нас есть некая модель объекта, которая хранит информацию, которую необходимо отобразить польователю. Если в этой модели есть картинка, то ее отобразим кастомным всплывающим окном, если же есть заголовок, то обычным всплывающим окном, если же только сообщение, то простым тостом (Toast), если же ни под какие критерии не попали — залогируем ошибку. Суть в том, что все модели с информацией обрабатывает главный класс, все проверки находятся внутри (в итоге не нужно писать каждый раз огромные условия — switch case, if else if else if… ).

Итак, нам нужна модель класса

Для обработки информации нам нужен интерфейс, выглядеть он будет примерно так

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

Начнем с самой простой реализации, логирующей ошибку

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

Далее по цепочке у нас обычный тост.

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

Рассмотрим выше стоящий в этой цепочке элемент, всплывающее окно с заголовком и текстом

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

И самое верхнее звено нашей цепочки, которое может отобразить максимальное количество разнообразной информации пользователю

Здесь те же самые действия — устанавливаем следующее звено в цепи обязанностей, в методе отображения информации проверяем наличие картинки, если ее нет, передаем обязанность следующему звену (в конце объясню детальнее).

Разметка в нашем случае состоит из картинки, заголовка и описания

А теперь рассмотрим как это все работает, для этого на главном экране создадим 4 кнопки и будем обрабатывать их

Рассмотрим детально код

При создании экрана создаем главное звено цепи —
MessageChain mMainMessageChain = new AlertDialogWithPicMessage(this);

После чего создаем второе звено
MessageChain secondMessageChain = new AlertDialogMessage(this);

Третье звено цепочки обязанностей
MessageChain thirdMessageChain = new ToastMessage(this);

И последнее звено для логирования
MessageChain lastMessageChain = new LogMessage();

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

В итоге получается такая последовательность

AlertDialogWithPicMessage -> AlertDialogMessage -> ToastMessage -> LogMessage

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

Для большей ясности посмотрим на скриншоты

Самое примечательное то, что все методы обработки кнопок в конечном итоге вызывает один и тот же метод у главного звена цепочки

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

Приведу еще одну параллель с реальной жизнью. Представьте команду разработки, состояющую из Лидера разработки, старшего разработчика, младшего разработчика и стажера. Команде разработки поступает задача. Лидер разработки смотрит на эту задачу и решает, достаточно ли сложная чтобы браться за нее самому или же можно отдать ее старшему разработчику. Или он эту задачу решает сам или передает по цепочке вниз. Старший разработчик смотрит на задачу и если она слишком сложная для младшего разработчика, то делает ее сам, иначе передает младшему. Младший разработчик аналогично исследует задачу, если она примитивна настолько, что ее может решить стажер, то отдает задачу ему, иначе решает ее сам. Стажеру же достаются самые примитивные задачи, с которыми он однозначно сможет справиться.

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

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

Запись опубликована в рубрике Программирование Android, Программирование Java. Добавьте в закладки постоянную ссылку.