Polimorfismo en C#

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

Es la capacidad de un objeto de adoptar diferentes formas.

Es la capacidad que tienen los objetos de una clase de ofrecer respuesta distinta en función de los parámetros (diferentes implementaciones) utilizados durante su invocación. 

En Java, esto se consigue gracias a la herencia y las interfaces.

Animal a = new Dog();
Animal b = new Cat();
class Animal{
    public void makeSound(){
      Console.WriteLine("Grr...");
    }
  }
  class Cat : Animal{
    public void makeSound(){
      Console.WriteLine("Meow");
    }
  }
  class Dog : Animal{
    public void makeSound(){
      Console.WriteLine("Woof");
    }
  }

Sobrecarga y sobreescritura

La sobreecarga y la sobreescritura son dos mecanismos polimórficos.

Recordando la definición de polimorfismo:

Es la capacidad que tienen los objetos de una clase de ofrecer respuesta distinta en función de los parámetros (diferentes implementaciones) utilizados durante su invocación. 

Esto también se aplica a la sobrecarga y la sobreescritura.

  class OverloadOverride
  {
    static void Main(string[] args)
    {
      Son h = new Son();
      Son.Override("Be Welcome ", "Pablo");
      Son.Overload(3);

    }
  }
  class Father
  {
    public static void Override(string welcomeTxt, string nombre)
    {
      Console.WriteLine(welcomeTxt + nombre);
    }
    public static void Overload(string byeByeTxt, string nombre)
    {
      Console.WriteLine(byeByeTxt + nombre);
    }
  }
  class Son : Father
  {
    //Los parámetros de entrada no deben cambiar
    //El tipo devuelto no debe cambiar.
    public static void Override(string welcomeTxt, string nombre)
    {
      Console.WriteLine(welcomeTxt + "......" + nombre);
    }

    //Los parámetros de entrada deben cambiar.
    //El tipo de dato devuelto puede cambiar.
    public static int Overload(int byeByeCode)
    {
      Console.WriteLine(byeByeCode);
      return 4;
    }
  }

Abstracción

Métodos abstractos

Tenemos una clase «Cosa» que tiene un método «botar». Las clases «Ladrillo» y «Pelota» heredan de «Cosa».

La clase Cosa tiene un método abstracto llamado «botar». Es abstracto porque dependiendo de si instanciamos un ladrillo o una pelota habrá que sobrescribir el código para que bote de una forma determinada.

Un método abstracto es aquel que sólo tiene una declaración y no dispone de cuerpo. Está pensado para ser sobrescrito, luego no es posible utilizar el modificador private con un método abstracto.

Polimorfismo en C# 1
Polimorfismo en C# 2

Se declaran de la siguiente forma (quitando las llaves del cuerpo de la función y poneindo un ; en su lugar):

abstract public void botar();

Clases abstractas

  • Si una clase tiene al menos un método abstracto, dicha clase debe ser abstracta.
  • Una clase que herede de una clase abstracta debe implementar todos sus métodos abstractos (no es necesario sobrescribir los métodos no abstractos).
  • Abstracto viene a significar «sin definir».

Ejercicio – animales con clase abstracta

Implemente las clases del siguiente diagrama:

Polimorfismo en C# 3

Desarrolle una clase con el nombre MainClass, que contenga un método static void main(String args[]), que al ejecutarse genere una instancia de Vaca, Cerdo y Gallina pasándoles en el constructor el sonido que deben emitir (“muuuuuu”, “oinkoink”, “kokoroko”, por ejemplo). Sobreescribir el método comunicarse de cada clase para que cada una muestre un mensaje distinto. Puede ser algo del tipo «Cuando la vaca tiene leche hace » + sonido.

Llamar a los métodos comunicarse() de cada una de las tres instancias.

Interfaces

Una interface es un contrato, una forma de asegurarse que todo el mundo que la implemente va a hacer algo. No nos importa como vayan a hacerlo pero estamos seguros que si una clase implementa una interface entonces va a tener que cumplir el contrato e implementar lo acordado.

En Java, una interface es un tipo de referencia, similar a una clase, cuyo cuerpo puede contener:

  • Default methods (métodos con cuerpo).
  • Métodos estáticos (también pueden tener cuerpo)
  • Métodos abstractos.
  • Constantes.

Una clase que implemente una interface también deberá implementar todos sus métodos.

Una variable estática definida dentro de una interfaz será implícitamente definida como constante.

Todos los métodos abstractos, estáticos y default de una interfaz son implícitamente public. Por tanto, es posible omitir este modificador.

Una interfaz está pensada para ser sobrescrita, luego no tiene sentido utilizar modificadores privados dentro de una interfaz y no están permitidos.

interface Instrument{
	void play();//automáticamente público
}

class Violin: Instrument{
  
	public void play(){
		Console.WriteLine("Suena un violin");
	}
}

Ejemplo de uso

En el siguiente ejemplo, tenemos dependencias de la clase TraductorMaster y TranslateAll. La clase Conector equivaldría a nuestro inyector de dependencias (si lo estuviesemos usando) y se encarga de suministrar una dependencia a la interfaz. Las dependencias TraductorMaster y TranslateAll son intercambiables entre sí, ya que ambas implementan la misma interfaz y por tanto cumplen el mismo contrato.

public interface ITranslate
{
    void translate(string txt);
}
class MainClass
  {
    static void Main(string[] args)
    {
      ITranslate implementacionEscogida = new TraductorMaster();
      Connector conector = new Connector(implementacionEscogida);
      conector.traducir("Hola");
    }
  }
public class Main2 {
	public static void main(String[] args) {
		// El inyector de dependencias se encargaría de pasarle el TraductorMaster a la interfaz
		ITranslate implementacionEscogida = new TraductorMaster();
		Conector conector = new Conector(implementacionEscogida);
		conector.traducir("Hola");
	}
}
class Connector
{
    private ITranslate traductor;

    public Connector(ITranslate implementacionTraductor)
    {
      this.traductor = implementacionTraductor;
    }

    // En un caso real, con inyector de dependencias, el método traducir no sería necesario,
    // podríamos llamar directamente al método translate a partir de la interfaz
    public void traducir(string texto)
{
      this.traductor.translate(texto);
    }
}
class TraductorMaster : ITranslate{
  public void translate(string txt){
      Console.WriteLine(txt + " traducido");
  }
}
abstract class TranslateAll : ITranslate
{
    public void translate(string txt)
{
        Console.WriteLine(txt + "traducido");
    }

}

Ejercicio – animales con interfaz

Implemente las clases del siguiente diagrama.

Polimorfismo en C# 4

Desarrolle una clase con el nombre MainClass, que contenga un método public static void main(String args[]), que al ejecutarse genere una instancia de Vaca, Cerdo y Gallina pasándoles en el constructor el sonido que deben emitir («muuuuuu», «oinkoink», «kokoroko», por ejemplo). Sobreescribir el método comunicarse de cada clase para que cada una muestre un mensaje distinto. Puede ser algo del tipo “Cuando la vaca tiene leche hace ” + sonido.

Instanciar además un objeto de la clase Granjero que también implementará la interfaz comunicable.

Llamar a los métodos comunicarse() de cada una de las tres instancias.

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.