Niedawno przeczytałem o dyrektorze inwersji zależności w doskonałej książce Roberta.C.Martina Zwinne zasady, wzorce i praktyki w języku C#. Jest jednak jeden aspekt tego zlecenia, który moim zdaniem nie w pełni rozumiem.W jaki sposób funkcja Dependency-Inversion Principal (DIP) zmniejsza potrzebę wprowadzania zmian w modułach zależnych, gdy zmieniają się zależności?
Robert wyjaśnia, że gdy moduły wysokopoziomowe są zależne od modułów niższego poziomu, zmiany w modułach niższego poziomu mogą również spowodować zmianę modułów wyższego poziomu. Demonstruje to z poniższym przykładzie:
public class Button
{
private Lamp lamp;
public void Poll(){
if(/*some condition*/)
Lamp.TurnOn();
}
}
O tym kodzie Robert mówi „Klasa Przycisk zależy bezpośrednio od klasy Lamp Zależność ta oznacza, że przycisk będzie wpływ zmian do źródła światła.”
Jak widzę to możliwe są dwa rodzaje zmian, które możemy wprowadzić do klasy lampy:
1) może chcemy zmienić wewnętrzną implementację klasy, ale bez wpływu na interfejs publiczny.
2) Możemy zdecydować się na zmianę interfejsu publicznego, aby przekazać parametr do metody TurnOn.
Nie rozumiem, że w pierwszym przypadku, dlaczego nasze zmiany spowodują zmianę w klasie Button? Publiczny interfejs do lampy nie uległ zmianie, więc dlaczego przycisk musiałby się zmienić?
W drugim przypadku widzę, że wymagałoby to zmiany przycisku. Ale w takim przypadku, w jaki sposób w zależności od abstrakcji może to zmienić? Z pewnością, jeśli mam uzasadniony powód, aby zmienić interfejs na Lampę, to zmieniałbym także interfejs w abstrakcji, od której zależy Lamp i Button. W takim przypadku muszę zmienić przycisk tak, jak zmieniła się abstrakcja, od której to zależy.
Zdaję sobie sprawę, że istnieją inne korzyści dla DIP, takie jak możliwość ponownego użycia modułów wyższego poziomu, posiadanie interfejsów przez moduły wyższego poziomu oraz możliwość wyboru implementacji zależności w czasie wykonywania, jednak staram się zrozumieć, w jaki sposób zmniejsza się DIP potrzeba zmiennych modułów do zmiany, gdy zmienia się interfejs do modułu niższego poziomu i/lub dlaczego wewnętrzne zmiany w module zależnym mogą powodować zmiany w modułach wyższego poziomu.
Dzięki Daniel. Widzę, że zmiana konstruktora konkretnej usługi jest przykładem, gdzie zależność od interfejsu izolowałaby klasę zależną od zmiany (zakładając, że nie wykonuje ona konstrukcji), ale nadal czuję, że czegoś mi brakuje. Robert mówi o uzależnieniu przechodnim w swoim artykule: jeśli A-> B i B-> C, to zmiana w klasie C może wymusić zmianę w klasie B iw klasie A_. Wciąż nie bardzo rozumiem, jak to się dzieje. Nawet jeśli wprowadziliśmy zmianę w publicznym interfejsie C, dlaczego miałoby to wpływ na A? – John
jeśli klasa c get jest nową zależnością, a ta zależność nie jest dostępna w klasie b, ale jest dostępna w a, to może wymagać tej zależności od b, więc b może ją dostarczyć do c – Daniel