[Перевод] Пара слов о паттерне “Пассивное Представление” (Passive View)
Компоненты, связанные с логикой отображения и поведением приложения, перенесены в контроллер, в результате чего вся работа по управлению состоянием виджетов выполняется исключительно в контроллере.
Это выдержка из моей книги Further Enterprise Application Architecture development, работу над которой я начал в середине нулевых. К сожалению, с тех пор слишком много других не менее важных вещей стали требовать моего внимания, поэтому у меня не было времени как следует поработать над книгой и просвета в обозримом будущем не предвидится. Поэтому имейте ввиду, что этот материал находится в черновом варианте и я не буду вносить никаких исправлений или обновлений, пока не найду время закончить эту книгу.
Извечной проблемой при построении полнофункциональных клиентских систем является сложность их тестирования. Фреймворки очень большой части таких полнофункциональных клиентских систем создаются без оглядки на необходимость автоматизированного тестирования. Программное управление этими фреймворками часто бывает очень сложным.
Паттерн «Пассивное Представление» (Passive View) призван помочь нам с этим, сводя присутствие какой-либо логики в компонентах пользовательского интерфейса к абсолютному минимуму, перемещая ее в контроллер, который теперь не только обрабатывает ответы на пользовательские события, но и выполняет все обновления представлений. Это позволяет сосредоточить тестирование на контроллере, минимизируя риски возникновения проблем в представлении.
Что из себя представляет этот паттерн?
Этот паттерн является одной из вариаций паттернов model-view-controller (MVC) и model-view-presenter (MVP). Как и в случае с этими широко известными паттернами, пользовательский интерфейс здесь разделен между представлением (view), которое занимается непосредственно отображением, и контроллером (controller), который реагирует на действия пользователя (user gestures). Самым важным отличием пассивного представления является то, что представление, как мы можем догадаться, становится полностью пассивным и больше не отвечает за самообновление на основе модели. Вся логика из представления перенесена в контроллер. В результате между представлением и моделью нет никакой зависимости.
Рисунок 1: В отличие от большинства MVC-конфигураций, в пассивном представлении отсутствуют какие-либо зависимости между представлением и моделью.
Глядя на наш типовой пример с окном для расчета налогов (assessment window), мы видим разделение представление/контроллер, но на этот раз всю работу по выяснению того, как представление должно отображать модель, выполняет контроллер. Виджет текстового поля принимает пользовательский ввод и сразу же передает его контроллеру в рамках классической MVP-динамики. После контроллер обновляет модель, а затем обрабатывает перезагрузку представления на основе обновленной модели. Работа, связанная с перезагрузкой представления, заключается в извлечении всех необходимых данных из модели и последующем обновлении виджетов на основе этих данных. Наш пример демонстрирует грубую синхронизацию, т.е. любое изменение приводит к полной перезагрузке.
Рисунок 2: Когда происходит редактирование текста, контроллер должен обработать все реакции пользовательского интерфейса.
Рисунок 3: Классы для нашего примера расчетом налогов.
Основной причиной для задействования пассивного представления является тестирование, в рамках которого мы можем заменить представление тестовым дублером (Test Double), чтобы можно было протестировать контроллер без необходимости какого-либо взаимодействия с пользовательским интерфейсом. Для этого необходимо создать промежуточный шлюз (Gateway), как показано на рисунке 4. Это та же техника, которую мы бы использовали для контроллера-супервизора (Supervising Controller). Как и в случае с контроллером-супервизором, я привел в качестве примера заглушку (stub), но сюда также хорошо подходит и мок (mock).
Рисунок 4: Создаем шлюз для представления, чтобы его можно было легко заменить тестовым дублером.
Когда следует использовать этот паттерн?
Основной мотивацией для реализации пассивного представления является облегчение и улучшение тестирования. С представлением, урезанным до беспрекословного подчинения контроллеру, мы минимизируем риск, опуская тестирование представление. Контроллер может запускаться и тестироваться вне среды пользовательского интерфейса — если мы используем тестовый дублер вместо представления, нам даже не нужно заботиться о доступности классов, задействованных в пользовательском интерфейсе.
Пассивное представление — не единственный способ повысить степень пригодности представления для наших тестовых стратегий. Модель представления (Presentation Model) и контролер-супервайзер представляют из себя вполне разумную альтернативу. Преимущество пассивного представления над этими двумя паттернами заключается в том, что обе альтернативы требуют, чтобы представление выполняло часть работы по синхронизации, что приводит к чуть более неудобному для тестирования поведению, чем в пассивном представлении. Является ли эта разница существенной или нет, это уже дело вашего вкуса.
Еще одним преимуществом пассивного представления является очень большая наглядность. В рамках этого паттерна у нас нет критической необходимости задействовать наблюдателя (Observer) или декларативные сопоставления. Это значительно упрощает читаемость кода и дает нам возможность без особого труда увидеть, что происходит — особенно полезно, когда вы пытаетесь отладить код, когда что-то идет не так.
Часто бывает, что реализация юнитов объектно-ориентированным подходом создает сложности при изменении/добавлении новых механик в игру. На конкретные классы завязываются компоненты системы и код становится сильно связным. Приглашаем вас на бесплатный урок, где рассмотрим, как при помощи компонентного подхода (не ECS) можно гибко изменять функциональность юнитов таким образом, чтобы система была слабо связной.