Zwykły stary obiekt CLR a obiekt transferu danych

405

POCO = Plain Old CLR (lub lepiej: Class) Object

DTO = Obiekt transferu danych

W tym poście jest różnica, ale szczerze mówiąc większość blogów, które czytam, opisuje POCO w sposobie definiowania DTO: DTO to proste pojemniki danych używane do przenoszenia danych między warstwami aplikacji.

Czy POCO i DTO to to samo?

Patrick Peters
źródło
5
„POCO = Plain Old CLR (lub lepiej: Class) Object”. Zatem obiektami tego rodzaju w VB.NET byłyby również POCO, a nie POVO.
J. Polfer,

Odpowiedzi:

568

POCO przestrzega zasad OOP. Powinien (ale nie musi) mieć stan i zachowanie. POCO pochodzi od POJO, wymyślonego przez Martina Fowlera [ tutaj anegdota ]. Użył terminu POJO jako sposobu, aby uczynić bardziej seksownym odrzucenie ciężkich implementacji EJB dla szkieletu. POCO powinno być używane w tym samym kontekście w .Net. Nie pozwól, aby ramy dyktowały projekt twojego obiektu.

Jedynym celem DTO jest przeniesienie stanu i nie powinno ono zachowywać się. Zobacz wyjaśnienie DTO Martina Fowlera, aby zobaczyć przykład użycia tego wzorca.

Oto różnica: POCO opisuje podejście do programowania (staromodne programowanie obiektowe), w którym DTO jest wzorcem używanym do „przesyłania danych” za pomocą obiektów.

Chociaż możesz traktować POCO jak DTO, ryzykujesz utworzenie anemicznego modelu domeny, jeśli to zrobisz. Ponadto istnieje rozbieżność w strukturze, ponieważ DTO powinny być zaprojektowane do przesyłania danych, a nie do reprezentowania prawdziwej struktury domeny biznesowej. Powoduje to, że DTO wydają się być bardziej płaskie niż rzeczywista domena.

W domenie o dowolnej złożoności prawie zawsze lepiej jest tworzyć oddzielne POCO domeny i tłumaczyć je na DTO. DDD (projekt oparty na domenie) definiuje warstwę antykorupcyjną (kolejny link tutaj , ale najlepiej jest kupić książkę ), która jest dobrą strukturą, która wyjaśnia segregację.

Michael Meadows
źródło
Wiem, że dużo tu wspominałem Martina Fowlera, ale ukuł termin POJO i napisał książkę PoEAA, która jest ostatecznym odniesieniem dla DTO.
Michael Meadows
Nie jestem pewien, czy DTO nie powinien mieć zachowań. Sędziując według schematu Martina Fowlera, DTO może mieć zachowania.
Beatles1692
39
@ Beatles1692, przedstawione metody to kod serializacji. Prawdopodobnie jest to zbyt szerokie stwierdzenie, by powiedzieć „brak zachowania”. Co powiesz na „brak logiki biznesowej”. Kod serializacji i obiekty niskiego poziomu, takie jak kod skrótu, równość i tostring, powinny być dopuszczalne.
Michael Meadows
1
@PositiveGuy Model służy innym celom niż DTO. DTO powinno służyć do przesyłania danych z jednej domeny do drugiej (nie ma znaczenia, czy są one w tym samym środowisku uruchomieniowym). Model „reprezentuje” aspekt domeny, taki jak ekran, usługa lub źródło danych. Modele obejmują stan i zachowanie, które są reprezentatywne dla tego, co modelują.
Michael Meadows
2
Pamiętaj, że anemiczne modele domen niekoniecznie są złe, szczególnie jeśli twoja aplikacja jest w większości CRUD. Wolę prostotę niż Martin Fowler.
Mariusz Jamro
50

Prawdopodobnie jest to dla mnie zbędne, ponieważ wypowiedziałem się już w moim blogu, ale ostatni akapit tego artykułu podsumowuje:

