Является ли буква C в MVC действительно необходимой?

38

Я понимаю роль модели и представления в шаблоне Model-View-Controller, но мне трудно понять, зачем нужен контроллер.

Давайте предположим, что мы создаем шахматную программу, используя подход MVC; игровое состояние должно быть моделью, а графический интерфейс должен быть представлением. Какой именно контроллер в этом случае?

Это просто отдельный класс, в котором есть все функции, которые будут вызываться, когда вы, скажем, нажимаете на плитку? Почему бы просто не выполнить всю логику модели в самом представлении?

Энн Нонимус
источник
1
Лично это то, что я делаю . Могут быть случаи, когда нет альтернативы MVC, но я терпеть не могу.
Майк Данлавей
10
Три слова ... «Разделение концерна».
Трэвис Дж
4
Почти все программы Windows до .net использовали Doc-View без контроллера. Кажется, это было относительно успешно.
Мартин Беккет
Мартин, недееспособный монолит.
Независимый
Я ответил ниже, но добавлю, что да, вы можете создавать приложения без отдельных классов контроллеров, но это не будет MVC. Вы предполагаете «подход MVC», так что да, контроллеры играют важную роль. Если вы выберете какую-то парадигму, которая не является MVC, вполне возможно, что у вас не будет никаких контроллеров.
Калеб

Ответы:

4

Используя ваш пример, Контроллер определит, что является законным ходом или нет. Контроллер сообщит представителю, как расположить фигуры на доске при запуске, используя информацию, полученную от Модели. Контроллер может обрабатывать больше вещей, но главное - подумать о бизнес-логике на этом уровне.

Бывают моменты, когда все, что делает контроллер, это передает информацию туда и обратно, как страница регистрации. В других случаях Контроллер является трудной частью разработки, потому что на этом уровне нужно сделать много вещей, например, обеспечить соблюдение правил или выполнить сложную математику. Не забудьте контроллер!

