Plain Old CLR Object vs Data Transfer Object

405

POCO = Plain Old CLR (or better: Class) Object

DTO = objet de transfert de données

Dans cet article, il y a une différence, mais franchement la plupart des blogs que j'ai lus décrivent POCO dans la façon dont le DTO est défini: les DTO sont de simples conteneurs de données utilisés pour déplacer des données entre les couches d'une application.

POCO et DTO sont-ils la même chose?

Patrick Peters
la source
5
"POCO = Plain Old CLR (or better: Class) Object". Ainsi, les objets de cette nature dans VB.NET seraient également des POCO, pas des POVO.
J.Polfer

Réponses:

568

Un POCO suit les règles de la POO. Il doit (mais n'est pas obligé) avoir un état et un comportement. POCO vient de POJO, inventé par Martin Fowler [ anecdote ici ]. Il a utilisé le terme POJO comme un moyen de rendre plus sexy le rejet des implémentations EJB lourdes du framework. POCO doit être utilisé dans le même contexte dans .Net. Ne laissez pas les cadres dicter la conception de votre objet.

Le seul but d'un DTO est de transférer un état et ne devrait avoir aucun comportement. Voir l' explication de Martin Fowler d'un DTO pour un exemple de l'utilisation de ce modèle.

Voici la différence: POCO décrit une approche de la programmation (bonne programmation orientée objet à l'ancienne), où DTO est un modèle qui est utilisé pour "transférer des données" en utilisant des objets.

Bien que vous puissiez traiter les POCO comme des DTO, vous courez le risque de créer un modèle de domaine anémique si vous le faites. De plus, il y a un décalage dans la structure, car les DTO doivent être conçus pour transférer des données, et non pour représenter la véritable structure du domaine d'activité. Le résultat de cela est que les DTO ont tendance à être plus plats que votre domaine réel.

Dans un domaine d'une complexité raisonnable, il est presque toujours préférable de créer des POCO de domaine séparés et de les traduire en DTO. DDD (conception pilotée par domaine) définit la couche anti-corruption (un autre lien ici , mais la meilleure chose à faire est d' acheter le livre ), qui est une bonne structure qui rend la ségrégation claire.

Michael Meadows
la source
Je sais que j'ai beaucoup fait référence à Martin Fowler ici, mais il a inventé le terme POJO et écrit le livre PoEAA qui est la référence définitive pour le DTO.
Michael Meadows
Je ne sais pas si un DTO ne devrait pas avoir de comportements. Selon le diagramme de Martin Fowler, le DTO pourrait avoir des comportements.
Beatles1692
39
@ Beatles1692, les méthodes décrites sont le code de sérialisation. C'est probablement une déclaration trop large pour dire «pas de comportement». Que diriez-vous «pas de logique métier». Le code de sérialisation et les objets de bas niveau comme le code de hachage, l'égalité et la chaîne de caractères doivent être acceptables.
Michael Meadows,
1
@PositiveGuy Un modèle sert un objectif différent d'un DTO. Le DTO doit être utilisé pour transférer des données d'un domaine à un autre (qu'elles soient ou non dans le même runtime n'a pas d'importance). Un modèle "représente" un aspect d'un domaine, comme un écran, un service ou une source de données. Les modèles incluent l'état et le comportement, qui sont représentatifs de ce qu'ils modélisent.
Michael Meadows
2
Veuillez noter que les modèles de domaine anémiques ne sont pas nécessairement mauvais, surtout si votre application est principalement CRUD. Privilégiez la simplicité à Martin Fowler.
Mariusz Jamro
50

Il est probablement redondant pour moi de contribuer puisque j'ai déjà indiqué ma position dans mon article de blog, mais le dernier paragraphe de cet article résume les choses:

Donc, en conclusion, apprenez à aimer le POCO et assurez-vous de ne pas diffuser de fausses informations sur le fait qu'il s'agit de la même chose qu'un DTO. Les DTO sont de simples conteneurs de données utilisés pour déplacer des données entre les couches d'une application. Les POCO sont des objets métier à part entière avec la seule exigence qu'ils sont Ignorants de la Persistance (pas de méthodes get ou save). Enfin, si vous n'avez pas encore vérifié le livre de Jimmy Nilsson, récupérez-le dans les piles de votre université locale. Il a des exemples en C # et c'est une excellente lecture.

BTW, Patrick J'ai lu le POCO comme un article sur le style de vie, et je suis entièrement d'accord, c'est un article fantastique. C'est en fait une section du livre de Jimmy Nilsson que j'ai recommandée. Je n'avais aucune idée qu'il était disponible en ligne. Son livre est vraiment la meilleure source d'informations que j'ai trouvée sur POCO / DTO / Repository / et d'autres pratiques de développement DDD.


la source
4
Lien vers l'article de blog: rlacovara.blogspot.com/2009/03/…
Jamie Ide
28

POCO est simplement un objet qui ne dépend pas d'un framework externe. C'est PLAIN.

Qu'un POCO ait un comportement ou non, cela n'a pas d'importance.

Un DTO peut être POCO tout comme un objet de domaine (qui serait généralement riche en comportement).

En règle générale, les DTO sont plus susceptibles de prendre des dépendances sur des cadres externes (par exemple, des attributs) à des fins de sérialisation, car ils sortent généralement à la frontière d'un système.

Dans les architectures de style Onion typiques (souvent utilisées dans une approche DDD), la couche de domaine est placée au centre et ses objets ne devraient donc pas, à ce stade, avoir de dépendances en dehors de cette couche.

Neil
la source
15

J'ai écrit un article sur ce sujet: DTO vs Value Object vs POCO .

En bref:

  • DTO! = Objet de valeur
  • DTO ⊂ POCO
  • Objet de valeur ⊂ POCO
Vladimir
la source
6

Je pense qu'un DTO peut être un POCO. DTO est plus sur l'utilisation de l'objet tandis que POCO est plus sur le style de l'objet (découplé des concepts architecturaux).

Un exemple où un POCO est quelque chose de différent de DTO est quand vous parlez de POCO à l'intérieur de votre modèle de domaine / modèle logique métier, qui est une belle représentation OO de votre domaine problématique. Vous pouvez utiliser les POCO tout au long de l'application, mais cela pourrait avoir des effets secondaires indésirables, comme une fuite de connaissances. Les DTO sont par exemple utilisés à partir de la couche de service avec laquelle l'interface utilisateur communique, les DTO sont une représentation plate des données et ne sont utilisés que pour fournir des données à l'interface utilisateur et communiquer les modifications à la couche de service. La couche service est chargée de mapper les deux sens du DTO aux objets du domaine POCO.

Mise à jour Martin Fowler a déclaré que cette approche est une route difficile à prendre et ne devrait être prise qu'en cas de disparité significative entre la couche de domaine et l'interface utilisateur.

Davy Landman
la source
2
@David Landman, le lien que vous avez inclus concerne le modèle DTO local, c'est-à-dire lorsque les DTO sont utilisés pour l'état de transfert dans les limites de votre système. Dans ces cas, vous devez être très prudent, car dans votre système, vous devez déjà avoir un domaine bien défini qui peut être partagé. Lors du transfert d'état au-delà des limites du système, le DTO est difficile à éviter et assez approprié dans tous les cas.
Michael Meadows,
@Michal Meadows, oui, le lien parle en effet d'un sous-ensemble différent de problèmes. Mais je pense que dans le cas d'un transfert d'état à travers une frontière système, vous devriez utiliser un service de traduction pour mapper le POCO d'un contexte au POCO d'un autre contexte. Ou parlez-vous de limites au niveau du système?
Davy Landman
1

Un cas d'utilisation principal pour un DTO consiste à renvoyer des données à partir d'un service Web. Dans ce cas, POCO et DTO sont équivalents. Tout comportement dans le POCO serait supprimé lorsqu'il est renvoyé d'un service Web, donc peu importe qu'il ait ou non un comportement.

John Saunders
la source
5
Je pense que votre réponse dénature ce qui se passe un peu. Dans le cas d'un service Web, un proxy est généré en fonction de l'état exposé d'un objet. Cela signifie qu'un DTO est créé séparément du POCO qui se trouve juste avoir le même état public que le POCO. Cela peut sembler subtil, mais c'est important. La raison en est que même si le proxy est identique à l'original, il n'est pas réellement construit à partir de la même classe.
Michael Meadows,
Euh non. On utilise un DTO pour retourner / recevoir des données entre les niveaux, dans ce cas, un service Web. On choisit un DTO car il n'a que des données et aucun comportement. Il est vrai que la classe proxy sera également probablement un DTO, et que si vous aviez utilisé une classe POCO à la place, un proxy aurait été créé. Mais dans ce cas, la classe POCO est effectivement un DTO, car son comportement ne se traduira pas. Je dis toujours utiliser un DTO car vous ne manquerez pas un comportement qui n'a jamais existé.
John Saunders,
5
** Sémantiquement: les services Web exposent des sacs d'état d'objet à l'aide de WSDL. Des procurations sont générées à partir de ceux-ci. Ceux-ci ne peuvent pas inclure le comportement. Si vous consommez un service Web, la seule relation entre votre objet et l'objet de domaine exposé est qu'il a le même état public créé sur la base d'une inspection.
Michael Meadows
7
@John, je pense que vous réagissez de manière excessive. Je dis que vous avez raison, mais votre formulation est trompeuse. "Dans ce cas, POCO et DTO sont équivalents." Sémantiquement, ce n'est pas vrai. Les POCO peuvent être utilisés comme DTO et vice versa, mais cela ne signifie pas qu'ils sont équivalents ... pas plus qu'une voiture et une camionnette ne sont équivalentes, même si elles peuvent toutes deux être utilisées pour vous conduire à l'épicerie. Ils ont une fonction qui se chevauchent, mais vous auriez du mal à trouver quelqu'un pour vous dire qu'un aperçu est équivalent à un F350, même dans le contexte du voyage d'épicerie.
Michael Meadows,
3
Cette réponse est tellement fausse, un service Web n'est pas assez générique pour un. Plus important encore, c'est un fait bien établi que le DTO n'est PAS un POCO. DTO est un conteneur de données, tandis que POCO sont des objets en tant que propriétés et ignorent la persistance (pas de méthodes get ou save).
Tom Stickel
1

voici la règle générale: DTO == mal et indicateur de logiciel sur-conçu. POCO == bon. les modèles «d'entreprise» ont détruit le cerveau de beaucoup de gens dans le monde Java EE. veuillez ne pas répéter l'erreur en .NET land.

benmmurphy
la source
7
Pourriez-vous élaborer, s'il vous plaît? Le DTO est requis lors du retour des données d'un service Web, afin d'éviter l'implémentation et les spécificités de la plateforme dans le contrat.
John Saunders
1
Oui, les John DTO sont conçus pour ce que vous dites et fonctionnent bien. Mais malheureusement, ils sont souvent utilisés lorsqu'ils ne sont pas requis dans les applications Web à un seul niveau et ont peu de valeur.
Craig
9
Je pense, @drscroogemcduck, que vous n'aimez peut-être pas les DTO parce qu'ils sont utilisés en premier lieu plutôt qu'en dernier recours, mais ils ne sont pas intrinsèquement mauvais ... pas plus que les fameux schémas singleton ou d'usine. Ce qui est mal, ce sont les architectes qui poussent les frameworks dans la gorge des développeurs qui les forcent à créer des DTO pour tout. Pour ce qu'ils font, le transfert de données, les DTO (si cela est fait avec prudence) sont la solution idéale.
Michael Meadows,
0

Les classes DTO sont utilisées pour sérialiser / désérialiser les données de différentes sources. Lorsque vous souhaitez désérialiser un objet à partir d'une source, peu importe de quelle source externe il s'agit: service, fichier, base de données, etc. objet. après cela, vous copiez ces données sur le XModel que vous souhaitez utiliser. Un sérialiseur est une belle technologie pour charger des objets DTO. Pourquoi? vous n'avez besoin que d'une fonction pour charger (désérialiser) l'objet.

Herman Van Der Blom
la source
0

TL; DR:

Un DTO décrit le modèle de transfert d'état. Un POCO ne décrit rien. C'est une autre façon de dire "objet" dans la POO. Il vient de POJO (Java), inventé par Martin Fowler qui le décrit littéralement comme un nom plus sophistiqué pour «objet» parce que «objet» n'est pas très sexy.

Un DTO est un modèle d'objet utilisé pour transférer l'état entre les couches concernées. Ils peuvent avoir un comportement (c'est-à-dire peuvent techniquement être un poco) tant que ce comportement ne mute pas l'état. Par exemple, il peut avoir une méthode qui se sérialise.

Un POCO est un objet simple, mais ce que l'on entend par «simple», c'est qu'il n'est pas spécial. Cela signifie simplement que c'est un objet CLR sans motif implicite. Un terme générique. Il n'est pas fait pour fonctionner avec un autre cadre. Donc, si votre POCO a des [JsonProperty]décorations EF ou partout dans ses propriétés, par exemple, alors je dirais que ce n'est pas un POCO.

Voici quelques exemples de différents types de modèles d'objets à comparer:

  • Afficher le modèle : utilisé pour modéliser les données d'une vue. A généralement des annotations de données pour faciliter la liaison et la validation. Dans MVVM, il agit également comme un contrôleur. C'est plus qu'un DTO
  • Objet de valeur : utilisé pour représenter des valeurs
  • Racine agrégée : utilisée pour gérer l'état et les invariants
  • Gestionnaires : utilisés pour répondre à un événement / message
  • Attributs : utilisés comme décorations pour répondre aux préoccupations transversales
  • Service : utilisé pour effectuer des tâches complexes
  • Contrôleur : utilisé pour contrôler le flux des demandes et des réponses
  • Usine : utilisé pour configurer et / ou assembler des objets complexes à utiliser lorsqu'un constructeur n'est pas assez bon. Également utilisé pour prendre des décisions sur les objets à créer lors de l'exécution.
  • Référentiel / DAO : utilisé pour accéder aux données

Ce ne sont que des objets, mais notez que la plupart d'entre eux sont généralement liés à un motif. Vous pouvez donc les appeler «objets» ou vous pouvez être plus précis sur son intention et l'appeler par ce qu'elle est. C'est aussi pourquoi nous avons des modèles de conception; décrire des concepts complexes dans quelques ouvrages. Le DTO est un modèle. La racine agrégée est un modèle, View Model est un modèle (par exemple MVC et MVVM). POCO n'est pas un modèle.

Un POCO ne décrit pas un modèle. C'est juste une manière différente de se référer aux classes / objets dans la POO. Considérez-le comme un concept abstrait; ils peuvent faire référence à n'importe quoi. OMI, il y a une relation à sens unique, car une fois qu'un objet atteint le point où il ne peut servir qu'un seul objectif proprement, il n'est plus un POCO. Par exemple, une fois que vous marquez votre classe avec des décorations pour la faire fonctionner avec un cadre, ce n'est plus un POCO. Donc:

  • Un DTO est un POCO
  • Un POCO n'est pas un DTO
  • Un modèle de vue est un POCO
  • Un POCO n'est pas un modèle de vue

Le but de faire une distinction entre les deux est de maintenir des schémas clairs et cohérents afin de ne pas croiser les préoccupations et conduire à un couplage serré. Par exemple, si vous avez un objet métier qui a des méthodes pour muter l'état, mais qui est également décoré en enfer avec des décorations EF pour l'enregistrement dans SQL Server ET JsonProperty afin qu'il puisse être renvoyé via un point de terminaison API. Cet objet serait intolérant à changer, et serait probablement jonché de variantes de propriétés (par exemple UserId, UserPk, UserKey, UserGuid, où certains d'entre eux sont marqués pour ne pas être enregistrés dans la base de données et d'autres marqués pour ne pas être sérialisés vers JSON au point de terminaison API).

Donc, si vous me disiez que quelque chose était un DTO, je m'assurerais probablement qu'il n'a jamais été utilisé pour autre chose que pour déplacer l'état. Si vous me disiez que quelque chose était un modèle de vue, je m'assurerais probablement qu'il ne soit pas enregistré dans une base de données. Si vous m'avez dit que quelque chose était un modèle de domaine, je m'assurerais probablement qu'il ne dépendait de rien en dehors du domaine. Mais si vous me disiez que quelque chose était un POCO, vous ne me diriez pas grand-chose du tout.

Sinaesthetic
la source
-13

Ne les appelez même pas DTO. On les appelle des modèles ... point final. Les modèles n'ont jamais de comportement. Je ne sais pas qui est venu avec ce terme stupide DTO mais ce doit être une chose .NET est tout ce que je peux comprendre. Pensez aux modèles de vue en MVC, même chose **, les modèles sont utilisés pour transférer l'état entre les couches côté serveur ou sur la période de connexion, ce sont tous des modèles. Propriétés avec données. Ce sont des modèles que vous passez au-dessus du fil. Modèles, Modèles Modèles. C'est ça.

Je souhaite que le terme stupide DTO s'éloigne de notre vocabulaire.

PositiveGuy
la source
1
je ne sais pas d'où vous vient cette idée que les modèles n'ont jamais de comportement. Comment modélisez-vous autre chose que CRUD sans modéliser le comportement? Même les ViewModels ont un comportement dans de nombreux cas, en particulier dans les applications MVVM. DTO est un terme utile car il décrit avec précision le but; pour transférer des données.
Gerald
9
downvoted pour être factuellement incorrect, et pour l'attitude pontificatrice.
joedotnot
Absurdité. Les modèles devraient être des conteneurs stupides. Il n'y a pas de DTO, c'est un terme inventé par MS. Vous transférez des modèles entre des domaines, des services et des applications. Période. Le DTO est un gaspillage de terme qui n'est pas nécessaire et ne fait que confondre davantage les choses. Modèles, modèles et plus de modèles c'est tout. Les modèles peuvent ou non avoir un comportement. Les modèles de vue ne devraient pas. Ce comportement doit être dans un BL, pas dans la classe Model.
PositiveGuy
Je suis d'accord que les DTO sont fonctionnellement des modèles. Les ViewModels ont un comportement et c'est ce à quoi vous vous liez dans MVVM. CEPENDANT, j'ai écrit une application où mes modèles étaient plus intelligents (essentiellement des VM mais je ne voulais pas les appeler que) et ils "acceptaient" un objet DTO. Cela m'a permis d'avoir plus d'options avec le framework. Donc, à partir de CRUD (ou même d'EF), je transmettais l'objet via les services WCF et recevais l'objet DTO et l'encapsulais (en ajoutant OnProp Change, etc.). Mes ViewModels ont effectué une encapsulation supplémentaire et peuvent avoir accepté deux (ou une liste) de "Modèles". La définition rigide serait VM.
SQLMason
"Vous transférez des modèles entre domaines, services et applications" Pourquoi pensez-vous que le terme modèle est plus approprié et plus approprié que le terme DTO pour ce comportement que vous décrivez?
caa