Предыдущий выпуск: Вступление
Начнём с самого избитого. Когда человека спрашивают, какие шаблоны проектирования ты знаешь, и он говорит, ну... MVC, и над ним смеются, потому что это самый распространённый шаблон и по факту человек ничего не знает.
Тем не менее, избитость и распространённость этого шаблона говорит лишь о том, что он очень полезен. Поэтому не надо комплексовать.
Какую проблему решаем?
Разберёмся на примере веб-страницы. Веб-страница была придумана как обычный текст c разметкой в формате HTML. Её содержимое статично. Каждый раз, когда вы запрашиваете HTML-страницу с сайта, она приходит одна и та же.
Затем появилась технология CGI (Common Gateway Interface), которая позволяла делать динамические страницы. То есть вы запрашивали HTML-страницу, но хитрый веб-сервер не отдавал её вам, а запускал у себя программу, которая генерировала страницу, и вот эту сгенерированную страницу он уже отдавал. Так как программа может сгенерировать что угодно, то появилась возможность делать динамические страницы, наполняя их разными данными, такими как профиль пользователя, список товаров, лента новостей и т.д.
Кроме того, стало возможным отправлять данные на сервер – заполнять формы, писать сообщения на форумах, загружать картинки. На том конце их принимала и обрабатывала всё та же программа.
Таким образом CGI-программа стала контроллером, то есть "управляющим", тем, кто контролирует потоки данных.
Однако появилась проблема.
Данные в HTML-странице завёрнуты в некий дизайн. Это заголовки, стили, шрифты, отступы, разные цвета, картинки, ссылки, в общём вёрстка контента.
Так как CGI-программа должна сгенерировать страницу целиком, то она должна вставить в выходной поток и все элементы дизайна, и таблицы, и формы, и прочее. Это значит, что HTML нужно писать прямо в коде программы. Скажем, если нужен большой заголовок красного цвета, то программа должна была вывести:
echo '<h1 style="color:red">Hello World</h1>';
Получается, что для того, чтобы просто поменять кусочек дизайна, нужно лезть в код программы и исправлять его. Это и неудобно, и ухудшает читаемость вообще всего, и приводит к ошибкам.
Поэтому стало очевидным, что дизайн и программный код нужно разделить. HTML-страница стала отдельным шаблоном, или представлением данных. Можно представить её как пустую вёрстку, то есть каркас, в который в нужные места контроллер вставляет данные. Таким образом, контроллер не содержит в себе никакого дизайна, а только заполняет готовый внешний шаблон чистыми данными. Если нужно поменять дизайн, то меняется не программа, а представление (шаблон). Также удобно, что один контроллер теперь может работать с разными шаблонами, ведь ему всё равно, какой у них дизайн.
Из трёх букв MVC мы сейчас освоили V (View, представление) и C (Controller, контроллер). Это уже сам по себе паттерн, суть которого в том, чтобы отделить данные от представления. Данными занимается контроллер, а представлением – HTML-шаблон.
Но остаётся еще буква M – Model, она же модель. Она относится к работе с данными.
Например, контроллер работает с профилем пользователя, который хранится в базе. В этот профиль входят: имя, телефон, email, год рождения, пол, ну и так далее. Все эти атрибуты должны быть выведены на странице (то есть в представлении) в определённых местах. Также, если пользователь захочет отредактировать свой профиль, то эти атрибуты будут отправлены контроллеру, а контроллер должен будет их сохранить в базе.
Атрибуты профиля нужно как-то валидировать, например, чтобы телефон был правильным, чтобы пароль был надёжным, и так далее. Если всем этим будет заниматься контроллер, то его код превратится в лапшу.
Поэтому все атрибуты профиля объединяются в один объект, который инкапсулирует всё внутри себя. Кроме того, этот же объект занимается валидацией данных, их форматированием (например дата-время), проверкой уникальности и т.д. В общем, мы получаем модель данных пользователя. Эта модель знает, как:
- получить данные пользователя из базы и загрузить в себя, подготовив для использования
- получить извне новые данные, валидировать их, и в случае успеха сохранить
- преобразовать данные в нужный формат
Теперь контроллеру не нужно заботиться о безопасности, достаточности и валидности данных. Всё это сделает модель. Модель занимается только данными, а контроллер теперь занимается только своей прямой функцией – управляет процессом. Для генерации страницы профиля он совершает следующие действия:
- загрузить данные в модели (да, модель может быть не одна)
- вставить данные из моделей в шаблон
Вот теперь мы получили Model-View-Controller, самый банальный шаблон проектирования, который используется во всех современных фреймворках для веб-сайтов: Yii, Symphony, Laravel и др.
Да, и учтите, что вы можете иметь несколько разных контроллеров. Для этого нужно маршрутизировать запросы. Скажем, если запрос относится к редактированию пользователя, то он направляется на контроллер, который обслуживает пользователей. Если к сообщениям форума, то на контроллер, который обслуживает форум. У каждого контроллера есть своё представление (или несколько представлений) и свои модели. Впрочем, ничего не мешает разным контроллерам использовать одно и то же представление или одну и ту же модель.
Где ещё можно использовать MVC?
Да где угодно, где у вас есть необходимость показать представление данных пользователю – игровые интерфейсы, электронные таблицы... Управляющий процессом контроллер у вас, по сути, есть всегда – это ваша программа. Представление, по сути, тоже есть всегда – ведь пользователь что-то видит на экране. Так что осталось понять, нужна ли вам будет модель, и какая.
Пример: В своей игре я добавил в интерфейс скины, то есть разные версии дизайна кнопок, окошек и пр. Представление – это просто разметка, где какой элемент интерфейса должен находиться. Моделью стал объект, который умеет получать графику для скинов и готовить из неё нужные элементы. Далее, контроллеру нужно только сказать – покажи вот это представление с данными из вот этой модели. Представление тянет из модели стандартные элементы, такие как "главное меню", "кнопка назад", "кнопка настроек", и модель про них в курсе, потому что она модель, созданная именно для этого. Стандартные элементы размещаются в нужных местах разметки. Они уже имеют нужную графику в текущем скине, так как об этом позаботилась модель.
Чтобы поменять скин, нужно просто сказать модели – используй этот скин. И всё остальное изменится само собой.
В следующем выпуске мы обсудим шаблон Стратегия.