JustinDoesWork
источник
36
«Используя ваш пример, Контроллер определит, что было законным ходом или нет». Это плохой пример :( такая логика должна быть и в модели. В противном случае ваша логика будет разделена между контроллером и моделью.
Дайм
6
@Dime - модель не должна содержать никакой логики. Контроллер будет единой логикой, следовательно, «контролирующей».
Трэвис Дж
34
@TravisJ Не совсем согласен. Контролировать не значит знать, как выполнять работу. Речь идет о контроле тех объектов, которые делают. Следовательно, логика для выполнения работы будет в модели, и контроллер будет контролировать, какую модель использовать для выполнения необходимых требований действия и т. Д. Слишком много логики в контроллерах, на мой взгляд, было бы рецептом для блоттинга контроллера ...
Дреза
25
Весь смысл ООП состоит в том, чтобы связать вместе кусочки данных и поведения и инкапсулировать их состояние. «Модель» моделирует как поведение, так и данные.
Миско
12
-1 Контроллер не должен содержать бизнес-логики. Модель - это «приложение», оно содержит данные и имеет вызываемые процедуры для всего, что может происходить в приложении; не обязательно все в одном файле или классе. Представление визуализирует состояние модели. Контроллер соединяет модель / представление и реальный мир / ввод. Хотите «опубликовать» приложение как веб-приложение? Просто нужен контроллер, который обрабатывает HTTP и соответствующее представление на основе HTML. Хотите интерфейс командной строки для вашего приложения? Просто нужен соответствующий контроллер и просмотр. Модель, бизнес-логика, никогда не меняется в этих случаях.
deceze
39

Почему бы просто не выполнить всю логику модели в самом представлении?

Контроллер - это клей, который связывает модель и вид вместе, а также изоляция, которая разделяет их. Модель не должна ничего знать о представлении и наоборот (по крайней мере, в версии Apple от MVC). Контроллер действует как двусторонний адаптер, переводя действия пользователя из представления в сообщения для модели и конфигурируя представление с данными из модели.

Использование контроллера для разделения модели и представления делает ваш код более пригодным для повторного использования, более тестируемым и более гибким. Рассмотрим ваш шахматный пример. Модель, конечно, будет включать в себя игровое состояние, но она также может содержать логику, которая влияет на изменения игрового состояния, например, определение того, является ли ход законным, и решение о завершении игры. Представление отображает шахматную доску и фигуры и отправляет сообщения, когда фигура движется, но она ничего не знает о значении фигур, как движется каждая фигура и т. Д. Контроллер знает как модель, так и представление, а также общий поток программы. Когда пользователь нажимает кнопку «новая игра», это контроллер, который сообщает модели о создании игры и использует состояние новой игры для настройки игрового поля. Если пользователь делает ход,

Посмотрите, что вы получите, сохранив модель, и посмотрите отдельно:

  • Вы можете изменить модель или вид, не меняя другой. Возможно, вам придется обновить контроллер, когда вы меняете любой из них, но в некотором смысле это является преимуществом: части программы, которые могут измениться, сконцентрированы в контроллере.

  • Модель и вид могут быть использованы повторно. Например, вы можете использовать тот же вид шахматной доски с RSS-каналом, что и модель, чтобы проиллюстрировать известные игры. Или вы можете использовать ту же модель и заменить представление веб-интерфейсом.

  • Легко написать тесты для модели и вида, чтобы убедиться, что они работают так, как должны.

  • Как модель, так и представление часто могут использовать в своих интересах стандартные детали: массивы, карты, наборы, строки и другие контейнеры данных для модели; кнопки, элементы управления, текстовые поля, изображения, таблицы и другие для представления.

Калеб
источник
1
В оригинальной архитектуре MVC для настольных приложений представления были активными классами, непосредственно наблюдали за моделью и отключались от контроллера.
Кевин Клайн
Проблема со всеми ответами состоит в том, что существует столько же интерпретаций MVC, сколько людей публикуют. И перечисленные выше преимущества относятся только к одной конкретной интерпретации MVC. Если поместить большую часть логики в контроллер (или модель) и вызвать вызов View / инициировать определенные вызовы методов на контроллере, то это делает комбинацию Controller / Model автономной и очень многократно используемой. В большинстве случаев это новый взгляд, который необходим. У меня никогда не было необходимости повторно использовать представление. Даже ваш пример RSS может быть легко обработан с помощью нового представления, в котором используется старый вид с промежуточным слоем RSS.
Данк
2
@Dunk: жизненно важно отделить бизнес-логику от пользовательского интерфейса, чтобы бизнес-логика могла быть протестирована напрямую.
Кевин Клайн
@ Кевин: Я полностью согласен, бизнес-логика не принадлежит пользовательскому интерфейсу. Тем не менее, контроллер не должен быть частью пользовательского интерфейса. Вот что я имею в виду под множеством определений. В определении одного человека контроллер обрабатывает нажатия кнопок, в то время как другой человек помещает это как часть представления. Если представление знает, как превратить действия оператора (т. Е. Нажатия кнопок / выбор элементов) в запросы приложений, то контроллер / модель становятся очень многократно используемыми практически с любым пользовательским интерфейсом, который может включать графический интерфейс, консоль или сетевые интерфейсы.
Данк
1
@Dunk: Я полагаю, что вы можете называть все, что вам нравится, «контроллером», но в архитектуре MVC контроллер зависит и, следовательно, является частью пользовательского интерфейса.
Кевин Клайн
7

Существует много, много разных способов реализации этого общего шаблона проектирования, но основная идея состоит в том, чтобы разделить различные проблемы по мере необходимости. MVC - хорошая абстракция в том смысле, что:

Модель : Представляет эти данные, что бы это ни значило.
Представление : Представляет пользовательский интерфейс, что бы это ни значило.
Контроллер : Представляет клей, который вызывает взаимодействие этой модели и представления, что бы это ни значило.

Это чрезвычайно гибко, потому что это не определяет многое. Многие тратят большую часть пропускной способности, споря о том, что может означать каждый элемент, какие имена следует использовать вместо них, и должны ли на самом деле быть 3, 2, 4 или 5 компонентов, но при этом не хватает смысла. определенная степень.

Идея состоит в том, чтобы отделить разные «кусочки» логики, чтобы они не перекрывались. Держите ваши презентации вместе, ваши данные вместе, логику вместе, общение. И так далее. В определенной степени, чем меньше эти проблемные области перекрываются, тем легче делать с ними интересные вещи.

Это все, о чем ты действительно должен беспокоиться.

tylerl
источник
3
Клей, клей, мне нравится это определение, оно так правильно: вся модель должна быть названа MVG, и люди перестали бы чесать головы в поисках элегантности там, где ничего нет.
ZJR
1
+1 за «клей»; это также означает, что это та часть, которая лучше всего подходит для написания на языке сценариев (так как те, которые имеют тенденцию превосходить в склеивании).
Донал Феллоуз
@DonalFellows Мне нравится, что много думал. Что-то, что «склеивает» 2 разные сущности вместе, требует большой гибкости, которую продвигают слабо типизированные языки сценариев (например, JavaScript)
Zack Macomber
4

Все хорошие ответы пока. Мои два цента в том, что мне нравится думать о контроллере как о том, что он в первую очередь состоит из вопросов типа Что и где?

  • Меня спросили, можно ли переместить шахматную фигуру (вид) в x. Это
    разрешено? Я не уверен, но я знаю, где и у кого спросить (модель).
  • Что-то попросило меня сохранить мои данные. Как, черт возьми, я это делаю? Я знаю, где спросить, хотя! Как мы сохраняем данные или куда они сохраняются, я понятия не имею, но этот класс репозитория должен знать. Я перешлю это и позволю этому иметь дело с этим.
  • Я должен показать текущую позицию шахматной фигуры пользователю, в который она перенесла модель. не уверен, хочу ли я показать кусок как зеленый или желтый? Бах, кого это волнует, я знаю, что есть представление, которое может с этим справиться, поэтому я передам им данные, и они могут решить, как они будут показаны.

Эти маленькие фрагменты - примеры того, как я пытаюсь вспомнить абстракцию и концепцию, которую MVC пытается донести. Что, где и как мои три основных мыслительных процесса.

Что и где => Контроллер Как и когда => Модели и представления

По сути, мои действия контроллера, как правило, небольшие и компактные, и при чтении их иногда выглядят пустой тратой времени. При ближайшем рассмотрении они выступают в роли сигнальщика, направляя различные запросы соответствующим работникам, но сами не выполняют никакой реальной работы.

dreza
источник
2

Контроллер может помочь абстрагировать интерфейсы Представления и Модели, чтобы им не приходилось напрямую узнавать друг о друге. Чем меньше объект должен знать, тем более портативным и тестируемым он становится.

Например, Модель может воспроизводить другой экземпляр через один Контроллер. Или сетевой контроллер может соединить два объекта Views игрока вместе. Или это может быть тест Тьюринга, где никто не знает, какой.

hotpaw2
источник
2

Это действительно вступает в игру, когда вы имеете дело с обработчиками событий, но вам все еще нужен контроллер для обработки взаимодействий между представлением и моделью. В идеале вы не хотите, чтобы представление узнало что-либо о модели. Подумайте, хотите ли вы, чтобы jsp выполнял все вызовы базы данных напрямую? (Если это не что-то вроде поиска входа в систему.) Вы хотите, чтобы представление отображало данные и не имело никакой бизнес-логики, если только это не логика отображения представления, но не сама по себе бизнес-логика.

В GWT вы получаете более чистое разделение с MVP. В представлении нет бизнес-логики (если все сделано правильно). Презентатор действует как контроллер, а представление не знает модель. Данные модели просто передаются в представление.


источник
1

Document-View (то есть представление модели) - это стандартная модель для большинства приложений Windows, написанных на MFC, поэтому она должна работать во многих случаях.

Мартин Беккет
источник
1

Я понимаю роль модели и представления в шаблоне Model-View-Controller, но мне трудно понять, зачем нужен контроллер.

Вы уверены в этом? (По крайней мере, как первоначально описано). Суть модели - быть моделью предметной области. Предполагается, что представление отображает модель домена для пользователя. Контроллер должен отображать вход низкого уровня на модель высокого уровня. Насколько я могу судить, аргументация является чем-то вроде: A) высокого уровня использования SRP. Б) Модель считалась важной частью приложения, поэтому держите в ней неважные и быстро меняющиеся вещи. C) легко тестируемая (и способная на сценарии) бизнес-логика.

