В этой статье я хотел бы показать вам, почему использование шаблона MVC недостаточно для создания гибких и масштабируемых приложений. Я также предложу возможные решения выявленных проблем.
В шаблоне Model View Controller нет ничего плохого. Это решает проблему, для которой она была изобретена — отделить логику обработки пользовательских запросов от логики представления.
До изобретения этого шаблона логика обработки пользовательских запросов и логика представления были тесно связаны в одном файле. Это значительно усложнило обслуживание и привело к появлению множества ошибок в системе.
Шаблон MVC является хорошим выбором, когда прикладные модули более или менее независимы друг от друга. Например, они вызываются из главного меню. Давайте представим, что для завершения бизнес-процесса нам необходимо пройти пошаговые модули: A. B, C, D. Объект, созданный в модуле A, становится доступным в модуле B. Объект, созданный в модуле B, а также объект, созданный в модуле A стать доступным в модуле C и т. д.
В этом случае пользователь должен знать порядок работы с системными модулями, чтобы иметь возможность вносить необходимые изменения. Также, если процесс работы с системой изменился (изменилась бизнес-модель или модель домена), пользователь может адаптироваться к новому процессу без изменений в пользовательском интерфейсе.
Все в порядке, пока система не используется небольшим количеством людей, когда нет проблем научить их пользоваться ею. Как насчет системы доставки для большого числа пользователей?
В этом случае для упрощения работы приложение должно знать, как с ним работать и проводить пользователя по системе шаг за шагом, открывая дальнейшие шаги.
Но здесь кроется хитрое использование паттерна MVC. Как видно из рисунка ниже, заманчиво сослаться из представления модуля «А» (Вид) непосредственно к контроллеру (контроллеру) модуля «В», из модуля «В» в модуль «С», из модуля «С» в ». D ‘и т. Д.
(Или от контроллера модуля «А» к контроллеру модуля «В». Или, что еще хуже, от контроллера модуля «А» до представления (вида) модуля «В»)
Бизнес-процесс будет плотно сшит в 3 просмотра. Я согласен, что это немного сбивает с толку. Поскольку отношения распределены по нескольким файлам — менять бизнес-процессы будет громоздко.
И вам необходимо жестко кодировать бизнес-логику в операторах if / else, чтобы иметь возможность поддерживать различные варианты A, B, C, D. К сожалению, такой подход довольно часто используется для создания приложений.
Как вернуть прежнюю слабую связь с системными модулями, но сохранить описанные бизнес-процессы внутри.
Для этого вам нужно перенести конфигурацию бизнес-процессов из модулей и разместить их отдельно. Для обеспечения взаимодействия пользователей и всех модулей через один Root или Front Controller. В этом случае контроллер будет извлекать из конфигурации, какие модули в каком порядке предоставить пользователю. Модули будут связываться через корневой контроллер посредством событий, чтобы обеспечить подход слабой связи.
Конфигурация некоторого основного потока может выглядеть так:
<?xml version="1.0"?> <application initial="A"> <module id="A"> <on event="next" to="B"/> </module>
<module id="B" >
<on event="previous" to="A"/> <on event="next" to="C"/> </module>
<module id="C">
<on event="previous" to="B"/> <on event="next" to="D"/> </module>
<module id="D">
<on event="previous" to="C"/> <on event="finish" to="finish"/> </module>
<on event="cancel" to="cancel"/> <final id="finish" /> <final id="cancel" /> </application>
В этом случае довольно просто изменить поведение системы, просто удалив некоторые шаги из конфигурации:
<?xml version="1.0"?> <application initial="A"> <module id="A">
<on event="next" to="D"/> </module>
<module id="D">
<on event="previous" to="A"/> <on event="finish" to="finish"/> </module>
<on event="cancel" to="cancel"/> <final id="finish" /> <final id="cancel" /> </application>
Для настройки состояний модуля и переходов между ними очень удобно использовать конечные автоматы (Finite State Machine). После введения наследования и полиморфизма в конфигурацию он становится очень мощным инструментом для описания бизнес-процессов. Для хорошей наглядности мы использовали XML-формат файлов конфигурации, но это также может быть некоторая реализация Domain Specific Language, чтобы иметь возможность проверять конфигурацию во время компиляции.
Примерами таких конечных автоматов в мире Java могут служить:
· Spring Web Flow — расширение Spring MVC, и поэтому неплохо использовать с моделью HTTP Request / Response.
· Lexaden Web Flow — создан специально для быстрой разработки гибких корпоративных приложений AJAX Vaadin.
Основное отличие заключается в том, что Spring Web Flow в основном создается для сред, тесно связанных с моделью HTTP-запросов / ответов, и поэтому может быть неудобно использовать его с компонентными инфраструктурами AJAX, такими как Vaadin . Страница будет постоянно обновляться, а преимущества AJAX будут игнорироваться.
Вместо этого Lexaden Web Flow предоставляет всю мощь описанного подхода на уровне запросов AJAX. Используя все лучшее из компонентной модели Vaadin, она позволяет создавать гибкие, масштабируемые и очень надежные корпоративные приложения.
PS статья « Создание расширенной навигации для корпоративных приложений» подробно описывает решение, основанное на Lexaden Web Flow.