Vamos dizer que eu tenho uma Car
aula:
public class Car
{
public string Engine { get; set; }
public string Seat { get; set; }
public string Tires { get; set; }
}
Digamos que estamos criando um sistema sobre um estacionamento, vou usar grande parte da Car
classe, então fazemos uma CarCollection
classe, pode haver alguns métodos adicionais, como FindCarByModel
:
public class CarCollection
{
public List<Car> Cars { get; set; }
public Car FindCarByModel(string model)
{
// code here
return new Car();
}
}
Se estou fazendo uma aula ParkingLot
, qual é a melhor prática?
Opção 1:
public class ParkingLot
{
public List<Car> Cars { get; set; }
//some other properties
}
Opção 2:
public class ParkingLot
{
public CarCollection Cars { get; set; }
//some other properties
}
É uma boa prática criar um ClassCollection
de outro Class
?
CarCollection
pouco ao invés de umList<Car>
redor? Especialmente porque o CarCollection não estende a classe Backing List nem implementa a interface Collection (tenho certeza que o C # tem coisas semelhantes).public class CarCollection
não implementa IList ou ICollection, etc ... assim você não pode passá-lo para algo que esteja bem com uma lista. Alega como parte de seu nome que é uma coleção, mas não implementa nenhum desses métodos.CarColection
com umaTotalTradeValue
propriedade. O DDD não é a única maneira de projetar sistemas, apenas apontando como uma opção.Respostas:
Antes dos genéricos no .NET, era prática comum criar coleções 'digitadas' para que você tivesse
class CarCollection
etc para todos os tipos necessários para agrupar. No .NET 2.0 com a introdução de Generics, uma nova classeList<T>
foi introduzida, o que evita que você tenha que criarCarCollection
etc, como pode criarList<Car>
.Na maioria das vezes, você acha que isso
List<T>
é suficiente para seus propósitos; no entanto, pode haver momentos em que você queira ter um comportamento específico em sua coleção. Se você acredita que esse seja o caso, você tem algumas opções:List<T>
por exemplopublic class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
public class CarCollection : CollectionBase<Car> {}
Se você optar pela abordagem de encapsulamento, exponha no mínimo o enumerador para declará-lo da seguinte maneira:
Sem fazer isso, você não pode fazer um
foreach
over-the-collection.Alguns motivos pelos quais você pode querer criar uma coleção personalizada são:
IList<T>
ouICollection<T>
É uma boa prática? bem, isso depende de por que você está fazendo isso, se é por exemplo um dos motivos que eu listei acima, então sim.
A Microsoft faz isso regularmente, aqui estão alguns exemplos bastante recentes:
Quanto aos seus
FindBy
métodos, eu ficaria tentado a colocá-los em métodos de extensão para que eles possam ser usados contra qualquer coleção que contenha carros:Isso separa a preocupação de consultar a coleção da classe que armazena os carros.
fonte
ClassCollection
mesmo para o adicionar, excluir métodos de atualização, adicionando um novoCarCRUD
que irá encapsular todos esses métodos ...CarCRUD
extensão, pois exigir o uso seria difícil, a vantagem de colocar a lógica de crud personalizada na classe de coleção é que não há como contorná-la. Além disso, talvez você não se importe com a lógica Localizar no assembly principal em queCar
etc são declarados, que pode ser uma atividade apenas da interface do usuário.Não. A criação de
XXXCollection
classes praticamente ficou fora de moda com o advento dos genéricos no .NET 2.0. De fato, existe aCast<T>()
extensão LINQ bacana que as pessoas usam hoje em dia para extrair coisas desses formatos personalizados.fonte
ClassCollection
? é uma boa prática colocá-los no lugar principalClass
?FindCarByModel
método, isso faz sentido como um método no seu repositório, que é um pouco mais complexo do que apenas umaCar
coleção.Muitas vezes, é útil ter métodos orientados a domínio para localizar / cortar coleções, como no exemplo FindByCarModel acima, mas não há necessidade de recorrer à criação de classes de coleção de wrapper. Nesta situação, agora criarei normalmente um conjunto de métodos de extensão.
Você adicionar tantos filtro ou utilidade métodos para essa classe como você gosta, e você pode usá-los em qualquer lugar que você tem
IEnumerable<Car>
, o que inclui qualquer coisaICollection<Car>
, matrizes deCar
,IList<Car>
etc.Como nossa solução de persistência possui um provedor LINQ, frequentemente criarei métodos de filtro semelhantes que operam e retornam
IQueryable<T>
, para que possamos aplicar essas operações ao repositório também.O idioma do .NET (bem, C #) mudou muito desde a 1.1. Manter as classes de coleção personalizadas é um problema, e você ganha muito pouco com a herança
CollectionBase<T>
que não obtém com a solução do método de extensão, se tudo que você precisa são métodos de filtro e seletor específicos do domínio.fonte
Eu acho que o único motivo para criar uma classe especial para armazenar uma coleção de outros itens deve ser quando você adiciona algo de valor a ela, algo mais do que apenas encapsular / herdar de uma instância de
IList
ou outro tipo de coleção.Por exemplo, no seu caso, adicionar uma função que retorne sublistas de carros estacionados em espaços de lotes pares / irregulares ... E mesmo assim ... talvez apenas se for reutilizado com frequência, porque se for preciso apenas uma linha com um LinQ agradável função e é usado apenas uma vez, qual é o objetivo? BEIJO !
Agora, se você planeja oferecer muitos métodos de classificação / localização, sim, acho que isso pode ser útil porque é aqui que eles devem pertencer, nessa classe de coleção especial. Essa também é uma boa maneira de "ocultar" as complexidades de algumas consultas "encontrar" ou o que você poderia fazer em um método de classificação / localização.
fonte
Class
Eu prefiro ir com a opção a seguir, para que você possa adicionar seu método à coleção e usar a vantagem da lista.
e então você pode usá-lo como C # 7.0
Ou você pode usá-lo como
- Versão genérica graças ao comentário @Bryan
e então você pode usá-lo
fonte