Подумайте, если вы хотите, чтобы ваша шахматная программа использовалась слепыми, поменяйте местами вид звуковой версии и контроллер, работающий с клавиатурой. Скажем, вы хотите добавить игры по почте, добавить контроллер, который принимает текст. Чистая версия игры? Контроллер, который принимает команды от сокета, сделал бы работу. Добавьте хороший 3D-рендеринг, классный новый вид. Нулевая модель меняет необходимые шахматы - это еще шахматы.

Если вы смешаете ввод с представлением модели, вы потеряете эту способность. Внезапно шахматы - это не шахматы, а шахматы с мышью, которые отличаются от шахмат с клавиатурой или сетевым подключением.

stonemetal
источник
0

Я думаю, что MVC тупой, возможно, в определенных областях он работает хорошо, но лично даже веб-сайты, которые я пишу, не подходят для mvc. Существует причина, по которой вы слышите внешний интерфейс, серверную часть и никогда не заканчиваете базу данных или что-то еще

ИМО должен быть API (бэкэнд) и приложение, которое использует API (веб-интерфейс). Я думаю, вы могли бы вызвать GET-запрос к контроллеру (который просто вызывает API-интерфейс бэкэнда) и html-представлению, но я обычно не слышал, чтобы люди говорили о представлении как о чистом html или как о модели как бэкэнд-API.

