Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save joelalejandro/b3eaa1e125a13bc12fa2d0fba1418162 to your computer and use it in GitHub Desktop.
Save joelalejandro/b3eaa1e125a13bc12fa2d0fba1418162 to your computer and use it in GitHub Desktop.
Modelado de clases, herencia y composición
// 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