Sobes.tech
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:

  1. 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.
  2. 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ę
          }
      }
      
  3. 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();
      
  4. 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();
          }
      }
      
  5. 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.