ИМО все должно быть сплошным API. На самом деле они не должны быть твердыми (как в чистом и хорошо построенном), но его внутренние компоненты должны оставаться закрытыми, и приложение / внешний интерфейс / за пределами API никогда не должно сообщать соединение с базой данных или иметь возможность выполнять необработанные запросы.

Теперь, если ваш код / ​​дизайн включает в себя клей хорошо. Если в вашей шахматной игре есть какая-то разметка, которую вы можете отредактировать для оформления GUI, графический интерфейс собирает координаты / ввод и вызывает MovePiece (srcPosition, dstPostion) (который может возвращать bool или enum, чтобы сказать, является ли это правильным ходом или нет ) и все в порядке со всей логикой в ​​модели, тогда обязательно назовите ее MVC. Тем не менее, я бы все-таки упорядочил вещи по классам и API и позаботился о том, чтобы не было кухонного класса, который бы затрагивал все (и никаких API, чтобы знать обо всем).


источник
Вы можете прислушиваться к своему мнению, но этот ответ не пытается ответить на вопрос ОП.
Калеб
0

Подумайте о браузере, который отображает статическую веб-страницу. Модель - это HTML. Вид - это фактический результат на экране.

Теперь добавьте немного JavaScript. Это Контроллер. Когда пользователь нажимает кнопку или перетаскивает что-то, что событие отправляется в JavaScript, он решает, что делать, и изменяет базовый HTML (модель), и браузер / средство визуализации отображает эти изменения на экране (вид).

Возможно, нажата другая кнопка, событие отправляется какому-либо обработчику (контроллеру), и это может вызвать запрос на отправку дополнительных данных в веб-сервис. Затем результат добавляется в HTML (модель).

Контроллер реагирует на события и контролирует, что находится в модели и, следовательно, что находится на экране / представлении.

Отступив немного назад, вы можете рассматривать весь браузер как представление, а сервер как контроллер, а данные - как модель. Когда пользователь нажимает кнопку в браузере на событие, которое он отправил на сервер (контроллер), он собирает ресурсы в виде HTML-страницы (модель) и отправляет их обратно в браузер для отображения (вид)

Внизу на сервере, будь то asp, php или java, 'code' (Controller) получает событие click и запрашивает базу данных или хранилище документов (Model) и создает HTML. С точки зрения сервера, результатом всех его действий является представление (HTML) базового хранилища данных (модель). Но с точки зрения клиента результатом его запроса к серверу является его модель (HTML)

Даже если вы перемешаете свой JavaScript в своем HTML или свой PHP в своем HTML, модель, представление, контроллер все еще существует. Даже если вы думаете о своем запросе к серверу и ответе от сервера как о простой улице с двусторонним движением, все равно есть Модель, Представление и Контроллер.

Зевс
источник
-2

По моему опыту, в традиционной настольной программе mvc gui контроллер заканчивается спагеттизацией. Большинство людей не тратят время на выделение класса контроллера.

книга банды четырех говорит:

Шаблоны проектирования в Smalltalk MVC

Триада классов Model / View / Controller (MVC) [KP88] используется для создания пользовательских интерфейсов в Smalltalk-80. Просмотр шаблонов проектирования внутри MVC должен помочь вам понять, что мы подразумеваем под термином «шаблон».

MVC состоит из трех видов объектов. Модель - это объект приложения, представление - это экранное представление, а контроллер определяет, как пользовательский интерфейс реагирует на ввод данных пользователем. До MVC проекты пользовательского интерфейса обычно объединяли эти объекты. MVC разъединяет их для повышения гибкости и повторного использования.

MVC разделяет представления и модели, устанавливая между ними протокол подписки / уведомления. Представление должно гарантировать, что его внешний вид отражает состояние модели. Всякий раз, когда данные модели изменяются, модель уведомляет представления, которые зависят от нее. В ответ каждое представление получает возможность обновить себя. Этот подход позволяет вам присоединить несколько представлений к модели, чтобы обеспечить различные презентации. Вы также можете создавать новые виды для модели, не переписывая ее.

