A Pen by Joel Alejandro Villarreal Bertoldi on CodePen.
Created
September 5, 2020 00:09
-
-
Save joelalejandro/b3eaa1e125a13bc12fa2d0fba1418162 to your computer and use it in GitHub Desktop.
Modelado de clases, herencia y composición
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Ejemplo de modelado de una clase, utilizando su constructor | |
// para cargar todos los parámetros. | |
class Persona { | |
constructor(nombre, apellido, mail, edad, telefono){ | |
// Utilizamos this ("esto") para guardar los valores que entraron | |
// como parámetros del constructor en esta instancia (copia) | |
// de la clase. | |
this.nombre = nombre; | |
this.apellido = apellido; | |
this.mail = mail; | |
this.edad = edad; | |
this.telefono = telefono; | |
} | |
} | |
class PersonaUsandoObjetoComoArgumento { | |
// Como el constructor sigue siendo una función, podemos utilizar | |
// cualquier tipo de dato en los parámetros. Para no tener que pasar | |
// muchos parámetros en variables separadas, podemos utilizar | |
// un único parámetro de tipo objeto, con las propiedades que | |
// querramos. | |
constructor(datosPersona){ | |
this.nombre = datosPersona.nombre; | |
this.apellido = datosPersona.apellido; | |
this.mail = datosPersona.mail; | |
this.edad = datosPersona.edad; | |
this.telefono = datosPersona.telefono; | |
} | |
} | |
// Así se instanciaría una persona utilizando varios argumentos. | |
// Siempre se recomienda que haya pocos parámetros, ya que a medida | |
// que se van sumando, es difícil saber de qué se trata. | |
// Por ejemplo, sin ver la definición de la clase, ¿qué significa el 30? | |
// No está claro a partir de esta línea por sí sola. | |
const persona1 = new Persona("Joel", "Bertoldi", "[email protected]", 30, "12312312321"); | |
// Así se instanciaría una persona utilizando el parámetro de tipo objeto. | |
// La ventaja de este estilo de constructores es que nos deja ver claramente | |
// qué propiedad va con qué valor. | |
const persona2 = new PersonaUsandoObjetoComoArgumento({ | |
nombre: "Joel", | |
apellido: "Bertoldi", | |
mail: "[email protected]", | |
edad: 30, | |
telefono: "1232132131" | |
}); | |
///////////////////////////////////////////////////////////////////////////////////// | |
// Podemos relacionar clases a través de dos patrones primordiales en la programación | |
// orientada a objetos: herencia y composición. | |
///////////////////////////////////////////////////////////////////////////////////// | |
// PATRÓN DE HERENCIA | |
// El patrón de herencia nos permite compartir todas las propiedades y funciones | |
// que posea la clase a que nos relacionemos. Se utiliza la palabra "extend" | |
// para ello. | |
// Por ejemplo: una entidad Estudiante comparte todos los datos de Persona, | |
// y además tiene algunos datos específicos. Entonces, para no repetir | |
// las declaraciones, podemos decir que Estudiante *extiende de* o *hereda de* | |
// Persona. | |
class Estudiante extends Persona { | |
// Observemos que el constructor sigue pidiendo todos los datos: | |
// el hecho de que heredemos no quita que aún necesitamos todos los datos. | |
constructor (nombre, apellido, mail, edad, telefono, comision, cuotaAlDia) { | |
// Utilizamos la funcion super() para llamar al constructor de la clase | |
// de la cual se hereda. En este caso, se llama a la función "constructor" | |
// de la clase Persona. | |
super(nombre, apellido, mail, edad, telefono); | |
// Acá ya estamos haciendo lo que es específico de la clase Estudiante. | |
this.comision = comision; | |
this.cuotaAlDia = cuotaAlDia; | |
} | |
} | |
// Pensemos en el patrón de herencia como una jerarquía de relaciones madre-hija: | |
// | |
// SerVivo | |
// |__ Mamífero | |
// |__ Persona | |
// |__ Estudiante | |
// | |
// Trabajar con el patrón de herencia tiene algunas restricciones: | |
// | |
// - Sólo se puede heredar de *una* clase. Si por ejemplo, estuviéramos modelando | |
// una clase ManualDeEstudio y quisiéramos que herede propiedades de una clase | |
// Libro y de una clase PublicacionEscrita, no sería posible. | |
// | |
// - El patrón de herencia tiene sentido cuando se comparten *TODAS* las propiedades | |
// y funcionalidades de la clase de la cual se hereda y cuando no se modifica | |
// el comportamiento de ninguna de sus funcionalidades. Si estamos considerando | |
// que una clase sirve en un 90% pero hay un 10% que no encaja, es preferible | |
// no utilizar herencia, ya que de hacerlo estaríamo reutilizando código de una forma | |
// improlija y poco intuitiva. | |
///////////////////////////////////////////////////////////////////////////////////// | |
// PATRÓN DE COMPOSICIÓN | |
// El patrón de composición nos permite combinar funcionalidades de distintas | |
// clases, relacionando clases de manera indirecta y sin establecer la jerarquía | |
// restrictiva que define el patrón de herencia. | |
class EstudianteComposicion1 { | |
// Como siempre, pedimos todos los datos, ya sea utilizando parámetros múltiples | |
// o un parámetro de tipo objeto. | |
constructor(nombre, apellido, mail, edad, telefono, comision, cuotaAlDia) { | |
// Acá está la principal diferencia: observemos que no hay llamada a super(). | |
// Lo que hacemos es crear el objeto Persona a partir de la información disponible. | |
this.persona = new Persona(nombre, apellido, mail, edad, telefono); | |
this.comision = comision; | |
this.cuotaAlDia = cuotaAlDia; | |
} | |
} | |
// Fijémonos que la instanciación no tiene ningún cambio: es una lista de parámetros. | |
const estudiante1 = new EstudianteComposicion1("Joel", "Bertoldi", "[email protected]", 30, "12345829", "A", true); | |
// Pensemos en el patrón de composición como una caja con objetos adentro: | |
// | |
// [------- Computadora --------] | |
// [ ] | |
// [ [Pantalla] [Teclado] ] | |
// [ [Mouse] [Procesador] ] | |
// [ ] | |
// [----------------------------] | |
// | |
// Para poder imitar esto con herencia, tendríamos que hacer algo como: | |
// | |
// Procesador | |
// |__ Teclado | |
// |__ Mouse | |
// |__ Pantalla | |
// |__ Computadora | |
// | |
// Pero, ¿tiene sentido el orden? ¿Un teclado, un mouse, una pantalla, | |
// un procesador... comparten funcionalidad e información? La respuesta | |
// no debería sorprendernos: estamos *forzando* el uso de un patrón | |
// en un escenario dnode no tiene sentido. | |
// | |
// El patrón de composición se llama así por algo: tiene que ver | |
// con ensamblar un objeto a partir de otros objetos más pequeños. | |
///////////////////////////////////////////////////////////////////////////////////// | |
// OPTIMIZANDO LOS PARÁMETROS DEL CONSTRUCTOR | |
// Ahora, aprovechando que los parámetros pueden tener cualquier tipo de dato | |
// (incluido objeto), podemos abreviar la lista de parámetros, y pedir que | |
// se pase una instancia *creada* de Persona al constructor. | |
class EstudianteComposicion2 { | |
constructor(persona, comision, cuotaAlDia) { | |
// Entonces, en el constructor es simplemente una asignación de variables. | |
this.persona = persona; | |
this.comision = comision; | |
this.cuotaAlDia = cuotaAlDia; | |
} | |
} | |
// En esta creación del estudiante, fijémonos que el primer argumento ahora es | |
// una instanciación de Persona (new Persona(...)) con todos sus datos, | |
// y luego vienen los datos específicos de la clase EstudianteComposicion2. | |
const estudiante2 = new EstudianteComposicion2( | |
new Persona("Joel", "Bertoldi", 30, "1232172", true), | |
"A", | |
true | |
); | |
// Podemos seguir acortando la lista de parámetros haciendo que tanto | |
// los datos de la persona como los datos del estudiante sean pasados | |
// al constructor en parámetros de tipo objeto. | |
class EstudianteComposicion3 { | |
constructor(datosPersona, datosEstudiante) { | |
this.persona = datosPersona; | |
this.comision = datosEstudiante.comision; | |
this.cuotaAlDia = datosEstudiante.cuotaAlDia; | |
} | |
} | |
// Entonces, el primer argumento ahora es una instancia de Persona, | |
// y el segundo es un objeto que contiene los datos específicos de | |
// la clase EstudianteComposicion3. | |
const estudiante3 = new EstudianteComposicion3( | |
new Persona("Joel", "Bertoldi", 30, "1232172", true), | |
{ comision: "A", cuotaAlDia: true } | |
); | |
///////////////////////////////////////////////////////////////////////////////////// | |
// ALGUNOS OTROS EJEMPLOS VISTOS EN CLASE | |
class Comision { | |
constructor(curso, idDeComision, profe, alumnos) { | |
this.curso = curso; | |
this.idDeComision = idDeComision; | |
this.profe = profe; | |
this.alumnos = alunmos; | |
} | |
} | |
// Este ejemplo incluye una composición con Persona. | |
class Docente { | |
constructor(datosPersona, linkCurriculum, antiguedad, especializacion) { | |
this.persona = datosPersona; | |
this.linkCurriculum = linkCurriculum; | |
this.antiguedad = antiguedad; | |
this.especializacion = especializacion; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment