Содержание
- 1 MVC — что это?
- 2 «Классическое» понимание MVC
- 3 Что такое архитектура MVC в Java?
- 4 Практика: пишем MVC-приложение
- 5 Преимущества архитектуры
- 6 Реализация
- 7 Что такое MVC: основные идеи и принципы
- 8 Шаг 1. Отделить бизнес-логику приложения от пользовательского интерфейса
- 9 Шаг 2. Используя шаблон Наблюдатель, добиться еще большей независимости модели, а также синхронизации пользовательских интерфейсов
- 10 Шаг 3. Разделение интерфейса на Вид и Контроллер
- 11 Немного о взаимосвязи Вида и Контроллера с Моделью
- 12 MVC: в чем профит?
- 13 Подведение итогов
MVC — что это?
MVC — это архитектурный паттерн, который несет в себе четкое разделение ответственности за различную функциональность разрабатываемого приложения. Первое впечатление от MVC — кажется, что все очень запутано и сложно, но это совсем не так. Давайте рассмотрим пример паттерна MVC из реальной жизни — на основе похода в кафе.
В любом кафе есть посетители (пользователи), которые могут подойти к кассиру за прилавком (controller+view) и попросить меню (интерфейс view), чтобы заказать какое-либо блюдо. Задача кассира — проверить, что кафе способно дать пользователю заказанное блюдо, и передать заказ повару (model). Повар просто готовит заказанное блюдо, и ему абсолютно все равно, что из себя представляет посетитель, способен ли он оплатить заказ и т. п., его задача — просто качественно приготовить блюдо. Как только повар (модель) заканчивает готовку блюда, он передает его обратно кассиру (вид), который проверяет, что блюдо действительно то самое, и отдает его посетителю, проконтролировав, чтобы тот его оплатил.
По принципу MVC на данный момент работают многие приложения и веб-сайты. Возьмем, к примеру, любую соцсеть. Когда вы заходите к себе на страницу и кликаете кнопку «Друзья», вы уже точно знаете, какой будет результат этого действия — список с вашими друзьями по соцсети. Как тут устроен принцип MVC? Нажав на кнопку «Друзья», вы отправляете запрос на сервер соцсети с просьбой показать вам список ваших друзей. Так реализован controller.
Сервер обрабатывает ваш запрос — из базы данных он «достает» всех ваших друзей, чтобы отправить вам их список. Так реализована model.
Выбрав из всех своих пользователей ваших друзей, соцсеть представляет вашему вниманию страницу с их списком. Так реализован view.
Древнейшая история
MVC — это не шаблон проекта, это конструкционный шаблон, который описывает способ построения структуры нашего приложения, сферы ответственности и взаимодействие каждой из частей в данной структуре.
Впервые она была описана в 1979 году, конечно же, для другого окружения. Тогда не существовало концепции веб приложения. Tim Berners Lee (Тим Бернерс Ли) посеял семена World Wide Web (WWW) в начале девяностых и навсегда изменил мир. Шаблон, который мы используем сегодня, является адаптацией оригинального шаблона к веб разработке.
Бешеная популярность данной структуры в веб приложениях сложилась благодаря её включению в две среды разработки, которые стали очень популярными: Struts и Ruby on Rails. Эти две среды разработки наметили пути развития для сотен рабочих сред, созданных позже.
MVC для веб приложений
Идея, которая лежит в основе конструкционного шаблона MVC, очень проста: нужно чётко разделять ответственность за различное функционирование в наших приложениях:
Приложение разделяется на три основных компонента, каждый из которых отвечает за различные задачи. Давайте подробно разберём компоненты на примере.
Контроллер (Controller)
Контроллер управляет запросами пользователя (получаемые в виде запросов HTTP GET или POST, когда пользователь нажимает на элементы интерфейса для выполнения различных действий). Его основная функция — вызывать и координировать действие необходимых ресурсов и объектов, нужных для выполнения действий, задаваемых пользователем. Обычно контроллер вызывает соответствующую модель для задачи и выбирает подходящий вид.
Модель (Model)
Модель — это данные и правила, которые используются для работы с данными, которые представляют концепцию управления приложением. В любом приложении вся структура моделируется как данные, которые обрабатываются определённым образом. Что такое пользователь для приложения — сообщение или книга? Только данные, которые должны быть обработаны в соответствии с правилами (дата не может указывать в будущее, e-mail должен быть в определённом формате, имя не может быть длиннее Х символов, и так далее).
Модель даёт контроллеру представление данных, которые запросил пользователь (сообщение, страницу книги, фотоальбом, и тому подобное). Модель данных будет одинаковой, вне зависимости от того, как мы хотим представлять их пользователю. Поэтому мы выбираем любой доступный вид для отображения данных.
Модель содержит наиболее важную часть логики нашего приложения, логики, которая решает задачу, с которой мы имеем дело (форум, магазин, банк, и тому подобное). Контроллер содержит в основном организационную логику для самого приложения (очень похоже на ведение домашнего хозяйства).
Вид (View)
Вид обеспечивает различные способы представления данных, которые получены из модели. Он может быть шаблоном, который заполняется данными. Может быть несколько различных видов, и контроллер выбирает, какой подходит наилучшим образом для текущей ситуации.
Веб приложение обычно состоит из набора контроллеров, моделей и видов. Контроллер может быть устроен как основной, который получает все запросы и вызывает другие контроллеры для выполнения действий в зависимости от ситуации.
Разберём пример
Предположим, нам надо разработать онлайновый книжный магазин. Пользователь может выполнять следующие действия: просматривать книги, регистрироваться, покупать, добавлять пункты к текущему заказу, создавать или удалять книги (если он администратор). Давайте посмотрим, что произойдёт, когда пользователь нажмёт на категорию фэнтези для просмотра названий книг, которые имеются в нашем магазине.
У нас есть определённый контроллер для обработки всех действий, связанных с книгами (просматривать, редактировать, создавать и так далее). Давайте назовем его books_controller.php в нашем примере. Также нам нужна модель, например, book_model.php, которая обрабатывает данные и логику, связанные с позицией в магазине. В заключение, нам нужно несколько видов для представления данных, например, список книг, страница для редактирования и так далее.
Следующий рисунок показывает, как обрабатывается запрос пользователя для просмотра списка книг по теме фэнтези:
Контроллер (books_controller.php) получает запрос пользователя [1] (запрос HTTP GET или POST). Мы можем организовать центральный контроллер, например, index.php, который получает запрос и вызывает books_controller.php.
Контроллер проверяет запрос и параметры, а затем вызывает модель(book_model.php), запрашивая у неё список доступных книг по теме фэнтези
Модель получает данные из базы (или из другого источника, в котором хранится информация) [3], применяет фильтры и необходимую логику, а затем возвращает данные, которые представляют список книг [4].
Контроллер использует подходящий вид [5] для представления данных пользователю [6-7]. Если запрос приходит с мобильного телефона, используется вид для мобильного телефона; если пользователь использует определённое оформление интерфейса, то выбирается соответствующий вид, и так далее.
Для чего программисты применяют MVC
MVC-архитектура нужна в первую очередь для того, чтобы разделять разрабатываемый продукт на логические части, которые можно создавать по отдельности. По сути, это будут отдельные блоки одного приложения, каждый из которых можно менять сколько угодно по отдельности, при этом не трогая другие.
Это дает возможность работать над одним приложением нескольким разработчикам сразу над разными блоками. Каждому такому разработчику не нужно будет вникать в код другого блока и другого разработчика — он будет просто трудиться над своей задачей. А в конце все блоки одного приложения соединяются воедино, и получается приложение, работающее по паттерну MVC.
То есть очевидно преимущество данного подхода в разработке — это разделение приложения и его разработки на составные части.
«Классическое» понимание MVC
При описании MVC, обычно ссылаются на его реализацию в Smalltalk’е в 1978-88 годах. Поскольку в то время взаимодействие с пользователем происходила чуть ли не напрямую от опроса клавиатуры, а вывод на порт дисплея, то чтобы как-то упорядочить этот код и были придуманы разные методологии. Их основаная задача — избавление от спаггети-кода.
Те кто помнит программирование на Бейсике, прекрасно понимают о чем речь: все эти goto делали код совершенно нечитаемым. Со временем такой код был упорядочн с помощью функций, процедур, модулей/библиотек. Дальнейшее развитие привело к ООП, который ввел ограничение видимости, что почти решило проблему пространства имен.
С появлением визуального программирования, когда взаимодействие с пользователем перешло на совершенно другой уровень, концепция MVC немного поменялась, поскольку стало уже не так ясно за что отвечает View (Представление) и какая у него связь с Controller (Контролёр). И это породило жуткую путаницу, поскольку даже элементарная кнопка на форме может быть сразу и Представлением (сама себя отрисовывает), и Контролёром, поскольку может генерировать и обрабатывать события (методы), и даже Моделью, поскольку может содержать в себе необходимые данные.
Про Web вообще лучше и не упоминать. В PHP обычно всё в куче, а попытка сделать «по науке» только приводит к существенному разбуханию кода.
Если вы пытались найти в гугле примеры и описания MVC, то видели насколько велик «разброд и шатание» по этому вопросу. Но, чтобы понять суть MVC достаточно лишь посмотреть на примеры, где нет абстракции, а есть реальный код.
Что такое архитектура MVC в Java?
Проекты моделей, основанные на архитектуре MVC в Java, следуют шаблону проектирования MVC и отделяют логику приложения от пользовательского интерфейса при разработке программного обеспечения. Как следует из названия, шаблон MVC имеет три слоя:
- Модель – представляет бизнес-уровень приложения.
- Просмотр – определяет представление приложения.
- Контроллер – управляет потоком приложения.
В контексте программирования Java модель состоит из простых классов , представление отображает данные, а контроллер состоит из сервлетов. Это разделение приводит к тому, что пользовательские запросы обрабатываются следующим образом:
- Браузер на клиенте отправляет запрос страницы контроллеру, присутствующему на сервере.
- Контроллер выполняет действие по вызову модели, тем самым извлекая необходимые данные в ответ на запрос.
- Затем контроллер передает полученные данные в представление.
- Представление отображается и отправляется обратно клиенту для отображения в браузере.
Разделение программного приложения на эти три отдельных компонента является хорошей идеей по ряду причин.
Практика: пишем MVC-приложение
Чтобы лучше вникнуть в этот паттерн, стоит применить его на практике. Для этого создайте WPF-приложение и сверстайте такую форму:
Это и есть View — его видит пользователь. Тут есть кнопка, при нажатии на которую вызывается Controller:
privatevoidCalculateButton_Click(object sender, RoutedEventArgs e) //Метод, который вызывается при нажатии на кнопку «Посчитать»{ //Валидация полученных данныхstring text1 = Num1TextBox.Text.Trim(); string text2 = Num2TextBox.Text.Trim(); int num1 = 0; int num2 = 0; if (!string.IsNullOrEmpty(text1) && !string.IsNullOrEmpty(text2)) { try { num1 = Convert.ToInt32(text1); num2 = Convert.ToInt32(text2); } catch (Exception exc) { } Calculate(num1, num2); //Передача данных модели } }
Контроллер получает пользовательский ввод и обрабатывает данные. Он также может проверять права пользователя. Если валидация проходит успешно, данные передаются в Model:
publicvoidCalculate(int num1, int num2){ result = num1 + num2; //Проведение операций с полученными данными UpdateView(); //Вызов обновления представления }
Модель проводит с этими данными необходимые операции, а затем вызывает метод обновления вида:
publicvoidUpdateView(){ ResultTextBlock.Text = result.ToString(); //Изменение вида }
Преимущества архитектуры
Архитектура 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(), являющийся частью контроллера, обновляет сведения о курсе на консоли.
Что такое MVC: основные идеи и принципы
- VC — это набор архитектурных идей и принципов для построения сложных информационных систем с пользовательским интерфейсом;
- MVC — это аббревиатура, которая расшифровывается так: Model-View-Controller.
Дисклеймер: MVC — это не паттерн проектирования. MVC — это именно набор архитектурных идей и принципов для построения сложных систем с пользовательским интерфейсом. Но для удобства, чтобы каждый раз не повторять: “Набор архитектурных идей…”, мы будем называть MVC паттерном. Начнем с простого. Что же скрывается за словами Model-View-Controller? При разработке систем с пользовательским интерфейсом, следуя паттерну MVC нужно разделять систему на три составные части. Их, в свою очередь, можно называть модулями или компонентами. Говори как хочешь, но дели на три. У каждой составной компоненты будет свое предназначение. Model. Первая компонента/модуль — так называемая модель. Она содержит всю бизнес-логику приложения. View. Вторая часть системы — вид. Данный модуль отвечает за отображение данных пользователю. Все, что видит пользователь, генерируется видом. Controller. Третьим звеном данной цепи является контроллер. В нем хранится код, который отвечает за обработку действий пользователя (любое действие пользователя в системе обрабатывается в контроллере). Модель — самая независимая часть системы. Настолько независимая, что она не должна ничего знать о модулях Вид и Контроллер. Модель настолько независима, что ее разработчики могут практически ничего не знать о Виде и Контроллере. Основное предназначение Вида — предоставлять информацию из Модели в удобном для восприятия пользователя формате. Основное ограничение Вида — он никак не должен изменять модель. Основное предназначение Контроллера — обрабатывать действия пользователя. Именно через Контроллер пользователь вносит изменения в модель. Точнее в данные, которые хранятся в модели. Приведем еще раз схему, которую тебе уже показывали на лекции: Из всего этого можно сделать вполне логичный вывод. Сложную систему нужно разбивать на модули. Опишем кратко шаги, как можно добиться подобного разделения.
Шаг 1. Отделить бизнес-логику приложения от пользовательского интерфейса
Ключевая идея MVC состоит в том, что любое приложение с пользовательским интерфейсом в первом приближении можно разбить на 2 модуля: модуль, отвечающий за реализацию бизнес-логики приложения, и пользовательский интерфейс. В первом модуле будет реализован основной функционал приложения. Данный модуль будет ядром системы, в котором реализуется модель предметной области приложения. В концепции MVC данный модуль будет нашей буковкой M, т.е. моделью. Во втором модуле будет реализован весь пользовательский интерфейс, включая отображение данных пользователю и логику взаимодействия пользователя с приложением. Основная цель такого разделения — сделать так, чтобы ядро системы (Модель в терминологии MVC) могла независимо разрабатываться и тестироваться.
Шаг 2. Используя шаблон Наблюдатель, добиться еще большей независимости модели, а также синхронизации пользовательских интерфейсов
Здесь мы преследуем 2 цели:
- Добиться еще большей независимости модели.
- Синхронизировать пользовательские интерфейсы.
Понять, что подразумевается под синхронизацией пользовательских интерфейсов, поможет следующий пример. Предположим, мы покупаем билет в кино через интернет и видим количество свободных мест в кинотеатре. Одновременно с нами покупать билет в кино может кто-то еще. Если этот кто-то купит билет раньше нас, нам бы хотелось увидеть, что количество свободных мест на наш сеанс уменьшилось. А теперь поразмышляем о том, как это может быть реализовано внутри программы. Предположим, у нас есть ядро системы (наша модель) и интерфейс (веб страница, на которой мы осуществляем покупку). На сайте 2 пользователя одновременно выбирают место. Первый пользователь купил билет. Второму пользователю необходимо отобразить на странице эту информацию. Как это должно произойти? Если мы из ядра системы будем обновлять интерфейс, наше ядро, наша модель, будет зависима от интерфейса. При разработке и тестировании модели придется держать в голове различные способы обновления интерфейса. Чтобы достичь этого, необходимо реализовать шаблон Наблюдатель. С его помощью модель рассылает уведомления об изменениях всем подписчикам. Интерфейс, являясь таким подписчиком, получит уведомление и обновится. Шаблон Наблюдатель позволяет модели с одной стороны информировать интерфейс (вид и контроллер) о том, что в ней произошли изменения, а с другой — фактически ничего о них “не знать”, и тем самым оставаться независимой. С другой стороны, это позволит синхронизировать пользовательские интерфейсы.
Шаг 3. Разделение интерфейса на Вид и Контроллер
Продолжаем делить приложение на модули, но уже на более низком уровне иерархии. На этом шаге пользовательский интерфейс (который был выделен в отдельный модуль на шаге 1) делится на вид и контроллер. Сложно провести строгую черту между видом и контроллером. Если говорить о том, что вид — это то, что видит пользователь, а контроллер — это механизм, благодаря которому пользователь может взаимодействовать с системой, можно обнаружить некоторое противоречие. Элементы управления, например, кнопки на веб-странице или виртуальная клавиатура на экране телефона, это по сути часть контроллера. Но они так же видны пользователю, как и любая часть вида. Здесь скорее речь идет о функциональном разделении. Основная задача пользовательского интерфейса — обеспечить взаимодействие пользователя с системой. Это означает, что у интерфейса всего 2 функции:
- выводить и удобно отображать пользователю информацию о системе;
- вводить данные и команды пользователя в систему (передавать их системе);
Данные функции и определяют то, как нужно делить интерфейс на модули. В итоге, архитектура системы выглядит так: Итак, у нас появилось приложение из трех модулей, которые называются Модель, Вид и Контроллер. Резюмируем:
- Следуя принципам MVC, систему нужно разделять на модули.
- Самым важным и независимым модулем должна быть модель.
- Модель — ядро системы. Нужна возможность разрабатывать и тестировать ее независимо от интерфейса.
- Для этого на первом шаге сегрегации системы нужно разделить ее на модель и интерфейс.
- Далее, с помощью шаблона Наблюдатель, укрепляем модель в ее независимости и получаем синхронизацию пользовательских интерфейсов.
- Третьим шагом делим интерфейс на контроллер и вид.
- Все, что на ввод информации от пользователя в систему — это в контроллер.
- Все что на вывод информации от системы к пользователю — это в вид.
Осталось обсудить еще одну важную вещь и можно пить какао.
Немного о взаимосвязи Вида и Контроллера с Моделью
Когда пользователь вводит информацию через контроллер, он тем самым вносит изменения в модель. По крайней мере, пользователь вносит изменения в данные модели. Когда пользователь получает информацию через элементы интерфейса (через Вид), пользователь получает информацию о данных модели. Как это происходит? Посредством чего Вид и Контроллер взаимодействуют с моделью? Ведь не может быть так, что классы Вида напрямую используют методы классов Модели для чтения/записи данных, иначе ни о какой независимости Модели не может быть и речи. Модель представляет тесно связанный между собой набор классов, к которым, по-хорошему, ни у Вида, ни у Контроллера не должно быть доступа. Для связи Модели с Видом и Контроллером необходимо реализовать шаблон проектирования Фасад. Фасад модели будет той самой прослойкой между Моделью и интерфейсом, через которую Вид получает данные в удобном формате, а Контроллер изменяет данные, вызывая нужные методы фасада.
MVC: в чем профит?
Основная цель следования принципам MVC — отделить реализацию бизнес-логики приложения (модели) от ее визуализации (вида). Такое разделение повысит возможность повторного использования кода. Польза применения MVC наиболее наглядна в случаях, когда пользователю нужно предоставлять одни и те же данные в разных формах. Например, в виде таблицы, графика или диаграммы (используя различные виды). При этом, не затрагивая реализацию видов, можно изменить реакции на действия пользователя (нажатие мышью на кнопке, ввод данных). Если следовать принципам MVC, можно упростить написание программ, повысить читаемость кода, сделать легче расширение и поддержку системы в будущем.
Подведение итогов
Есть множество программных архитектур, но Model-View-Controller — самая популярная и распространенная. Она снижает сложность кода и делает программы понятными.
Теперь вы знаете концепции, лежащие в основе паттерна MVC.
- https://CoderNet.ru/articles/drugoe/mvc_chto_eto_takoe_v_chem_otlichiya_mezhdu_frejmvorkom_i_arxitekturoj/
- https://ruseller.com/lessons.php?id=666
- https://maxsite.org/page/java-mvc
- https://java-blog.ru/osnovy/arhitektura-mvc-java
- https://skillbox.ru/media/code/chto_takoe_mvc_bazovye_kontseptsii_i_primer_prilozheniya/
- https://javarush.ru/groups/posts/2536-chastjh-7-znakomstvo-s-patternom-mvc-model-view-controller
- https://nuancesprog.ru/p/13708/