Компоненты DTO - это юридические лица или DTO?
У меня есть вопрос терминологии. Ссылаясь на Фаулера, DTO - это "объект, который переносит данные между процессами, чтобы уменьшить количество вызовов методов". ( http://martinfowler.com/eaaCatalog/dataTransferObject.html). Как я понимаю, единственный способ уменьшить количество вызовов методов - это объединить их. Таким образом, DTO является составным объектом, содержащим некоторые объекты.
Например, у нас есть две простые сущности CoinInfo и ProductInfo:
public class CoinInfo
{
public int CoinId { get; set; }
public int Denomination { get; set; }
public int Quantity { get; set; }
}
public class ProductInfo
{
public int ProductId { get; set; }
public ProductTypes ProductType { get; set; }
public int Price { get; set; }
public int Count { get; set; }
}
И у нас также есть сложный объект SomeDto, объединяющий CoinInfo и ProductInfo.
public class SomeComplex
{
public List<CoinInfo> UserWallet { get; set; }
public List<ProductInfo> Products { get; set;}
}
Итак, ProductInfo и CoinInfo также являются "DTO" или просто "сущностями"?
3 ответа
Объекты передачи данных вступают в игру, когда вы пересекаете границу класса, компонента или приложения. Вы используете DTO для уменьшения связи между классами, компонентами или приложениями.
Например, при создании службы, которая будет использоваться клиентами, вы можете использовать три компонента:
- Сервис: содержит бизнес-логику и, возможно, какой-то шаблон хостинга сервисов (хотя обычно вам нужен последний бит в его собственном проекте).
- Клиентская библиотека: приложения могут использовать для вызова методов в службе
- Объекты передачи данных: на них ссылаются как сервис, так и клиент.
Теперь ваше клиентское приложение, которое хочет взаимодействовать с этой службой, должно ссылаться только на клиентскую библиотеку и библиотеку DTO. Какие другие типы использует ваш сервис, чтобы творить свою магию, совершенно не интересует клиента и должен оставаться скрытым.
Теперь смысл DTO заключается в том, что вы используете их для моделирования своего API. Вы сами решаете, что будет доступно вашему сервису и как будут выглядеть эти данные. Вы можете выбрать композицию, объединяя меньшие DTO в более крупные, как вы показываете.
То, что вы должны иметь в виду, это не выставлять сервисные службы через DTO. Вы используете слово "сущности", что заставляет меня думать, что вы пытаетесь раскрыть, например, модели Entity Framework, агрегированные в DTO. Вы не должны этого делать. Делая это, вы создаете "дырявую абстракцию", усложняя как изменение базы данных (добавление или удаление столбцов, замену вашего ORM, ...), так и изменение информации, возвращаемой службой (добавление или удаление свойств, ...). Кроме того, использование моделей Entity Framework в качестве DTO создает проблемы с массовым назначением, отложенной загрузкой и циклическими ссылками, которые требуют обходных путей.
Вы можете обойти эти потенциальные проблемы, используя атрибуты, чтобы либо ORM, либо ваш сервисный сериализатор игнорировали эти посторонние свойства, но это все еще обходные пути. Если вам действительно нужно представить DTO, которые очень похожи на ваши модели данных, тогда представьте отображение (например, с помощью AutoMapper):
- Service.Data: содержит "сущности".
- Сервис: сопоставляет "сущности" с DTO и возвращает / принимает последнее.
- Клиентская библиотека: все еще только видит и должен ссылаться на DTO.
В этом сценарии слой данных вашего сервиса и модели, возвращаемые из вашего сервиса, разъединены.
Если все это не то, что вас беспокоит, а просто номенклатура: да, все три класса, которые вы показываете, являются DTO.
Поскольку CoinInfo
а также ProductInfo
было бы также целесообразно выполнять операции CRUD (т.е. создание, чтение, обновление, удаление). Я бы сказал, что связанный корень и его собственные ассоциации также являются DTO.
Когда вы спрашиваете, являются ли эти классы сущностями, это зависит от того, что вы понимаете под сущностью. Если вы хотите знать, являются ли они объектами домена, это не так, если только вы не используете их в своем домене, и в конце концов это противоречит цели использования шаблона DTO.
DTO лучше всего работает с фасадами, потому что они не обязательно привязаны к домену, поскольку они просто интерфейсы для упрощения домена или любого другого уровня (это будет зависеть от реализации фасада). То есть DTO должен быть лучшим выбором для ввода и вывода данных на фасады и с них.
Другими словами: вы не должны выводить объекты домена через физические границы, потому что объект домена может содержать слишком много информации, которая может быть пустой тратой передачи данных, а также вы можете предоставлять данные, которые являются частными для домена и не должны быть известны потребители всего домена.
DTO играют свою собственную роль, отображая только необходимые данные, которые должны быть представлены слоям поверх фактического домена. Кроме того, иногда доменные объекты содержат бесполезные данные, которые могут быть сериализованы / десериализованы и восстанавливают действительное состояние всего объекта (они могут иметь некоторую связь с подключениями к данным: подумайте о Entity Framework или прокси NHibernate, которые связаны с контекстом или сеансом домена соответственно... это просто пример, есть много других).
Мое понимание DTO состоит в том, что они выполняют очень похожую роль "parcelable" в Android (что также требует, чтобы переменные-члены были parcelable (либо нативные типы, либо непосредственно реализуют интерфейс parcelable).
Parcelable используется при пересечении границ процесса (IPC), а DTO - немного более широкий шаблон. (для IPC, связь клиент / сервер и т. д.) (чтобы объяснить, что такое "parcelable" и чем отличается DTO)
DTO, похоже, имеет ту же иерархическую структуру, все внутри DTO должно быть сериализуемым (хотя оно не требует наличия определенного интерфейса, как в случае с Android), поэтому я бы сказал, что все 3 являются DTO. просто некоторые более сложные, чем другие.
Стоит отметить, что еще одним преимуществом является инкапсуляция механизма сериализации для передачи данных по проводам. Инкапсулируя сериализацию, подобную этой, DTO не допускают этой логики в остальной части кода
По вашей ссылке
Parcelable - требует, чтобы вы включили код сериализации в класс. В то время как DTO это просто хорошая практика (не обязательно, я не думаю)
(извините за такое большое сравнение Android, я надеюсь, что сравнение / контраст помогает)