Semplice oggetto CLR vecchio vs oggetto trasferimento dati


405

POCO = Plain Old CLR (o meglio: Class) Object

DTO = Oggetto trasferimento dati

In questo post c'è una differenza, ma francamente la maggior parte dei blog che leggo descrivono POCO nel modo in cui è definito DTO: i DTO sono semplici contenitori di dati utilizzati per spostare i dati tra i livelli di un'applicazione.

POCO e DTO sono la stessa cosa?


5
"POCO = oggetto CLR (o meglio: classe) semplice vecchio". Pertanto, oggetti di questa natura in VB.NET sarebbero anche POCO, non POVO.
J. Polfer,

Risposte:


568

Un POCO segue le regole di OOP. Dovrebbe (ma non è necessario) avere stato e comportamento. POCO viene da POJO, coniato da Martin Fowler [ aneddoto qui ]. Ha usato il termine POJO come un modo per rendere più sexy il rifiuto delle pesanti implementazioni del bean EJB. POCO dovrebbe essere usato nello stesso contesto in .Net. Non lasciare che i quadri dettino il design del tuo oggetto.

L'unico scopo di un DTO è trasferire lo stato e non dovrebbe avere alcun comportamento. Vedi la spiegazione di Martin Fowler di un DTO per un esempio dell'uso di questo modello.

Ecco la differenza: POCO descrive un approccio alla programmazione (buona programmazione vecchio stile orientata agli oggetti), in cui DTO è un modello che viene utilizzato per "trasferire dati" utilizzando oggetti.

Mentre puoi trattare i POCO come DTO, corri il rischio di creare un modello di dominio anemico se lo fai. Inoltre, c'è una discrepanza nella struttura, dal momento che i DTO dovrebbero essere progettati per trasferire dati, non per rappresentare la vera struttura del dominio aziendale. Il risultato di ciò è che i DTO tendono ad essere più piatti del tuo dominio reale.

In un dominio di qualsiasi ragionevole complessità, stai quasi sempre meglio creare POCO di dominio separati e tradurli in DTO. DDD (domain driven design) definisce il livello anticorruzione (un altro link qui , ma la cosa migliore da fare è acquistare il libro ), che è una buona struttura che rende chiara la segregazione.


So di aver fatto molto riferimento a Martin Fowler qui, ma ha coniato il termine POJO e ha scritto il libro PoEAA che è il riferimento definitivo per DTO.
Michael Meadows,

Non sono sicuro che un DTO non dovrebbe avere comportamenti. A giudicare dal diagramma di Martin Fowler, il DTO potrebbe avere comportamenti.
Beatles1692,

39
@ Beatles1692, i metodi illustrati sono codice di serializzazione. Probabilmente è una frase troppo ampia per dire "nessun comportamento". Che ne dici di "nessuna logica aziendale". Il codice di serializzazione e oggetti di basso livello come codice hash, uguaglianza e tostring dovrebbero essere accettabili.
Michael Meadows,

1
@PositiveGuy Un modello ha uno scopo diverso da un DTO. DTO dovrebbe essere per il trasferimento di dati da un dominio a un altro (indipendentemente dal fatto che siano nello stesso runtime). Un modello "rappresenta" un aspetto di un dominio, come una schermata, un servizio o un'origine dati. I modelli includono stato e comportamento, che sono rappresentativi di ciò che stanno modellando.
Michael Meadows,

2
Tieni presente che i modelli di dominio anemici non sono necessariamente dannosi, soprattutto se la tua app è principalmente CRUD. Favorisci la semplicità rispetto a Martin Fowler.
Mariusz Jamro,

50

Probabilmente è ridondante per me contribuire poiché ho già dichiarato la mia posizione nel mio articolo sul blog, ma il paragrafo finale di quell'articolo riassume le cose:

Quindi, in conclusione, impara ad amare il POCO e assicurati di non diffondere alcuna disinformazione sul fatto che sia la stessa cosa di un DTO. I DTO sono semplici contenitori di dati utilizzati per spostare i dati tra i livelli di un'applicazione. I POCO sono oggetti business a tutti gli effetti con l'unico requisito di essere Ignoranti di persistenza (nessun metodo get o save). Infine, se non hai ancora controllato il libro di Jimmy Nilsson, prendilo dalle pile dell'università locale. Ha esempi in C # ed è un'ottima lettura.

A proposito, Patrick ho letto il POCO come un articolo sullo stile di vita, e sono completamente d'accordo, è un articolo fantastico. In realtà è una sezione del libro di Jimmy Nilsson che ho raccomandato. Non avevo idea che fosse disponibile online. Il suo libro è davvero la migliore fonte di informazioni che ho trovato su POCO / DTO / Repository / e altre pratiche di sviluppo DDD.


