Middle+
Jakie mechanizmy pomagają przestrzegać zasady odwrócenia zależności?
sobes.tech AI
Odpowiedź od AI
Zasada odwrócenia zależności (Dependency Inversion Principle - DIP) jest realizowana za pomocą kilku powiązanych mechanizmów:
-
Abstrakcje:
- Interfejsy i klasy abstrakcyjne definiują kontrakty, a nie konkretne implementacje. Moduły wysokiego poziomu zależą od tych abstrakcji, a nie od klas konkretnych niskiego poziomu.
-
Wstrzykiwanie zależności (Dependency Injection - DI):
- Zamiast tworzyć zależności bezpośrednio w klasie, są one przekazywane z zewnątrz. Umożliwia to łatwą wymianę implementacji zależności bez zmiany kodu klasy.
- Składnia C# do wstrzykiwania przez konstruktor:
public class HighLevelModule { private readonly ILowLevelDependency _dependency; // Zależność od abstrakcji public HighLevelModule(ILowLevelDependency dependency) // Wstrzykiwanie przez konstruktor { _dependency = dependency; } public void PerformAction() { _dependency.Execute(); // Użycie zależności przez abstrakcję } } - Składnia C# do wstrzykiwania przez właściwość:
public class AnotherHighLevelModule { public ILowLevelDependency Dependency { get; set; } // Wstrzykiwanie przez właściwość public void PerformAction() { Dependency?.Execute(); // Użycie zależności przez abstrakcję } } - Składnia C# do wstrzykiwania przez metodę:
public class YetAnotherHighLevelModule { public void PerformAction(ILowLevelDependency dependency) // Wstrzykiwanie przez metodę { dependency.Execute(); // Użycie zależności przez abstrakcję } }
-
Kontenery IoC (Inversion of Control Containers):
- Frameworki, które automatyzują proces zarządzania i wstrzykiwania zależności. Tworzą instancje klas i rozwiązują ich zależności zgodnie z ustawionymi regułami.
- Przykład użycia popularnego kontenera IoC (np. StructureMap):
// Rejestracja zależności // container.Configure(cfg => // { // cfg.For<ILowLevelDependency>().Use<ConcreteLowLevelDependency>(); // Rejestracja abstrakcji i jej konkretnej implementacji // cfg.For<HighLevelModule>().Use<HighLevelModule>(); // }); // Uzyskanie instancji klasy z rozwiązanymi zależnościami // var highLevelModule = container.GetInstance<HighLevelModule>(); // highLevelModule.PerformAction();
-
Faktory:
- Klasy odpowiedzialne za tworzenie instancji innych klas. Mogą ukrywać szczegóły tworzenia konkretnych implementacji i zwracać abstrakcje.
- Składnia C# dla przykładu użycia fabryki:
public interface ILowLevelDependencyFactory { ILowLevelDependency Create(); } public class LowLevelDependencyFactory : ILowLevelDependencyFactory { public ILowLevelDependency Create() { return new ConcreteLowLevelDependency(); // Tworzenie konkretnej implementacji } } public class HighLevelModuleWithFactory { private readonly ILowLevelDependency _dependency; public HighLevelModuleWithFactory(ILowLevelDependencyFactory factory) // Wstrzykiwanie fabryki { _dependency = factory.Create(); // Użycie fabryki do tworzenia zależności } public void PerformAction() { _dependency.Execute(); } }
-
Zasada najmniejszych wiedzy (Law of Demeter):
- Chociaż nie jest to bezpośredni mechanizm DIP, przestrzeganie tej zasady (mówić tylko z "swoimi przyjaciółmi") często prowadzi do zmniejszenia bezpośrednich zależności i ułatwia stosowanie DIP.