Cześć.
Chciałem zapytać o sposób poprawnego projektowania klasy w przypadku gdy wiemy, że do klasy będzie dodawanych wiele nowych pól podczas pisania całego systemu.
Czy jest jakieś inne, lepsze podejście niż klasa z n-ilością ...{get; set;}? Chodzi mi o projektowanie zgodne z podejściem obiektowym. I w sumie, to czy i gdzie, może mieć sens podejście z klasą z samymi właściwościami? Zastanawiam się czy taka opcja nie wpływa na dużo większą podatność na błędy?. Dodam jeszcze, że klasa jest mapowana na tabele w DB przy użyciu EF. Z góry dzięki za odpowiedzi.
Klasa z samymi propertisami nadaje się jako DTO właśnie np. jako encja bazodanowa, model danych w API Restowym czy message z Kafki.
Nie ma to za dużo wspólnego z OOP ale miałem na obowiązku żeby system informatyczny był w 100% OOP.
Czyli dobrą praktyką jest, że gdy klasa ma być encją DB to nie ładować do niej żadnej logiki?
corthell napisał(a):
Czyli dobrą praktyką jest, że gdy klasa ma być encją DB to nie ładować do niej żadnej logiki?
Bardzo dobrą. Niech ta klasa służy jako mapowanie do bazy i nic więcej. Jeśli ma dużo kolumn, to po co do logiki pchać je wszystkie, jeśli ze wszystkich się nie korzysta? Lepiej zrobić projekcję na klasę domenową z takimi danymi, jakie są potrzebne dla obsługi przypadku użycia.
@SkrzydlatyWąż: I po utworzeniu takiej klasy po projekcji można używać w sposób zgodny z OOP, czy prywatne , walidowane pola, uniemożliwiać budowanie obiektu z jakimiś polami bez wartości itp? Zdaje sobie sprawę, że opcji rozwiązań może być wiele bo zakładam, że nie ma tego nigdzie ścisłe tego opisanego, jednak zdaje sie na Wasze doświadczenie.
corthell napisał(a):
Czy jest jakieś inne, lepsze podejście niż klasa z n-ilością ...{get; set;}?
No np. dużo klas z małą liczbą właściwości. Albo słownik. To, czy coś jest lepsze zależy od kontekstu, a tego nie znamy.
Zastanawiam się czy taka opcja nie wpływa na dużo większą podatność na błędy?
Jeśli pchasz tę klasę z warstwy data access na frontend, to owszem, może wpłynąć negatywnie.
corthell napisał(a):
@SkrzydlatyWąż: I po utworzeniu takiej klasy po projekcji można używać w sposób zgodny z OOP, czy prywatne , walidowane pola, uniemożliwiać budowanie obiektu z jakimiś polami bez wartości itp?
Ale jeśli to ma być używana przez ORMa (wolę nazwę persistence model
niż encja DB
), to czemu chciałbyś to wszystko w niej robić?
Logikę biznesową zaimplementuj w innych klasach.
Jako zwolennik niemutowalności tworzyłbym niemutowalny obiekt przez konstruktor, a właściwości tylko jako { get; }
.Jeśli są potrzebne na zewnątrz, też mogą być niemutowalne. Są w C# System.Collections.Immutable
. I zamiast tworzyć mnóstwo właściwości, w klasach domenowych według mnie lepiej skupić się kompozycji, czyli składać je z innych obiektów. Prosty przykład: Order
zawiera właściwość OrderDetails
. Zamiast wielu właściwości - te są zebrane w jednym OrderDetails
. Ale to też zależy, czy robisz np. w XAMLu i potrzebujesz { set; }
? Bo jeśli framework tego nie wymusza, to po co setter? Wydzielenie oddzielnej klasy walidatora może być sensowniejsze niż walidowanie w konstruktorze czy setterach (czego osobiście nie lubię).
Tworzenie obiektu bez wartości nie brzmi dobrze, chyba że z pustą kolekcją. Czy nie lepiej zrobić oddzielną klasę CanceledOrder
z wypełnioną właściwością CancellationReason
niż Order z CancellationReason = null
? Trywialny przykład, ale sens chyba widoczny.
SkrzydlatyWąż napisał(a):
Jako zwolennik niemutowalności tworzyłbym niemutowalny obiekt przez konstruktor, a właściwości tylko jako { get; }
.Jeśli są potrzebne na zewnątrz, też mogą być niemutowalne. Są w C# System.Collections.Immutable
.
Entity Framework ogarnia takie rzeczy? Bo jeśli nie, to za wiele autor nie poszaleje.
@somekind: Entity Framework Core ogarnia wywoływanie konstruktora, co do kolekcji - raczej nie. Co to niemutowania - miałem na myśli niemutowanie klas z domeny. Klasy mapujące bazę niech się mutują, ale ja bym na nich nie robił domenowej logiki :)
SkrzydlatyWąż napisał(a):
corthell napisał(a):
Czyli dobrą praktyką jest, że gdy klasa ma być encją DB to nie ładować do niej żadnej logiki?
Bardzo dobrą. Niech ta klasa służy jako mapowanie do bazy i nic więcej. Jeśli ma dużo kolumn, to po co do logiki pchać je wszystkie, jeśli ze wszystkich się nie korzysta? Lepiej zrobić projekcję na klasę domenową z takimi danymi, jakie są potrzebne dla obsługi przypadku użycia.
Nie mogę się całkowicie z tym zgodzić. O ile zasadniczo wydaje się to być ok podejściem, to trzeba to przemyśleć. Może się okazać, że przez to kod w pewnym momencie będzie bardzo mocno zduplikowany.
No i? Co w związku z tym że będzie duzo duplikacji? Unikanie duplikacji jest wazne w logice a nie strukturach danych.
Może dojść do tego sporo niepotrzebnej roboty przy zmianach. Dodanie jakiegoś pola, czy usunięcie. Dlatego piszę o przemyśleniu tego.