Инициализировать коллекцию можно не только элементом или перечислением. Можно сделать метод Add, принимающий любой тип и использовать значения этого типа в инициализаторе. Правда можно напороться на то, что компилятор не может определить, какой из Add-методов использовать, если их типы имеют что-то общее.
Самый простой пример — сообщение об ошибке или любое другое сервисное представление, которое показывается через return View("%ViewName%");. Некоторые из них тоже нуждаются в каких-то данных.
А так же частичные представления, которые вызываются из остальных, и показываются на многих страницах.
Если запрос был именно таким, то это частный случай, когда контроллеру только и остается, как передать управление представлению. Нормальная ситуация.
Если же запрос был каким-то другим, например, «сохранить профиль пользователя», то контроллер сначала повоздействует на модель, и по успеху операции решит, «Отрендерить профиль пользователя с id=2» или показать сообщение об ошибке.
Не факт.
Во-первых, если эта логика будет в контроллере, там же будет находиться еще оповещение модели о действии пользователя и, возможно, предварительная валидация входных данных.
Во-вторых, если это представление используется в нескольких действиях контроллера или даже в нескольких контроллерах, то при изменении логики отображения приходится переписывать тесты для всех затронутых действий (нарушение SRP в действии).
Если в контракте сервиса указано, что он может бросать такие-то исключения, и это нормально, то можно ловить их прямо в представлении (если мы можем показать вместо этих данных какую-то альтернативу).
Если же нет, можно воспользоваться перегрузкой метода OnException контроллера:
А как бы вы отнеслись к простому модульному тестированию класса-предка представления, если не делать его абстрактным, и всю логику поместить в него? Ведь Razor по большому счету просто добавляет метод рендеринга шаблона.
Как раз, если представление сможет само позаботиться о себе, контроллер перестанет делать эту работу за него. И у него останется вполне себе понятная задача: изменить состояние модели (если это нужно) и выбрать представление для показа.
На счет споров — да, отходить от шаблона можно, ничего такого в этом нет, это может быть нужно по разным причинам. Я здесь не для споров, а для того, чтобы помочь кому-то посмотреть глубже в эту абстракцию, увидеть ее суть.
Да, кстати, именно по этому строение модели всегда поверхностно освещается при обсуждении MVC. Нет каких-то законов, говорящих, какой ей быть, кроме предоставления API
Полнофункциональная модель — это когда в ней есть функционал для всех возможных действий над ней. Есть счет — должен быть какой-то класс-менеджер, или что-то иное, с помощью которого можно этот счет открыть, закрыть, пополнить, получить какие-то связанные с ним данные и т.п.
Конечно, в представлении логика есть, просто обычно она предельно упрощена. Нет смысла запрещать ей быть сложнее.
По поводу контроллера как конечной точки маршрутизации — да, в общем описании шаблона нет таких слов, но здесь я везде указываю уточнение «в веб-разработке», а в ней это именно так.
Да, я понимаю. Я разбирал этот шаблон (и других его родственников) достаточно глубоко, и не только в вебе. Конкретно — в десктопных приложениях и в игровой архитектуре. Но это тема для отдельной статьи.
Хм, да, вы правы. Используется Model 2. Но разве вам не кажется, что у него есть изъяны?
По поводу тестирования — зависимости, которые внедряются в эти слои, обычно тестируются отдельно, а View тестируется через связку виртуального браузера и Page Object Pattern
Согласен с вами. Не совсем применимо. Да, примерно здесь как раз и находится основная несостыковка этого шаблона и их реализации. Тем не менее приблизиться к шаблону можно, и я показываю, как. Приходится писать класс-предок представления или использовать Helper-классы из слоя View. Будет хорошо, если в следующих версиях фреймворка это будет проще. Но достигаемое разделение ответственности между слоями сыграет хорошую службу, повысит тестируемость и гибкость приложения.
Да, извините. Я руководствуюсь такой схемой:
М — полнофункциональная модель предметной области. Не имеет связи ни с контроллером, ни с представлением.
V — средство отображения, кроме шаблонов обладающее собственной логикой (порой и сами шаблоны не нужны, если вывод происходит в других форматах). Имеет связь с моделью, но обычно только на извлечение данных. И имеет связь с контроллерами (конкретно здесь не напрямую, а через запрос и его маршрутизацию).
C — набор действий — конечных точек маршрутизации. Имеет связь с моделью: переводит действие пользователя на её язык, и связь с представлением: выбирает, какое нужно отобразить.
Да, MVC не очень хорош для веба. По большому счету тут могут быть полезны разные подходы. Можно ведь делать и одностраничное приложение с логикой представления полностью вынесенной в браузер, оставив на сервере только REST-API. Но чаще хорошо подходят гибридные решения.
Инициализировать коллекцию можно не только элементом или перечислением. Можно сделать метод
Add
, принимающий любой тип и использовать значения этого типа в инициализаторе. Правда можно напороться на то, что компилятор не может определить, какой изAdd
-методов использовать, если их типы имеют что-то общее.Самый простой пример — сообщение об ошибке или любое другое сервисное представление, которое показывается через
return View("%ViewName%");
. Некоторые из них тоже нуждаются в каких-то данных.А так же частичные представления, которые вызываются из остальных, и показываются на многих страницах.
Вы ведь манипулируете моделью прежде, чем отобразить представление?
Мы с вами это уже обсуждали в другой ветке. Это сбор представлением всех недостающих данных и их подготовка к вставлению в шаблон.
Если же запрос был каким-то другим, например, «сохранить профиль пользователя», то контроллер сначала повоздействует на модель, и по успеху операции решит, «Отрендерить профиль пользователя с id=2» или показать сообщение об ошибке.
Во-первых, если эта логика будет в контроллере, там же будет находиться еще оповещение модели о действии пользователя и, возможно, предварительная валидация входных данных.
Во-вторых, если это представление используется в нескольких действиях контроллера или даже в нескольких контроллерах, то при изменении логики отображения приходится переписывать тесты для всех затронутых действий (нарушение SRP в действии).
Если в контракте сервиса указано, что он может бросать такие-то исключения, и это нормально, то можно ловить их прямо в представлении (если мы можем показать вместо этих данных какую-то альтернативу).
Если же нет, можно воспользоваться перегрузкой метода
OnException
контроллера:На счет споров — да, отходить от шаблона можно, ничего такого в этом нет, это может быть нужно по разным причинам. Я здесь не для споров, а для того, чтобы помочь кому-то посмотреть глубже в эту абстракцию, увидеть ее суть.
Конечно, в представлении логика есть, просто обычно она предельно упрощена. Нет смысла запрещать ей быть сложнее.
По поводу контроллера как конечной точки маршрутизации — да, в общем описании шаблона нет таких слов, но здесь я везде указываю уточнение «в веб-разработке», а в ней это именно так.
Да, я понимаю. Я разбирал этот шаблон (и других его родственников) достаточно глубоко, и не только в вебе. Конкретно — в десктопных приложениях и в игровой архитектуре. Но это тема для отдельной статьи.
По поводу тестирования — зависимости, которые внедряются в эти слои, обычно тестируются отдельно, а View тестируется через связку виртуального браузера и Page Object Pattern
М — полнофункциональная модель предметной области. Не имеет связи ни с контроллером, ни с представлением.
V — средство отображения, кроме шаблонов обладающее собственной логикой (порой и сами шаблоны не нужны, если вывод происходит в других форматах). Имеет связь с моделью, но обычно только на извлечение данных. И имеет связь с контроллерами (конкретно здесь не напрямую, а через запрос и его маршрутизацию).
C — набор действий — конечных точек маршрутизации. Имеет связь с моделью: переводит действие пользователя на её язык, и связь с представлением: выбирает, какое нужно отобразить.