Что входит в «Контроллер» в «MVC»? - PullRequest
177 голосов
/ 19 июня 2009

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

Допустим, например, у меня довольно простое приложение (я специально думаю о Java, но я полагаю, что те же принципы применимы и в других местах). Я организую свой код в 3 пакета, которые называются app.model, app.view и app.controller.

В пакете app.model у меня есть несколько классов, которые отражают реальное поведение приложения. Они extends Observable и используют setChanged() и notifyObservers(), чтобы активировать представления для обновления при необходимости.

В пакете app.view есть класс (или несколько классов для разных типов отображения), который использует компоненты javax.swing для обработки отображения. Некоторые из этих компонентов должны быть возвращены в модель. Если я правильно понимаю, представление не должно иметь ничего общего с обратной связью - с этим должен справиться Контроллер.

Так что я на самом деле вставляю в контроллер? Поместить ли public void actionPerformed(ActionEvent e) в представление просто вызовом метода в контроллере? Если да, следует ли выполнять какие-либо проверки и т. Д. В контроллере? Если да, то как я могу отправить сообщения об ошибках обратно в View - это должно пройти через Модель снова, или Контроллер должен просто отправить его обратно в View?

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

Извините за длинный вопрос, я просто хотел документировать свое понимание процесса, и, надеюсь, кто-то может прояснить этот вопрос для меня!

Ответы [ 13 ]

481 голосов
/ 19 июня 2009

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

В форме разговора:

Просмотр : «Эй, контроллер, пользователь только что сказал мне, что хочет удалить элемент 4».
Контролер : "Хм, проверив свои учетные данные, ему разрешено это сделать ... Эй, модель, я хочу, чтобы ты получил элемент 4 и сделал все, что ты делаешь, чтобы удалить его."
Модель : "Элемент 4 ... получил его. Он удален. Обратно к вам, Контроллер."
Контроллер : "Здесь я соберу новый набор данных. Обратно к вам, просмотр."
Просмотр : "Круто, я покажу пользователю новый набор."

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

64 голосов
/ 19 июня 2009

Проблема с MVC заключается в том, что люди думают, что вид, контроллер и модель должны быть максимально независимыми друг от друга. Они не - видение и контроллер часто переплетаются - воспринимают это как M(VC).

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

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

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

Представьте себе вид без контроллера, например, кто-то в другой комнате в сети в другой комнате наблюдает за положением робота, когда координаты (x, y) текут по консоли прокрутки. Этот вид просто отображает состояние модели, но у этого парня нет контроллера. Опять же, легко представить это представление без контроллера.

Подумайте о контроллере без представления, например, кто-то заперся в шкафу с радиоуправлением, настроенным на частоту робота. Этот контроллер отправляет входные данные и вызывает переходы состояний, не имея представления о том, что они делают с моделью (если что-либо). Легко представить, но не очень полезно без какой-либо обратной связи с представлением.

Наиболее удобный пользовательский интерфейс координирует представление с контроллером, чтобы обеспечить более интуитивно понятный пользовательский интерфейс. Например, представьте себе представление / контроллер с сенсорным экраном, показывающее текущее положение робота в 2-D и позволяющее пользователю коснуться точки на экране, которая как раз оказывается перед роботом. Контроллеру нужны подробности о представлении, например, положение и масштаб области просмотра, а также положение точки, которой коснулись пикселя, относительно положения пикселя робота на экране), чтобы правильно интерпретировать это (в отличие от парня, запертого в шкафу с радиоконтроллером).

Я уже ответил на ваш вопрос? : -)

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

... должна быть любая проверка и т. Д. сделано в контроллере? Если да, то как Я возвращаю сообщения об ошибках обратно в Просмотр - должен ли это пройти через Модель снова, или должен контроллер просто отправить его обратно в View?

Если проверка выполняется в представлении, что мне поставить в контроллере?

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

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

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

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

23 голосов
/ 19 июня 2009

Вот хорошая статья по основам MVC.

В нем говорится ...

Контроллер - контроллер переводит взаимодействие с целью действия, которые должны быть выполнены моделью.

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

Есть еще одна хорошая статья на Фаулере .

16 голосов
/ 01 сентября 2009

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

9 голосов
/ 19 июня 2009

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

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

9 голосов
/ 19 июня 2009

