Herencia en C#
Cómo usar la herencia para reutilizar código y construir una relación sólida entre clases relacionadas.
Los lenguajes de scripting con los que es compatible
Unity tienen una característica llamada Herencia. La herencia es uno de los pilares de la Programación Orientada a Objetos o POO.
Cuando una clase hereda de otra gana las características de la clase de la que hereda.
Cuando se habla sobre la herencia, la clase de la que se hereda se llama clase Base o Parent. La clase que hereda se llama la clase derivada o Child.
Parent => child
El resultado de la herencia es que los elementos que existen en la clase Base también estarán disponibles en la clase derivada. Por lo tanto, los métodos y las variables se pueden usar en la clase derivada como si fuera la clase Base.
Por ejemplo, considera que tienen una clase Base llamada Class A, la misma que contiene dos métodos:
Dance() y
Sing(). Si tienes otra clase, Class B, que hereda de Class A, entonces Class B también tendrá dos métodos:
Dance() y
Sing(). No es necesario crear esos métodos en Class B porque ya existen en Class A.
// Parent
class A
{
public void Dance() { /*...*/ }
public void Sing() { /*...*/ }
}
// Child
class B : A { /*...*/ }
public class AccessExample : MonoBehaviour
{
// B puede usar los métodos de A
var b = new B();
b.Dance();
b.Sing()
}Cuando estamos tratando con asuntos de herencia, hay tres modificadores de acceso que tenemos que conocer:
public (público),
private (privado) y
protected(protegido), ya deberías estar familiarizado con estos conceptos de modificadores de acceso
public y
private.
Solo ten en cuenta que las herramientas de una clase base que son públicas van a existir y estarán disponibles en la clase derivada, mientras que las herramientas que son privadas existirán, pero no serán accesibles en la clase derivada.
// Parent
class A
{
public void Dance() { /*...*/ }
private void Sing() { /*...*/ }
}
// Child
class B : A { /*...*/ }
public class AccessExample : MonoBehaviour
{
// B puede usar los métodos de A
var b = new B();
b.Dance();
// no será accesible
// b.Sing()
}El modificador de acceso
protected actúa como un híbrido entre los
public y
private. Todas las herramientas de una clase Base que son protegidas existirán y serán accesibles en una clase derivada, como herramientas públicas, pero no podrán ser accedidas fuera de las clases base o derivadas como herramientas privadas.
// Parent
class A
{
protected void Dance() { /*...*/ }
protected void Sing() { /*...*/ }
}
// Child
class B : A
{
public void DanceAndSing()
{
// accesible
Dance();
Sing();
}
}
public class AccessExample : MonoBehaviour
{
var b = new B();
// accesible
b.DanceAndSing();
// no serán accesibles
// b.Dance()
// b.Sing()
}Es muy probable que la mayoría de las clases que has usado hasta ahora en
Unity han sido heredadas. Ciertamente, todos los scripts que se aplican como componentes para
GameObjects son
MonoBehaviours. Esto significa que han heredado de la clase
MonoBehaviours.
Por defecto, los scripts hechos en
Unity siguen este formato:
public class seguido del nombre de la clase, seguido de dos puntos y el nombre de la clase:
MonoBehaviours.
public class SomeClass : MonoBehaviour
{
/*...*/
}Los dos puntos en el nombre de una clase está diciéndole al script que hereda de MonoBehaviour, para hacer que esta clase herede de otra clase, simplemente cambia el nombre
MonoBehaviours con el nombre de cualquier otra clase.
Para cambiar la clase de tal manera que no herede de ninguna clase Base, simplemente elimina los dos puntos y el nombre de la clase padre.
public class SomeClass
{
/*...*/
}Tal vez te estés preguntando por qué nuestros scripts heredan de
MonoBehaviours. Elementos como
GameObjects, Transform, el método
Start(), el método
Update() y más, todos provienen de
MonoBehaviours.
Nuestros scripts heredan de
MonoBehaviours de tal manera que tengan acceso a esas herramientas. La estructura hereditaria es jerárquica. Una manera muy común de considerar la herencia es compararla con el reino animal.
Es este ejemplo, tenemos una clase
Base llamada
Animal. Esta clase contiene todas las definiciones y propiedades necesarias para hacer que la clase se comporte como un animal. De esta clase
Base Animal podemos tener un par de clases derivadas:
Vertebrados e
Invertebrados. La clase Vertebrados sería, entonces, por consiguiente la clase
Base para más clases, tales como
mamíferos,
reptiles o
anfibios. Cada una de estas clases derivadas toman la información que proveen su clase
Base y añadirían más a ella.
Al igual que nuestro ejemplo sobre los animales, la herencia en la
Programación Orientada a Objetos se conoce como una relación. Esto significa que la clase derivada es una clase
Base. Un reptil es un
Vertebrados. Un mamífero es un
Animal.
Un ejemplo en
Unity que tal vez habrás encontrado antes es: Un
Capsule Collider (colisionador en forma de cápsula) es un
Collider (colisionador). Este concepto se cubrirá más a fondo en Polimorfismo.
La idea de la herencia puede ser muy útil y aplicable en el desarrollo de los videojuegos. Por ejemplo, podemos tener una clase llamada Humanoid. Esta clase cubre todas las cosas que los
Humanoides deben hacer en nuestro juego. Tenemos entonces dos clases derivadas:
Enemy y
Player. Estas controlan los particulares de cómo los jugadores y los enemigos funcionan en el juego mientras que ya se comportan como
Humanoides, porque han heredado todos los miembros de la clase
Humanoides. Luego podemos tener dos más clases derivadas de
Enemy:
Orc (orcos) y
Globin (duende). Estas ya se comportan como enemigos los mismos que se comportan como
Humanoides. De esta manera, tenemos que escribir mucho menos código para hacer que los
Orc y los
Globin se comporten como quieres que se comporten, porque estamos reusando el código de
Humanoides y
Enemy.
Los constructores son una excepción a lo que las clases derivadas heredan ya que son únicos a la clase y nunca se comparten. Sin embargo; cuando se invoca un constructor en una clase derivada, el constructor de su clase base se invoca justo antes.
Desde que las clases pueden tener muchos tipos diferentes de constructores tal vez querramos poder controlar cuál constructor de la clase
Base se invoca. Lo hacemos con la palabra reservada base. Al seguir la lista de parámetros del constructor de la clase derivada con dos puntos puedes invocar explícitamente un constructor específico de la clase base usando la palabra clase base en la lista de parámetros de la clase base.
public class Apple : Fruit
{
public Apple() : base("apple") { /* constructor code...*/}
}Si el constructor de la clase base no se invoca explícitamente, entonces el constructor por defecto todavía se llamará implícitamente.
Aparte de invocar el constructor de la clase base, puedes usar la palabra reservada de la clase base para acceder a otros miembros de la clase base. Esto es muy útil en situaciones donde quieras acceder la versión de la clase base de algo, porque es diferente que la versión de la clase derivada. Esto pasa a menudo cuando estamos sobreescribiendo funciones.
public class Fruit
{
public Fruit(string name) { /* constructor code...*/ }
public virtual void Juicy() { /*...*/}
}
public class Apple : Fruit
{
public Apple() : base("apple")
{
/* constructor code...*/
}
public virtual void Juicy() override
{
/*algún código jugoso */
base.Juicy(); // acceso a la versión de la clase base
}
}Para obtener más información sobre esto, consulta la sección de overriding (sobrescritura) .
Gist del proyectoApoya el contenido de mi blog a través de:
Fuente: