Una clase puede "heredar" o "descender" de otra clase (o "extenderla"). Esto significa que si una clase B extiende de una clase A, B "hereda" todos los métodos y propiedades de A. Para eso se declara class B extends A. Por ejemplo:
class Animal {
constructor(habitat){
this.habitat = habitat
}
comer = () => console.log("Nom nom nom")
}
class Conejo extends Animal { }
const conejo = new Conejo("pradera")
conejo.comer() // "Nom nom nom"
conejo.habitat // "pradera"Si la clase heredada tiene más parámetros en su constructor que la clase de la que hereda, entonces hay que llamar a la función super dentro del constructor de la clase hija (debe ser lo primero que se haga) y pasarle los argumentos que corresponden a la clase de la que hereda:
class Animal {
constructor(habitat){
this.habitat = habitat
}
comer = () => console.log("Nom nom nom")
}
class Conejo extends Animal {
constructor(habitat, color){
super(habitat)
this.color = color
}
}- Clase abstracta es una clase que no se puede instanciar (no se puede llamar con
new). Para lograrlo, en su constructor tenemos que chequear que quien lo esté llamando no sea la propia clase, de la siguiente forma
class Abstracta {
constructor() {
if (this.constructor === Abstracta) {
throw new ClaseNoInstanciableError(this)
}
}
}- Método abstracto es un método que se encuentra en una clase y que no puede ser usado por una instancia de la misma, sino por una clase que descienda de esta y que sobrescriba dicho método. Nos sirve de plantilla para indicar que las clases que herende de dicha clase tienen que implementar dicho método. Para evitar que sea utilizado, podemos arrojar un error:
class Animal {
comer = () => throw new MetodoNoImplentadoError()
}
class Conejo extends Animal {
comer = () => console.log("Nom nom nom")
}
const animal = new Animal() // OJO! Animal debería ser una clase abstracta, el ejemplo es solo a modo de ilustración
animal.comer() // Error
const conejo = new Conejo()
conejo.comer() // "Nom nom nom"Una clase tiene que tener una única responsabilidad, es decir, encargarse de una única cosa. Cuando vemos que comienza a manejar más de la cuenta, o cosas que no le corresponde, hay que separarla en nuevas clases. Lo mismo aplica a métodos.
Cuando tenemos propiedades cuyo no depende de valores que se le pasan al constructor, podemos declararlo fuera de este, para una mayor legibilidad. Esto:
class Ejemplo {
constructor() {
this.propiedadA = "a"
this.propiedadB = "b"
this.propiedadC = "c"
}
}es lo mismo que esto:
class Ejemplo {
propiedadA = "a"
propiedadB = "b"
propiedadC = "c"
}Se puede extender la clase Error para tener errores custom y no tener que repetir siempre el mismo mensaje cada vez que generarmos un error del mismo tipo. Esto se hace de la siguiente forma:
class CustomError extends Error {
constructor(mensaje) {
super()
this.name = "CustomError"
this.message = "Mensaje custom"
}
}y se usa arrojándolo:
throw new CustomError()Además, podemos pasarles otros parámetros para que el error sea más informativo. Algunos errores comunes que podemos tener son ArgumentoInvalidoError, MetodoNoImplementadoError, ClaseNoInstanciableError, etc.
- Podemos acceder al nombre de una clase con la propiedad
name, por ejemplo,Animal.name
Una propiedad o método estático no necesita tener una instancia para poder ser utilizado. Por ejemplo, cuando usamos Math.random(), no necesitamos crear una instancia de la clase Math.
Una propiedad estática tiene un valor fijo, no puede ser asignado dinámicamente (porque necesitaríamos una instancia para eso), ni manipulado. Es de solo lectura.
Un método estático no puede acceder a ninguna propiedad de la clase que no sea estática (porque se necesitaría una instancia para asignarlas).
En ambos casos, se usa la palabra reservada static antes de la propiedad o método:
class Ejemplo {
static propiedadPublicaEstatica
static #propiedadPrivadaEstatica
static metodoPublicoEstatico() {
// ...
}
static #metodoPrivadoEstatico() {
// ...
}
}
Ejemplo.propiedadPublicaEstatica // no hace falta instanciar Ejemplo
Ejemplo.metodoPublicoEstatico() // no hace falta instanciar EjemploLos métodos y propiedes estáticas son muy útiles en clases de tipo "helpers" o utilitarias.
- Crear una clase abstracta
Criaturacon- nombre
- vida
- vidaMaxima
- ataque
- Crear la clase
Heroey la clase abstractaMonstruoy hacerlas descender deCriatura - Crear tres clases concretas
Orco,GoblinyKoboldque desciendan deMonstruo, que en su constructor deben llamar a su clase ascendiente con valores específicos que necesita su constructor - Crear la clase
Juegopara manejar el flujo del juego:- debe tener una propiedad
historialque es un array que inicializa vacío - debe tener un método
loguearque agregue un mensaje al historial y lo muestre en consola - debe loguear cada acción y mensaje relativo al juego (p.ej.: "Atacas a monstruo! Le sacás 8 de vida", "No puedes investigar")
- debe tener una propiedad
monstruoque representa el monstruo actual - debe tener un método
investigarque genere un nuevo mostruo aleatorio y lo asigne amonstruo - debe tener un método
atacarque permita atacar amonstruo - debe permitir
investigarsólo si el monstruo actual no tiene vida - debe permitir
atacarsólo si el monstruo actual tiene vida
- debe tener una propiedad
- Extraer la lógica de combate en una clase
Combatey refactorizar el código.Juegodebería tenerCombatey delegarle responsabilidades - Centralizar las distintas posibles acciones (atacar, investigar) dentro de un único método (p. ej.
ejecutar) que tome como argumento un string, y ejecute la acción que corresponde. - Chequear si el juego está terminado o no (si
Heroeno tiene vida), e impedir hacer acciones si lo está - Permitir reiniciar el juego
- Agregarle a
Heroela propiedadinventario, que es un array que inicializa vacio - Crear una clase
Itemconnombrey el métodoutilizar, dicho método debe tener como parámetroobjetivoy debe invocar al metodo para sumarle vida al objetivo - Agregar a
Heroeel métodoutilizarItem, que tome como argumento un ítem y llame a su métodoutilizarpasándose a sí mismo como argumento, luego debe eliminar dicho ítem deinventario - Agregar a
Juegoel métodoutilizarItem, que llame al métodoutilizarItemdeHeroe - Hacer que
investigartenga un probabilidad de encontrar un monstruo o una poción y agregarla ainventariodeHeroe - Extraer la lógica de inventario en una clase
Inventario, que permita agregar, utilizar y remover ítems, e imprimir una lista de ítems. Agregar la posibilidad de utlizar y ver ítems como acciones del juego. - Agregar una clase
Area. Una área puede ser investigado sólo una vez, y de la investigación puede resultar un ítem, un monstruo, o nada. - Refactorizar el código para que el monstruo se encuentre en una área. El
Juegodebe tener ahora un área actual. Agregar la posibilidad de moverse para cambiar a una nueva área. - Agregar al juego la acción de descansar, que cura vida. Sólo puede realizarse en una área que haya sido investigada y en la que no se haya descubierto nada. Cuando descansa,
Heroese vuelve descansada, y no puede volver a descansar hasta que esté cansada. Se cansa cuando es atacada.