Pull to refresh

DTO vs POCO vs Value Object

Programming *.NET *C# *ООP *
В этой статье я бы хотел прояснить различия между DTO (Data Transfer Object), Value Object и POCO (Plain Old CLR Object), также известным как POJO в среде Java.

Определения DTO, POCO и Value Object


Вначале небольшая ремарка по поводу Value Object. В C# существует похожая концепция, называемая Value Type. Это всего лишь деталь имплементации того, как объекты хранятся в памяти и мы не будем касаться этого. Value Object, о котором пойдет речь, — понятие из среды DDD (Domain-Driven Design).

Ок, давайте начнем. Вы возможно заметили, что такие понятия как DTO, Value Object и POCO часто используются как синонимы. Но действительно ли они означают одно и то же?

DTO — это класс, содержащий данные без какой-либо логики для работы с ними. DTO обычно используются для передачи данных между различными приложениями, либо между слоями внутри одного приложения. Их можно рассматривать как хранилище информации, единственная цель которого — передать эту информацию получателю.

С другой стороны, Value Object — это полноценный член вашей доменной модели. Он подчиняется тем же правилам, что и сущности (Entities). Единственное отличие между Value Object и Entity в том, что у Value Object-а нет собственной идентичности. Это означает, что два Value Object-а с одинаковыми свойствами могут считаться идентичными, в то время как две сущности отличаются друг от друга даже в случае если их свойства полностью совпадают.

Value Object-ы могут содержать логику и обычно они не используются для передачи информации между приложениями.

POCO (Plain Old CLR Object) — термин, созданный как аналогия для POJO. POJO не может использоваться в .NET из-за того, что буква “J” в нем означает “Java”. POCO имеет ту же семантику, что и POJO.

POJO был представлен Мартином Фаулером в качестве альтернативы для JavaBeans и других «тяжелых» enterprise-конструкций, которые были популярны в ранних 2000-х.

Основной целью POJO было показать, что домен приложения может быть успешно смоделирован без использования JavaBeans. Более того, JavaBeans вообще не должны быть использованы для этой цели.

В среде .NET нет прямой аналогии для JavaBeans, т.к. Microsoft никогда не представляла ничего похожего, но мы можем придумать некоторую параллель.

Вы можете думать о классе Component из System.ComponentModel как о понятии, противоположном POCO. В .NET существует множество классов, наследующих от Component, например DBCommand из System.Data или EventLog из System.Diagnostics.

Наследовать доменные классы от Component в большинстве случаев не имеет никакого смысла, т.к. это решение привносит в модель ненужную сложность. Использование тяжеловесных классов из .NET Framework для подобных целей противоречит принципу YAGNI.

Другой хороший пример анти-POCO подхода — Entity Framework до версии 4.0. Каждый класс, сгенерированный EF, наследовал от EntityObject, что привносило в домен логику, специфичную для EF. Начиная с версии 4, Entity Framework добавил возможность работать с POCO моделью — возможность использовать классы, которые не наследуются от EntityObject.

Таким образом, понятие POCO означает использование настолько простых классов насколько возможно для моделирования предметной области. Это понятие помогает придерживаться принципов YAGNI, KISS и остальных best practices. POCO классы могут содержать логику.

Корреляция между понятиями


Есть ли связи между этими тремя понятиями? В первую очередь, DTO и Value Object отражают разные концепции и не могут использоваться взаимозаменяемо. С другой стороны, POCO — это надмножество для DTO и Value Object:

image

Другими словами, Value Object и DTO не наследуют никаким сторонним компонентам и таким образом являются POCO. В то же время, POCO — это более широкое понятие: это может быть Value Object, Entity, DTO или любой другой класс в том случае если он не наследует компонентам, не относящимся напрямую к решаемой вами проблеме.

Вот свойства каждого из них:

image

Заметьте, что POCO-класс может и иметь, и не иметь собственной идентичности, т.к. он может быть как Value Object, так и Entity. Также, POCO может содержать, а может и не содержать логику внутри себя. Это зависит от того, является ли POCO DTO.

Заключение


Вышесказанное в статье можно суммировать следующим образом:

  • DTO != Value Object
  • DTO ⊂ POCO
  • Value Object ⊂ POCO

Английская версия статьи: DTO vs Value Object vs POCO
Tags:
Hubs:
Total votes 17: ↑15 and ↓2 +13
Views 124K
Comments Comments 35