Podsumowując, naucz się kochać POCO i upewnij się, że nie rozpowszechniasz żadnych nieporozumień na temat tego, że jest to to samo, co DTO. DTO to proste kontenery danych służące do przenoszenia danych między warstwami aplikacji. POCO są pełnoprawnymi obiektami biznesowymi z jednym wymogiem, że są ignorantami trwałości (bez metod pobierania lub zapisywania). Na koniec, jeśli jeszcze nie sprawdziłeś książki Jimmy'ego Nilssona, odbierz ją ze stosów lokalnych uniwersytetów. Ma przykłady w języku C # i jest świetną lekturą.

BTW, Patrick Przeczytałem POCO jako artykuł Lifestyle i całkowicie się zgadzam, to fantastyczny artykuł. To właściwie fragment z książki Jimmy'ego Nilssona, który poleciłem. Nie miałem pojęcia, że ​​jest dostępny online. Jego książka jest naprawdę najlepszym źródłem informacji na temat POCO / DTO / Repository / i innych praktyk programistycznych DDD.


źródło
4
Link do artykułu na blogu: rlacovara.blogspot.com/2009/03/...
Jamie Ide
28

POCO to po prostu obiekt, który nie jest zależny od zewnętrznych ram. To jest ZWYKŁE.

To, czy POCO ma zachowanie, czy nie, jest nieistotne.

DTO może być POCO, podobnie jak obiekt domeny (który zazwyczaj byłby bogaty w zachowanie).

Zazwyczaj DTO częściej przyjmują zależności od zewnętrznych ram (np. Atrybutów) do celów serializacji, ponieważ zazwyczaj wychodzą na granicy systemu.

W typowych architekturach typu cebulowego (często używanych w ramach szeroko pojętego podejścia DDD) warstwa domeny jest umieszczana w środku, więc jej obiekty nie powinny w tym momencie mieć zależności poza tą warstwą.

Neil
źródło
15

Napisałem artykuł na ten temat: DTO vs Value Object vs POCO .

W skrócie:

  • DTO! = Obiekt wartości
  • DTO ⊂ POCO
  • Obiekt wartości ⊂ POCO
Vladimir
źródło
6

Myślę, że DTO może być POCO. DTO bardziej dotyczy korzystania z obiektu, podczas gdy POCO jest bardziej stylem obiektu (oddzielony od koncepcji architektonicznych).

Jednym z przykładów, w których POCO jest czymś innym niż DTO, jest mówienie o POCO w modelu domeny / modelu logiki biznesowej, który jest niezłą reprezentacją problemu w domenie problemowej. Możesz używać POCO w całej aplikacji, ale może to mieć niepożądane skutki uboczne, takie jak wyciek wiedzy. DTO są na przykład używane z warstwy usługowej, z którą komunikuje się interfejs użytkownika, DTO są płaską reprezentacją danych i są używane tylko do dostarczania interfejsowi danych i przekazywania zmian z powrotem do warstwy usług. Warstwa usługi odpowiada za odwzorowanie obu sposobów DTO na obiekty domeny POCO.

Aktualizacja Martin Fowler powiedział, że takie podejście jest trudną drogą i należy je podjąć tylko wtedy, gdy istnieje znaczące niedopasowanie między warstwą domeny a interfejsem użytkownika.

Davy Landman
źródło
2
@David Landman, podany link służy do lokalnego wzorca DTO, czyli wtedy, gdy DTO są używane do stanu transferu w granicach twojego systemu. W takich przypadkach powinieneś być bardzo ostrożny, ponieważ w swoim systemie powinieneś mieć już dobrze zdefiniowaną domenę, którą można udostępniać. Podczas przenoszenia stanu poza granice systemu DTO jest trudny do uniknięcia i całkiem odpowiedni we wszystkich przypadkach.
Michael Meadows
@Michal Meadows, tak, link rzeczywiście mówi o innym podzbiorze problemów. Ale myślę, że w przypadku przenoszenia stanu przez granicę systemu powinieneś użyć usługi tłumaczącej, aby zmapować POCO z jednego kontekstu do POCO z innego kontekstu. A może mówisz o granicach na poziomie systemu?
Davy Landman
1