Следующая диаграмма показывает модель и три вида. (Мы упустили контроллеры для простоты.) Модель содержит некоторые значения данных, и представления, определяющие электронную таблицу, гистограмму и круговую диаграмму, отображают эти данные различными способами. Модель связывается со своими представлениями при изменении значений, и представления связываются с моделью для доступа к этим значениям.

Взятый за чистую монету, этот пример отражает дизайн, который разделяет представления от моделей. Но дизайн применим к более общей проблеме: разъединение объектов так, что изменения одного могут повлиять на любое количество других, не требуя, чтобы измененный объект знал детали других. Этот более общий дизайн описывается шаблоном проекта Observer (стр. 293).

Другая особенность MVC заключается в том, что представления могут быть вложенными. Например, панель управления кнопками может быть реализована как сложное представление, содержащее вложенные представления кнопок. Пользовательский интерфейс для инспектора объектов может состоять из вложенных представлений, которые можно повторно использовать в отладчике. MVC поддерживает вложенные представления с классом CompositeView, подклассом View. Объекты CompositeView действуют так же, как объекты View; составное представление может использоваться везде, где оно может использоваться, но оно также содержит вложенные представления и управляет ими.

Опять же, мы можем думать об этом как о дизайне, который позволяет нам рассматривать составное представление так же, как мы рассматриваем один из его компонентов. Но дизайн применим к более общей проблеме, которая возникает всякий раз, когда мы хотим сгруппировать объекты и рассматривать группу как отдельный объект. Этот более общий дизайн описан с помощью шаблона проектирования Composite (163). Это позволяет вам создать иерархию классов, в которой некоторые подклассы определяют примитивные объекты (например, Button), а другие классы определяют составные объекты (CompositeView), которые собирают примитивы в более сложные объекты.

MVC также позволяет вам изменить способ, которым представление реагирует на ввод пользователя, не изменяя его визуальное представление. Например, вы можете изменить способ реагирования на клавиатуру или использовать всплывающее меню вместо командных клавиш. MVC инкапсулирует механизм ответа в объекте Controller. Существует иерархия классов контроллеров, облегчающая создание нового контроллера в качестве варианта существующего.

Представление использует экземпляр подкласса Controller для реализации конкретной стратегии ответа; Чтобы реализовать другую стратегию, просто замените экземпляр на контроллер другого типа. Можно даже изменить контроллер представления во время выполнения, чтобы позволить представлению изменить способ, которым он реагирует на ввод пользователя. Например, представление можно отключить, чтобы оно не принимало ввод, просто предоставив ему контроллер, который игнорирует входные события.

Отношение View-Controller является примером шаблона проектирования Strategy (315). Стратегия - это объект, представляющий алгоритм. Это полезно, когда вы хотите заменить алгоритм статически или динамически, когда у вас много вариантов алгоритма или когда алгоритм имеет сложные структуры данных, которые вы хотите инкапсулировать.

MVC использует другие шаблоны проектирования, такие как Factory Method (107), чтобы указать класс контроллера по умолчанию для представления, и Decorator (175), чтобы добавить прокрутку к представлению. Но основные отношения в MVC задаются шаблонами проектирования Observer, Composite и Strategy.

Рэй Тайек
источник
1
Похоже, весь этот пост минус первые два абзаца взяты дословно из Design Patterns . Я отформатировал этот раздел как цитату, чтобы читатели это понимали - отредактируйте, если я цитировал абзацы, которые принадлежат вам.
Калеб
1
Я должен не согласиться с вашим мнением о том, что «диспетчер оказывается спагеттизованным в поле зрения». Возможно, это зависит от используемой платформы и среды, но в программировании Cocoa и Cocoa Touch гораздо чаще создают соответствующие контроллеры, чем пропускают их. Если программист Objective-C опускает одну из категорий, почти наверняка это будет страдающая модель.
Калеб
Если вы согласны с тем, что это «правильная» интерпретация MVC, то MVC абсолютно ничего не покупает. Это может быть просто MV и опускание C, потому что каждый раз, когда вы создаете новое представление, вам также необходимо создать новый контроллер. Так какой смысл в том, чтобы прилагать усилия, чтобы отделить их, кроме как по теоретическим причинам разделения интересов.
Данк