Menu
Coddy logo textTech

Interfaces Explícitas

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy. Lección 28 de 70.

Cuando una clase implementa múltiples interfaces que tienen miembros con el mismo nombre, te enfrentas a una colisión de nombres. La implementación explícita de interfaces resuelve esto permitiéndote proporcionar implementaciones separadas para cada interfaz.

Con la implementación explícita, se antepone el nombre de la interfaz al nombre del miembro y se omite el modificador de acceso:

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");
    }
}

Los miembros implementados explícitamente solo pueden ser accedidos a través de una variable del tipo de interfaz, no a través de la clase misma:

var adapter = new UniversalAdapter();
// adapter.Connect();  // ¡No compilará!

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

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

Esta técnica también es útil cuando desea ocultar miembros de la interfaz de la API pública de la clase. Si un método solo tiene sentido cuando se trata al objeto como una interfaz específica, la implementación explícita mantiene limpia el área de superficie de su clase mientras sigue cumpliendo con el contrato.

challenge icon

Desafío

Fácil

Construyamos un sistema generador de informes que demuestre cómo la implementación explícita de interfaces permite que una sola clase proporcione comportamientos diferentes según la interfaz que se esté utilizando. Crearás un documento que se pueda formatear de manera diferente para su visualización y para su impresión.

Organizarás tu código en cuatro archivos:

  • IDisplayable.cs: Define una interfaz llamada IDisplayable en el espacio de nombres Reports. Esta interfaz representa contenido que se puede mostrar en pantalla. Debe declarar un método Render() que devuelva una cadena.
  • IPrintable.cs: Define una interfaz llamada IPrintable en el espacio de nombres Reports. Esta interfaz representa contenido que se puede enviar a una impresora. También debe declarar un método Render() que devuelva una cadena; ¡observa que esto crea una colisión de nombres con IDisplayable!
  • Report.cs: Define una clase Report en el espacio de nombres Reports que implemente tanto IDisplayable como IPrintable. El informe debe tener una propiedad Title (string) y una propiedad Content (string), con un constructor que establezca ambos valores. Usa la implementación explícita de interfaces para proporcionar comportamientos diferentes de Render():
    • Al representarse para su visualización: "[SCREEN] {Title}: {Content}"
    • Al representarse para su impresión: "[PRINT] {Title} | {Content}"
  • Program.cs: En tu archivo principal, crea un Report usando los valores de entrada. Puesto que solo se puede acceder a las implementaciones explícitas a través de variables de interfaz, almacena el mismo informe tanto en una variable IDisplayable como en una variable IPrintable; después, llama a Render() en cada una para mostrar cómo el mismo objeto produce una salida diferente según la interfaz que estés utilizando.

Recibirás dos entradas:

  • Título del informe
  • Contenido del informe

Imprime la salida con este formato:

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

Por ejemplo, si las entradas son Sales Report y Q4 revenue increased by 15%, la salida debe ser:

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

Observa cómo el mismo objeto Report se comporta de manera diferente según la referencia de interfaz que uses para acceder a él. ¡Este es el poder de la implementación explícita de interfaces: resolver colisiones de nombres y, al mismo tiempo, proporcionar un comportamiento apropiado para cada contexto!

Pruébalo tú mismo

using System;
using Reports;

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

        // TODO: Crea un objeto Report con el title y content

        // TODO: Almacena el informe en una variable IDisplayable

        // TODO: Almacena el mismo informe en una variable IPrintable

        // TODO: Imprime la versión de visualización llamando a Render() en IDisplayable
        Console.WriteLine("Display version:");
        // Imprime el resultado del renderizado aquí

        // TODO: Imprime la versión de impresión llamando a Render() en IPrintable
        Console.WriteLine("Print version:");
        // Imprime el resultado del renderizado aquí
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C# online