Podstawowym przypadkiem użycia DTO jest zwracanie danych z usługi internetowej. W tym przypadku POCO i DTO są równoważne. Każde zachowanie w POCO zostanie usunięte, gdy zostanie zwrócone z usługi sieciowej, więc tak naprawdę nie ma znaczenia, czy ma zachowanie.

John Saunders
źródło
5
Myślę, że twoja odpowiedź źle przedstawia to, co się dzieje. W przypadku usługi sieci web proxy jest generowane na podstawie odsłoniętego stanu obiektu. Oznacza to, że DTO jest tworzony niezależnie od POCO, który akurat ma taki sam stan publiczny jak POCO. Może się to wydawać subtelne, ale jest ważne. Powodem jest to, że nawet jeśli proxy jest identyczne z oryginałem, tak naprawdę nie jest zbudowane z tej samej klasy.
Michael Meadows
O nie. Jeden używa DTO do zwracania / odbierania danych między warstwami, w tym przypadku usługą internetową. Jeden wybiera DTO, ponieważ ma tylko dane i nie zachowuje się. Prawdą jest, że klasa proxy prawdopodobnie będzie również DTO i że jeśli zamiast tego użyjesz klasy POCO, to proxy zostanie utworzone. Ale w tym przypadku klasa POCO jest faktycznie DTO, ponieważ jej zachowanie się nie przełoży. Nadal mówię, że używaj DTO, ponieważ nie umknie ci zachowanie, które nigdy nie istniało.
John Saunders
5
** Semantycznie: usługi sieci Web ujawniają torby stanu obiektu za pomocą WSDL. Z nich generowane są proxy. Nie mogą one obejmować zachowania. Jeśli korzystasz z usługi internetowej, jedyną relacją między twoim obiektem a odsłoniętym obiektem domeny jest to, że ma on ten sam stan publiczny utworzony na podstawie inspekcji.
Michael Meadows
7
@John, myślę, że przesadzasz. Mówię, że masz rację, ale twoje sformułowania wprowadzają w błąd. „W tym przypadku POCO i DTO są równoważne.” Semantycznie to nie prawda. POCO mogą być używane jako DTO i vice versa, ale to nie znaczy, że są równoważne ... nie więcej niż samochód i pikap są równoważne, nawet jeśli oba mogą być użyte do doprowadzenia cię do sklepu spożywczego. Mają funkcję nakładania się, ale trudno byłoby znaleźć kogoś, kto powiedziałby, że wgląd jest równoważny F350, nawet w kontekście podróży spożywczej.
Michael Meadows
3
Ta odpowiedź jest tak bardzo błędna, że ​​usługa internetowa nie jest dla niej wystarczająco ogólna. Najważniejsze jest to, że DTO nie jest POCO. DTO jest kontenerem danych, podczas gdy POCO są obiektami jako właściwości i są ignorantami w utrzymywaniu (brak metod get lub save).
Tom Stickel,
1

oto ogólna zasada: DTO == zło i wskaźnik nadmiernie zaprojektowanego oprogramowania. POCO == dobre. Wzorce „przedsiębiorczości” zniszczyły mózgi wielu ludzi w świecie Java EE. proszę nie powtarzać błędu w krainie .NET.

benmmurphy
źródło
7
Czy mógłbyś opracować, proszę? Podczas zwracania danych z usługi internetowej wymagane są DTO, aby uniknąć implementacji i specyfiki platformy w umowie.
John Saunders,
1
Tak, John DTO są zaprojektowane do tego, co mówisz i działają dobrze. Ale niestety często się przyzwyczajają, gdy nie są wymagane w aplikacjach internetowych jednowarstwowych i mają niewielką wartość.
Craig,
9
Wydaje mi się, @drscroogemcduck, że być może nie lubisz DTO, ponieważ są one używane raczej jako środek ostateczny niż ostateczny, ale nie są z natury złe ... nie bardziej niż niesławny singleton lub wzorce fabryczne. Tym, co jest złe, są architekci, którzy pchają ramy w gardło deweloperów, które zmuszają ich do tworzenia DTO na wszystko. Do tego, co robią, przesyłanie danych, DTO (jeśli są wykonywane ostrożnie) są idealnym rozwiązaniem.
Michael Meadows
0

