Bien qu'il s'agisse d'une question générale, elle est également spécifique à un problème que je rencontre actuellement. J'ai actuellement une interface spécifiée dans ma solution appelée
public interface IContextProvider
{
IDataContext { get; set; }
IAreaContext { get; set; }
}
Cette interface est souvent utilisée tout au long du programme et j'ai donc un accès facile aux objets dont j'ai besoin. Cependant, à un niveau assez bas d'une partie de mon programme, j'ai besoin d'accéder à une autre classe qui utilisera IAreaContext et effectuera certaines opérations hors de celle-ci. J'ai donc créé une autre interface d'usine pour faire cette création appelée:
public interface IEventContextFactory
{
IEventContext CreateEventContext(int eventId);
}
J'ai une classe qui implémente IContextProvider et est injectée à l'aide de NinJect. Le problème que j'ai est que la zone où j'ai besoin d'utiliser ce IEventContextFactory a accès au IContextProvider uniquement et utilise elle-même une autre classe qui aura besoin de cette nouvelle interface. Je ne veux pas avoir à instancier cette implémentation d' IEventContextFactory au bas niveau et préfère plutôt travailler avec l' interface IEventContextFactory . Cependant, je ne veux pas non plus avoir à injecter un autre paramètre via les constructeurs juste pour le faire passer à la classe qui en a besoin, c'est-à-dire
// 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();
}
}
Donc ma question principale est, est-ce que cela serait acceptable ou est-ce même une pratique courante ou bonne de faire quelque chose comme ça (interface étendre une autre interface):
public interface IContextProvider : IEventContextFactory
ou devrais-je envisager de meilleures alternatives pour atteindre ce dont j'ai besoin. Si je n'ai pas fourni suffisamment d'informations pour faire des suggestions, faites-le moi savoir et je peux en fournir davantage.
la source
Réponses:
Bien que les interfaces décrivent uniquement le comportement sans implémentation, elles peuvent toujours participer aux hiérarchies d'héritage. Par exemple, imaginez que vous ayez, disons, l'idée commune d'un
Collection
. Cette interface fournirait quelques éléments communs à toutes les collections, comme une méthode pour parcourir les membres. Ensuite, vous pouvez penser à des collections d'objets plus spécifiques tels que aList
ou aSet
. Chacun d'eux hérite de toutes les exigences de comportement de aCollection
, mais ajoute des exigences supplémentaires spécifiques à ce type particulier de collection.Chaque fois qu'il est logique de créer une hiérarchie d'héritage pour les interfaces, vous devriez. Si deux interfaces sont toujours trouvées ensemble, elles devraient probablement être fusionnées.
la source
Oui, mais seulement si cela a du sens. Posez-vous les questions suivantes et si une ou plusieurs s'appliquent, il est acceptable d'hériter d'une interface d'une autre.
Dans votre exemple, je ne pense pas que cela répond oui à aucun de ceux-là. Vous feriez peut-être mieux de l'ajouter comme autre propriété:
la source
IContextProvider
étendreIEventContextFactory
, l'ContextProvider
implémentation devra également implémenter cette méthode. Si vous l'ajoutez en tant que propriété, vous dites qu'un aContextProvider
aIEventContextFactory
mais ne connaît pas réellement les détails de l'implémentation.Oui, c'est bien d'étendre une interface d'une autre.
La question de savoir si c'est la bonne chose à faire dans un cas spécifique dépend de l'existence ou non d'une véritable relation «est-un» entre les deux.
Qu'est-ce qui est requis pour une relation «est-un» valide?
Premièrement, il doit y avoir une réelle différence entre les deux interfaces, c'est-à-dire qu'il doit y avoir des instances qui implémentent l'interface parent mais pas l'interface enfant. S'il n'y a pas et qu'il n'y aura jamais d'instances qui n'implémentent pas les deux interfaces, les deux interfaces doivent à la place être fusionnées.
Deuxièmement, il doit être le cas que chaque instance de l'interface enfant doit nécessairement être une instance du parent: il n'y a pas de logique (raisonnable) selon laquelle vous créeriez une instance de l'interface enfant qui n'aurait pas de sens en tant qu'instance de l'interface parent.
Si ces deux éléments sont vrais, l'héritage est la bonne relation pour les deux interfaces.
la source
IReadOnlyList
peut être utile, même si toutes mes classes de liste implémententIList
(qui est dérivée deIReadOnlyList
).Si une interface veut toujours exiger / fournir l'autre, alors allez-y. J'ai vu cela dans quelques cas
IDisposible
qui avaient du sens. En général cependant, vous devez vous assurer qu'au moins une des interfaces se comporte plus comme un trait que comme une responsabilité.Pour votre exemple, ce n'est pas clair. S'ils sont tous les deux toujours ensemble, créez une seule interface. Si l'un a toujours besoin de l'autre, je serais préoccupé par le type d'héritage "X et 1" qui conduit très souvent à de multiples responsabilités et / ou à d'autres problèmes d'abstraction qui fuient.
la source