Основная проблема здесь — сцепление. Идея модели, которая является буквой "M" в "MVC", заключается в том, что она не имеет внешних зависимостей. Это «ядро» вашего приложения. Дерево зависимостей хорошо спроектированной архитектуры приложения должно выглядеть примерно так:
+---------------------------------------> Views
| |
| |
| v
Controllers ----+-> Model Transformer -----> View Model
| \ |
| \ |
v \ v
Data Access <---- Persistence --------> Domain Model
| /
| /
v /
Mapper ------+
Теперь я понимаю, что не совсем убедительно просто сказать «вот архитектура, это то, что вы должны использовать», поэтому позвольте мне объяснить, что здесь происходит:
- Контроллер получает запрос.
- Контроллер обращается к какому-то уровню сохранения (например, репозиторию).
- Уровень сохраняемости извлекает данные, а затем использует преобразователь для сопоставления с моделью предметной области.
- Контроллер использует преобразователь для преобразования модели предметной области в модель представления.
- Контроллер выбирает необходимое представление и применяет к нему модель представления.
Итак, почему это хорошо?
Модель предметной области не имеет зависимостей. Это очень хорошо, это означает, что легко выполнять валидацию, писать тесты и т. д. Это означает, что вы можете изменить что-либо еще в любом месте вашей архитектуры, и это никогда не сломает модель. Это означает, что вы можете повторно использовать модель в разных проектах.
Уровень сохраняемости возвращает экземпляры модели предметной области. Это означает, что его можно смоделировать как полностью абстрактный интерфейс, не зависящий от платформы. Компонент, которому необходимо использовать уровень постоянства (например, контроллер), не берет на себя никаких дополнительных зависимостей. Это идеально подходит для внедрения зависимостей слоя сохраняемости и, опять же, для тестируемости. Сочетание постоянства, доступа к данным и преобразователя может существовать в собственной сборке. В более крупных проектах вы даже можете еще больше отделить картограф и заставить его работать с общим набором записей.
Контроллер имеет только две нисходящие зависимости — модель предметной области и уровень сохраняемости. Модель должна редко меняться, так как это ваша бизнес-модель, а поскольку уровень сохраняемости является абстрактным, контроллер практически никогда не нужно менять (за исключением добавления новых действий).
Представления зависят от отдельной модели пользовательского интерфейса. Это изолирует их от изменений в модели предметной области. Это означает, что если ваша бизнес-логика изменится, вам не нужно менять каждое представление в вашем проекте. Это позволяет представлениям быть «тупыми», какими и должны быть представления — они не более чем заполнители для данных представления. Это также означает, что должно быть просто воссоздать представление, используя другой тип пользовательского интерфейса, т. е. интеллектуальное клиентское приложение, или переключиться на другой механизм представления (Spark, NHaml и т. д.).
Теперь при использовании O/R Mappers, таких как Linq to SQL или Entity Framework, очень возникает соблазн рассматривать классы, которые они генерируют, как модель предметной области. Конечно, это выглядит как модель предметной области, но это не так. Почему?
Классы сущностей привязаны к вашей реляционной модели, которая со временем может и будет значительно отличаться от вашей предметной модели;
Классы сущностей тупые. Трудно поддерживать какие-либо сложные сценарии проверки или интегрировать какие-либо бизнес-правила. Это называется анемичной моделью предметной области.
Классы сущностей имеют скрытые зависимости. Хотя они могут выглядеть как обычные POCO, на самом деле они могут иметь скрытые ссылки на базу данных (т. е. отложенную загрузку ассоциаций). Это может привести к тому, что проблемы, связанные с базой данных, перейдут к логике представления, где вы меньше всего сможете должным образом проанализировать происходящее и отладить.
Но самое главное, "модель предметной области" больше не является независимой. Она не может существовать вне любой сборки, имеющей логику доступа к данным. Ну, вроде как можно, есть способы добиться этого, если вы действительно потрудитесь над этим, но это не так, как делает это большинство людей, и даже если вы это сделаете, вы обнаружите, что фактический дизайн модели предметной области ограничивается вашей реляционной моделью и, в частности, тем, как ведет себя EF. Суть в том, что если вы решите изменить свою модель постоянства, вы сломаете модель предметной области, а ваша модель предметной области является основой почти для всего остального в вашем приложении. .
Классы Entity Framework не являются моделью предметной области. Они являются частью реляционной модели данных и имеют такие же или похожие имена, которые вы могли бы дать классам в модели предметной области. Но они совершенно разные с точки зрения управления зависимостями. Использование классов, созданных с помощью инструмента ORM, в качестве модели вашей предметной области может привести только к чрезвычайно хрупкой архитектуре/дизайну; каждое изменение, которое вы вносите почти в любую часть приложения, будет иметь множество предсказуемых и непредсказуемых каскадных эффектов.
Кажется, есть много людей, которые думают, что вам не нужна сплоченная, независимая модель предметной области. Обычно оправданием является то, что (а) это небольшой проект и/или (б) их модель предметной области на самом деле не имеет никакого поведения. Но небольшие проекты становятся большими, а бизнес-правила (намного) усложняются, а анемичная или несуществующая модель предметной области — это не то, что можно просто убрать с помощью рефакторинга.
На самом деле это самая коварная черта дизайна сущностей как моделей; кажется некоторое время работает нормально. Вы не узнаете, насколько велика эта ошибка, пока не пройдет год или два, когда вы утонете в отчетах о дефектах и запросах на изменение, отчаянно пытаясь собрать воедино реальную модель предметной области по частям.
person
Aaronaught
schedule
25.02.2010