4
Link all'articolo di blog: rlacovara.blogspot.com/2009/03/…
Jamie Ide

28

POCO è semplicemente un oggetto che non dipende da un framework esterno. È PIANO.

Che un POCO abbia un comportamento o meno è irrilevante.

Un DTO può essere POCO come un oggetto di dominio (che in genere sarebbe ricco di comportamento).

In genere i DTO hanno maggiori probabilità di assumere dipendenze da framework esterni (ad es. Attributi) ai fini della serializzazione in quanto in genere escono al limite di un sistema.

Nelle tipiche architetture in stile Onion (spesso utilizzate in un approccio ampiamente DDD) il livello del dominio è posizionato al centro e quindi i suoi oggetti non dovrebbero, a questo punto, avere dipendenze al di fuori di quel livello.



6

Penso che un DTO possa essere un POCO. DTO riguarda più l'utilizzo dell'oggetto mentre POCO è più dello stile dell'oggetto (disaccoppiato dai concetti architettonici).

Un esempio in cui un POCO è qualcosa di diverso rispetto a DTO è quando parli di POCO all'interno del tuo modello di dominio / modello di logica aziendale, che è una bella rappresentazione OO del tuo dominio problematico. È possibile utilizzare i POCO in tutta l'intera applicazione, ma ciò potrebbe avere effetti collaterali indesiderati come tali perdite di conoscenza. I DTO sono ad esempio utilizzati dal livello di servizio con cui l'interfaccia utente comunica, i DTO sono una rappresentazione piatta dei dati e vengono utilizzati solo per fornire dati all'interfaccia utente e comunicare le modifiche al livello di servizio. Il livello di servizio ha il compito di mappare in entrambi i modi il DTO sugli oggetti di dominio POCO.

Aggiornamento Martin Fowler ha affermato che questo approccio è una strada pesante da prendere e dovrebbe essere preso solo se c'è una significativa discrepanza tra il livello di dominio e l'interfaccia utente.


2
@David Landman, il collegamento incluso è per il modello DTO locale, ovvero quando i DTO vengono utilizzati per lo stato di trasferimento all'interno del limite del sistema. In questi casi, dovresti stare molto attento, poiché all'interno del tuo sistema dovresti già avere un dominio ben definito che può essere condiviso. Quando si trasferisce lo stato oltre i confini del sistema, il DTO è difficile da evitare e abbastanza appropriato in tutti i casi.
Michael Meadows,

@Michal Meadows, sì, il link parla davvero di un diverso sottoinsieme di problemi. Ma penso che nel caso del trasferimento dello stato attraverso un limite del sistema, dovresti usare un servizio di traduzione per mappare il POCO da un contesto al POCO da un altro contesto. O stai parlando di limiti a livello di sistema?
Davy Landman,

1

Un caso d'uso primario per un DTO è la restituzione dei dati da un servizio Web. In questo caso, POCO e DTO sono equivalenti. Qualsiasi comportamento nel POCO verrebbe rimosso quando viene restituito da un servizio Web, quindi non importa se ha un comportamento.


5
Penso che la tua risposta travisi cosa succede un po '. Nel caso di un servizio Web, viene generato un proxy basato sullo stato esposto di un oggetto. Ciò significa che un DTO viene creato separatamente dal POCO che ha lo stesso stato pubblico del POCO. Può sembrare sottile, ma è importante. Il motivo è che anche se il proxy è identico all'originale, in realtà non è costruito dalla stessa classe.
Michael Meadows,

Uh, no. Uno utilizza un DTO per restituire / ricevere dati tra livelli, in questo caso un servizio web. Uno sceglie un DTO perché ha solo dati e nessun comportamento. È vero che anche la classe proxy sarà probabilmente un DTO e che se tu avessi usato invece una classe POCO, sarebbe stato creato un proxy. Ma in questo caso, la classe POCO è effettivamente un DTO, poiché il suo comportamento non si tradurrà. Dico ancora usare un DTO perché non mancherete comportamenti che non sono mai esistiti.
John Saunders,

5
** Semanticamente: i servizi Web espongono i sacchetti di stato degli oggetti utilizzando WSDL. I proxy sono generati da questi. Questi non possono includere comportamenti. Se si utilizza un servizio Web, l'unica relazione tra l'oggetto e l'oggetto dominio esposto è che ha lo stesso stato pubblico creato in base all'ispezione.
Michael Meadows,

