Шаблоны GRASP: Controller (контроллер)

    Привет, Хабр! Меня зовут Владислав Родин. В настоящее время я являюсь руководителем курса «Архитектор высоких нагрузок» в OTUS, а также преподаю на курсах, посвященных архитектуре ПО.

    Специально к старту нового набора на курс «Архитектура и шаблоны проектирования» я продолжаю серию своих публикаций про шаблоны GRASP.





    Введение


    Описанные в книге Craig'а Larman'а «Applying UML and patterns, 3rd edition», GRASP'овские паттерны являются обобщением GoF'овских паттернов, а также непосредственным следствием принципов ООП. Они дополняют недостающую ступеньку в логической лестнице, которая позволяет получить GoF'овские паттерны из принципов ООП. Шаблоны GRASP являются скорее не паттернами проектирования (как GoF'овские), а фундаментальными принципами распределения ответственности между классами. Они, как показывает практика, не обладают особой популярностью, однако анализ спроектированных классов с использованием полного набора GRASP'овских паттернов является необходимым условием написания хорошего кода.

    Полный список шаблонов GRASP состоит из 9 элементов:

    • Information Expert
    • Creator
    • Controller
    • Low Coupling
    • High Cohesion
    • Polymorphism
    • Pure Fabrication
    • Indirection
    • Protected Variations

    В прошлый раз мы обсудили целых два принципа Low Coupling и High Cohesion. Сейчас я предлагаю рассмотреть еще один достаточно важный принцип GRASP, позволяющий установить правила обработки входящих системных событий. Ниже поговорим о том, что из себя представляет Controller.

    Controller


    Формулировка


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

    Мотивировка


    В системе необходимо обрабатывать входящие системные события (пользователи нажимают на кнопки, срабатывают таймеры и так далее). Это можно сделать либо в отдельном объекте (Controller), либо разбросать по всему коду. Например, в нужном месте из бизнес — логики можно слазить и узнать нажал пользователь на кнопку или нет. Второй подход согласно изучаемому шаблону является неправильным. Дело в том, что для обработки многопоточного входа (а ввод пользователя всегда многопоточен) необходимо писать и поддерживать многопоточный код. Таким образом, в коде нашей бизнес — логики появляются технические нюансы синхронизации (мьютексы, семафоры, synchronized — блоки и так далее). Наличие всего этого добра сбивает с толку программиста, читающего код бизнес — логики. Более того, применение таких приемов придется дублировать в нескольких участках кода бизнес — логики. Помимо этого, наличие многопоточности усложняет код приложения на порядок. Многопоточный код сложно покрыть юнит — тестами.

    Решение


    Идея шаблона состоит в том, чтобы не размазывать этот сложный код по всему приложению. Такой объект как Controller будет превращать многопоточный вход в один поток. Код бизнес — логики будет однопоточным. Шаблон не описывает то, как Conroller будет превращать многопоточный вход в один поток, но он должен это так или иначе делать (ставить запросы в очередь, создавать свою копию объекта бизнес — логики для каждого потока).

    Преимущества


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

    Имеет месте улучшение условий для повторного использования компонентов. Когда вся многопоточность сосредоточена в этом самом Conroller'е, мы можем переключить код бизнес — логики на другой вход, просто дописав другой Conroller (добавить поддержку веб-сервиса, перенести код в однопоточную среду).

    Недостатки


    Controller может оказаться перегруженным. В связи с этим, conroller может из себя представлять package или отдельный компонент.

    Аналогия с гексагональной архитектурой


    Controller в некотором смысле может быть рассмотрен в контексте гексагональной архитектуры в качестве защиты от пользовательского ввода. Данная архитектура предполагает, что наша система (бизнес — логика) живет во «враждебном окружении». Она как — то взаимодействует с базами данных, получает пользовательский ввод, конфигурацию, осуществляет вывод и так далее. Каждый элемент может быть «враждебным»: база данных может отвалиться, конфигурация может быть невалидной или отсутствовать вовсе, вывод может быть заблокирован, ввод может быть некорректным. Для корректной обработки всех таких сценариев предполагается защита нашей бизнес — логики некоторыми адаптерами и фасадами.

    Вывод


    Многопоточность в коде бизнес — логики является злом, усложняющим этот код на порядок. Ее следует избегать, выделяя объект, превращающий многопоточный вход в однопоточный какими — либо способами. Данный объект называется Controller'ом.



    Узнать о курсе подробнее




    OTUS. Онлайн-образование
    Цифровые навыки от ведущих экспертов

    Комментарии 1

      0

      В априори однопоточном коде такие контроллеры не нужны в принципе?

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

      Самое читаемое