Princípio de inversão de dependência C#

Resumo : neste tutorial, você aprenderá sobre o Princípio de Inversão de Dependência C# que promove o desacoplamento de módulos de software.

Introdução ao Princípio de Inversão de Dependência C#

O Princípio de Inversão de Dependência (DIP) é o último princípio dos princípios SOLID:

O Princípio da Inversão de Dependência afirma que módulos de alto nível não devem depender de módulos de baixo nível, mas ambos devem depender de abstrações.

Para entender o Princípio da Inversão de Dependência, primeiro você precisa entender os conceitos de módulos de alto e baixo nível.

Em geral, módulos de alto nível são módulos que contêm a lógica principal da aplicação, enquanto módulos de baixo nível são módulos que fornecem funcionalidade de suporte. Em outras palavras, os módulos de alto nível especificam o que o aplicativo fará, enquanto os módulos de baixo nível especificam como o aplicativo o fará.

Tradicionalmente, os módulos de baixo nível dependem de módulos de alto nível, pois os módulos de alto nível chamam os módulos de baixo nível para executar a funcionalidade necessária. No entanto, isso cria um acoplamento forte entre os dois módulos. Portanto, é difícil alterar um módulo sem afetar o outro.

O Princípio da Inversão de Dependência resolve este problema introduzindo uma camada de abstração entre os módulos de alto e baixo nível.

Esta camada de abstração é representada por uma interface, que define os métodos que o módulo de baixo nível deve implementar para fornecer sua funcionalidade. O módulo de alto nível depende desta interface em vez do módulo de baixo nível. Em outras palavras, o Princípio da Inversão de Dependência promove a dissociação dos módulos de software.

Exemplo de Princípio de Inversão de Dependência C#

O exemplo a seguir é uma ilustração da violação do princípio de inversão de dependência:

namespace DIP;

public class DatabaseService
{
    public void Save(string message)
    {
        Console.WriteLine("Save the message into the database");
    }
}
public class Logger
{
    private readonly DatabaseService _databaseService;

    public Logger(DatabaseService databaseService)
    {
        _databaseService = databaseService;
    }
    public void Log(string message)
    {
        _databaseService.Save(message);
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var logger = new Logger(new DatabaseService());
        logger.Log("Hello");
    }
}
Linguagem de código:  C#  ( cs )

Neste exemplo, temos duas classes principais DatabaseServicee Logger:

  • O DatabaseServiceé um módulo de baixo nível que fornece acesso ao banco de dados.
  • O Loggeré um módulo de alto nível que registra dados.

A Loggerclasse depende DatabaseServicediretamente da classe. Em outras palavras, o módulo de alto nível ( Logger) depende do módulo de baixo nível ( DatabaseService).

Em vez de fazer com que a Loggerclasse dependa da DatabaseServiceclasse, podemos introduzir uma interface chamada IDataServiceda qual ambas as classes dependem:

namespace DIP;

public interface IDataService
{
    public void Save(string message);
}

public class DatabaseService: IDataService
{
    public void Save(string message)
    {
        Console.WriteLine("Save the message into the database");
    }
}

public class Logger
{
    private readonly IDataService _dataService;

    public Logger(IDataService dataService)
    {
        _dataService = dataService;
    }

    public void Log(string message)
    {
        _dataService.Save(message);
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var logger = new Logger(new DatabaseService());
        logger.Log("Hello");
    }
}Linguagem de código:  C#  ( cs )

Neste exemplo:

Primeiro, defina a IDataAccessinterface que possui o Save()método:

public interface IDataService
{
    public void Save(string message);
}Linguagem de código:  C#  ( cs )

Segundo, redefina o DatabaseAccessque implementa a IDataAccessinterface:

public class DatabaseService: IDataService
{
    public void Save(string message)
    {
        Console.WriteLine("Save the message into the database");
    }
}Linguagem de código:  C#  ( cs )

Terceiro, altere o membro e o construtor da Loggerclasse para usar a IDataAccessinterface em vez da DatabaseAccessclasse:

public class Logger
{
    private readonly IDataService _dataService;

    public Logger(IDataService dataService)
    {
        _dataService = dataService;
    }

    public void Log(string message)
    {
        _dataService.Save(message);
    }
}Linguagem de código:  C#  ( cs )

Ao fazer isso, podemos desacoplar as classes Loggere DatabaseService, facilitando a alteração de uma classe sem afetar uma à outra.

Além disso, podemos facilmente trocar a DatabaseServiceclasse por uma classe diferente que implemente a IDataServiceinterface. Por exemplo, podemos definir FileServiceuma classe que salva uma mensagem em um arquivo de texto, passando-a para a Loggerclasse.

Resumo

  • O Princípio da Inversão de Dependência afirma que módulos de alto nível não devem depender de módulos de baixo nível, mas ambos devem depender de abstrações.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *