Embora essa seja uma pergunta geral, ela também é específica para um problema que estou enfrentando no momento. Atualmente, tenho uma interface especificada na minha solução chamada
public interface IContextProvider
{
IDataContext { get; set; }
IAreaContext { get; set; }
}
Essa interface é frequentemente usada em todo o programa e, portanto, tenho fácil acesso aos objetos de que preciso. No entanto, em um nível bastante baixo de uma parte do meu programa, preciso acessar outra classe que use o IAreaContext e realize algumas operações fora dele. Então, eu criei outra interface de fábrica para fazer essa criação chamada:
public interface IEventContextFactory
{
IEventContext CreateEventContext(int eventId);
}
Eu tenho uma classe que implementa o IContextProvider e é injetada usando o NinJect. O problema que tenho é que a área em que preciso usar esse IEventContextFactory tem acesso apenas ao IContextProvider e ela mesma usa outra classe que precisará dessa nova interface. Não quero instanciar essa implementação do IEventContextFactory no nível baixo e preferiria trabalhar com a interface IEventContextFactory . No entanto, eu também não quero injetar outro parâmetro através dos construtores apenas para que ele seja passado para a classe que precisa dele, ou seja,
// example of problem
public class MyClass
{
public MyClass(IContextProvider context, IEventContextFactory event)
{
_context = context;
_event = event;
}
public void DoSomething()
{
// the only place _event is used in the class is to pass it through
var myClass = new MyChildClass(_event);
myClass.PerformCalculation();
}
}
Portanto, minha pergunta principal é: isso seria aceitável ou é mesmo comum ou uma boa prática fazer algo assim (a interface estende outra interface):
public interface IContextProvider : IEventContextFactory
ou devo considerar melhores alternativas para alcançar o que preciso. Se eu não fornecer informações suficientes para dar sugestões, avise-me e posso fornecer mais.
fonte
Respostas:
Embora as interfaces descrevam apenas o comportamento sem nenhuma implementação, elas ainda podem participar de hierarquias de herança. Como exemplo, imagine que você tem, digamos, a idéia comum de a
Collection
. Essa interface forneceria algumas coisas comuns a todas as coleções, como um método para iterar sobre os membros. Então você pode pensar em algumas coleções mais específicas de objetos, como aList
ou aSet
. Cada um deles herda todos os requisitos de comportamento de aCollection
, mas adiciona requisitos adicionais específicos para esse tipo específico de coleção.Sempre que faz sentido criar uma hierarquia de herança para interfaces, você deve. Se duas interfaces sempre forem encontradas juntas, elas provavelmente deverão ser mescladas.
fonte
Sim, mas apenas se fizer sentido. Faça as seguintes perguntas e, se uma ou mais forem aplicáveis, é aceitável herdar uma interface de outra.
No seu exemplo, não acho que responda sim a nenhum deles. Talvez seja melhor adicioná-lo como outra propriedade:
fonte
IContextProvider
estenderIEventContextFactory
, aContextProvider
implementação também precisará implementar esse método. Se você adicioná-lo como uma propriedade, estará dizendo que aContextProvider
possui um,IEventContextFactory
mas na verdade não conhece os detalhes da implementação.Sim, é bom estender uma interface de outra.
A questão de saber se é a coisa certa a ser feita em um caso específico depende se existe uma verdadeira relação "é-a" entre os dois.
O que é necessário para um relacionamento "é-a" válido?
Primeiro, deve haver uma diferença real entre as duas interfaces, ou seja, deve haver instâncias que implementam a interface pai, mas não a interface filho. Se não houver e nunca haverá instâncias que não implementem as duas interfaces, as duas interfaces devem ser mescladas.
Segundo, deve ser o caso de que toda instância da interface filho deve necessariamente ser uma instância do pai: não há lógica (razoável) sob a qual você criaria uma instância da interface filho que não faria sentido como uma instância do pai. a interface pai.
Se os dois forem verdadeiros, a herança é o relacionamento correto para as duas interfaces.
fonte
IReadOnlyList
pode ser útil, mesmo que todas as minhas classes de lista sejam implementadasIList
(das quais é derivadaIReadOnlyList
).Se a única interface sempre deseja exigir / fornecer a outra, vá em frente. Eu já vi isso em alguns casos com os
IDisposible
quais fizeram sentido. Em geral, porém, você deve garantir que pelo menos uma das interfaces se comporte mais como uma característica do que como uma responsabilidade.Para o seu exemplo, isso não está claro. Se ambos estiverem sempre juntos, faça apenas uma interface. Se um sempre precisar do outro, eu ficaria preocupado com o tipo de herança "X e 1" que muitas vezes leva a múltiplas responsabilidades e / ou outros problemas de abstração com vazamento.
fonte