Как стать автором
Обновить

Комментарии 22

Для меня утверждения, что сервис и репозиторий — это модель, и соответственно модель должна хранить бизнес-логику звучат диковато. Я бы сказал, что у меня эти понятия вообще находятся в разных слоях проекта. Модель (ViewModel) — слой с веб-сайтом, сервис — слой с бизнес-логикой, репозиторий — слой DAL.
Также не понял, зачем представлению знать как именно модель сохраняет свое состояние? По мне так представлению должно быть глубоко без разницы, откуда модель берет свои данные и куда девает
Вы что-то путаете
Представление знает абсолютно все о модели, кроме того, как именно она сохраняет свои состояния


Модель — это не только класс/структура с функциональностью объекта Model/ActiveRecord или какой еще там. Я привык использовать термины «моделирование данных» и «моделирование приложения». От сюда и ее обязанности.

Модель заказов обязана хранить логику и ограничения заказов в интернет-магазине.

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

Если ваш репозиторий реализует паттерн итератор или позволяет получить все хранимые объекты, сам хранит в себе массив моделей, и имеет состояние (данные о своих моделях), то его, вполне, можно использовать как модель в представлении. Он не многим отличается от DataProvider объектов в таком случае.

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

В одном из моих приложений существует модель, которая хранит состояния между запросами по средством кук. Куки считываются при каждом запросе. По внутренним правилам модель заполняется данными, которые зависят от кук. Несколько сервисов из doman logic layer зависят от того какие данные хранятся в модели. Но я нигде не отображаю данную модель. Модель может проверять куки, потому что именно модели ответственны за валидацию. И все на своих местах.

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

А вот Microsoft считает с точностью да наоборот) По крайней мере нигде у них в примерах не видел бизнес логику в модели. Максимум — правила валидации для полей. Да и в моем понимании нельзя мешать бизнес-логику, валидацию и управление данными в одной модели (у вас же это один класс?). Может я что-то не понял, покажите вашу модель на этой картинке
image
Очень советую прочитать вам замечательную статью habrahabr.ru/post/175465/, которая является переводом blog.astrumfutura.com/2008/12/the-m-in-mvc-why-models-are-misunderstood-and-unappreciated/

Большинство (если не все) фреймворков опускают модели до уровня доступа к данным. Модели очень сильно недооценены в примерах и гайдах. И уж на один источник, типа Microsoft, я бы не ровнялся. Я изучил множество источников, лучших практик и сам классический паттерн от «банды четырех». Уж создатели паттерна понимают лучше для чего он предназначался, чем Microsoft.

Да и в моем понимании нельзя мешать бизнес-логику, валидацию и управление данными в одной модели (у вас же это один класс?)

Для валидации используются объекты-валидаторы. Бизнес-логика конкретной предметной области, за которую отвечает модель, лежит именно в модели, верно.
За что минусы? За то, что Microsoft учит делать тонкие модели www.asp.net/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-4 и толстые контроллеры www.asp.net/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-9?
За то, что пропагандирует использовать модели только для DataAccess и отображения в представлении? Оооок.

Вы когда-нибудь пробовали писать тесты для контроллера? Или может Вы можете легко инстанцировать контроллер вне приложения, без запуска всего MVC стека, перехватчиков запросов и помощников действий? Я пробовал. Это ад. Контроллеры зависимы от своих приложений и фреймворков на которых они написаны — модели нет. Вы пытались писать сервисы, где надо будет уверенным в корректности передаваемых данных? Неужели свою проверку данных сделать легче чем использовать магию моделей? Сколько языков и фреймворков Вы попробовали? C# и ASP .NET? Кто-то ковырял Revel(golang), Play/Spring(Java), Yii/Kohana/Laravel/Zend(PHP), Rails(Ruby)? Я уже не говорю про миллионы фреймворков для JS. Из одного туториала и примеров использования одного фреймворка делаем выводы по всему паттерну и игнорируем кучи трудов в интернете и на бумаге? Ооок, минусуйте дальше.
Тише-тише, я вас не минусил) В программировании нет четких понятий «правильно» или «неправильно», каждый использует тот подход, который ему ближе. За себя просто скажу, что мне подход Microsoft ближе, чем тот, который описываете вы. Мне не нравится когда модель содержит бизнес логику, т.к. она у меня содержится и обрабатывается в отдельном слое специальными сервисами. А модель — это просто класс с данными, описывающими объект. Может, с опытом мое мнение и поменяется.
Кстати, если контроллер написан грамотно с использованием DI, то трудностей с его тестированием (Mock объекты) возникнуть не должно
Я понимаю что это были не Вы).
Тут проблема терминологии. Я понимаю под моделью все что сохраняет состояние и может быть использовано для абстрактного моделирования приложения, а не то что наследуется от класса/структуры Model/CModel/TypeModel/ActiveRecord::Base и какие там еще бывают Model и AR.

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

