Cómo organizar su código orientado a objetos con herencia

Es común reutilizar código en la programación orientada a objetos. Las clases existen para que pueda crear objetos sin tener que escribir las mismas variables y funciones una y otra vez.

Pero, ¿qué pasa con las clases en sí? A veces, las clases también son muy similares. Por ejemplo, un árbol tiene ramas, raíces y tronco. Eso se aplica a Elms, Oaks y Ponderosa Pines.

Si estuviera agregando un árbol a un juego, podría crear partes de árboles para docenas de árboles. Pero sería más fácil crear una clase de árbol y hacer que todos los demás árboles heredaran sus propiedades.

¿Por qué es importante la herencia?

Existe un concepto en la programación orientada a objetos llamado "manténgalo SECO". SECO significa "No se repita". Si se encuentra copiando y pegando mucho código, también está dejando espacio para muchos errores.

Digamos que estás escribiendo el código para un nuevo juego de Tamagotchi. La primera mascota virtual será un oso polar. Entonces crea una clase llamada PolarBear en JavaScript / TypeScript.

 class PolarBear {
private _weight: number = 990;
constructor(weight: number = 0) {
this._weight = weight
}
makeNoise() {
console.log("made a roar");
}
eat() {
console.log("eats whatever it wants");
}
sleep() {
console.log("got a good night's sleep");
}
roam() {
console.log("wandered about aimlessly");
}
}

Entonces su jefe le dice que la alta dirección tuvo un gran avance. Se dieron cuenta de que ya no son los 90 y que pueden caber más de 5K de memoria en el Tamagotchi. Y ahora quieren todos los osos.

Te arremangas y vuelves al trabajo, creando copias de la clase de osos. Entonces tu jefe vuelve a llamar a tu puerta. Resulta que quieren que el juego sea más educativo. Ahora debes agregar información de origen a cada mascota.

Ya no estás duplicando código. Ahora está cambiando cientos de líneas de código para las ocho especies de osos. Así es como ocurren los errores y se introducen los errores.

Mientras te mueves, tu jefe se acerca una vez más. Ahora la alta gerencia también quiere a todos los roedores en el juego. Oh, y una jirafa.

Sabes que cuando termines, querrán monos o algo más. Tiene que haber una mejor manera.

En lugar de crear Tamogatchi de próxima generación, siempre puedes jugar con los existentes .

Herencia al rescate

Para dominar su colección de animales virtuales, necesitará organizarse. La herencia le ayuda a organizar sus clases añadiéndoles relaciones de padres e hijos.

Los osos negros, los osos pardos y los osos perezosos son todos osos. Los osos, roedores y monos son todos animales. Y así es como estructuraremos nuestro árbol genealógico.

Así es como se ve una parte del código:

 class Animal {
private _weight: number;
private _origin: string;
constructor(weight: number = 0, origin: string = "") {
this._weight = weight;
this._origin = origin;
}
makeNoise(noise: string = "") {
console.log("made a noise that sounded like: " + noise);
}
eat(food: string = "") {
console.log("eats " + food);
}
sleep() {
console.log("got a good night's sleep");
}
roam() {
console.log("wandered about aimlessly");
}
}
class Bear extends Animal {
constructor(weight: number, origin: string) {
super(weight, origin);
}
makeNoise(noise: string = "roar") {
super.makeNoise(noise);
}
eat(food: string = "whatever it wants") {
super.eat(food);
}
}
class GrizzlyBear extends Bear {
constructor(weight: number = 600, origin: string = "North America") {
super(weight, origin);
}
}
class Panda extends Bear {
constructor(weight: number = 230, origin: string = "China") {
super(weight, origin);
}
makeNoise() {
super.makeNoise("squeek");
}
eat() {
super.eat("shoots and leaves");
}
}

Puedes jugar con el código en la zona de pruebas de TypeScript .

Esa fue una gran muestra, pero el código es bastante simple y todas las clases descienden de la clase Animal . Puedes ver que Bear extiende Animal . Y GrizzlyBear y Panda amplían la clase Bear . La clase Bear crea funciones predeterminadas de sonido y comida . La clase GrizzlyBear usa esas funciones predeterminadas, pero Panda no.

En otras palabras, la clase GrizzlyBear no anula las funciones de Bear . Debido a que GrizzlyBear extiende Bear , usará las funciones definidas por Bear automáticamente. Pero dado que Panda anula las funciones makeNoise y eat , las usará en su lugar.

Encontrar relaciones con la técnica "is-a, has-a"

Para averiguar si una clase realmente debería extender otra clase, puede preguntarse si existe una relación "es-un" o "tiene-un" entre ellos.

  • Un lémur "es-un" mono.
  • Un canguro "es-un" marsupial.
  • Sin embargo, la pata de un conejo no es un conejo. Un conejo "tiene" un pie.

Este ejemplo es un poco simplista, pero cuando se trata de clases del mundo real, puede ser muy útil.

Comprensión y práctica práctica de la herencia

¿Listo para aplicar lo aprendido?

  • Visite la caja de arena y complete el resto de las clases de animales del ejemplo anterior.
  • Agrega una clase de mono .
  • Agregue una clase ProboscisMonkey que amplíe su clase de mono.

La herencia es más que un código bien organizado. Es una parte fundamental de la programación orientada a objetos. La herencia ayuda a agilizar la comunicación entre objetos. Y permite un diseño orientado a objetos más avanzado, como con el polimorfismo. Puede obtener más información sobre la herencia en la documentación de TypeScript .