E 'un buon progetto creare un'interfaccia che eredita da più interfacce per ridurre la quantità di dipendenze di un client?

1

Stavo rifacendo una domanda per rispettare i principi SOLIDI. Quando stavo applicando la segregazione dell'interfaccia ho trovato il seguente caso:

interface A
{ 
    void methodA();
    void methodA2();
}

interface B
{ 
    void methodB();
    void methodB2();
}

interface C : A, B
{ 
    void methodC();
}

interface D
{ 
    void methodD();
    void methodD2();
    void methodD3();
    //Same signature and semantics as in interface C
    void methodC();

}

Poiché methodC è lo stesso nell'interfaccia C e D ma l'interfaccia D non ha bisogno dei metodi di A e B, ho estratto methodC in un'altra interfaccia, quindi il design sarebbe.

interface A
{ 
    void methodA();
    void methodA2();
}

interface B
{ 
    void methodB();
    void methodB2();
}

interface C : A, B, E
{ 
}

interface D : E
{ 
    void methodD();
    void methodD2();
    void methodD3();
}

interface E
{
    void methodC();
}

Ora ho e interfaccia solo con metodi ereditati e nessun metodo a sé stante. Ciò significa che non devo refactoring i client che dipendono dall'interfaccia C per segregarlo.

Questo è un buon progetto considerando l'interfaccia refactored C non dichiara i propri metodi ma funge solo da contenitore di ereditarietà? Devo invece ridefinire i client che dipendono dall'interfaccia C e aggiungere dipendenze dirette all'interfaccia A, B ed E? In pratica questo non ha molto impatto sul codice in quanto esiste un solo client, ma è concettualmente valido?

Inoltre, questa sarebbe una buona scelta progettuale per evitare di avere troppe dipendenze dirette (parametri del costruttore se si utilizza l'iniezione delle dipendenze del costruttore, ad esempio) che sono semanticamente correlate?

    
posta Cesar Hernandez 20.11.2018 - 21:36
fonte

1 risposta

3

Le interfacce riguardano un contratto. Il consumatore e il produttore di queste interfacce non si preoccupano l'un l'altro, solo che seguono lo stesso protocollo operativo e forniscono la stessa semantica.

Scenario

  1. Non ci sono utenti per le interfacce: A, B o E. Solo consumatori per C.
  2. Ci sono consumatori per ogni interfaccia: A, B ed E. Solo che esiste un'implementazione che fornisce tutti e tre.
  3. L'interfaccia C cambia il protocollo / semantica integrando o perfezionando la relazione tra A, B ed E.

Nello scenario 1, poiché non ci sono consumatori per quel servizio specifico, il software non ne ha bisogno. A meno che non vi siano altre ragioni per cui non sia stata ripetuta la domanda, è possibile comprimere tali definizioni in C. Anche se mantenere queste sub-interfacce per "test" è probabile che diventi controproducente.

Nello scenario 2, poiché non esiste un consumatore per C, il sistema non ne ha bisogno, è solo una comodità sintattica. Rimuoverlo e rendere l'implementazione ereditata direttamente dalle interfacce A, B ed E. Sta rendendo più difficile iniettare un comportamento alternativo nel codice e probabilmente sta complicando molti dei tuoi test unitari.

In Scenario 3, osservate attentamente il protocollo operativo e le garanzie semantiche offerte dalle sottointerfacce. L'interfaccia derivata C espande quella logica in modo sostituibile? Un consumatore che utilizza le sottointerfacce, ad esempio A, si sorprende quando un servizio non correlato, ad esempio B, è cambiato in modo illogico?

Se è veramente consistente, quindi facendolo estendere A, B ed E comunica la semantica estesa, assicurati che sia ovvio attraverso i test unitari descrittivi / documentazione.

Se non è coerente, non estendere tali interfacce, ma copia le loro definizioni localmente. Dovrebbero essere trattati in modo diverso, perché mentre i nomi dei metodi sembrano simili hanno semantica diversa e / o pattern operativi.

interface C
{
    void methodA();
    void methodA2();
    void methodB();
    void methodB2();
    void methodC();
}

Applicare logica simile per l'interfaccia D.

    
risposta data 21.11.2018 - 00:35
fonte

Leggi altre domande sui tag