github.com/jinzhu/gorm тут лежит прекрасный ORM для Golang, который похож на Ваш подход, но это только в контексте ORM, а не фреймворка.

Лично мне всегда был ближе подход user.login() чем userService.login(&user);
Business Logic Layer.

Data Access, в идеальном мире, осуществляется через ORM, который выстреливает заполненными моделями, а не сама модель занимается выборкой данных по привязанной таблице/файлу (исключение — паттерн ActiveRecord).
Насколько я понял, вы и предлагаете использовать модель как ActiveRecord? Как вы сделаете выборку всех активных пользователей?
var userModel = new UserModel();
var activeUsers = userModel.GetActiveUsers();

Так?

А валидацию модели пользователя и добавление его в базу?
Насколько я понял, вы и предлагаете использовать модель как ActiveRecord?

Нет. Это лишь один из возможных вариантов.

Как вы сделаете выборку всех активных пользователей?

Лучше всего использовать предопределенные скоупы объектов запроса. Только к моделированию это почти не относится. Скорее к зонам видимости. Если разговор о них, то да. Модель или скоупы должны знать как именно взять активных пользователей, а контроллер/виджет/сервис знают только то, что они хотят получить активных пользователей, не имея представления как это происходит и откуда идет чтение: база/файл.

activeUsers = UserModel.find().active().all()


А валидацию модели пользователя и добавление его в базу?

user.validate // - валидация
user.save // - сохранение

Метод validate вызывает все зарегистрированные валидаторы.
Метод save сохраняет состояние в базу/файл/посылает на удаленный сервер.
я вас понял, спасибо
Только сейчас дошло. Вы говорили о ViewModel, но Model и ViewModel — это разные вещи. VM используется вместо контроллера в паттерне MVVM и предназначена, в первую очередь, для SPA, десктопов и мобильных приложений. Более того VM — это Presentation Logic Layer.
VM используется вместо контроллера в паттерне MVVM

Совершенно не обязательно, что только там. Я вот, например, использую ViewModel в проектах ASP.NET MVC. И представляет оно собой модель данных для представления, а также может содержать некоторые методы, которое представление будет использовать (например, получение списков, отображаемых в представлении). А это противоречит вашему подходу: вы из контроллера передаете полную модель данных, а я только те данные, которые будут нужны представлению.
Я вот, например, использую ViewModel в проектах ASP.NET MVC.

Либо Вы мешаете два паттерна, либо используете MVVM.

В любом случае, как я уже сказал, VM и M нельзя сравнивать, это разные вещи.

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

Я такого не говорил. Я передаю из контроллера то что контроллер может передать и настоятельно рекомендую не связывать знание данных, необходимых для представления, с контроллером. Более того для операций чтения можно не использовать контроллер, контроллер предназначен для обработки пользовательского ввода, что в классическом MVC, что в Модели 2.
а в случае скриптовых языков и вовсе умирает до следующего запроса
Это справедливо только для PHP. Python, Ruby, Node.js — все это живет, даром, что скриптовое.
Пожалуй, Вы правы. Изменю эту момент в статье.
Справедливо для большинства кода на PHP, но не для всего. Напишу на днях статью об этом.
Вообще самое большое заблуждение в MVC когда в контроллере return render();
А как же V?
Модель это обмен данными с БД и т.п.
Контроллер логика обработки этих данных и подготовка к View
Так какого хрена все суют View в контроллер? Это уже нативный MvC получается
Контроллер должен тоже вернуть подготовленный для View массив данных (final class V будет уже рендерить и т.п.), а не «html»!

Потом разработчикам тяжело гибко манипулировать контроллерами, когда на его выходе html уже. Зачем он мне надо? Может я хочу получить для своего контроллера класса данные «стандартного» контроллера engine (чтобы не писать свой код получения их) и отправить измененные данные на View
промахнулся с ответом.
Модель это обмен данными с БД и т.п.
Контроллер логика обработки этих данных и подготовка к View

Это не верно.
Обменом данными с БД занимается объект базы данных, или чаще DAO. Модель может взаимодействовать с этим объектом путем построения запросов и предоставлять интерфейс типа find/save как верхний уровень абстракции.

Контроллер должен только обработать пользовательский запрос и вызывать методы модели, если того требует запрос. Никаких подготовок для View. Контроллер не должен знать что нужно V для отображения. Он должен отдать то, что может. Построение пользовательского интерфейса — это уже задача View, и больше никто не должен заботиться о данных необходимых для V кроме как сам V. Тут нам помогают виджеты, помощники видов и прочие магические бесы.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации