Le interfacce dovrebbero estendere (e in tal modo ereditare metodi di) altre interfacce

13

Anche se questa è una domanda generale, è anche specifica di un problema che sto attualmente vivendo. Al momento ho un'interfaccia specificata nella mia soluzione chiamata

public interface IContextProvider
{
   IDataContext { get; set; }
   IAreaContext { get; set; }
}

Questa interfaccia è spesso utilizzata in tutto il programma e quindi ho un facile accesso agli oggetti di cui ho bisogno. Tuttavia, a un livello piuttosto basso di una parte del mio programma ho bisogno di accedere ad un'altra classe che userà IAreaContext ed eseguire alcune operazioni su di essa. Così ho creato un'altra interfaccia factory per fare questa creazione chiamata:

public interface IEventContextFactory 
{
   IEventContext CreateEventContext(int eventId);
}

Ho una classe che implementa IContextProvider e viene iniettata usando NinJect. Il problema che ho è che l'area in cui ho bisogno di usare questo IEventContextFactory ha accesso solo a IContextProvider e se stessa utilizza un'altra classe che avrà bisogno di questa nuova interfaccia. Non voglio dover istanziare questa implementazione di IEventContextFactory al livello basso e preferirei lavorare con l'interfaccia IEventContextFactory . Tuttavia, non voglio neanche dover iniettare un altro parametro attraverso i costruttori solo per farlo passare alla classe che ne ha bisogno, cioè

// 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();      
    }
}

Quindi la mia domanda principale è, sarebbe accettabile o è addirittura normale o buona pratica fare qualcosa del genere (l'interfaccia estende un'altra interfaccia):

public interface IContextProvider : IEventContextFactory

o dovrei considerare alternative migliori per ottenere ciò di cui ho bisogno. Se non ho fornito informazioni sufficienti per dare suggerimenti fammelo sapere e posso fornire di più.

    
posta dreza 04.09.2012 - 22:46
fonte

4 risposte

10

Mentre le interfacce descrivono solo il comportamento senza alcuna implementazione, possono comunque partecipare alle gerarchie di ereditarietà. Ad esempio, immagina di avere, per esempio, l'idea comune di Collection . Questa interfaccia fornirebbe alcune cose che sono comuni a tutte le collezioni, come un metodo per iterare sui membri. Quindi puoi pensare ad alcune raccolte più specifiche di oggetti come List o Set . Ognuno di questi eredita tutti i requisiti di comportamento di Collection , ma aggiunge requisiti aggiuntivi specifici per quel particolare tipo di raccolta.

Ogni volta che ha senso creare una gerarchia di ereditarietà per le interfacce, allora dovresti. Se due interfacce verranno sempre trovate insieme, allora dovrebbero probabilmente essere unite.

    
risposta data 04.09.2012 - 23:52
fonte
6

Sì, ma solo se ha senso. Porsi le seguenti domande e se uno o più si applicano, è accettabile ereditare un'interfaccia da un'altra.

  1. Interfaccia A estendere logicamente l'interfaccia B, ad esempio IList aggiungendo funzionalità a ICollection.
  2. L'interfaccia A deve definire un comportamento già specificato da un'altra interfaccia, ad esempio implementando IDisposable se ha risorse che devono essere riordinate o IEnumerable se può essere iterato su.
  3. Ogni implementazione dell'interfaccia A richiede il comportamento specificato dall'interfaccia B?

Nel tuo esempio, non penso che risponda di sì a nessuno di questi. Potrebbe essere meglio aggiungerlo come un'altra proprietà:

public interface IContextProvider
{
   IDataContext DataContext { get; set; }
   IAreaContext AreaContext { get; set; }
   IEventContextFactory EventContextFactory { get; set; }
}
    
risposta data 05.09.2012 - 00:10
fonte
3

Sì, è bene estendere un'interfaccia da un'altra.

La questione se sia la cosa giusta da fare in un caso specifico dipende dal fatto che esista una vera relazione "è-a" tra i due.

Che cosa è richiesto per una valida relazione "è-a"?

In primo luogo, deve esserci una vera differenza tra le due interfacce, vale a dire, devono esserci istanze che implementano l'interfaccia genitore ma non l'interfaccia figlio. Se non ci sono e non ci saranno mai istanze che non implementano entrambe le interfacce, le due interfacce dovrebbero invece essere unite.

In secondo luogo, deve essere il caso che ogni istanza dell'interfaccia figlio deve necessariamente essere un'istanza del genitore: non esiste una logica (ragionevole) in base alla quale si creerebbe un'istanza dell'interfaccia figlio che non avrebbe senso come un'istanza dell'interfaccia genitore.

Se entrambi sono veri, l'ereditarietà è la giusta relazione per le due interfacce.

    
risposta data 05.09.2012 - 00:15
fonte
1

Se l'unica interfaccia sempre vuole richiedere / fornire l'altro, allora vai avanti. L'ho visto in alcuni casi con IDisposible che ha avuto senso. In generale, tuttavia, dovresti assicurarti che almeno una delle interfacce si comporti più come un tratto che come una responsabilità.

Per il tuo esempio, non è chiaro. Se sono entrambi sempre insieme, crea un'unica interfaccia. Se uno ha sempre bisogno dell'altro, sarei preoccupato dell'ereditarietà di "X e 1" che molto spesso porta a molteplici responsabilità e / o altri problemi di astrazione che perdono.

    
risposta data 04.09.2012 - 23:25
fonte

Leggi altre domande sui tag