Архитектура MVC в Java
В области веб-разработки Model-View-Controller является одним из самых обсуждаемых шаблонов проектирования в современном мире веб-программирования. Архитектура MVC изначально была включена в две основные среды веб-разработки – Struts и Ruby on Rails.
- Шаблон проектирования в разработке программного обеспечения – это метод решения часто возникающей проблемы при разработке программного обеспечения.
- Проектирование модели, указывает, какой тип архитектуры вы используете для решения проблемы или разработки модели.
- Существует два типа моделей проектирования: архитектура модели 1, архитектура модели 2 (MVC).
Что такое архитектура MVC в Java?
Проекты моделей, основанные на архитектуре MVC в Java, следуют шаблону проектирования MVC и отделяют логику приложения от пользовательского интерфейса при разработке программного обеспечения. Как следует из названия, шаблон MVC имеет три слоя:
- Модель – представляет бизнес-уровень приложения.
- Просмотр – определяет представление приложения.
- Контроллер – управляет потоком приложения.
В контексте программирования Java модель состоит из простых классов , представление отображает данные, а контроллер состоит из сервлетов. Это разделение приводит к тому, что пользовательские запросы обрабатываются следующим образом:
- Браузер на клиенте отправляет запрос страницы контроллеру, присутствующему на сервере.
- Контроллер выполняет действие по вызову модели, тем самым извлекая необходимые данные в ответ на запрос.
- Затем контроллер передает полученные данные в представление.
- Представление отображается и отправляется обратно клиенту для отображения в браузере.
Разделение программного приложения на эти три отдельных компонента является хорошей идеей по ряду причин.
Преимущества архитектуры
Архитектура MVC предлагает множество преимуществ для программиста при разработке приложений, которые включают в себя:
- Несколько разработчиков могут работать с тремя слоями (Модель, Вид и Контроллер) одновременно.
- Обеспечивает улучшенную масштабируемость, которая дополняет способность приложения расти.
- Поскольку компоненты имеют низкую зависимость друг от друга, их легко поддерживать.
- Модель может быть повторно использована несколькими представлениями, что обеспечивает возможность повторного использования кода.
- Принятие MVC делает приложение более выразительным и простым для понимания.
- Расширение и тестирование приложения становится легким.
Реализация
Для реализации веб-приложения на основе шаблона проектирования MVC мы создадим:
- Course Class, который выступает в качестве модельного слоя.
- CourseView Class, который определяет уровень представления (уровень представления).
- CourseContoller Class, который действует как контроллер.
Теперь давайте рассмотрим эти слои один за другим.
Слой модели
В шаблоне проектирования MVC модель представляет собой уровень данных, который определяет бизнес-логику системы, а также представляет состояние приложения. Объекты модели получают и сохраняют состояние модели в базе данных. На этом уровне мы применяем правила к данным, которые в конечном итоге представляют концепции, которыми управляет наше приложение. Теперь давайте создадим модель, используя Course Class.
package MyPackage; public class Course < private String CourseName; private String CourseId; private String CourseCategory; public String getId() < return CourseId; >public void setId(String id) < this.CourseId = id; >public String getName() < return CourseName; >public void setName(String name) < this.CourseName = name; >public String getCategory() < return CourseCategory; >public void setCategory(String category) < this.CourseCategory = category; >>
Код прост для понимания и не требует пояснений. Он состоит из функций, чтобы получить/установить детали Course.
Уровень представления
Этот уровень шаблона проектирования MVC представляет выходные данные приложения или пользовательского интерфейса. Он отображает данные, извлеченные из слоя модели контроллером, и представляет данные пользователю при каждом запросе. Он получает всю необходимую информацию от контроллера и ему не нужно напрямую взаимодействовать с бизнес-уровнем. Давайте создадим представление, используя ClassView Class.
package MyPackage; public class CourseView < public void printCourseDetails(String CourseName, String CourseId, String CourseCategory)< System.out.println("Course Details: "); System.out.println("Name: " + CourseName); System.out.println("Course ID: " + CourseId); System.out.println("Course Category: " + CourseCategory); >>
Этот код просто для печати значений на консоль. Далее у нас есть контроллер веб-приложения.
Уровень контроллера
Контроллер похож на интерфейс между моделью и представлением. Он получает пользовательские запросы от уровня представления и обрабатывает их, включая необходимые проверки. Затем запросы отправляются в модель для обработки данных. После обработки данные снова отправляются обратно в контроллер, а затем отображаются в представлении. Давайте создадим ClassContoller Class, который действует как контроллер.
package MyPackage; public class CourseController < private Course model; private CourseView view; public CourseController(Course model, CourseView view)< this.model = model; this.view = view; >public void setCourseName(String name) < model.setName(name); >public String getCourseName() < return model.getName(); >public void setCourseId(String id) < model.setId(id); >public String getCourseId() < return model.getId(); >public void setCourseCategory(String category) < model.setCategory(category); >public String getCourseCategory() < return model.getCategory(); >public void updateView() < view.printCourseDetails(model.getName(), model.getId(), model.getCategory()); >>
Беглый взгляд на код скажет нам, что этот класс контроллера просто отвечает за вызов модели для получения/установки данных и обновления представления на основе этого.
Класс Main
Давайте назовем этот класс «MVCPatternDemo.java». Проверьте код ниже.
package MyPackage; public class MVCPatternDemo < public static void main(String[] args) < //fetch student record based on his roll no from the database Course model = retriveCourseFromDatabase(); //Create a view : to write course details on console CourseView view = new CourseView(); CourseController controller = new CourseController(model, view); controller.updateView(); //update model data controller.setCourseName("Python"); System.out.println("nAfter updating, Course Details are as follows"); controller.updateView(); >private static Course retriveCourseFromDatabase() < Course course = new Course(); course.setName("Java"); course.setId("01"); course.setCategory("Programming"); return course; >>
Приведенный выше класс извлекает данные Course из функции, используя которую пользователь вводит набор значений. Затем он помещает эти значения в модель Course. Затем он инициализирует представление, которое мы создали ранее в статье. Кроме того, он также вызывает класс CourseController и связывает его с классом Course и классом CourseView. Затем метод updateView(), являющийся частью контроллера, обновляет сведения о курсе на консоли. Проверьте вывод ниже.
Вывод
Course Details: Name: Java Course ID: 01 Course Category: Programming After updating, Course Details are as follows Course Details: Name: Python Course ID: 01 Course Category: Programming
Архитектура MVC обеспечивает совершенно новый уровень модульности вашего кода, что делает его более удобным для чтения и сопровождения. Это подводит нас к концу этой статьи. Надеюсь, вам понятно все, что с вами поделились.
Многоуровневая архитектура в проекте на Java (Часть 1)
В настоящее время в разработке ПО достаточно часто применяется многоуровневая архитектура или многослойная архитектура (n-tier architecture), в рамках которой компоненты проекта разделяются на уровни (или слои). Классическое приложение с многоуровневой архитектурой, чаще всего, состоит из 3 или 4 уровней, хотя их может быть и больше, учитывая возможность разделения некоторых уровней на подуровни. Одним из примеров многоуровневой архитектуры является предметно-ориентированное проектирование (Domain-driven Design, DDD), где основное внимание сконцентрировано на предметном уровне.
В проектах с многоуровневой архитектурой можно выделить четыре уровня (или слоя):
- Слой представления, с которым взаимодействует пользователь или клиентский сервис. Реализацией слоя представления может быть, например, графический пользовательский интерфейс или веб-страница.
- Сервисный слой, реализующий взаимодействие между слоями представления и бизнес-логики. Примерами реализаций сервисного слоя являются контроллеры, веб-сервисы и слушатели очередей сообщений.
- Слой бизнес-логики, в котором реализуется основная логика проекта. Компоненты, реализующие бизнес-логику, обрабатывают запросы, поступающие от компонентов сервисного слоя, а так же используют компоненты слоя доступа к данным для обращения к источникам данных.
- Слой доступа к данным — набор компонентов для доступа к хранимым данным. В качестве источников данных могут выступать различного рода базы данных, SOAP и REST-сервисы, файлы на файловой системе и т.д.
Направление зависимостей между слоями идёт от слоя представления к слою доступа к данным. В идеальной ситуации каждый слой зависит только от следующего слоя: слой представления зависит от сервисного слоя (например, представление зависит от контроллера), сервисный слой зависит от слоя бизнес-логики (например, контроллер зависит от бизнес-сервиса), а слой бизнес-логики — от слоя доступа к данным (например, бизнес-сервис зависит от репозитория). При этом компоненты бизнес-слоя могут зависеть от других компонентов бизнес-слоя, тогда как в других слоях аналогичные зависимости нежелательны (например, зависимость одного репозитория от другого). Так же нежелательны зависимости в обратном направлении (бизнес-слой не должен зависеть от сервисного слоя) и зависимости между слоями, не являющимися соседними (сервисный слой не должен зависеть от слоя доступа к данным, например).
На практике иногда приходится сталкиваться с примерами, когда бизнес-логика частично или полностью находится в контроллере, а иногда встречаются и вовсе случаи обращения компонентов слоя представления к слою доступа к данным. Несоблюдение разделения кода между слоями непременно приводит к путанице, замедляет процесс разработки и развития проекта и делает процесс поддержки проекта трудоёмким и дорогим.
Допустим, у нас есть код, реализующий бизнес-логику приложения, который находится в контроллере. Что если нам требуется разработать SOAP-сервис, реализующий ту же функциональность? Мы можем скопировать существующий код в SOAP-сервис и внести в него изменения по мере необходимости. Будет ли ли такой подход работать? Да! Вызовет ли такой подход проблемы? Тоже да! В процессе жизненного цикла проекта требования к нему имеют свойство меняться, что ведёт к неизбежным изменениям и в коде. Но при таком подходе нам придётся изменить код и в контроллере, и в SOAP-сервисе, а также внести изменения в их тесты (вы же тестируете свой код?). Но граздо правильнее будет вынести общий код, реализующий бизнес-логику, в компонент слоя бизнес-логики. В этом случае в контроллере и SOAP-сервисе останется код, преобразующий запрос к общему виду, понятному компоненту бизнес-логики.
Очевидным фактом является то, что бизнес-логика — самая важная составляющая вашего проекта. И именно с проработки компонентов слоя бизнес-логики должна начинаться разработка проекта.
К слову сказать, очень хорошей практикой является применение UML, в данном конкретном случае — диаграммы классов. Из собственной практики помню случай, когда я решил для почти готового проекта составить диаграмму классов, результатом чего стал рефакторинг, уменьшивший количество кода примерно на 20%. Составление диаграммы классов на ранних этапах разработки позволяет уменьшить дублирование кода, сделать структуру классов и зависимости между ними более понятными.
В так полюбившейся мне книге Роберта Марина «Чистая архитектура» автор пропагандирует идею независимости (или минимизации зависимости) архитектуры приложения от внешних факторов: фреймворков, баз данных и прочих сторонних зависимостей. Это говорит не об отказе от использования этих зависимостей (вы же не будете разрабатывать собственный механизм трансляции HTTP-вызовов или хранения данных?), а о минимизации их влияния на архитектуру вашего проекта.
Разработка бизнес-логики
Давайте возьмём в качестве примера разработку блокнота, который пользователь может использовать для работы с заметками. Заметьте, я не указал, что это будет онлайн-сервис или настольное приложение. Для начала определимся с набором типов (классов и интерфейсов), которые нам понадобятся для нашего проекта. Класс-сущность, описывающий заметку — Note, компонент бизнес-логики, реализующий работу с заметками — NoteService, ещё нам потребуется компонент слоя доступа к данным — NoteRepository. Простая реализация NoteService — SimpleNoteService, использует NoteRepository для доступа к источнику данных. Диаграмма классов, описывающая текущую архитектуру, будет достаточно простая:
Теперь можно описать эти типы в коде, написать тесты для SimpleNoteService и реализовать этот класс.