Klasy DTO służą do serializacji / deserializacji danych z różnych źródeł. Jeśli chcesz dokonać deserializacji obiektu ze źródła, nie ma znaczenia, jakie to źródło zewnętrzne: usługa, plik, baza danych itp., Możesz chcieć skorzystać tylko z niektórych jego części, ale chcesz w łatwy sposób zserializować dane do postaci obiekt. następnie skopiujesz te dane do XModel, którego chcesz użyć. Serializator to piękna technologia do ładowania obiektów DTO. Dlaczego? potrzebujesz tylko jednej funkcji do załadowania (deserializacji) obiektu.

Herman Van Der Blom
źródło
0

TL; DR:

DTO opisuje wzór przeniesienia stanu. POCO niczego nie opisuje. To inny sposób na powiedzenie „obiekt” w OOP. Pochodzi z POJO (Java), wymyślonego przez Martina Fowlera, który dosłownie opisuje go jako bardziej wyszukaną nazwę dla „obiektu”, ponieważ „obiekt” nie jest zbyt seksowny.

DTO to wzorzec obiektowy używany do przenoszenia stanu między warstwami wzbudzającymi obawy. Mogą mieć zachowanie (tj. Technicznie mogą być poco), o ile zachowanie to nie mutuje stanu. Na przykład może mieć metodę serializacji.

POCO jest prostym przedmiotem, ale „zwykły” oznacza, że ​​nie jest wyjątkowy. Oznacza to po prostu, że jest to obiekt CLR bez domyślnego wzorca. Ogólny termin. Nie jest przeznaczony do pracy z innymi ramami. Więc jeśli na przykład twoje POCO ma [JsonProperty]dekoracje EF, to na przykład argumentowałbym, że to nie POCO.

Oto przykłady różnych rodzajów wzorców obiektów do porównania:

  • Model widoku : służy do modelowania danych dla widoku. Zwykle zawiera adnotacje danych, które pomagają w wiązaniu i sprawdzaniu poprawności. W MVVM działa również jako kontroler. To więcej niż DTO
  • Obiekt wartości : służy do reprezentowania wartości
  • Korzeń zagregowany : służy do zarządzania stanem i niezmiennikami
  • Procedury obsługi : używane w odpowiedzi na zdarzenie / wiadomość
  • Atrybuty : używane jako dekoracje w rozwiązywaniu problemów przekrojowych
  • Usługa : służy do wykonywania złożonych zadań
  • Kontroler : służy do kontroli przepływu żądań i odpowiedzi
  • Fabryka : służy do konfigurowania i / lub składania złożonych obiektów do użycia, gdy konstruktor nie jest wystarczająco dobry. Służy również do podejmowania decyzji, które obiekty należy utworzyć w czasie wykonywania.
  • Repozytorium / DAO : służy do uzyskiwania dostępu do danych

To wszystko są tylko obiekty, ale zauważ, że większość z nich jest na ogół związana ze wzorem. Możesz więc nazwać je „przedmiotami” lub możesz być bardziej szczegółowy na temat jego intencji i nazwać to tym, czym jest. Dlatego też mamy wzorce projektowe; opisać złożone pojęcia w kilku pracach. DTO jest wzorem. Łączny katalog główny to wzorzec, a widok modelu to wzorzec (np. MVC i MVVM). POCO nie jest wzorem.

POCO nie opisuje wzoru. Jest to po prostu inny sposób odwoływania się do klas / obiektów w OOP. Pomyśl o tym jako o abstrakcyjnej koncepcji; mogą odnosić się do wszystkiego. IMO istnieje jednak relacja jednokierunkowa, ponieważ gdy obiekt osiągnie punkt, w którym może służyć tylko jednemu celowi, nie jest już POCO. Na przykład, kiedy oznaczysz swoją klasę dekoracjami, aby działała z jakimś szkieletem, nie będzie już POCO. W związku z tym:

  • DTO to POCO
  • POCO nie jest DTO
  • Model widoku to POCO
  • POCO nie jest modelem widoku

