Sobes.tech
Middle+

Quais mecanismos ajudam a cumprir o princípio da inversão de dependências?

sobes.tech IA

Resposta da IA

O princípio da inversão de dependências (Dependency Inversion Principle - DIP) é cumprido através de vários mecanismos interrelacionados:

  1. Abstrações:

    • Interfaces e classes abstratas definem contratos, não implementações concretas. Módulos de alto nível dependem dessas abstrações, não de classes concretas de baixo nível.
  2. Injeção de dependências (Dependency Injection - DI):

    • Em vez de uma classe criar suas dependências diretamente, elas são passadas de fora. Isso permite substituir facilmente as implementações de dependências sem alterar o código da classe.
    • Sintaxe C# para injeção via construtor:
      public class HighLevelModule
      {
          private readonly ILowLevelDependency _dependency; // Dependência da abstração
      
          public HighLevelModule(ILowLevelDependency dependency) // Injeção via construtor
          {
              _dependency = dependency;
          }
      
          public void PerformAction()
          {
              _dependency.Execute(); // Uso da dependência via abstração
          }
      }
      
    • Sintaxe C# para injeção via propriedade:
      public class AnotherHighLevelModule
      {
          public ILowLevelDependency Dependency { get; set; } // Injeção via propriedade
      
          public void PerformAction()
          {
              Dependency?.Execute(); // Uso da dependência via abstração
          }
      }
      
    • Sintaxe C# para injeção via método:
      public class YetAnotherHighLevelModule
      {
          public void PerformAction(ILowLevelDependency dependency) // Injeção via método
          {
              dependency.Execute(); // Uso da dependência via abstração
          }
      }
      
  3. Contêineres IoC (Inversion of Control Containers):

    • Frameworks que automatizam o processo de gestão e injeção de dependências. Criam instâncias de classes e resolvem suas dependências de acordo com regras configuradas.
    • Exemplo de uso de um contêiner IoC popular (por exemplo, StructureMap):
      // Registro de dependência
      // container.Configure(cfg =>
      // {
      //     cfg.For<ILowLevelDependency>().Use<ConcreteLowLevelDependency>(); // Registro da abstração e sua implementação concreta
      //     cfg.For<HighLevelModule>().Use<HighLevelModule>();
      // });
      
      // Obtenção de uma instância da classe com dependências resolvidas
      // var highLevelModule = container.GetInstance<HighLevelModule>();
      // highLevelModule.PerformAction();
      
  4. Fábricas:

    • Classes que criam instâncias de outras classes. Podem ocultar detalhes de criação de implementações concretas e retornar abstrações.
    • Sintaxe C# para exemplo de uso de uma fábrica:
      public interface ILowLevelDependencyFactory
      {
          ILowLevelDependency Create();
      }
      
      public class LowLevelDependencyFactory : ILowLevelDependencyFactory
      {
          public ILowLevelDependency Create()
          {
              return new ConcreteLowLevelDependency(); // Criação de uma implementação concreta
          }
      }
      
      public class HighLevelModuleWithFactory
      {
          private readonly ILowLevelDependency _dependency;
      
          public HighLevelModuleWithFactory(ILowLevelDependencyFactory factory) // Injeção da fábrica
          {
              _dependency = factory.Create(); // Uso da fábrica para criar a dependência
          }
      
          public void PerformAction()
          {
              _dependency.Execute();
          }
      }
      
  5. Princípio do menor conhecimento (Lei de Demeter):

    • Embora não seja um mecanismo direto do DIP, seguir esse princípio (falar apenas com "seus amigos próximos") muitas vezes reduz as dependências diretas e facilita a aplicação do DIP.