Должна ли модель быть просто структурами данных? Где в MVC находятся сервисы (доступ к данным, бизнес-логика)?
Предположим, у меня есть представление, которое показывает список заказов клиентов. У меня есть класс контроллера, который обрабатывает щелчки по элементам управления представлением (кнопкам и т. д.).
Должен ли контроллер запускать код доступа к данным? Подумайте, нажмите кнопку, перезагрузите запрос заказа. Или это вообще должно проходить через слой модели?
Любой пример кода был бы отличным!





Представление будет передавать то, что должно произойти при щелчке в пользовательском интерфейсе, на уровень управления, который будет содержать ВСЮ бизнес-логику, и, в свою очередь, будет вызывать уровень модели, который будет только выполнять вызовы базы данных. Только уровень модели должен выполнять вызовы базы данных, иначе вы лишитесь цели шаблона проектирования MVC.
Подумайте об этом таким образом. Допустим, вы меняете свою базу данных. Вы хотели бы ограничить количество требуемых изменений кода и сохранить все эти изменения вместе, не затрагивая другие части вашего приложения. Таким образом, сохраняя весь доступ к данным на уровне модели, даже простые вызовы, вы ограничиваете любые изменения, необходимые для уровня модели. Если бы вам пришлось по какой-либо причине обойти уровень модели, вам бы теперь пришлось распространить любые необходимые изменения на любой код, который знает о базе данных, что сделало бы такое обслуживание более сложным, чем должно быть.
Мне нравится сохранять «контракты» или интерфейсы для сохранения модели или доступа к сервисам на уровне домена (модели). Я помещаю реализации доступа к данным или вызовов служб на другом уровне.
Контроллеры создаются с помощью конструкторов, которые принимают интерфейсы для служб, например ISomeService в качестве параметров. Сами контроллеры не знают, как реализованы уровни обслуживания, но они могут получить к ним доступ. Тогда я легко могу заменить SqlSomeService или InMemorySomeService.
Я также довольно доволен конкретной реализацией службы, которая принимает репозиторий уровня домена (модели) в качестве параметра для своего конструктора. Например: ICatalogRepository с SqlServerCatalogRepositry: ICatalogRepository передается CatalogService (ICatalogRepository, ISomeOtherDependency).
Такое разделение проще с фреймворками внедрения зависимостей.
Обычно я реализую MVC следующим образом:
Просмотр - получает данные от контроллера и генерирует вывод. Обычно здесь должна отображаться только логика отображения. Например, если вы хотите взять существующий сайт и создать его версию для мобильных устройств / iPhone, вы должны иметь возможность сделать это, просто заменив представления (при условии, что вам нужна такая же функциональность).
Модель - доступ к данным в моделях. В моих приложениях весь SQL находится на уровне модели, прямой доступ к данным в представлениях или контроллерах запрещен. Как указывает Эли в другом ответе, идея здесь состоит в том, чтобы (по крайней мере частично) изолировать ваши контроллеры / представления от изменений в структуре базы данных. Модели также являются хорошим местом для реализации такой логики, как обновление даты «последнего изменения» при каждом изменении поля. Если основным источником данных для вашего приложения является внешний веб-сервис, подумайте, нужно ли переносить его в класс модели.
Контроллеры - используются для склеивания моделей и представлений. Реализуйте здесь логику приложения, проверяйте формы, передавайте данные из моделей в представления и т. д.
Например, в моих приложениях, когда запрашивается страница, контроллер будет извлекать любые данные, которые требуются от моделей, и передавать их представлению для создания страницы, которую видит пользователь. Если эта страница была формой, она может быть отправлена, контроллер выполняет проверку, создает необходимую модель и использует ее для сохранения данных.
Если вы последуете этому методу, модели станут довольно универсальными и пригодными для повторного использования. Ваши контроллеры имеют управляемый размер и сложность, потому что доступ к данным и отображение были удалены для моделей и представлений соответственно, а ваши представления должны быть достаточно простыми, чтобы дизайнер (после небольшого обучения) мог их понять.
Подумайте об объекте или службе доступа к данным, внедренной в ваш контроллер, тогда ваш контроллер не пострадает от изменений в базе данных.
как насчет включения валидации в модель? Я думал о том, чтобы модель проверяла и сохраняла данные или аннулировала, создавала список нарушений (опять же в рамках модели), терпела неудачу при сохранении и возвращала модель (через контроллер) обратно в представление для исправления - любые предложения ?
Я бы не стал помещать код доступа к данным в контроллер.
Чтобы опираться на то, что уже было сказано, важно подумать о наложении слоев ВНУТРИ слоев. Например, у вас, вероятно, будет несколько уровней внутри самой модели - уровень доступа к данным, который выполняет любой доступ к ORM и базе данных, и более абстрактный уровень, который представляет бизнес-объекты (без каких-либо знаний о том, КАК получить доступ к их данным).
Это позволит вам легче тестировать компоненты вашей системы, поскольку она поддерживает имитацию.
@ak, я попытался отредактировать это, чтобы улучшить вопрос, включая добавление лучшего заголовка. Пожалуйста, не стесняйтесь улучшать мои правки :-)