SOLID PRINCIPLES Flashcards
(34 cards)
¿Que es STUPID?
STUPID es simplemente un acrónimo basado en seis code smells que describen cómo NO debe ser el software que
desarrollamos
- Singleton: patrón singleton
- Tight Coupling: alto acoplamiento
- Untestability: código no testeable
- Premature optimization: optimizaciones prematuras
- Indescriptive Naming: nombres poco descriptivos
- Duplication: duplicidad de código
STUPID 1: Singleton como code smell
El patrón Singleton es un patrón de diseño que busca asegurar que una clase tenga una única instancia en toda la aplicación y proporciona un punto de acceso global a esa instancia.
¿Cómo funciona?
- La clase tiene una propiedad estática que almacena la instancia única.
- Al intentar crear una nueva instancia, el constructor verifica si ya existe una instancia en esa propiedad estática:
- Si existe, devuelve esa instancia.
- Si no existe, crea una nueva, la almacena en la propiedad estática y la devuelve.
```javascript
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance; // Devuelve la instancia existente
}
this.title = “my singleton”; // Inicializa la nueva instancia
Singleton.instance = this; // Almacena la instancia única
}
}
let mySingleton = new Singleton();
let mySingleton2 = new Singleton();
console.log(“Singleton 1: “, mySingleton.title); // “my singleton”
mySingleton.title = “modified in instance 1”;
console.log(“Singleton 2: “, mySingleton2.title); // “modified in instance 1”
~~~
Problemas del Singleton
-
Exposición global del estado
- Como el Singleton es accesible globalmente, cualquier parte de la aplicación puede modificar su estado. Esto dificulta rastrear los cambios y genera dependencias implícitas entre módulos, complicando el mantenimiento.
-
Dificultad para realizar pruebas unitarias
- Las pruebas unitarias deben ser independientes, pero el Singleton mantiene su estado entre ejecuciones.
- Si una prueba modifica el estado, otra prueba podría fallar inesperadamente.
-
Acoplamiento fuerte
- Los módulos que acceden directamente al Singleton introducen una dependencia implícita, dificultando cambios futuros, como reemplazarlo por otra implementación.
Cohesión
Cohesión
La cohesión se refiere a qué tan relacionados están los elementos dentro de un módulo o clase. Un módulo tiene alta cohesión cuando todas las partes que lo componen están muy enfocadas en una única responsabilidad o propósito. Un código con alta cohesión es más fácil de entender, mantener y probar, ya que todas las piezas del código están muy conectadas entre sí para lograr un objetivo claro.
Ejemplo de alta cohesión:
Imagina una clase que solo se encarga de realizar cálculos:
```javascript
class Calculadora {
sumar(a, b) {
return a + b;
}
restar(a, b) { return a - b; } } ~~~
- Aquí, todos los métodos de la clase están relacionados con el cálculo.
- Esto hace que la clase sea fácil de entender y sólo se enfoque en una tarea (realizar cálculos).
- Esta clase tiene alta cohesión.
Ejemplo de baja cohesión:
Si la misma clase comenzara a hacer más tareas no relacionadas, como enviar correos y manipular texto, perdería cohesión:
```javascript
class Utilidades {
enviarCorreo(correo) {
// lógica para enviar correo
}
convertirTextoAMayusculas(texto) { return texto.toUpperCase(); } sumar(a, b) { return a + b; } } ~~~
- Aquí, los métodos están desconectados entre sí: enviar correos, modificar texto y realizar cálculos.
- Esto crea una clase que es difícil de entender y mantener porque tiene responsabilidades divididas, lo que se traduce en baja cohesión.
Acoplamiento
Acoplamiento
El acoplamiento mide qué tan dependientes están los módulos entre sí. Un sistema tiene alto acoplamiento cuando los módulos están estrechamente interconectados y dependen unos de otros. Por el contrario, un sistema con bajo acoplamiento tiene módulos más independientes, lo que facilita el mantenimiento, las pruebas y la reutilización.
Ejemplo de alto acoplamiento:
Imagina una clase Pedido que depende directamente de la clase Notificador:
```javascript
class Pedido {
constructor() {
this.notificador = new Notificador(); // Dependencia directa
}
procesar() { this.notificador.enviarNotificacion("Pedido procesado"); } }
class Notificador {
enviarNotificacion(mensaje) {
console.log(“Notificación enviada:”, mensaje);
}
}
~~~
- En este caso, Pedido depende directamente de Notificador.
- Si alguna vez cambias el funcionamiento de Notificador, tendrás que modificar también la clase Pedido.
- Esto es alto acoplamiento porque los módulos no son independientes.
Ejemplo de bajo acoplamiento:
En este caso, si pasamos el Notificador como parámetro al constructor de Pedido, reducimos la dependencia directa.
Esto se llama Inyección de Dependencias:
```javascript
class Pedido {
constructor(notificador) {
this.notificador = notificador; // Inyección de dependencia
}
procesar() { this.notificador.enviarNotificacion("Pedido procesado"); } }
class Notificador {
enviarNotificacion(mensaje) {
console.log(“Notificación enviada:”, mensaje);
}
}
// Uso:
const notificador = new Notificador();
const pedido = new Pedido(notificador);
pedido.procesar();
~~~
- Aquí, Pedido no depende directamente de la clase Notificador, sino que la recibe desde fuera.
- Esto es bajo acoplamiento, porque puedes cambiar la implementación de Notificador sin necesidad de modificar la clase Pedido.
El equilibrio entre cohesión y acoplamiento
El equilibrio entre cohesión y acoplamiento
- Alta cohesión significa que los módulos o clases deben enfocarse en una sola responsabilidad y tener todo lo necesario para cumplir con esa responsabilidad. Esto mejora la comprensión y el mantenimiento del código.
- Bajo acoplamiento significa que los módulos deben depender lo menos posible unos de otros. Esto facilita la reutilización, el cambio y las pruebas, ya que cada módulo puede ser modificado de manera independiente.
El verdadero desafío en el diseño de sistemas es encontrar el equilibrio entre cohesión y acoplamiento. Si maximizas la cohesión, podrías crear módulos muy específicos pero con muchas dependencias entre ellos, lo que aumenta el acoplamiento. Por el contrario, si minimizas el acoplamiento, puedes terminar con módulos más dispersos y difíciles de gestionar. Por eso, la clave es favorecer un bajo acoplamiento sin sacrificar la cohesión.
Esto permitirá crear sistemas modulares, fáciles de mantener, probar y extender.
Código no testeable
El código no testeable suele ser el resultado de un alto acoplamiento y la FALTA de inyección de dependencias. Este último aspecto se aborda con el principio SOLID de inversión de dependencias. Aunque existen técnicas específicas para solucionar estos problemas, la clave es diseñar el sistema teniendo en cuenta la testabilidad desde el inicio. Esto nos permite detectar problemas como el alto acoplamiento y las dependencias de estado global de manera temprana. Estos temas se explorarán más a fondo en las secciones de Unit Testing y TDD.
Optimización Prematura
Evitar la Complicación Innecesaria
“Cuando lleguemos a ese río, cruzaremos ese puente”. Retrasar decisiones permite enfocarse en lo más importante: las reglas de negocio, donde está el valor real. Al aplazar estas decisiones, se obtiene más información sobre los requisitos del proyecto, lo que facilita tomar mejores decisiones.
Donald Knuth (el de The Art of Computer Programming) afirmaba que la optimización prematura es la raíz de todos los males. No se trata de escribir código no optimizado, sino de evitar desarrollar abstracciones innecesarias que compliquen el software sin necesidad.
Complejidad Esencial vs. Complejidad Accidental
La complejidad accidental ocurre cuando se introduce una solución innecesariamente compleja en un proyecto software. La complejidad esencial es la inherente al problema, la cual debe ser la única presente. Sin embargo, a menudo agregamos complejidad accidental debido al desconocimiento o falta de planificación, lo que hace el proyecto difícil de mantener y poco adaptable al cambio.
Fred Brooks, en su artículo No Silver Bullet, distinguió entre estas dos complejidades, basándose en la descomposición aristotélica del conocimiento.
STUPID 2: Indescriptive Naming
nombres poco
descriptivos. Básicamente viene a decirnos que los nombres de variables, métodos
y clases deben seleccionarse con cuidado para que den expresividad y significado a
nuestro código
Principio DRY (Don’t Repeat Yourself)
El último principio del acrónimo STUPID hace referencia al principio DRY, que nos aconseja evitar la duplicación de código. La idea central de DRY es que cada pieza de conocimiento o lógica debe tener una única representación dentro del sistema. Esto mejora la mantenibilidad, reduce errores y facilita las modificaciones en el futuro.
Aunque este principio es valioso, es importante recordar que no es absoluto. Existen excepciones donde la duplicación puede ser necesaria, por ejemplo, en casos de optimización o cuando la claridad del código se ve beneficiada.
En resumen, el principio DRY es fundamental para escribir código más limpio y fácil de mantener, pero siempre se debe considerar el contexto y las necesidades del proyecto.
Principios STUPID: Orden y Significado
- S - Singleton: Evitar la creación de instancias innecesarias de una clase.
- T - Tight coupling: Evitar el alto acoplamiento entre componentes.
- U - Untestability: Evitar código difícil de testear.
- P - Premature optimization: Evitar la optimización prematura que añade complejidad innecesaria.
- I - Inconsistent interfaces: Evitar interfaces inconsistentes que complican la interacción entre componentes.
- D - Duplication: Evitar la duplicación de código (principio DRY).
- S - Speculative generality: Evitar abstracciones innecesarias o generalizaciones especulativas que añaden complejidad.
Duplicidad Real: Qué Es y Cómo Evitarla
La duplicidad real ocurre cuando el código es idéntico y cumple la misma función en múltiples lugares del proyecto. Esto implica que, al hacer un cambio, debemos propagarlo manualmente en todos esos lugares, lo cual aumenta las probabilidades de error humano.
Ejemplo:
Imagina que tienes el siguiente código duplicado en dos funciones diferentes:
```javascript
function calcularDescuento1(precio) {
return precio * 0.9;
}
function calcularDescuento2(precio) {
return precio * 0.9;
}
~~~
Si necesitamos cambiar la lógica del descuento (por ejemplo, modificar el porcentaje), tendríamos que hacerlo en ambos lugares, lo que aumenta la posibilidad de cometer errores.
Solución:
Unifica la lógica del descuento en una sola función y reutilízala.
```javascript
function calcularDescuento(precio, porcentaje = 0.9) {
return precio * porcentaje;
}
~~~
Este formato ayuda a recordar lo que es la duplicidad real y cómo solucionarla con un ejemplo práctico.
Duplicidad Accidental: Qué Es y Cómo Evitarla
Duplicidad Accidental: Qué Es y Cómo Evitarla
La duplicidad accidental ocurre cuando el código parece el mismo pero cumple funciones diferentes. A diferencia de la duplicidad real, en este caso, no es necesario propagar el cambio a todos los lugares donde aparece el código, ya que el cambio solo afectará a uno de esos lugares. A pesar de esto, es un tipo de código que deberíamos evitar y buscar unificar.
Ejemplo:
Imagina que tienes dos funciones que calculan el impuesto en diferentes situaciones:
```javascript
function calcularImpuestoVenta(precio) {
return precio * 0.21; // Impuesto sobre ventas del 21%
}
function calcularImpuestoServicios(precio) {
return precio * 0.18; // Impuesto sobre servicios del 18%
}
~~~
Aunque el código se ve similar, cada función está haciendo un cálculo con un porcentaje diferente. Si necesitas cambiar el porcentaje, es probable que solo debas cambiar uno de los lugares, lo que introduce el riesgo de inconsistencias.
Solución:
Unifica la lógica de cálculo del impuesto y hazla flexible para manejar diferentes porcentajes:
```javascript
function calcularImpuesto(precio, porcentaje) {
return precio * porcentaje;
}
~~~
Principios SOLID: Qué Son
Los principios SOLID nos guían sobre cómo organizar nuestras funciones, estructuras de datos y componentes de software. Aunque originalmente se aplican a clases en la orientación a objetos, estos principios también son útiles para agrupaciones de funciones y datos (por ejemplo, en una Closure). Son fundamentales para cualquier tipo de producto software, ya sea orientado a objetos o no.
El acrónimo SOLID fue creado por Michael Feathers y popularizado por Robert C. Martin en su libro Agile Software Development: Principles, Patterns, and Practices. Los cinco principios tienen como objetivo mejorar la mantenibilidad, simplificar los cambios y facilitar el testing del código.
Principios SOLID: Qué Son Ancronimo
-
Single Responsibility (Responsabilidad Única)
Cada clase debe tener una única responsabilidad para evitar cambios innecesarios.
Ejemplo: Separar cálculo de salario y generación de reportes. -
Open/Closed (Abierto/Cerrado)
Las clases deben estar abiertas para la extensión pero cerradas para la modificación.
Ejemplo: Añadir nuevos descuentos sin modificar el código original. -
Liskov Substitution (Sustitución de Liskov)
Las subclases deben ser reemplazables por sus clases base sin alterar el comportamiento.
Ejemplo: SustituirPerro
porAnimal
sin problemas. -
Interface Segregation (Segregación de Interfaz)
Las interfaces deben ser específicas y no forzar la implementación de métodos innecesarios.
Ejemplo: Crear interfaces pequeñas, comoImprimible
, sin agregar métodos irrelevantes. -
Dependency Inversion (Inversión de Dependencia)
Las clases deben depender de abstracciones, no de clases concretas.
Ejemplo: Usar una interfazProcesadorDePago
en lugar de una clase concreta comoPaypal
.
Responsabilidad Única (SRP): Resumen y Ejemplo
El principio de responsabilidad única no se refiere a tener clases con un solo método, sino a diseñar componentes que solo estén expuestos a una fuente de cambio. Cada módulo o clase debe ser responsable de un único aspecto de la funcionalidad del software.
Ejemplo:
```javascript
class UseCase {
doSomethingWithTaxes() {
console.log(“Do something related with taxes …”);
}
saveChangesInDatabase() {
console.log(“Saving in database …”);
}
sendEmail() {
console.log(“Sending email …”);
}
}
function start() {
const myUseCase = new UseCase();
myUseCase.doSomethingWithTaxes();
myUseCase.saveChangesInDatabase();
myUseCase.sendEmail();
}
start();
~~~
En este ejemplo, la clase UseCase
mezcla tres capas de lógica: negocio, presentación y persistencia, lo cual viola el principio de responsabilidad única (SRP). Cada método podría ser responsable de distintos actores:
-
Contabilidad podría cambiar
doSomethingWithTaxes
. -
Marketing podría modificar
sendEmail
. -
Base de datos podría cambiar
saveChangesInDatabase
.
Aunque en proyectos pequeños no siempre se percibe la necesidad, diferenciar responsabilidades aumenta la flexibilidad y tolerancia al cambio en el software.
Este resumen incluye el código de ejemplo y muestra cómo la violación del principio SRP afecta la flexibilidad del software.
Responsabilidad Única (SRP) aplicado a componentes de Vue
El principio de responsabilidad única nos dice que un componente debe encargarse de una sola responsabilidad. En Vue, esto significa que un componente debe tener un único propósito y no mezclar diferentes tipos de lógica (como la presentación, la lógica de negocio o la persistencia de datos) dentro del mismo componente.
Ejemplo de Violación del SRP en Vue
Supongamos que tienes un componente de Vue que maneja tanto la lógica de negocio (calcular impuestos), como el envío de emails y la persistencia de datos:
```vue
<template>
<div>
<button @click="handleClick">Ejecutar Acción</button>
</div>
</template>
<script> export default { data() { return { user: { name: 'Juan', email: 'juan@example.com' }, }; }, methods: { handleClick() { this.doSomethingWithTaxes(); this.saveChangesInDatabase(); this.sendEmail(); }, doSomethingWithTaxes() { console.log("Calculando impuestos..."); }, saveChangesInDatabase() { console.log("Guardando cambios en la base de datos..."); }, sendEmail() { console.log("Enviando email a: " + this.user.email); } } } </script>
En este ejemplo, el componente hace tres cosas diferentes: 1. **Cálculo de impuestos** (`doSomethingWithTaxes`) 2. **Persistencia de datos** (`saveChangesInDatabase`) 3. **Envío de emails** (`sendEmail`) Problema con este Enfoque Este componente **viola el principio de responsabilidad única** porque está manejando múltiples responsabilidades: - El cálculo de impuestos puede cambiar debido a nuevas regulaciones fiscales (lo que involucra a un equipo de contabilidad). - El proceso de enviar emails podría cambiar por necesidades de marketing. - La lógica de persistencia podría cambiar si se cambian los requisitos de la base de datos. Cómo Aplicar SRP en Vue Para aplicar el **SRP**, deberías dividir este componente en **múltiples componentes** o servicios que manejen cada responsabilidad por separado. Ejemplo de Cómo Corregirlo ```vue <!-- TaxCalculator.vue --> <template> <div> <p>Calculando impuestos...</p> </div> </template> <script> export default { methods: { calculateTaxes() { console.log("Calculando impuestos..."); } } } </script>
```vue
<!-- EmailSender.vue -->
<template>
<div>
<p>Enviando email...</p>
</div>
</template>
<script> export default { methods: { sendEmail(user) { console.log("Enviando email a: " + user.email); } } } </script>
```vue <!-- DatabaseSaver.vue --> <template> <div> <p>Guardando cambios...</p> </div> </template> <script> export default { methods: { saveChanges() { console.log("Guardando cambios en la base de datos..."); } } } </script>
```vue
<!-- MainComponent.vue -->
<template>
<div>
<TaxCalculator></TaxCalculator>
<EmailSender :user="user" />
<DatabaseSaver></DatabaseSaver>
</div>
</template>
<script> import TaxCalculator from './TaxCalculator.vue'; import EmailSender from './EmailSender.vue'; import DatabaseSaver from './DatabaseSaver.vue'; export default { components: { TaxCalculator, EmailSender, DatabaseSaver }, data() { return { user: { name: 'Juan', email: 'juan@example.com' } }; } } </script>
~~~
Beneficios
-
Flexibilidad: Cada componente tiene una única responsabilidad y puede evolucionar sin afectar a los demás. Si el cálculo de impuestos cambia, solo debes actualizar
TaxCalculator.vue
. - Mantenibilidad: Los cambios en una parte del sistema (por ejemplo, el envío de emails) no afectarán otras partes del sistema.
- Escalabilidad: A medida que el proyecto crezca, será más fácil agregar nuevas funcionalidades sin comprometer el código existente.
Este enfoque aplica el principio SRP de forma práctica a los componentes de Vue, asegurando que cada componente tenga un único propósito y facilitando el mantenimiento y evolución del código.
Vuex como Singleton
Sí, Vuex puede considerarse un Singleton en el contexto de gestión de estado, ya que:
- Una única instancia: Vuex crea una única instancia global de la tienda (store) para toda la aplicación. Este es el principio básico del patrón Singleton, que asegura que solo haya una instancia de la tienda y que todos los componentes accedan a esa misma instancia.
-
Acceso único a la tienda: Toda la aplicación de Vue interactúa con esa única tienda de Vuex. Los componentes no crean nuevas instancias de Vuex, sino que simplemente se conectan a la tienda global a través de
this.$store
.
Ejemplo de Vuex como Singleton:
store.js
(instancia única de Vuex):
```js
import { createStore } from ‘vuex’;
const store = createStore({
state: {
counter: 0,
},
mutations: {
increment(state) {
state.counter++;
},
},
actions: {
increment({ commit }) {
commit(‘increment’);
},
},
getters: {
getCounter: (state) => state.counter,
},
});
export default store;
~~~
main.js
(registrando Vuex en la aplicación):
```js
import { createApp } from ‘vue’;
import App from ‘./App.vue’;
import store from ‘./store’; // Única instancia de Vuex
createApp(App)
.use(store) // Usamos la tienda Vuex en toda la aplicación
.mount(‘#app’);
~~~
¿Cómo funciona Vuex como Singleton?
- Acceso global: Todos los componentes de la aplicación usan this.$store
para acceder al estado global, a las mutaciones, acciones y getters definidos en la tienda. No se crean instancias adicionales, ya que this.$store
se refiere siempre a la misma instancia.
- Centralización de la lógica de estado: La tienda Vuex centraliza todo el estado compartido y la lógica de modificación de este estado, asegurando que toda la aplicación esté sincronizada con esa única fuente de verdad.
Por lo tanto, Vuex actúa como un Singleton, ya que proporciona una instancia global de la tienda de estado que puede ser accedida y modificada por todos los componentes, asegurando que solo haya una instancia de esa tienda en toda la aplicación.
Detectar violaciones del SRP
Detectar violaciones del SRP:
Saber si estamos respetando o no el principio de responsabilidad única puede ser ambiguo. A continuación, algunas señales que indican una posible violación del SRP:
- Nombre demasiado genérico: Un nombre genérico puede derivar en un God Object, es decir, un objeto que realiza demasiadas tareas.
- Cambios frecuentes en la clase: Si un elevado porcentaje de cambios afecta a la misma clase, puede ser señal de que esa clase tiene demasiadas responsabilidades.
- La clase involucra múltiples capas de la arquitectura: Si una clase realiza tareas como acceder a la capa de persistencia o notificar al usuario, además de implementar la lógica de negocio, está violando el SRP.
- Número alto de imports: Un alto número de imports podría ser un indicio de violación del SRP, aunque no es una regla definitiva.
- Exceso de métodos públicos: Si una clase tiene una API con muchos métodos públicos, puede ser síntoma de que tiene demasiadas responsabilidades.
- Excesivo número de líneas de código: Si una clase tiene demasiadas líneas de código, puede ser un indicio de que está asumiendo varias responsabilidades.
OCP - Principio Open-Closed
Principio Open-Closed (Abierto/Cerrado)
*“Todas las entidades software deberían estar * ABIERTAS A EXTENSION Y CERRADAS A MODIFICACION” – Bertrand Meyer
El principio Open-Closed recomienda que, al introducir nuevos comportamientos en sistemas existentes, no se modifiquen los componentes antiguos, sino que se creen nuevos componentes. Esto se debe a que modificar clases o componentes que ya están siendo utilizados en otros lugares puede alterar su comportamiento y provocar efectos indeseados.
Ventajas:
- Mejora la estabilidad de la aplicación, evitando cambios frecuentes en las clases existentes.
- Reduce la fragilidad de las cadenas de dependencia, ya que hay menos partes móviles que podrían generar problemas.
- Facilita la extensión futura de nuevas clases sin tener que modificar el código existente.
Este principio ayuda a mantener un sistema más robusto y escalable a medida que evoluciona.
Aplicando el OCP (Open-Closed Principle)
Aunque el principio Open-Closed puede parecer contradictorio, existen varias formas de aplicarlo, dependiendo del contexto. Algunas técnicas comunes incluyen:
- Herencia y Composición: Se pueden usar mecanismos de extensión, como la herencia o la composición, para modificar el comportamiento de las clases sin alterar su código original. Sin embargo, se recomienda priorizar la composición sobre la herencia.
Ejemplo práctico: Desacoplar un elemento de infraestructura de la capa de dominio.
Imagina un sistema de gestión de tareas con una clase TodoService
que realiza una petición HTTP a una API REST para obtener las tareas. El código podría verse así:
```javascript
const axios = require(‘axios’);
class TodoExternalService {
requestTodoItems(callback) {
const url = ‘https://jsonplaceholder.typicode.com/todos/’;
axios.get(url).then(callback);
}
}
new TodoExternalService().requestTodoItems(response => console.log(response.data));
~~~
Problemas en este ejemplo:
1. Acoplamiento: La clase TodoExternalService
depende de una librería externa (axios
).
2. Violación del OCP: Si quisiéramos reemplazar axios
por fetch
u otra librería, tendríamos que modificar el código existente.
Solución: Usar un patrón adaptador para desacoplar la librería y aplicar el principio Open-Closed, permitiendo cambiar la implementación sin modificar el código original.
Este enfoque ayuda a mantener el sistema flexible y fácil de extender sin modificar el comportamiento existente.
Herencia
La herencia permite que una clase (subclase) herede las propiedades y métodos de otra clase (superclase).
-
Relación: “Es un”. Por ejemplo, un
Perro
es unAnimal
. -
Ventajas:
- Reutilización de código.
- Extensibilidad (agregar o sobrescribir métodos en la subclase).
-
Desventajas:
- Acoplamiento fuerte entre la subclase y la superclase.
- Puede generar una jerarquía rígida que limita la flexibilidad.
- Problemas con la herencia múltiple en lenguajes que la permiten.
Ejemplo:
```javascript
class Animal {
eat() {
console.log(“Eating…”);
}
}
class Dog extends Animal {
bark() {
console.log(“Barking…”);
}
}
const dog = new Dog();
dog.eat(); // Heredado de Animal
dog.bark(); // Definido en Dog
~~~
Composición
La composición permite que una clase incluya instancias de otras clases como propiedades, delegando comportamientos a estos objetos.
-
Relación: “Tiene un”. Por ejemplo, un
Coche
tiene unMotor
. -
Ventajas:
- Menor acoplamiento entre clases.
- Mayor flexibilidad en el diseño del sistema.
- Evita los problemas de la herencia múltiple.
-
Desventajas:
- Requiere más trabajo para delegar comportamientos a objetos internos.
- Puede ser más difícil de entender si no se usa correctamente.
Ejemplo:
```javascript
class Engine {
start() {
console.log(“Engine starting…”);
}
}
class Car {
constructor() {
this.engine = new Engine(); // Composición: Car tiene un Engine
}
drive() {
this.engine.start();
console.log(“Driving…”);
}
}
const myCar = new Car();
myCar.drive(); // Comportamiento delegando a Engine
~~~
ISP - Principio de segregación de
la interfaz
“Los clientes no deberían estar obligados a depender de interfaces que no utilicen.”
– Robert C. Martin
El principio de segregación de la interfaz establece que una clase no debe depender de métodos o propiedades que no necesita. Las interfaces deben diseñarse pensando en las clases que las usarán (principio de clase cliente), no en implementaciones existentes.
En lenguajes como JavaScript, donde no hay interfaces, se confía en el buen uso del duck typing: la validez de un objeto depende de sus métodos y propiedades, no de su jerarquía de clases.
Con TypeScript, las interfaces son herramientas poderosas para definir contratos claros y aplicar este principio de manera efectiva.
Contenido personalizado
Esto es dinámico y viene del componente padre.
Contenido personalizado
Esto es dinámico y viene del componente padre.
Encabezado Personalizado
Este es el contenido del cuerpo.
Encabezado Personalizado
Este es el contenido del cuerpo.
Encabezado Personalizado
Contenido específico
Encabezado Personalizado
{{ title }}
{{ description }}
{{ title }}
{{ description }}
Welcome
- Extra item 1
- Extra item 2
{{ type }} chart rendered!
Bar chart with barWidth: {{ barWidth }}
Line chart with lineThickness: {{ lineThickness }}
Pie chart with radius: {{ radius }}