7
@ John, penso che tu stia reagendo in modo esagerato. Sto dicendo che hai ragione, ma la tua formulazione è fuorviante. "In questo caso, POCO e DTO sono equivalenti." Semanticamente, non è vero. I POCO possono essere usati come DTO e viceversa, ma ciò non significa che siano equivalenti ... niente più che un'auto e un camioncino sono equivalenti, anche se entrambi possono essere usati per condurti al supermercato. Hanno una funzione sovrapposta, ma sarebbe difficile trovare qualcuno che ti dica che una visione equivale a un F350, anche nel contesto del viaggio in drogheria.
Michael Meadows,

3
Questa risposta è molto sbagliata, un servizio web non è abbastanza generico per uno. Ancora più importante è un fatto ben noto che DTO NON è un POCO. DTO è un contenitore di dati, mentre i POCO sono oggetti come proprietà e ignorano la persistenza (nessun metodo get o save).
Tom Stickel,

1

ecco la regola generale: DTO == male e indicatore di software troppo ingegnerizzato. POCO == buona. i modelli "enterprise" hanno distrutto il cervello di molte persone nel mondo Java EE. per favore non ripetere l'errore in .NET land.


7
Potresti elaborare, per favore? Sono richiesti DTO quando si restituiscono dati da un servizio Web, al fine di evitare l'implementazione e le specifiche della piattaforma nel contratto.
John Saunders,

1
Sì, i John DTO sono progettati per quello che dici e funzionano bene. Ma sfortunatamente vengono spesso utilizzati quando non richiesti nelle app Web a livello singolo e hanno poco valore.
Craig,

9
Penso, @drscroogemcduck, che forse non ti piacciono i DTO perché sono usati come prima risorsa piuttosto che come ultima risorsa, ma non sono intrinsecamente malvagi ... non più dei famigerati singleton o schemi di fabbrica. Ciò che è malvagio sono gli architetti che spingono quadri in gola agli sviluppatori che li costringono a realizzare DTO per tutto. Per quello che fanno, trasferendo i dati, i DTO (se eseguiti con prudenza) sono la soluzione perfetta.
Michael Meadows,

0

Le classi DTO vengono utilizzate per serializzare / deserializzare i dati da origini diverse. Quando vuoi deserializzare un oggetto da una fonte, non importa quale sia la fonte esterna: servizio, file, database ecc. Potresti voler usare solo una parte di questo ma vuoi un modo semplice per deserializzare quei dati in un oggetto. dopo di che copi quei dati su XModel che vuoi usare. Un serializzatore è una bellissima tecnologia per caricare oggetti DTO. Perché? hai solo bisogno di una funzione per caricare (deserializzare) l'oggetto.


0

TL; DR:

Un DTO descrive il modello di trasferimento dello stato. Un POCO non descrive nulla. È un altro modo di dire "oggetto" in OOP. Viene da POJO (Java), coniato da Martin Fowler che lo descrive letteralmente come un nome più elaborato per "oggetto" perché "oggetto" non è molto sexy.

Un DTO è un modello di oggetto utilizzato per trasferire lo stato tra i livelli di preoccupazione. Possono avere un comportamento (cioè tecnicamente può essere un poco) fintanto che quel comportamento non muta lo stato. Ad esempio, potrebbe avere un metodo che si serializza da solo.

Un POCO è un oggetto semplice, ma ciò che si intende per "semplice" è che non è speciale. Significa solo che è un oggetto CLR senza un modello implicito. Un termine generico. Non è fatto per funzionare con qualche altro framework. Quindi, se il tuo POCO ha [JsonProperty]o decorazioni EF in tutto le sue proprietà, per esempio, direi che non è un POCO.

Ecco alcuni esempi di diversi tipi di modelli di oggetti da confrontare:

  • Visualizza modello : utilizzato per modellare i dati per una vista. Di solito ha annotazioni di dati per aiutare l'associazione e la validazione. In MVVM, funge anche da controller. È più di un DTO
  • Valore oggetto : usato per rappresentare valori
  • Radice aggregata : utilizzata per gestire lo stato e gli invarianti
  • Gestori : utilizzati per rispondere a un evento / messaggio
  • Attributi : usati come decorazioni per affrontare questioni trasversali
  • Servizio : utilizzato per eseguire attività complesse
  • Controller : utilizzato per controllare il flusso di richieste e risposte
  • Factory : usato per configurare e / o assemblare oggetti complessi da usare quando un costruttore non è abbastanza buono. Utilizzato anche per prendere decisioni su quali oggetti devono essere creati in fase di esecuzione.
  • Repository / DAO : utilizzato per accedere ai dati

Questi sono tutti solo oggetti, ma notate che la maggior parte di essi è generalmente legata a uno schema. Quindi potresti chiamarli "oggetti" o potresti essere più specifico sulle sue intenzioni e chiamarlo per quello che è. Questo è anche il motivo per cui abbiamo modelli di progettazione; per descrivere concetti complessi in alcune opere. DTO è un modello. La radice aggregata è un modello, Visualizza modello è un modello (ad esempio MVC e MVVM). POCO non è un modello.

