Sobes.tech
Junior

Em que casos e para que fins usamos interfaces em C#?

sobes.tech IA

Resposta da IA

As interfaces em C# são usadas para alcançar os seguintes objetivos:

  1. Definição de contrato: A interface define um conjunto de membros (métodos, propriedades, eventos, indexadores) que uma classe ou estrutura que implementa essa interface deve definir. Isso garante consistência no comportamento de diferentes tipos.

    // Definição da interface
    public interface IDrawable
    {
        void Draw();
        int LineThickness { get; set; }
    }
    
    // Classe que implementa a interface
    public class Circle : IDrawable
    {
        public int LineThickness { get; set; }
    
        public void Draw()
        {
            // Lógica para desenhar um círculo
        }
    }
    
  2. Polimorfismo: O uso de interfaces permite trabalhar com objetos de diferentes tipos através de um tipo de interface comum. Isso é alcançado porque qualquer referência a um objeto que implementa a interface pode ser convertida para esse tipo de interface.

    // Método que trabalha com qualquer objeto que implemente IDrawable
    public void Render(IDrawable item)
    {
        item.Draw(); // Chama a implementação concreta do método Draw
    }
    
    // Uso:
    IDrawable circle = new Circle();
    Render(circle); // Será chamada a implementação de Draw() da classe Circle
    
  3. Herança múltipla: O C# não suporta herança múltipla de classes, mas permite que uma classe ou estrutura implemente vários interfaces. Isso permite que um tipo tenha comportamentos definidos em diferentes "contratos".

    public interface ISaveable
    {
        void Save();
    }
    
    public interface ILoadable
    {
        void Load();
    }
    
    // Classe que implementa múltiplas interfaces
    public class ConfigurationManager : ISaveable, ILoadable
    {
        public void Save()
        {
            // Lógica de salvamento
        }
    
        public void Load()
        {
            // Lógica de carregamento
        }
    }
    
  4. Acoplamento fraco (Decoupling): O uso de interfaces permite reduzir a dependência entre componentes. Em vez de depender de uma classe concreta, um componente pode depender de uma interface. Isso facilita a substituição de implementações e testes.

    public interface ILogger
    {
        void LogMessage(string message);
    }
    
    public class FileLogger : ILogger
    {
        public void LogMessage(string message)
        {
            // Lógica de gravação em arquivo
        }
    }
    
    public class DatabaseLogger : ILogger
    {
        public void LogMessage(string message)
        {
            // Lógica de gravação em banco de dados
        }
    }
    
    public class ProcessingEngine
    {
        private readonly ILogger _logger;
    
        // Dependência da interface, não de uma implementação concreta
        public ProcessingEngine(ILogger logger)
        {
            _logger = logger;
        }
    
        public void ProcessData()
        {
            // ...
            _logger.LogMessage("Dados processados.");
        }
    }
    
  5. Extensibilidade: As interfaces permitem adicionar facilmente novas implementações de comportamentos existentes sem alterar o código que usa essa interface.

  6. Documentação e auto-documentação: Uma interface bem nomeada com comentários em seus membros serve como uma forma de documentação, descrevendo qual comportamento é esperado dos objetos que implementam essa interface.