Menu
Coddy logo textTech

Interfaces Explícitas

Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy. Lição 28 de 70.

Quando uma classe implementa várias interfaces que têm membros com o mesmo nome, você se depara com uma colisão de nomes. A implementação explícita de interfaces resolve isso permitindo que você forneça implementações separadas para cada interface.

Com a implementação explícita, você prefixa o nome do membro com o nome da interface e omite o modificador de acesso:

public interface IAmericanPlug
{
    void Connect();
}

public interface IEuropeanPlug
{
    void Connect();
}

public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
    void IAmericanPlug.Connect()
    {
        Console.WriteLine("Connected to 120V");
    }
    
    void IEuropeanPlug.Connect()
    {
        Console.WriteLine("Connected to 220V");
    }
}

Membros implementados explicitamente só podem ser acessados por meio de uma variável do tipo da interface, não pela própria classe:

var adapter = new UniversalAdapter();
// adapter.Connect();  // Não vai compilar!

IAmericanPlug american = adapter;
american.Connect();  // Conectado a 120V

IEuropeanPlug european = adapter;
european.Connect();  // Conectado a 220V

Essa técnica também é útil quando você quer ocultar membros da interface da API pública da classe. Se um método só faz sentido ao tratar o objeto como uma interface específica, a implementação explícita mantém a superfície da sua classe limpa e, ao mesmo tempo, cumpre o contrato.

challenge icon

Desafio

Fácil

Vamos criar um sistema gerador de relatórios que demonstra como a implementação explícita de interfaces permite que uma única classe forneça comportamentos diferentes dependendo da interface que está sendo usada. Você criará um documento que pode ser formatado de maneira diferente para exibição e impressão.

Você organizará seu código em quatro arquivos:

  • IDisplayable.cs: Defina uma interface chamada IDisplayable no namespace Reports. Essa interface representa conteúdo que pode ser exibido na tela. Ela deve declarar um método Render() que retorna uma string.
  • IPrintable.cs: Defina uma interface chamada IPrintable no namespace Reports. Essa interface representa conteúdo que pode ser enviado para uma impressora. Ela também deve declarar um método Render() que retorna uma string — observe que isso cria uma colisão de nomes com IDisplayable!
  • Report.cs: Defina uma classe Report no namespace Reports que implemente IDisplayable e IPrintable. O relatório deve ter uma propriedade Title (string) e uma propriedade Content (string), com um construtor que defina ambos os valores. Use a implementação explícita de interface para fornecer comportamentos diferentes para Render():
    • Ao ser renderizado para exibição: "[SCREEN] {Title}: {Content}"
    • Ao ser renderizado para impressão: "[PRINT] {Title} | {Content}"
  • Program.cs: No seu arquivo principal, crie um Report usando os valores de entrada. Como as implementações explícitas só podem ser acessadas por meio de variáveis de interface, armazene o mesmo relatório em uma variável IDisplayable e em uma variável IPrintable, depois chame Render() em cada uma para mostrar como o mesmo objeto produz uma saída diferente com base na interface que você está usando.

Você receberá duas entradas:

  • Título do relatório
  • Conteúdo do relatório

Imprima a saída neste formato:

Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}

Por exemplo, se as entradas forem Sales Report e Q4 revenue increased by 15%, a saída deverá ser:

Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%

Observe como o mesmo objeto Report se comporta de maneira diferente dependendo da referência de interface usada para acessá-lo. Esse é o poder da implementação explícita de interfaces — resolver colisões de nomes e, ao mesmo tempo, fornecer um comportamento apropriado ao contexto!

Experimente você mesmo

using System;
using Reports;

class Program
{
    public static void Main(string[] args)
    {
        // Ler a entrada
        string title = Console.ReadLine();
        string content = Console.ReadLine();

        // TODO: Criar um objeto Report com o title e o content

        // TODO: Armazenar o report em uma variável IDisplayable

        // TODO: Armazenar o mesmo report em uma variável IPrintable

        // TODO: Imprimir a versão de exibição chamando Render() em IDisplayable
        Console.WriteLine("Display version:");
        // Imprimir o resultado do render aqui

        // TODO: Imprimir a versão de impressão chamando Render() em IPrintable
        Console.WriteLine("Print version:");
        // Imprimir o resultado do render aqui
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C# online