- Model-View-Controller
-
Шаблон проектирования Model-View-Controller Model-view-controller (MVC, «Модель-представление-поведение», «Модель-представление-контроллер») — схема использования нескольких шаблонов проектирования, с помощью которых модель данных приложения, пользовательский интерфейс и взаимодействие с пользователем разделены на три отдельных компонента так, что модификация одного из компонентов оказывает минимальное воздействие на остальные. Данная схема проектирования часто используется для построения архитектурного каркаса, когда переходят от теории к реализации в конкретной предметной области[1].
Содержание
История
Концепция MVC была описана в 1979 году[2] Трюгве Реенскаугом (англ. Trygve Reenskaug), тогда работающим над языком программирования Smalltalk в Xerox PARC. Оригинальная реализация описана в статье «Applications Programming in Smalltalk-80: How to use Model-View-Controller»[3]. Затем Джим Алтофф с командой разработчиков реализовали версию MVC для библиотеки классов Smalltalk-80.
В оригинальной концепции была описана сама идея и роль каждого из элементов модели, представления и контроллера. Но связи между ними были описаны без конкретизации. Кроме того, различали две основные модификации:
- Пассивная модель — модель не имеет никаких способов воздействовать на представление или контроллер, и используется ими в качестве источника данных для отображения. Все изменения модели отслеживаются контроллером и он же отвечает за перерисовку представления, если это необходимо. Такая модель чаще используется в структурном программировании, так как в этом случае модель представляет просто структуру данных, без методов их обрабатывающих.
- Активная модель — модель оповещает представление о том, что в ней произошли изменения, а представления, которые заинтересованы в оповещении, подписываются на эти сообщения. Это позволяет сохранить независимость модели как от контроллера, так и от представления.
Классической реализацией концепции MVC принято считать версию именно с активной моделью.
С развитием объектно-ориентированного программирования и понятия о шаблонах проектирования был создан ряд модификаций концепции MVC, которые при реализации у разных авторов могут отличаться от оригинальной. Так, например, Эриан Верми в 2004 году описал пример обобщенного MVC[4].
Назначение
Основная цель применения этой концепции состоит в разделении бизнес-логики (модели) от её визуализации (представления, вида). За счет такого разделения повышается возможность повторного использования. Наиболее полезно применение данной концепции в тех случаях, когда пользователь должен видеть те же самые данные одновременно в различных контекстах и/или с различных точек зрения. В частности, выполняются следующие задачи:
- К одной модели можно присоединить несколько видов, при этом не затрагивая реализацию модели. Например, некоторые данные могут быть одновременно представлены в виде электронной таблицы, гистограммы и круговой диаграммы.
- Не затрагивая реализацию видов, можно изменить реакции на действия пользователя (нажатие мышью на кнопке, ввод данных), для этого достаточно использовать другой контроллер.
- Ряд разработчиков специализируется только в одной из областей: либо разрабатывают графический интерфейс, либо разрабатывают бизнес-логику. Поэтому возможно добиться того, что программисты, занимающиеся разработкой бизнес-логики (модели), вообще не будут осведомлены о том, какое представление будет использоваться.
Концепция
Концепция MVC позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента:
- Модель (англ. Model). Модель предоставляет знания: данные и методы работы с этими данными, реагирует на запросы, изменяя своё состояние. Не содержит информации, как эти знания можно визуализировать.
- Представление, вид (англ. View). Отвечает за отображение информации (визуализацию). Часто в качестве представления выступает форма (окно) с графическими элементами.
- Контроллер (англ. Controller). Обеспечивает связь между пользователем и системой: контролирует ввод данных пользователем и использует модель и представление для реализации необходимой реакции.
Важно отметить, что как представление, так и контроллер зависят от модели. Однако модель не зависит ни от представления, ни от контроллера. Тем самым достигается назначение такого разделения: оно позволяет строить модель независимо от визуального представления, а также создавать несколько различных представлений для одной модели.
Для реализации схемы Model-View-Controller используется достаточно большое число шаблонов проектирования (в зависимости от сложности архитектурного решения), основные из которых «наблюдатель», «стратегия», «компоновщик»[5].
Наиболее типичная реализация отделяет вид от модели путем установления между ними протокола взаимодействия, используя аппарат событий (подписка/оповещение). При каждом изменении внутренних данных в модели она оповещает все зависящие от неё представления, и представление обновляется. Для этого используется шаблон «наблюдатель». При обработке реакции пользователя вид выбирает, в зависимости от нужной реакции, нужный контроллер, который обеспечит ту или иную связь с моделью. Для этого используется шаблон «стратегия», или вместо этого может быть модификация с использованием шаблона «команда». А для возможности однотипного обращения с подобъектами сложно-составного иерархического вида может использоваться шаблон «компоновщик». Кроме того, могут использоваться и другие шаблоны проектирования, например, «фабричный метод», который позволит задать по умолчанию тип контроллера для соответствующего вида.
Наиболее частые ошибки
Начинающие программисты (особенно в веб-программировании, где аббревиатура MVC стала популярна) очень часто трактуют архитектурную модель MVC как пассивную модель MVC. В этом случае модель выступает исключительно совокупностью функций для доступа к данным, а контроллер содержит бизнес-логику. В результате код моделей по факту является средством получения данных из СУБД, а контроллер представляет собой типичный модуль, наполненный бизнес-логикой, или скрипт в терминологии веб-программирования. В результате такого понимания MVC разработчики стали писать код, который Pádraic Brady, известный в кругах сообщества Zend Framework, охарактеризовал как ТТУК — «Толстые тупые уродливые контроллеры» (Fat Stupid Ugly Controllers)[6]:
Среднестатистический ТТУК получал данные из БД (используя уровень абстракции базы данных, делая вид, что это модель) или манипулировал, валидировал, записывал, а также передавал данные в вид. Такой подход стал очень популярен потому, что использование таких контроллеров похоже на классическую практику использования отдельного php-файла для каждой страницы приложения.
Но в объектно-ориентированном программировании используется активная модель MVC, где модель — это не только совокупность кода доступа к данным и СУБД, а вся бизнес-логика. В свою очередь, контроллеры представляют собой лишь элементы системы, в чьи непосредственные обязанности входит приём данных из запроса и передача их другим элементам системы. Только в этом случае контроллер становится «тонким» и выполняет исключительно функцию связующего звена (glue layer) между отдельными компонентами системы.
Пример контроллера MVC в рамках PHP5
<?php class Krugozor_Module_Advert_Controller_List extends Krugozor_Module_Advert_Controller_Common { public function run() { $this->getView()->loadI18n('Common/General', 'Advert/List'); $this->initTitle(); if (!$this->checkAccess()) { return $this->createNotification() ->setMessage($this->getView()->lang['notification']['forbidden_access']) ->setType('alert') ->setNotificationUrl('/admin/') ->run(); } $list = new Krugozor_Module_Advert_Service_List ( $this->getRequest(), $this->getMapper('Advert/Advert'), new Krugozor_Pagination_Manager(10, 10, $this->getRequest()) ); $this->getView()->adverts = $list->getList(); $this->getView()->pagination = $list->getPagination(); $this->getView()->id_category = $this->getRequest()->getRequest('id_category'); $this->getView()->id_user = $this->getRequest()->getRequest('id_user'); return $this->getView(); } } ?>
Данный пример иллюстрирует реальный код контроллера на PHP5 в рамках объектно-ориентированного приложения, построенного по концепции MVC. Здесь контроллер выступает в роли класса с единственным методом
run()
, который запускает Front-Controller. Цель контроллера — отдать в Представление (View) данные для формирования страницы со списком объявлений.В начале с помощью метода контроллера
getView()
программист получает объект Представления (View), который вызывает методы, специфичные для Представления (View): методloadI18n()
с помощью которого в Представление (View) подгружаются файлы интернационализации, а также методinitTitle()
, формирующий title HTML-страницы на основе данных, полученных в ходе разбора файлов интернационализации.Далее через метод контроллера
checkAccess()
проверяется, имеет ли пользователь доступ к этой странице. Если доступ не разрешён, формируется предупреждение и происходит перенаправление на ресурс «/admin/». Далее инстанцируется Модель (Model), а точнее, один из компонентов модели — сервисKrugozor_Module_Advert_Service_List
. Данный класс инкапсулирует логику получения массива объектов моделей на основе различных параметров из объекта запросаRequest
, а также взаимодействует с объектом пагинации.После получения данных от сервиса в Представление (View) передается массив моделей
adverts
, объект пагинацииpagination
, идентификатор запрошенной в URL-адресе категорииid_category
и идентификатор пользователяid_user
, после чего Представление (View) отдается во Front-Controller для дальнейшего действия (шаблонизации и вывод в выходной поток).В примере явно видно, что Контроллер представляет собой связующее звено между двумя основными компонентами системы — Моделью (Model) и Представлением (View). Модель ничего «не знает» о Представлении, а Контроллер не содержит в себе какой-либо бизнес-логики.
См. также
- Model-View-ViewModel
- Model-View-Presenter
- Фасад (шаблон проектирования)
- Ruby on Rails
- ASP.NET MVC Framework
Примечания
- ↑ Сергей Рогачев. Обобщённый Model-View-Controller 2007
- ↑ Trygve M. H. Reenskaug/MVC XEROX PARC 1978-79
- ↑ How to use Model-View-Controller (MVC)
- ↑ Vermeij. Arjan A Generic MVC Model in Java 2004
- ↑ Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес. Приёмы объектно-ориентированного проектирования. Паттерны проектирования 2001
- ↑ The M in MVC: Why Models are Misunderstood and Unappreciated | Pádraic Brady перевод
Литература
- Стивен Сандерсон ASP.NET MVC Framework с примерами на C# для профессионалов. — М.: Вильямс, 2009. — ISBN 978-5-8459-1609-9
Ссылки
Категории:- Парадигмы программирования
- Шаблоны проектирования
Wikimedia Foundation. 2010.