2012-08-01 4 views
5

Recentemente ho letto del Dependency-Inversion Principal in Robert.C. l'eccellente libro di Martin Agile Principals, Patterns and Practices in C#. Tuttavia, c'è un aspetto di questo principio che sento di non comprendere appieno.In che modo il Dipendente-Inversion Principal (DIP) riduce la necessità di apportare modifiche ai moduli dipendenti quando cambiano le loro dipendenze?

Robert spiega che quando i moduli di alto livello dipendono da moduli di livello inferiore, le modifiche nei moduli di livello inferiore possono far cambiare anche i moduli di livello superiore. Egli dimostra con il seguente esempio:

public class Button 
{ 
    private Lamp lamp; 
    public void Poll(){ 
     if(/*some condition*/) 
     Lamp.TurnOn(); 
    } 
} 

A proposito di questo codice di Robert dice "La classe Button dipende direttamente dalla classe Lamp Questa dipendenza implica che Button sarà influenzato da cambiamenti della lampada".

come la vedo io ci sono due possibili tipi di cambiamento che potremmo fare per la classe della lampada:

1) si può decidere di modificare l'implementazione interna della classe ma senza intaccare l'interfaccia pubblica.

2) Potremmo decidere di cambiare l'interfaccia pubblica per dire passare un parametro al metodo TurnOn.

Quello che non capisco è che nel primo caso perché le nostre modifiche comportano un cambiamento nella classe Button? L'interfaccia pubblica a Lamp non è cambiata, quindi perché Button dovrebbe cambiare?

Nel secondo caso posso vedere che questo ci richiederebbe di cambiare Button. Ma in questo caso come dipenderebbe da un'astrazione questo? Sicuramente, se ho un valido motivo per cambiare l'interfaccia con la lampada, cambierei anche l'interfaccia nell'astrazione dalla quale dipendono la lampada e il pulsante. In questo caso, quindi, devo cambiare Button in ogni caso in quanto l'astrazione da cui dipende è cambiata.

Mi rendo conto che esistono altri vantaggi per DIP come la riutilizzabilità dei moduli di livello superiore, la proprietà delle interfacce da parte dei moduli di livello superiore e la possibilità di scegliere le implementazioni delle dipendenze in fase di esecuzione, tuttavia sto cercando la necessità che i moduli dipendenti cambino quando l'interfaccia ad un modulo di livello inferiore cambia e/o perché i cambiamenti interni in un modulo dipendente possono causare cambiamenti nei moduli di livello superiore.

risposta

1

Credo che l'importante differenza che DIP introduce in questo esempio sia la proprietà dell'interfaccia. In particolare quale layer possiede l'interfaccia, dove Button è il client e Lamp è il server.

Nella dipendenza dalla classe lampada concreta, l'interfaccia (.TurnOn()) appartiene alla classe Lamp (server). Pertanto, è possibile prendere una decisione per modificare il metodo .TurnOn() basato esclusivamente sulle esigenze del server in quanto proprietario del metodo e ciò richiederà una modifica successiva alla classe Button (client).

Quando l'interfaccia viene astratta a una classe ISwitchableDevice Interface/Abstract, la proprietà viene trasferita al client oa un livello condiviso. Pertanto, una modifica all'interfaccia non può essere guidata direttamente dalle esigenze dei server, qualsiasi modifica alla classe Lamp (di proprietà del server) può essere apportata senza modificare l'interfaccia. E se sono richieste modifiche all'interfaccia ISwitchableDevice, ciò sarà guidato dalle esigenze del client o del livello condiviso.

0

Ad esempio, per quanto riguarda l'interfaccia, se vengono apportate modifiche al costruttore di Lamp (che è una parte dell'interfaccia pubblica) e si dipende da una base astratta, o un'interfaccia tali modifiche non si propagheranno a l'implementazione del pulsante (a meno che non lo costruisci lì, ma questo è parzialmente un altro problema).
Per quanto riguarda la "pura implementazione", un progetto correttamente incapsulato in cui non vengono apportate modifiche all'interfaccia di qualsiasi tipo (costruttori, eccezioni che possono essere generate ecc.) E nessuna dipendenza globale comune è cambiata, quindi non dovrebbe influire sul chiamante, quindi è meno di un problema.

Fondamentalmente, per quanto riguarda questi problemi, stiamo riducendo l'area di superficie, quindi dipendiamo da meno specifiche, anche se alcune specifiche saranno sempre necessarie.

Sia che un'astrazione sia o meno una confusione inutile o una separazione inestimabile, ciò deve essere deciso caso per caso.

+0

Grazie Daniel. Vedo che cambiare il costruttore di un servizio concreto è un esempio in cui, a seconda dell'interfaccia, si isola la classe dipendente dal cambiamento (supponendo che non faccia la costruzione), tuttavia sento ancora che mi manca qualcosa. Robert parla della dipendenza transitoria nel suo articolo: se A-> B e B-> C allora un cambiamento nella classe C può forzare il cambiamento nella classe B _e nella classe A_. Ancora non capisco come possa essere così. Anche se abbiamo apportato una modifica all'interfaccia pubblica di C, perché questo influirebbe su A? – John

+0

se la classe c ottiene una nuova dipendenza e quella dipendenza non è disponibile in classe b, ma è disponibile in a, quindi a potrebbe essere necessario fornire tale dipendenza a b così b può fornirla a c – Daniel

Problemi correlati