Jakie są korzyści z posiadania czystych modeli POCO?

16

Jakie są główne zalety posiadania czystych modeli POCO? Rozumiem, że modele powinny być czyste i proste, ale zazwyczaj lubię utrzymywać utrzymanie obiektów potomnych w klasach modeli. Na przykład, jeśli mam a ClassAi ClassBzdefiniowane w następujący sposób:

public class ClassA
{
    public string MyProp { get; set; }
    public IEnumerable<ClassB> Children { get; }

    public void AddChild(ClassB newChild) { /*... */ }
    public void RemoveChild(ClassB child) { /* ... */ }
}

public class ClassB
{
    public string SomeProp { get; set; }
} 

Czy jest coś z natury nie tak z metodami dodawania i usuwania? Czy zamiast tego powinienem po prostu odsłonić listę i pozwolić kodowi klienta na dodanie tego, co przechodzi odpowiedzialność za proste sprawdzanie poprawności danych, np. Nie jest zerowe i nie może być duplikowane do innej klasy?

Każda pomoc jest mile widziana, dzięki.

Jesse
źródło
Usunąłbym metody Dodaj / Usuń, chyba że dodadzą jakąś wartość, na przykład przetłumaczenie argumentu null ClassB na wersję obiektu o wzorze NullObject:AddChild(ClassB newChild) => Children.Add(newChild ?? new NullClassB())
Graham,
Jeśli kiedykolwiek miałeś do czynienia z bólem głowy klas ActiveRecord za pomocą setek metod, które mogą być lub nie być tym, czego chcesz w danym momencie, myślę, że łatwiej byłoby zrozumieć odwołanie.
Casey
Głównym powodem, dla którego należy unikać tego konkretnego projektu, jest niezgodność z wytycznymi dotyczącymi projektu .net. Jest to całkowicie arbitralne, ale ludzie oczekują, że kolekcja będzie zawierać metody mutacji.
Frank Hileman
@Casey Nie używam wzorca Active Record, metoda add polega po prostu na drobnej weryfikacji danych. Istnieje metoda usuwania, ponieważ kolekcja nie jest ujawniona, po prostu dodaje i usuwa z wewnętrznej listy. Zmieniłem to jednak, aby użyć innego typu kolekcji, który pozwala mi przeprowadzić weryfikację, wciąż korzystając z wbudowanych metod dodawania / usuwania.
Jesse

Odpowiedzi:

43

Twoje dwa pytania nie są ze sobą powiązane.

Jakie są korzyści z posiadania czystych modeli POCO?

Czysty POCO nie jest zależny od jakiegoś frameworku, konwencji, […] rzeczy lub ściśle związany z jakimś obiektem, który jest podobnie zależny. Innymi słowy, świat może całkowicie zmienić się wokół POCO i po prostu robi to, co robi, bez opieki. Nie możesz go zepsuć, aktualizując framework, przenosząc go do nowego systemu lub śmiesznie na niego patrząc. Po prostu działa. Jedyne zależności to rzeczy, o które wyraźnie prosi.

POCO to nic innego jak pomysł POJO. J został zmieniony na C, ponieważ ludzie patrzą na ciebie śmiesznie, gdy wyjaśnisz pojęcie, które ma nazwę Java w nazwie, jeśli ci ludzie używają C #. Pomysł nie zależy od języka. Mogliby po prostu nazwać to Plain Old Objects. Ale kto chce się chwalić używanie POO?

Pozwolę Fowlerowi wyjaśnić pochodzenie:

Termin ten został wymyślony, gdy Rebecca Parsons, Josh MacKenzie i ja przygotowywaliśmy się do wykładu na konferencji we wrześniu 2000 r. Podczas rozmowy wskazywaliśmy na wiele korzyści z kodowania logiki biznesowej w zwykłe obiekty Java zamiast używania Entity Beans. Zastanawialiśmy się, dlaczego ludzie są tak przeciwni używaniu zwykłych obiektów w swoich systemach i doszliśmy do wniosku, że dzieje się tak, ponieważ proste obiekty nie mają wymyślnej nazwy. Więc daliśmy im jeden i jest bardzo ładnie przyjęty.

martinfowler.com: POJO

Co do twojego drugiego pytania:

Czy jest coś z natury nie tak z metodami dodawania i usuwania?

Nie lubię Abezpośrednio wiedzieć B. Ale to jest DIP , a nie POJO .