Исходя из вашего вопроса, у меня складывается впечатление, что вы немного помутнели над ролью Модели. Модель фиксируется на данных, связанных с приложением; если у приложения есть база данных, работа модели будет заключаться в том, чтобы общаться с ней. Он также будет обрабатывать любую простую логику, связанную с этими данными; если у вас есть правило, которое говорит, что для всех случаев, когда TABLE.foo == "Ура!" и TABLE.bar == "Huzzah!" затем установите TABLE.field = "W00t!", затем вы хотите, чтобы модель позаботилась об этом.

Контроллер - это то, что должно обрабатывать основную часть поведения приложения. Итак, чтобы ответить на ваши вопросы:

«Поместить ли я открытый void actionPerformed (ActionEvent e) в представление просто с помощью вызова метода в контроллере?»

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

«Если это так, следует ли выполнять какие-либо проверки и т. Д. В контроллере?»

Основная часть вашей проверки действительно должна быть сделана Контроллером; он должен ответить на вопрос о том, являются ли данные действительными, а если нет, направить соответствующие сообщения об ошибках в представление. На практике вы можете включить несколько простых проверок работоспособности в слой View для улучшения взаимодействия с пользователем. (Я думаю в первую очередь о веб-средах, где вы можете захотеть, чтобы сообщение об ошибке появлялось в тот момент, когда пользователь нажимает «Отправить», а не ждать полного цикла отправки -> процесса -> загрузки страницы, прежде чем сообщить им, что они облажались .) Просто будь осторожен; Вы не хотите дублировать усилия больше, чем нужно, и во многих средах (опять же, я думаю о сети) вам часто приходится обрабатывать любые данные, поступающие из пользовательского интерфейса, как пачку грязной грязи ложь, пока вы не подтвердите, что это действительно законно.

«Если это так, как я могу отправить сообщения об ошибках обратно в View - это должно пройти через Модель снова, или Контроллер должен просто отправить его обратно в View?»

У вас должен быть установлен некоторый протокол, в котором View не обязательно будет знать, что будет дальше, пока контроллер не сообщит об этом. Какой экран вы показываете после того, как пользователь нажимает эту кнопку? Представление может не знать, и контроллер может не знать, пока он не просмотрит данные, которые он только что получил. Это может быть «Перейти к другому экрану, как и ожидалось» или «Оставаться на этом экране и отображать это сообщение об ошибке».

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

«Если проверка выполняется в представлении, что я помещаю в контроллер?»

см. Выше; реальная проверка должна быть в контроллере. И, надеюсь, у вас есть некоторое представление о том, что уже нужно поместить в контроллер. : -)

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

7 голосов
/ 19 июня 2009

Контроллер действительно является частью View. Его задача - выяснить, какие службы необходимы для выполнения запроса, разархивировать значения из представления в объекты, необходимые для интерфейса службы, определить следующее представление и преобразовать ответ обратно в форму, которую может использовать следующее представление. , Он также обрабатывает любые возникающие исключения и отображает их в представления, понятные пользователям.

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

Сервис-ориентированный: вот где работа сделана.

3 голосов
/ 19 июня 2009

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

Я придумал это после работы с веб-приложением большого размера, написанным разработчиками, которые думали, что они понимают MVC, но на самом деле этого не сделали. Их «контроллеры» сводятся к восьми строкам вызова методов статического класса, которые обычно нигде не вызываются: / / делают свои модели немного больше, чем способы создания пространств имен. Правильное рефакторинг делает три вещи: переводит весь SQL на уровень доступа к данным (он же модель), делает код контроллера более многословным, но гораздо более понятным и сводит на нет старые файлы «модели». : -)

3 голосов
/ 19 июня 2009

Контроллер предназначен прежде всего для координации между видом и моделью.

К сожалению, иногда это смешивается с представлением - в небольших приложениях, хотя это не так уж и плохо.

Я предлагаю вам поставить:

public void actionPerformed(ActionEvent e)

в контроллере. Тогда ваш слушатель действия, по вашему мнению, должен делегировать контроллеру.

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

Я бы определенно рекомендовал взглянуть на Passive View и Supervising Presenter (это, по сути, разделение Model View Presenter - по крайней мере, Фаулером). См:

http://www.martinfowler.com/eaaDev/PassiveScreen.html

http://www.martinfowler.com/eaaDev/SupervisingPresenter.html

1 голос
/ 19 июня 2009

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

В любом случае, правильная реализация MVC будет иметь только следующие взаимодействия: Модель -> Вид Вид -> Контроллер Контроллер -> Вид

Единственное место, где может быть другое взаимодействие, - это если вы используете наблюдателя для обновления представления, тогда представление должно будет запросить у контроллера информацию, которая ему нужна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...