Suponha que eu tenha várias entidades no meu modelo (usando EF), como Usuário, Produto, Fatura e Pedido.
Estou escrevendo um controle de usuário que pode imprimir os resumos dos objetos de entidade no meu aplicativo, onde as entidades pertencem a um conjunto pré-decidido; nesse caso, digo que os resumos de Usuário e Produto podem ser resumidos.
Todos os resumos terão apenas um ID e uma descrição, por isso crio uma interface simples para isso:
public interface ISummarizableEntity {
public string ID { get; }
public string Description { get; }
}
Em seguida, para as entidades em questão, crio uma classe parcial que implementa essa interface:
public partial class User : ISummarizableEntity
{
public string ID
{
get{ return UserID.ToString(); }
}
public string Description
{
get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
}
}
public partial class Product: ISummarizableEntity
{
public string ID
{
get{ return ProductID.ToString(); }
}
public string Description
{
get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
}
}
Dessa forma, meu controle de usuário / visão parcial pode ser vinculado a qualquer coleção de ISummarizableEntity e não precisa estar interessado na fonte. Foi-me dito que as interfaces não deveriam ser usadas como tipos de dados, mas não obtive mais informações do que isso. Até onde eu posso ver, embora as interfaces normalmente descrevam o comportamento, apenas o uso de propriedades não é um antipadrão, já que propriedades são apenas açúcar sintático para getters / setters de qualquer maneira.
Eu poderia criar um tipo de dados e um mapa concretos das entidades para isso, mas não vejo o benefício. Eu poderia fazer com que os objetos de entidade fossem herdados de uma classe abstrata e depois definir as propriedades, mas estou bloqueando as entidades para nenhum uso adicional, pois não podemos ter herança múltipla. Também estou aberto a ter qualquer objeto ISummarizableEntity se eu quiser (obviamente, renomeio a interface)
A solução que estou usando em minha mente é sustentável, extensível, testável e bastante robusta. Você pode ver o anti-padrão aqui?
EntitySummary
, comUser
eProduct
cada um com um método comopublic EntitySummary GetSummary()
?Respostas:
Interfaces não descrevem comportamento. Muito pelo contrário, às vezes.
As interfaces descrevem contratos, como "se eu devo oferecer esse objeto a qualquer método que aceite ISummarizableEntity, esse objeto deve ser uma entidade capaz de se resumir" - no seu caso, definido como sendo capaz de retornar um ID da string e Descrição da string.
Esse é um uso perfeito de interfaces. Nenhum anti-padrão aqui.
fonte
List
que não se comporte como uma lista?Você escolheu o melhor caminho para esse design porque está definindo um tipo específico de comportamento que será necessário para vários tipos diferentes de objetos. A herança nesse caso implicaria um relacionamento comum entre as classes que não existe realmente. Nesse caso, a composibilidade é preferida à herança.
fonte
As interfaces que carregam apenas propriedades devem ser evitadas, pois:
Aqui você está misturando duas preocupações:
Um resumo é composto de duas cadeias: um ID e uma descrição. Estes são dados simples:
Agora que você definiu o resumo, deseja definir um contrato:
Observe que o uso de inteligência em getters é um antipadrão e deve ser evitado: ele deve estar localizado em funções. Aqui está como as implementações se parecem:
fonte