candied_orange
źródło
Miałem bezpośrednią zależność od, Bdla uproszczenia, idealnie byłyby to oba zaimplementować interfejsy. Ale Awciąż ma listę IInterfaceB. Czy coś jest nie tak z tą AddChildmetodą, jeśli dzieci są luźno powiązane poprzez referencje interfejsu?
Jesse
6
Mogę zrobić całą masę głupich rzeczy dla uproszczenia. To, co mi się nie podoba, to wiedza A o B. A nie korzysta z B, więc nie ma potrzeby definiowania właściwego interfejsu A do komunikowania się z B. O ile mogę stwierdzić, A jest zbiorem. Więc A powinien poradzić sobie z B poprzez <T>, aby nie musiał nic o tym wiedzieć.
candied_orange
2
Widziałem też „PODO” dla „zwykłego, starego obiektu danych”, aby uniknąć jakiegokolwiek określenia języka w akronimie. PODO brzmi trochę głupio (trochę jak epitet, który można usłyszeć na Tatooine, dla mnie), bardziej niż POJO lub POCO, jak sądzę, ale znacznie mniej głupie niż POO.
KRyan
2
Zastanawiam się, jak dobrze wyglądałaby prezentacja Fowlera, gdyby nazwał ich POO?
Oliver,
3

Za pomocą opcji Dodaj i usuń wdrażasz Collection<T>funkcje. Zadaj sobie pytanie, dlaczego używasz IEnumerable<T>zamiast List<T>lub jakiejś innej zmiennej klasy? Najwyraźniej nie dlatego, że twoja kolekcja powinna być tylko do odczytu.

Jedynym powodem, dla którego mogę wymyślić, jest to, że chcesz kontrolować metody dostępu, które chcesz opublikować. W takim przypadku fajniej byłoby stworzyć własną klasę kolekcji, obudować listę, wdrożyć wybrane metody Dodaj i usuń oraz zaimplementujIEnumerable<T> . Następnie użyj tego zamiast IEnumerable<T>dla typu kolekcji dla dzieci.

Ale wydaje mi się, List<ClassB>że prawdopodobnie po prostu dobrze ci służy.

Martin Maat
źródło
0

Co AddChilddodaje do iRemoveChild usuwa? Jeśli pochodzi z bazy danych (lub innego rodzaju magazynu trwałości), masz rodzaj rekordu aktywnego. Niekoniecznie zawsze jest to zła rzecz, ale zdecydowanie zbliża się do zmartwień o ramy, konwencje, zależności itp., Jak wspomina @CandiedOrange.

Jednocześnie jaki byłby sens unikania zależności od klasy A do klasy B (lub przynajmniej interfejsu B), jeśli wszystkie są w tej samej aplikacji? W domenie świata rzeczywistego, którą modeluje twoja aplikacja, rzeczy zależą od siebie. Obiekty świata rzeczywistego zrobić mieć kolekcje innych obiektów, które „należą” do nich. Całkowicie właściwe jest reprezentowanie tych relacji w kodzie.

Jedynym powodem, dla którego staje się to trochę skomplikowane, jest to, że wydaje się, że musisz dokładnie zarządzać sposobem, w jaki klasa B zostaje skojarzona i odłączona od klasy A. Musisz więc wdrożyć małe zachowanie. Możesz albo zaimplementować go w klasie (co jest całkowicie „legalne”; patrz /programming//a/725365/44586 ), albo możesz mieć jakąś odrębną klasę, która zawiera takie zachowanie. Rób to, co najbardziej odpowiada twoim indywidualnym okolicznościom.

W każdym razie POJO / POCO jest tak naprawdę OOP, jak miało być, bez ozdób i bez obciążeń. Postępuj zgodnie z zasadami OOP, a będziesz bezpieczny.

John M. Gant
źródło
Naprawdę AddChild sprawdza tylko duplikację i ma wartość null, i nie pozwala na oba. Jest tam RemoveChild, ponieważ aby zapobiec dodaniu backdoora, kolekcja jest eksponowana jako IEnumerable. Wykonałby jednak tylko standardowe usunięcie z kolekcji.
Jesse
1
Dziękuję za wyjaśnienie. Tak, to brzmi dokładnie jak zachowanie, które powinno być w POCO, i zdecydowanie lepsze niż ujawnianie swojego podstawowego IEnumerable, aby osoby dzwoniące mogły dowolnie modyfikować lub zamieniać.
John M Gant,
Myślę, że Active Record to po prostu zły wzór.
Casey
1
@Casey, nie dostaniesz ode mnie żadnych argumentów na ten temat. Ale nie kłóciłbym się, gdyby ktoś chciał z niego skorzystać. Głównym punktem było to, że jeśli Jesse zamierzał zastosować wzorzec taki jak Active Record, który integruje wytrwałość z definicją modelu, miałby wszystkie problemy, które wyróżnia CandiedOrange, i tak naprawdę nie kwalifikowałby się jako POCO, z tego powodu. Ale i tak nie robi.
John M Gant,