Вы можете называть класс сущности на стороне клиента как угодно :-)
А если серьезно, давайте рассмотрим типичное обоснование утверждения, что это анти-шаблон.
Клиент не является уровнем представления
Я хочу быть очень ясным по этому поводу. Breeze разработан для многофункциональных клиентских веб-приложений. Клиент Breeze не является уровнем представления; он имеет уровень представления. Он также имеет собственную бизнес-модель и уровни доступа к данным.
Термины сущность и DTO означают разные вещи для разных людей. Мне нравится определение DDD Эвана для сущности и определение Фаулера для DTO в PoEAA.
Сущности клиента Breeze квалифицируются как сущности Эванса: Объекты, которые имеют четкую идентичность, которая проходит через время и различные представления. Вы также слышите, как они называются «эталонными объектами» [Fowler]. Сущности Breeze — это не просто сумки с имуществом; у них также есть бизнес-логика, и вы можете расширить их своими собственными.
Объекты Breeze не являются презентационными моделями. Они не зависят от какого-либо конкретного представления пользовательского интерфейса и обычно не реализуют проблемы представления.
Они разработаны таким образом, что их можно напрямую привязать к визуальным элементам управления. Это решение Breeze по проектированию производительности... решение о том, как мы реализуем объекты. Некоторым людям — людям, считающим, что свойства сущностей — это анти-шаблон, — это не понравится. Эванс молчит на этот вопрос. Фаулер это какает. Если это вас оскорбляет, вам может не понравиться Бриз. Двигайтесь вперед.
Отправить объекты или DTO?
Я собираюсь утверждать, что это ложная дихотомия.
Люди часто говорят, что отправлять объекты по сети — это антишаблон. Всегда отправлять DTO. За этим плохо сформулированным указом есть веская причина. Когда класс сущностей клиента и сервера идентичны, вы связываете реализацию сервера с реализацией клиента. Если модель изменяется на сервере, она должна измениться и на клиенте, и наоборот, даже если изменение относится только к одному из уровней. Это может помешать вам независимо развивать серверный и клиентский код. Мы можем принять такое соединение из соображений целесообразности (а целесообразность имеет значение!), но никто не хочет этого.
Класс сущности клиент Breeze не обязательно должен быть таким же, ни по форме, ни по бизнес-логике, как класс сущности сервер. Когда вы делаете запрос в Breeze, вы помещаете данные объекта в сеть и преобразуете их в клиентские объекты; при сохранении вы помещаете клиентский объект data в сеть и преобразуете его на сервере в серверные объекты. DTO могут быть вовлечены в любом направлении. Важным фактом является то, что классы могут быть разными.
Концептуально они, конечно, связаны. У вас будет чертовски много времени на преобразование данных между двумя представлениями, если значение сущности Customer
сильно расходится с двух сторон. Это верно как с явными DTO, так и без них.
Давайте также признаем, что легче преобразовывать данные в обоих направлениях, когда классы на самом деле одни и те же. Вы платите налог за сопоставление, когда они отличаются, и вы можете потерять возможность составлять запросы Breeze LINQ на клиенте. Вы можете заплатить налог, если хотите. Бризу все равно.
Я склоняюсь к тому, чтобы начать с одинаковых классов с обеих сторон и менять их по мере необходимости. Это хорошо сработало для большого процента классов RIA Services и DevForce. Самое главное, мне никогда не было сложно провести рефакторинг для разделения классов, когда в этом возникала необходимость.
‹rant› Беспокойные преувеличивают риски совместного использования определений классов и преуменьшают стоимость сопоставления слоев, преимущества которых редко реализуются на практике в течение всего срока службы приложения.‹/rant› >
Когда использовать презентационные модели
Вы написали:
Для более крупных систем с графами, уходящим вглубь на пять или шесть уровней, сущности необходимо преобразовать в DTO, чтобы сделать это проще. ... В большинстве случаев эти DTO будут представлять то, что хочет пользовательский интерфейс, и эквивалентны модели представления.
По моему опыту, это верно только в том случае, если вы предполагаете, что ваш клиент просто вставляет объекты на экран. Но я уже оговорил, что клиент — это приложение, а не уровень представления.
Я также утверждаю, что вам нужна модель домена на клиенте по той же причине, что и на сервере: чтобы рассуждать о домене. Вы делаете это независимо от презентации. Я предполагаю, что ваши объекты будут появляться на нескольких экранах в зависимости от разных правил представления. Это одна и та же модель, представленная многими способами. Мы называем это обходом данных.
Независимо от того, сколько граней вы поместите в модель, базовые данные модели и управляющие ими бизнес-правила должны оставаться неизменными. Вот что делает ее моделью предметной области, а не моделью представления.
FWIW, у меня всегда есть модель представления (также известная как ViewModel) в моих приложениях для организации действий представления. Так что я не спрашиваю себя PM или модель?. Вместо этого я выбираю либо, чтобы данные привязывали визуальные элементы управления непосредственно к объектам модели, которые я предоставляю через API виртуальной машины или вместо этого привязываю их к промежуточной модели представления элементов (также известной как Item ViewModel) который оборачивает некоторые объекты. Каким путем я пойду, зависит от приложения. На практике я начинаю с прямой привязки к сущностям и рефакторинга к Item ViewModel, когда это необходимо.
В любом случае я создам нужные мне PM (VM) на клиенте. Если мне нужна Item ViewModel, я также создаю ее на клиенте. Я не прошу свой сервер подготовить DTO для отображения моего клиента. Для меня это анти-шаблон, потому что он связывает сервер с клиентом.
Как? Если разработчику нужно изменить экран на клиенте, ему, возможно, придется подождать, пока кто-нибудь предоставит конечную точку поддерживающего сервера и DTO. Теперь нам нужно согласовать графики выпуска сервера и клиента, даже несмотря на то, что толчком к изменению было требование клиента, а не требование сервера.
Сервисное загрязнение
Это на самом деле хуже, чем это. Некоторым разработчикам серверной части приходится прекратить свою работу и добавить новый метод службы, чтобы удовлетворить требования клиента. Это не было одним из ее требований... но теперь это так. Со временем сервисный API значительно расширяется, и вскоре он полон похожих членов, которые выполняют одну и ту же работу немного разными способами.
В конце концов мы забываем, кто использует какой метод и для чего. Никто не осмеливается изменить существующий метод, опасаясь взлома неизвестного клиента. Итак, разработчик копирует что-то, что выглядит правильно, делает это немного по-другому и называет это как-то иначе. Эта модель загрязнения сервисного API должна быть знакома всем, кто работал с корпоративными приложениями.
Делать исключения
Каждое кажущееся правило предназначено для того, чтобы его нарушать. Конечно, бывают случаи, когда целесообразно и эффективно позволить серверу подготовить данные для отображения. Чаще всего это происходит с большими объемами данных только для чтения, которые обобщают еще больший объем сложных данных на уровне данных. Когда я иду по этому пути, я обычно руководствуюсь соображениями производительности. В остальном я остаюсь верен объектно-ориентированной архитектуре.
Когда кажется, что все в моем приложении соответствует исключению, я делаю вывод, что у меня неправильная архитектура для этого конкретного приложения... и это не должно быть приложение Бриз. Я не знаю, ваш это случай или нет.
Надеюсь это поможет.
person
Ward
schedule
09.06.2014