Un POCO non descrive uno schema. È solo un modo diverso di fare riferimento a classi / oggetti in OOP. Pensalo come un concetto astratto; possono riferirsi a qualsiasi cosa. IMO, esiste una relazione a senso unico, poiché una volta che un oggetto raggiunge il punto in cui può servire solo uno scopo in modo pulito, non è più un POCO. Ad esempio, una volta che contrassegni la tua classe con decorazioni per farla funzionare con qualche framework, non è più un POCO. Perciò:

  • Un DTO è un POCO
  • Un POCO non è un DTO
  • Un modello di visualizzazione è un POCO
  • Un POCO non è un modello di visualizzazione

Il punto nel fare una distinzione tra i due riguarda il mantenimento di schemi chiari e coerenti nello sforzo di non incrociare le preoccupazioni e condurre a un accoppiamento stretto. Ad esempio, se si dispone di un oggetto business che ha metodi per mutare lo stato, ma è anche decorato all'inferno con decorazioni EF per il salvataggio su SQL Server E JsonProperty in modo che possa essere rispedito su un endpoint API. Tale oggetto sarebbe intollerante al cambiamento e verosimilmente sarebbe disseminato di varianti di proprietà (ad es. UserId, UserPk, UserKey, UserGuid, in cui alcuni di essi sono contrassegnati per non essere salvati nel DB e altri contrassegnati per non essere serializzati in JSON all'endpoint API).

Quindi, se dovessi dirmi che qualcosa era un DTO, allora probabilmente mi assicurerei che non sia mai stato usato per qualcosa di diverso dallo spostamento dello stato. Se mi dicessi che qualcosa era un modello di visualizzazione, probabilmente mi assicurerei che non sia stato salvato in un database. Se mi avessi detto che qualcosa era un modello di dominio, probabilmente mi sarei assicurato che non dipendesse da qualcosa al di fuori del dominio. Ma se mi avessi detto che qualcosa era un POCO, non mi avresti detto molto.


-13

Non chiamarli nemmeno DTO. Si chiamano Modelli .... Periodo. Le modelle non hanno mai un comportamento. Non so chi sia venuto fuori con questo termine stupido DTO ma deve essere una cosa di .NET è tutto ciò che posso immaginare. Pensa ai modelli di visualizzazione in MVC, stessa cosa maledetta **, i modelli vengono utilizzati per trasferire lo stato tra i server lato layer o durante il periodo del filo, sono tutti modelli. Proprietà con dati. Questi sono modelli che si passano ove il filo. Modelli, Modelli Modelli. Questo è tutto.

Vorrei che lo stupido termine DTO andasse via dal nostro vocabolario.


1
non so dove hai avuto l'idea che le modelle non abbiano mai un comportamento. Come modellare qualcosa di diverso da CRUD senza comportamento di modellazione? Anche ViewModels ha un comportamento in molti casi, in particolare nelle app MVVM. DTO è un termine utile perché descrive accuratamente lo scopo; per trasferire dati.
Gerald,

9
declassato per essere effettivamente errato e per l'atteggiamento pontificante.
Joedotnot,

Senza senso. I modelli dovrebbero essere stupidi contenitori. Non esiste un DTO, è un termine inventato dagli Stati membri. Trasferisci modelli tra domini, servizi e app. Periodo. DTO è uno spreco di termini che non è necessario e confonde solo di più. Modelli, modelli e altri modelli. I modelli possono avere o meno comportamenti. Visualizza i modelli non dovrebbero. Tale comportamento dovrebbe essere in un BL, non nella classe Model.
Positivo

Sono d'accordo che i DTO sono funzionalmente modelli. ViewModels ha un comportamento ed è ciò a cui ti colleghi in MVVM. TUTTAVIA, ho scritto un'app in cui i miei modelli erano più intelligenti (fondamentalmente macchine virtuali ma non volevo chiamarli di così) e "accettavano" un oggetto DTO. Questo mi ha permesso di avere più opzioni con il framework. Quindi da CRUD (o anche EF), trasmetterei l'oggetto sui servizi WCF e riceverei l'oggetto DTO e lo incapsulerei (aggiungendo OnProp Change, ecc.). My ViewModels ha eseguito ulteriori incapsulamenti e potrebbe aver accettato due (o un elenco) di "Modelli". La definizione rigida sarebbe VM.
SQLMason,

"Trasferisci modelli tra domini, servizi e app" Perché pensi che il termine modello sia più appropriato e appropriato del termine DTO per questo comportamento che descrivi?
caa
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.