Rozróżnienie między nimi polega na tym, aby zachować przejrzystość i spójność wzorów, aby nie przekraczać obaw i prowadzić do ścisłego połączenia. Na przykład, jeśli masz obiekt biznesowy, który ma metody mutowania stanu, ale jest także udekorowany piekłem za pomocą dekoracji EF do zapisywania na SQL Server i JsonProperty, aby można go było odesłać przez punkt końcowy interfejsu API. Obiekt ten byłby nietolerancyjny do zmiany i prawdopodobnie byłby zaśmiecony wariantami właściwości (np. UserId, UserPk, UserKey, UserGuid, gdzie niektóre z nich są oznaczone, aby nie były zapisywane w bazie danych, a inne oznaczone, aby nie były serializowane, JSON w punkcie końcowym interfejsu API).

Więc jeśli miałbyś mi powiedzieć, że coś było DTO, prawdopodobnie upewniłbym się, że nigdy nie był używany do niczego innego niż przemieszczanie się. Jeśli powiedziałeś mi, że coś jest modelem widoku, prawdopodobnie upewniłbym się, że nie zostanie zapisany w bazie danych. Jeśli powiedziałeś mi, że coś jest modelem domeny, prawdopodobnie upewniłbym się, że nie ma zależności od niczego poza domeną. Ale gdybyś powiedział mi, że coś jest POCO, tak naprawdę wcale byś mi nie powiedział.

Sinaesthetic
źródło
-13

Nawet nie nazywaj ich DTO. Nazywają się Modele .... Okres. Modele nigdy nie zachowują się. Nie wiem, kto wymyślił ten głupi termin DTO, ale to chyba wszystko .NET to wszystko, co mogę wymyślić. Pomyśl o widokach modeli w MVC, o tym samym dam **, modele są używane do przesyłania stanu między warstwami po stronie serwera lub w okresie przewodowym, wszystkie są modelami. Właściwości z danymi. Są to modele, które przekazujesz przez drut. Modele, modele Modele. Otóż ​​to.

Chciałbym, żeby głupi termin DTO odszedł od naszego słownictwa.

PositiveGuy
źródło
1
nie wiem skąd pomysł, że modele nigdy się nie zachowują. Jak modelujesz coś innego niż CRUD bez zachowania modelowania? Nawet ViewModels zachowuje się w wielu przypadkach, szczególnie w aplikacjach MVVM. DTO jest przydatnym terminem, ponieważ dokładnie opisuje cel; przesyłać dane.
Gerald,
9
zlekceważony za to, że jest niepoprawny pod względem faktycznym, i za ponure podejście.
joedotnot
Nonsens. Modele powinny być głupimi pojemnikami. Nie ma DTO, jest to termin na MS. Możesz przenosić modele między domenami, usługami i aplikacjami. Kropka. DTO to strata czasu, która nie jest potrzebna i tylko dezorientuje. Modele, modele i więcej modeli to wszystko. Modele mogą, ale nie muszą, zachowywać się. Zobacz modele nie powinny. Takie zachowanie powinno być w BL, a nie w klasie Model.
PositiveGuy,
Zgadzam się, że DTO są funkcjonalnie modelami. ViewModels ma zachowanie i jest tym, z czym się łączysz w MVVM. JEDNAK napisałem aplikację, w której moje Modele były bardziej inteligentne (w zasadzie maszyny wirtualne, ale nie chciałem ich wywoływać) i „zaakceptowały” obiekt DTO. To pozwoliło mi mieć więcej opcji z frameworkiem. Tak więc z CRUD (lub nawet EF) przesyłałbym obiekt za pośrednictwem usług WCF, otrzymywałbym obiekt DTO i enkapsulował go (dodając zmianę OnProp itp.). Moje modele ViewModels wykonały dalszą enkapsulację i mogły zaakceptować dwa (lub listę) „modeli”. Sztywna definicja to maszyny wirtualne.
SQLMason
„Przenosisz modele między domenami, usługami i aplikacjami”. Dlaczego uważasz, że termin model jest bardziej odpowiedni i trafniejszy niż termin DTO dla opisywanego zachowania?
caa