Powiedzmy, że mam Car
klasę:
public class Car
{
public string Engine { get; set; }
public string Seat { get; set; }
public string Tires { get; set; }
}
Powiedzmy, że tworzymy system o parkingu, zamierzam wykorzystać dużo Car
klasy, więc tworzymy CarCollection
klasę, może mieć kilka dodatkowych metod, takich jak FindCarByModel
:
public class CarCollection
{
public List<Car> Cars { get; set; }
public Car FindCarByModel(string model)
{
// code here
return new Car();
}
}
Jeśli robię zajęcia ParkingLot
, jaka jest najlepsza praktyka?
Opcja 1:
public class ParkingLot
{
public List<Car> Cars { get; set; }
//some other properties
}
Opcja 2:
public class ParkingLot
{
public CarCollection Cars { get; set; }
//some other properties
}
Czy to dobra praktyka, aby stworzyć ClassCollection
inną Class
?
CarCollection
raczej niżList<Car>
dookoła? Zwłaszcza, że CarCollection nie rozszerza zaplecza klasy List, ani nawet nie implementuje interfejsu Collection (jestem pewien, że C # ma podobne rzeczy).public class CarCollection
nie implementuje IList ani ICollection itp., Dlatego nie można przekazać go do czegoś, co jest w porządku z listą. W ramach nazwy twierdzi, że jest kolekcją, ale nie implementuje żadnej z tych metod.CarColection
zTotalTradeValue
nieruchomości na niego. DDD nie jest jedynym sposobem projektowania systemów, tylko wskazując go jako opcję.Odpowiedzi:
Przed generycznymi w .NET powszechną praktyką było tworzenie kolekcji „na maszynie”, aby mieć
class CarCollection
itd. Dla każdego typu, który trzeba pogrupować. W .NET 2.0 z wprowadzeniem Generics wprowadzono nową klasę,List<T>
która oszczędza konieczności tworzeniaCarCollection
itp. Podczas tworzeniaList<Car>
.List<T>
Przez większość czasu okaże się, że jest to wystarczające do realizacji twoich celów, jednak może się zdarzyć, że będziesz chciał mieć określone zachowanie w swojej kolekcji, jeśli uważasz, że tak jest, masz kilka opcji:List<T>
na przykład klasę, która będzie hermetyzowaćpublic class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
public class CarCollection : CollectionBase<Car> {}
Jeśli wybierzesz metodę enkapsulacji, powinieneś przynajmniej odsłonić moduł wyliczający, aby zadeklarować go w następujący sposób:
Bez tego nie można przerobić
foreach
kolekcji.Niektóre powody, dla których warto utworzyć kolekcję niestandardową, to:
IList<T>
lubICollection<T>
Czy to dobra praktyka? cóż, to zależy od tego , dlaczego to robisz, jeśli jest to na przykład jeden z powodów, które wymieniłem powyżej, to tak.
Microsoft robi to dość regularnie, oto kilka całkiem nowych przykładów:
Jeśli chodzi o twoje
FindBy
metody, pokusiłbym się o zastosowanie ich w metodach rozszerzenia, aby można było ich używać przeciwko dowolnej kolekcji zawierającej samochody:Oddziela to kwestię zapytania kolekcji od klasy, która przechowuje samochody.
źródło
ClassCollection
parzystości dla metod dodawania, usuwania i aktualizacji, dodając nowy,CarCRUD
który będzie zawierał wszystkie te metody ...CarCRUD
rozszerzenia, ponieważ wymuszenie jego użycia byłoby trudne, zaletą umieszczenia niestandardowej logiki w klasie kolekcji jest to, że nie ma możliwości obejścia tego. Ponadto może nie obchodzić logiki Znajdź w zespole podstawowym, w którymCar
deklarowane są itp., Może to być działanie tylko interfejsu użytkownika.Nie. Tworzenie
XXXCollection
klas praktycznie przestało być modne wraz z pojawieniem się generics w .NET 2.0. W rzeczywistości istnieje fajneCast<T>()
rozszerzenie LINQ, którego ludzie używają w dzisiejszych czasach, aby wydobyć rzeczy z tych niestandardowych formatów.źródło
ClassCollection
? czy dobrą praktyką jest umieszczanie ich na głównej pozycjiClass
?FindCarByModel
metodzie, ma to sens jako metoda w repozytorium, która jest nieco bardziej złożona niż tylkoCar
kolekcja.Często przydatne są metody zorientowane na domeny do znajdowania / wycinania kolekcji, jak w powyższym przykładzie FindByCarModel, ale nie ma potrzeby uciekania się do tworzenia klas kolekcji opakowań. W tej sytuacji zazwyczaj utworzę teraz zestaw metod rozszerzenia.
Dodać dowolną liczbę filtrów lub użyteczności metod do tej klasy, jak chcesz, i można z nich korzystać w dowolnym miejscu masz
IEnumerable<Car>
, który zawiera wszystkoICollection<Car>
, tabliceCar
,IList<Car>
etc.Ponieważ nasze rozwiązanie utrwalające ma dostawcę LINQ, często tworzę również podobne metody filtrowania, które działają i zwracają
IQueryable<T>
, abyśmy mogli zastosować te operacje również w repozytorium.Idiom .NET (cóż, C #) bardzo się zmienił od 1.1. Utrzymywanie niestandardowych klas kolekcji jest uciążliwe, a dziedziczenie
CollectionBase<T>
po nich nie przynosi korzyści , ponieważ nie dostajesz rozwiązania z metodą rozszerzenia, jeśli wszystko, czego potrzebujesz, to metody filtrowania i selekcji specyficzne dla domeny.źródło
Myślę, że jedynym powodem, aby stworzyć specjalną klasę do przechowywania kolekcji innych przedmiotów, powinno być dodanie czegoś wartościowego, czegoś więcej niż tylko hermetyzacja / odziedziczenie po instancji
IList
lub innym typie kolekcji.Na przykład, w twoim przypadku, dodanie funkcji, która zwróciłaby podlisty samochodów zaparkowanych na parzystych / nierównych powierzchniach działki ... I nawet wtedy ... może tylko wtedy, gdy często jest ponownie używana, ponieważ jeśli zajmuje tylko jedną linię z ładnym LinQ funkcja i jest używana tylko raz, o co chodzi? KISS !
Teraz, jeśli planujesz zaoferować wiele metod sortowania / wyszukiwania, to tak, myślę, że może to być przydatne, ponieważ właśnie tam powinny one należeć, w tej specjalnej klasie kolekcji. Jest to również dobry sposób na „ukrycie” złożoności niektórych zapytań „znajdź” lub cokolwiek innego, co można zrobić w metodzie sortowania / wyszukiwania.
źródło
Class
Wolę iść z następującą opcją, abyś mógł dodać swoją metodę do kolekcji i skorzystać z zalet listy.
a następnie możesz użyć go jak w C # 7.0
Lub możesz go użyć jak
- Ogólna wersja dzięki komentarzowi @Bryan
i wtedy możesz go użyć
źródło