Obecnie pracuję jako programista solo nad moim obecnym projektem. Projekt odziedziczyłem od innego programisty, który odszedł z firmy. Jest to aplikacja internetowa w stylu kontrolera widoku modelu w języku C #. Używa Entity Framework do mapowania relacyjnego obiektu. Istnieją dwa różne zestawy klas dla typów w modelu domeny. Jeden zestaw służy do interakcji z ORM, a drugi jest używany jako modele w systemie MVC. Na przykład mogą istnieć dwie klasy:
public class Order{
int ID{get;set;}
String Customer{get;set;}
DateTime DeliveryDate{get;set;}
String Description{get;set;}
}
i
public class OrderModel{
String Customer{get;set;}
DateTime DeliveryDate{get;set;}
String Description{get;set;}
public OrderModel( Order from){
this.Customer= from.Customer;
// copy all the properties over individually
}
public Order ToOrder(){
Order result =new Order();
result.Customer = this.Customer;
// copy all the properties over individually
}
}
Mogę wymyślić kilka wad tego podejścia (więcej miejsc do zmiany kodu, jeśli coś się zmieni, więcej obiektów siedzi w pamięci, więcej czasu spędzonego na kopiowaniu danych), ale nie jestem pewien, jakie są zalety tego rozwiązania. Chyba większa elastyczność klas modelowych? Ale mogłem to osiągnąć, również podklasując klasy jednostek. Moją skłonnością byłoby połączenie tych dwóch grup klas lub ewentualnie, aby klasy modeli były podklasami klas jednostek. Czy brakuje mi więc czegoś ważnego? Czy to typowy wzorzec projektowy, o którym nie wiem? Czy istnieją dobre powody, aby nie przejść przez refaktor, który rozważam?
AKTUALIZACJA
Niektóre odpowiedzi tutaj uświadamiają mi, że w moim początkowym opisie projektu brakowało pewnych ważnych szczegółów. W projekcie istnieje także trzecia grupa klas: klasy modelu strony. Są one faktycznie używane jako model kopii strony. Zawierają również informacje specyficzne dla interfejsu użytkownika i nie byłyby przechowywane z zamówieniem w bazie danych. Przykładową klasą modelu strony może być:
public class EditOrderPagelModel
{
public OrderModel Order{get;set;}
public DateTime EarliestDeliveryDate{get;set;}
public DateTime LatestAllowedDeliveryDate{get;set;}
}
Całkowicie widzę, że użyteczność tej trzeciej grupy jest tutaj odrębna i nie planuję łączyć jej z czymś innym (chociaż mógłbym zmienić jej nazwę).
Klasy w grupie modeli są obecnie również używane przez interfejs API aplikacji, do którego również chciałbym się dowiedzieć, czy to dobry pomysł.
Powinienem również wspomnieć, że klient reprezentowany tutaj jako ciąg znaków miał uprościć przykład, a nie dlatego, że faktycznie jest reprezentowany w ten sposób w systemie. Rzeczywisty system ma klienta jako odrębny typ w modelu domeny z własnymi właściwościami
źródło
Odpowiedzi:
TAK
Chociaż wyglądają tak samo i reprezentują to samo w domenie, nie są to te same obiekty (OOP).
Jednym z nich jest
Order
część kodu związana z pamięcią danych. Drugi toOrder
znany interfejs użytkownika. Chociaż przyjemnym zbiegiem okoliczności jest to, że klasy te mają te same właściwości, nie ma gwarancji , że tak będzie.Lub, aby spojrzeć na to z innej perspektywy, rozważ zasadę pojedynczej odpowiedzialności. Kluczowym czynnikiem motywującym jest to, że „klasa ma jeden powód do zmiany”. Zwłaszcza, gdy mamy do czynienia z wszechobecnymi frameworkami, takimi jak ORM i / lub UI, twoje obiekty muszą być dobrze izolowane, ponieważ zmiany w frameworku często powodują zmianę twoich bytów.
Wiążąc swoje byty z obiema platformami, czynisz to o wiele gorszym.
źródło
Celem Modelu widoku jest zapewnienie rozdzielenia na dwa sposoby: poprzez dostarczenie danych w kształcie wymaganym przez Widok (niezależnie od modelu) i (szczególnie w MVVM) poprzez wypchnięcie części lub całości logiki Widoku z powrotem z Widoku do widoku modelu.
W modelu w pełni znormalizowanym klient nie byłby reprezentowany w modelu przez ciąg, ale przez identyfikator. Model, jeśli potrzebuje nazwy klienta, szukałby nazwy z tabeli Klienci, używając identyfikatora klienta znalezionego w tabeli Zamówienia.
Z drugiej strony model View może być bardziej zainteresowany
Name
klientem niż identyfikatorem. Nie wymaga identyfikatora, chyba że klient jest aktualizowany w modelu.Ponadto model widoku może i zwykle przyjmuje inny kształt (chyba że jest to czysty CRUD ). Obiekt modelu widoku faktury może mieć nazwę klienta, adresy i elementy zamówienia, ale model zawiera klientów i opisy.
Innymi słowy, faktury zwykle nie są przechowywane w taki sam sposób, w jaki są wyświetlane.
źródło
Pod pewnymi względami masz rację: oba odnoszą się do tego samego obiektu domeny, który jest nazywany
order
. Ale mylisz się co do tego, że nie jest to prawdziwe powielanie niż inna reprezentacja - wywodząca się z różnych celów. Jeśli chcesz zachować zamówienie, np. Chcesz uzyskać dostęp do każdej kolumny. Ale nie chcesz tego wyciec na zewnątrz. Poza tym przepychanie całych Istot przez drut nie jest tym, czego naprawdę chcesz. Znam przypadki, w których zbiór MBorders
został wysłany do klienta, gdzie wystarczy kilka kilobajtów .Krótko mówiąc - oto główne powody, dla których chcesz to zrobić:
1) Enkapsulacja - ukrywanie informacji o Twojej aplikacji
2) Małe modele są szybkie do serializacji i łatwe do przesłania
3) Służą one różnym celom, chociaż nakładają się na siebie, dlatego też powinny istnieć różne przedmioty.
4) Czasami sensowne jest posiadanie dla różnych zapytań różnych obiektów wartości . Nie wiem, jak to jest w C #, ale w Javie można używać POJO do zbierania wyników. Jeśli potrzebuję pojedynczego
order
, używam Order -Entity, ale jeśli potrzebuję tylko niektórych kolumn wypełnionych kwotami danych, użycie mniejszych Obiektów jest bardziej wydajne.źródło
(Zastrzeżenie: Widziałem, że jest używane tylko w ten sposób. Mogłem nie rozumieć prawdziwego celu takiego działania. Podejmij tę odpowiedź z podejrzliwością.)
Oto kolejny brakujący bit: konwersja między
Order
iOrderModel
.Order
Klasa jest przywiązany do swojego ORM, gdyOrderModel
jest związana z projektem swojego widoku modelu.Zazwyczaj te dwie metody będą dostarczane „w magiczny sposób” (czasami nazywane DI, IoC, MVVM lub jeszcze inną rzeczą). Oznacza to, że zamiast implementować te dwie metody konwersji w ramach
OrderModel
, będą one należeć do klasy poświęconej wzajemnej konwersji tych rzeczy; klasa ta zostanie w jakiś sposób zarejestrowana w frameworku, aby frameworek mógł go łatwo wyszukać.Powodem jest to, że robi to, gdy znajduje się przejście od
OrderModel
doOrder
, lub odwrotnie, wiesz, że niektóre dane muszą być ładowane z lub zapisać do ORM.źródło