Interfaces Múltiples
Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 27 de 70.
Mientras que una clase solo puede heredar de una clase base, puede implementar tantas interfaces como sea necesario. Esta es una de las ventajas clave que tienen las interfaces sobre las clases abstractas: permiten que una clase adopte múltiples comportamientos.
Para implementar múltiples interfaces, simplemente lístelas después de los dos puntos, separadas por comas:
public interface IFlyable
{
void Fly();
}
public interface ISwimmable
{
void Swim();
}
public class Duck : IFlyable, ISwimmable
{
public void Fly()
{
Console.WriteLine("Flying through the air");
}
public void Swim()
{
Console.WriteLine("Swimming in the pond");
}
}La clase Duck debe implementar todos los miembros de ambas interfaces. Esto modela escenarios del mundo real de forma natural: un pato genuinamente puede tanto volar como nadar, por lo que tiene sentido que cumpla con ambos contratos.
Al combinar la herencia con múltiples interfaces, la clase base debe ir primero:
public class Duck : Bird, IFlyable, ISwimmable
{
// Hereda de Bird, implementa ambas interfaces
}Esta flexibilidad te permite componer comportamientos de múltiples fuentes. Un Robot podría implementar IMovable, IChargeable e ISpeakable. Cada interfaz representa una única capacidad, y tu clase puede combinar exactamente lo que necesita.
Desafío
FácilVamos a construir un sistema de dispositivos para el hogar inteligente que demuestre cómo una sola clase puede implementar múltiples interfaces para obtener diferentes capacidades. Crearás dispositivos que pueden ser tanto controlables como tener funciones de gestión de red.
Organizarás tu código en cuatro archivos:
IControllable.cs: Define una interfaz llamadaIControllableen el espacio de nombresSmartHome. Esta interfaz representa dispositivos que se pueden encender y apagar. Debe declarar dos métodos:TurnOn()yTurnOff(), ambos devolviendo un string.INetworkConnected.cs: Define una interfaz llamadaINetworkConnecteden el espacio de nombresSmartHome. Esta interfaz representa dispositivos que pueden conectarse a una red. Debe declarar un métodoConnect(string network)que devuelva un string.SmartTV.cs: Define una claseSmartTVen el espacio de nombresSmartHomeque implemente tantoIControllablecomoINetworkConnected. El televisor debe tener una propiedadBrand(string) y una propiedadScreenSize(int, que representa las pulgadas). Crea un constructor que acepte ambos valores. Implementa todos los métodos de la interfaz:TurnOn()devuelve"{Brand} {ScreenSize}-inch TV is now ON"TurnOff()devuelve"{Brand} {ScreenSize}-inch TV is now OFF"Connect(string network)devuelve"{Brand} TV connected to {network}"
Program.cs: En tu archivo principal, crea unaSmartTVutilizando los valores de entrada. Demuestra la flexibilidad de las múltiples interfaces almacenando el mismo objeto TV en tres tipos de variables diferentes: el tipo concretoSmartTV, una variableIControllabley una variableINetworkConnected. Llama a los métodos apropiados a través de cada referencia para mostrar cómo el mismo objeto puede ser tratado de manera diferente según la interfaz con la que estés trabajando.
Recibirás tres entradas:
- Nombre de la marca del televisor
- Tamaño de la pantalla en pulgadas
- Nombre de la red a la que conectarse
Imprime la salida en este formato:
Via SmartTV:
{TurnOn() result}
{Connect(network) result}
Via IControllable:
{TurnOff() result}
Via INetworkConnected:
{Connect(network) result}Por ejemplo, si las entradas son Samsung, 55 y HomeWiFi, la salida debería ser:
Via SmartTV:
Samsung 55-inch TV is now ON
Samsung TV connected to HomeWiFi
Via IControllable:
Samsung 55-inch TV is now OFF
Via INetworkConnected:
Samsung TV connected to HomeWiFiObserva cómo se puede acceder al mismo objeto SmartTV a través de diferentes referencias de interfaz. Cuando se almacena como IControllable, solo puedes llamar a los métodos de control. Cuando se almacena como INetworkConnected, solo puedes llamar a los métodos de red. ¡Este es el poder de implementar múltiples interfaces: una clase adquiere múltiples capacidades mientras mantiene la flexibilidad en su uso!
Hoja de referencia
Una clase puede implementar múltiples interfaces enumerándolas después de los dos puntos, separadas por comas:
public interface IFlyable
{
void Fly();
}
public interface ISwimmable
{
void Swim();
}
public class Duck : IFlyable, ISwimmable
{
public void Fly()
{
Console.WriteLine("Flying through the air");
}
public void Swim()
{
Console.WriteLine("Swimming in the pond");
}
}La clase debe implementar todos los miembros de todas las interfaces.
Al combinar la herencia con múltiples interfaces, la clase base debe ir primero:
public class Duck : Bird, IFlyable, ISwimmable
{
// Hereda de Bird, implementa ambas interfaces
}Esto permite componer comportamientos de múltiples fuentes, donde cada interfaz representa una única capacidad.
Pruébalo tú mismo
using System;
using SmartHome;
class Program
{
public static void Main(string[] args)
{
// Leer las entradas
string brand = Console.ReadLine();
int screenSize = Convert.ToInt32(Console.ReadLine());
string network = Console.ReadLine();
// TODO: Crear un objeto SmartTV con los valores de entrada
// TODO: Almacenar el mismo objeto TV en tres tipos de variables diferentes:
// 1. Tipo SmartTV (clase concreta)
// 2. Tipo IControllable (referencia de interfaz)
// 3. Tipo INetworkConnected (referencia de interfaz)
// TODO: Imprimir la salida en el formato requerido:
// A través de SmartTV:
// - Llamar a TurnOn() y Connect(network)
// A través de IControllable:
// - Llamar a TurnOff()
// A través de INetworkConnected:
// - Llamar a Connect(network)
}
}
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
1Fundamentos de OOP
Archivos externosNamespaces y directivasIntro a clases y objetosLa palabra clave 'this'Métodos y parámetrosCampos vs PropiedadesConstructoresInicializadores de objetosResumen - Calculadora simple4Herencia
Sintaxis básica de herencia (:)La palabra clave 'base'Palabras clave Virtual y OverrideClases selladas (Sealed)La clase base 'object'Resumen: Jerarquía de empleados7Características avanzadas
Sobrecarga de operadoresIndexadores (this[])Sobrescritura de ToString()Métodos de extensiónResumen - Lista personalizada10Patrones de diseño - Parte 1
Introducción a los patrones de diseñoSingleton Thread-SafePatrón FactoryPatrón Observer (Eventos)Patrón Strategy2Propiedades y miembros estáticos
Propiedades autoimplementadasPropiedades de solo lectura y escrituraCampos y métodos estáticosClases estáticasMiembros con cuerpo de expresión5Polimorfismo e Interfaces
Polimorfismo: Compilación vs. EjecuciónInterfaz vs. Clase AbstractaInterfaces MúltiplesInterfaces ExplícitasUpcasting y DowncastingRepaso: Calculadora de Figuras8Conceptos avanzados de POO
Composición sobre herenciaGenéricos (clases y métodos)Delegados y eventosAtributos y ReflexiónIDisposable y la sentencia usingFundamentos de Inyección de dependencias11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Arquitectura de clases
Datos de instancia vs. estáticosPalabras clave 'readonly' y 'const'Campos de respaldoResumen - Gestor de cuentas bancarias6Encapsulamiento
Modificadores de accesoPropiedades para el encapsulamientoImplementación de ocultamiento de datosPatrones de inmutabilidadRepaso - Registros de estudiantes