├── .gitignore ├── assets ├── Builder.jpg ├── Command.jpg ├── Memento.jpg ├── State.jpg ├── Visitor.jpg ├── Iterator.jpg ├── Mediator.jpg ├── Singleton.jpg ├── ProxyPattern.jpg ├── BridgePattern.jpg ├── DesignPatterns.jpg ├── FacadePattern.jpg ├── templateMethod.jpg ├── AbstractFactory.jpg ├── CompositePattern.jpg ├── DecoratorPattern.jpg ├── FlyweightPattern.jpg ├── ObserverPattern.jpg ├── PrototypePattern.PNG ├── StrategyPattern.jpg ├── AdapterDesignPattern.jpg ├── ChainOfResponsibility.jpg └── FactoryMethodClassDiagram.jpg ├── package.json ├── Creacionales ├── Prototype │ ├── Prototype.ts │ └── Prototype.md ├── Singleton │ ├── Singleton.ts │ └── Singleton.md ├── Builder │ ├── Builder.md │ └── Builder.ts ├── FactoryMethod │ ├── FactoryMethod.md │ └── FactoryMethod.ts └── AbstractFactory │ ├── AbstractFactory.ts │ └── AbstractFactory.md ├── Estructurales ├── Bridge │ ├── SinBridge.ts │ ├── Bridge.ts │ └── Bridge.md ├── Adapter │ ├── Adapter.ts │ └── Adapter.md ├── Proxy │ ├── Proxy.ts │ └── Proxy.md ├── Composite │ ├── Composite.ts │ └── Composite.md ├── Facade │ ├── Facade.ts │ └── Facade.md ├── Decorator │ ├── Decorator.md │ └── Decorator.ts └── Flyweight │ ├── Flyweight.md │ └── Flyweight.ts ├── Comportamiento ├── Memento │ ├── Memento.md │ └── Memento.ts ├── Iterator │ ├── Iterator.md │ └── Iterator.ts ├── Strategy │ ├── Strategy.ts │ └── Strategy.md ├── State │ ├── State.md │ └── State.ts ├── Mediator │ ├── Mediator.ts │ └── Mediator.md ├── ChainOfResponsibility │ ├── ChainOfResponsibility.md │ └── ChainOfResponsibility.ts ├── Visitor │ ├── Visitor.md │ └── Visitor.ts ├── TemplateMethod │ ├── TemplateMethod.ts │ └── TemplateMethod.md ├── Observer │ ├── Observer.ts │ └── Observer.md └── Command │ ├── Command.md │ └── Command.ts ├── LICENSE └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /assets/Builder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Builder.jpg -------------------------------------------------------------------------------- /assets/Command.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Command.jpg -------------------------------------------------------------------------------- /assets/Memento.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Memento.jpg -------------------------------------------------------------------------------- /assets/State.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/State.jpg -------------------------------------------------------------------------------- /assets/Visitor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Visitor.jpg -------------------------------------------------------------------------------- /assets/Iterator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Iterator.jpg -------------------------------------------------------------------------------- /assets/Mediator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Mediator.jpg -------------------------------------------------------------------------------- /assets/Singleton.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/Singleton.jpg -------------------------------------------------------------------------------- /assets/ProxyPattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/ProxyPattern.jpg -------------------------------------------------------------------------------- /assets/BridgePattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/BridgePattern.jpg -------------------------------------------------------------------------------- /assets/DesignPatterns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/DesignPatterns.jpg -------------------------------------------------------------------------------- /assets/FacadePattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/FacadePattern.jpg -------------------------------------------------------------------------------- /assets/templateMethod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/templateMethod.jpg -------------------------------------------------------------------------------- /assets/AbstractFactory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/AbstractFactory.jpg -------------------------------------------------------------------------------- /assets/CompositePattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/CompositePattern.jpg -------------------------------------------------------------------------------- /assets/DecoratorPattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/DecoratorPattern.jpg -------------------------------------------------------------------------------- /assets/FlyweightPattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/FlyweightPattern.jpg -------------------------------------------------------------------------------- /assets/ObserverPattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/ObserverPattern.jpg -------------------------------------------------------------------------------- /assets/PrototypePattern.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/PrototypePattern.PNG -------------------------------------------------------------------------------- /assets/StrategyPattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/StrategyPattern.jpg -------------------------------------------------------------------------------- /assets/AdapterDesignPattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/AdapterDesignPattern.jpg -------------------------------------------------------------------------------- /assets/ChainOfResponsibility.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/ChainOfResponsibility.jpg -------------------------------------------------------------------------------- /assets/FactoryMethodClassDiagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thxmxs/Patrones-de-diseno-TypeScript/HEAD/assets/FactoryMethodClassDiagram.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "ts-node": "^10.9.2", 4 | "tsx": "^4.19.1", 5 | "typescript": "^5.6.3" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Creacionales/Prototype/Prototype.ts: -------------------------------------------------------------------------------- 1 | interface Prototype { 2 | clone(): Prototype; 3 | } 4 | 5 | class Pokemon implements Prototype { 6 | private nombre: string; 7 | 8 | constructor(nombre: string) { 9 | this.nombre = nombre; 10 | } 11 | 12 | getNombre() { 13 | console.log(`Soy el pokemon ${this.nombre}`); 14 | } 15 | 16 | setNombre(nombre: string) { 17 | this.nombre = nombre; 18 | } 19 | 20 | clone(): Prototype { 21 | return new Pokemon(this.nombre); 22 | } 23 | } 24 | 25 | let pokemon = new Pokemon("Pikachu"); 26 | pokemon.getNombre(); 27 | 28 | let pokemonClone = pokemon.clone(); 29 | (pokemonClone as Pokemon).getNombre(); 30 | -------------------------------------------------------------------------------- /Creacionales/Singleton/Singleton.ts: -------------------------------------------------------------------------------- 1 | class Logger{ 2 | private static instance: Logger; 3 | private logs: string[] = []; 4 | 5 | private constructor(){}; 6 | 7 | public static getInstance(): Logger{ 8 | if(!Logger.instance){ 9 | Logger.instance = new Logger(); 10 | } 11 | return Logger.instance; 12 | } 13 | 14 | public setLog(message: string): void{ 15 | const timeStamp = new Date().toISOString(); 16 | this.logs.push(`${timeStamp} ${message}`); 17 | } 18 | 19 | public getLogs(): string[]{ 20 | return this.logs; 21 | } 22 | } 23 | 24 | const logger = Logger.getInstance(); 25 | logger.setLog('Inicializando sistema de logs'); 26 | 27 | logger.getLogs(); -------------------------------------------------------------------------------- /Estructurales/Bridge/SinBridge.ts: -------------------------------------------------------------------------------- 1 | // Clase base para todas las formas 2 | abstract class FormaSinBridge { 3 | abstract drawer(): void; 4 | } 5 | 6 | // Implementaciones especificas para cada variante 7 | class CirculoPantalla extends FormaSinBridge { 8 | drawer() { 9 | console.log("Dibujando un círculo en la pantalla"); 10 | } 11 | } 12 | 13 | class CirculoImpresora extends FormaSinBridge { 14 | drawer() { 15 | console.log("Dibujando un círculo en la impresora"); 16 | } 17 | } 18 | 19 | class CuadradoPantalla extends FormaSinBridge { 20 | drawer() { 21 | console.log("Dibujando un cuadrado en la pantalla"); 22 | } 23 | } 24 | 25 | class CuadradoImpresora extends FormaSinBridge { 26 | drawer() { 27 | console.log("Dibujando un cuadrado en la impresora"); 28 | } 29 | } 30 | 31 | // Uso 32 | const circuloPantalla = new CirculoPantalla(); 33 | circuloPantalla.drawer(); 34 | 35 | const cuadradoImpresora = new CuadradoImpresora(); 36 | cuadradoImpresora.drawer(); 37 | -------------------------------------------------------------------------------- /Estructurales/Adapter/Adapter.ts: -------------------------------------------------------------------------------- 1 | //1. Target Interfaz esperada por el cliente 2 | interface Cargador{ 3 | cargarDispositivo(): void 4 | } 5 | 6 | //2. Adaptee: clase incompatible 7 | class CargadorEuropeo{ 8 | enchufarEnSocketEuropeo(): void { 9 | console.log("Cargando dispositivo utilizando un socket europeo"); 10 | } 11 | } 12 | 13 | //3. Adapter: traduce la interface del Adaptee al Target 14 | class AdapterCargadorEuropeo implements Cargador { 15 | private cargadorEuropeo: CargadorEuropeo; 16 | 17 | constructor(cargadorEuropeo: CargadorEuropeo){ 18 | this.cargadorEuropeo = cargadorEuropeo; 19 | } 20 | 21 | cargarDispositivo(): void { 22 | console.log("Adaptando cargador europeo a cargador standard"); 23 | this.cargadorEuropeo.enchufarEnSocketEuropeo(); 24 | } 25 | } 26 | 27 | // 4. Cliente 28 | function cargar(cargador: Cargador): void { 29 | cargador.cargarDispositivo(); 30 | } 31 | 32 | //uso 33 | const cargadorEuropeo = new CargadorEuropeo(); 34 | const adapter = new AdapterCargadorEuropeo(cargadorEuropeo); 35 | 36 | cargar(adapter); -------------------------------------------------------------------------------- /Comportamiento/Memento/Memento.md: -------------------------------------------------------------------------------- 1 | # Memento 2 | 3 | El patrón de diseño Memento es un patrón de comportamiento que permite capturar y restaurar el estado interno de un objeto sin violar su encapsulación. dando la posibilidad de deshacer (undo) o rehacer (redo) cambios hecho al objeto 4 | 5 | ### Componentes 6 | 7 | - Originator: 8 | 9 | - El objeto cuyo estado queremos guardar y restaurar. 10 | 11 | - Tiene métodos para crear y restaurar mementos. 12 | 13 | - Memento: 14 | 15 | - Es un objeto que almacena el estado interno del Originator. 16 | 17 | - Es accesible solo para el Originator (debería ser inmutable desde fuera). 18 | 19 | - Caretaker: 20 | 21 | - Es el encargado de almacenar los mementos. 22 | - No interactúa directamente con el estado del Originator, solo guarda y utiliza los mementos para restaurar estados. 23 | 24 | 25 | ### Ejemplo 26 | 27 | Supongamos que queremos implementar una aplicación de texto simple con funcionalidad para deshacer cambios. 28 | 29 | 30 | **Codigo** [`Memento`](./Memento.ts) 31 | 32 | ![Diagrama de clases Memento](../../assets/Memento.jpg) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Thomas C 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Creacionales/Builder/Builder.md: -------------------------------------------------------------------------------- 1 | # Builder 2 | 3 | El patrón Builder es un patrón de diseño creacional que se usa para construir objetos complejos paso a paso. A diferencia de los constructores tradicionales, el patrón Builder permite una construcción más flexible y controlada del objeto final, especialmente cuando tiene múltiples atributos opcionales o configurables. 4 | 5 | ### ¿Por qué usar el patrón prototype? 6 | 7 | - Flexibilidad en construcción: Permite crear objetos complejos paso a paso y configurar solo las partes necesarias. 8 | 9 | - Código más limpio: Evita constructores largos y sobrecargados con múltiples parámetros opcionales. 10 | 11 | - Código más limpio: Evita constructores largos y sobrecargados con múltiples parámetros opcionales. 12 | 13 | - Encapsulación: La lógica de construcción está oculta dentro del Builder y Director, manteniendo el código del cliente más simple. 14 | 15 | Un ejemplo seria por ejemplo la creación de un computador donde tiene multiples piezas que se pueden personalizar para distintos tipos de usos segun sus piezas; 16 | 17 | ### Ejemplo 18 | 19 | **Codigo** [`Builder`](./Builder.ts) 20 | 21 | ![Diagrama de clases Builder](../../assets/Builder.jpg) 22 | -------------------------------------------------------------------------------- /Creacionales/Singleton/Singleton.md: -------------------------------------------------------------------------------- 1 | # Singleton 2 | 3 | El patrón Singleton es un patrón de diseño que asegura que solo haya una única instancia de una clase en toda la aplicación. Además, proporciona un punto de acceso global para obtener esa instancia. 4 | 5 | ### ¿Como funciona? 6 | 7 | - Control de Instancia Única: La clase Singleton se asegura de que, cuando alguien pida una instancia de esta clase, siempre reciba la misma. 8 | 9 | - Punto de acceso global: Como solo hay una instancia, siempre accedes a ella desde un método específico que la clase ofrece (por ejemplo, getInstance()). 10 | 11 | ### Ventajas 12 | 13 | - Ahorra memoria: Al tener una única instancia, no estás creando varias copias de un objeto que debe ser único. 14 | 15 | - Fácil acceso: Puedes acceder a la instancia de manera directa y global, sin importar desde dónde la necesites en tu código. 16 | 17 | ### Desventajas 18 | 19 | - Dificultad para pruebas: Puede ser más difícil de probar, porque una vez que creas la instancia, es complicado reiniciar su estado o reemplazarla en pruebas. 20 | 21 | ### Ejemplo 22 | 23 | **Codigo** [`Singleton`](./Singleton.ts) 24 | 25 | ![Diagrama de clases Singleton](../../assets/Singleton.jpg) 26 | -------------------------------------------------------------------------------- /Estructurales/Proxy/Proxy.ts: -------------------------------------------------------------------------------- 1 | //interfaz comun 2 | interface Imagen{ 3 | mostrar(): void; 4 | } 5 | 6 | //sujeto real 7 | class ImagenReal implements Imagen{ 8 | private nombreArchivo: string; 9 | 10 | constructor(nombreArchivo:string){ 11 | this.nombreArchivo = nombreArchivo; 12 | this.cargarDesdeDiscoDuro(); 13 | } 14 | 15 | private cargarDesdeDiscoDuro(): void{ 16 | console.log(`Cargando ${this.nombreArchivo}`) 17 | } 18 | 19 | mostrar(): void { 20 | console.log(`Mostrando ${this.nombreArchivo}`) 21 | } 22 | } 23 | 24 | //Proxy 25 | class ProxyImagen implements Imagen{ 26 | private imagenReal: ImagenReal | null = null; 27 | private nombreArchivo: string; 28 | 29 | constructor(nombreArchivo: string){ 30 | this.nombreArchivo = nombreArchivo; 31 | } 32 | 33 | mostrar(): void { 34 | if(this.imagenReal === null){ 35 | this.imagenReal = new ImagenReal(this.nombreArchivo); 36 | } 37 | this.imagenReal.mostrar() 38 | } 39 | } 40 | 41 | //uso 42 | const imagen = new ProxyImagen("Perfil.png"); 43 | imagen.mostrar();//carga y muestra la imagen 44 | imagen.mostrar();//vuelve a mostrar la imagen sin volver a cargarla -------------------------------------------------------------------------------- /Estructurales/Composite/Composite.ts: -------------------------------------------------------------------------------- 1 | // Componente (interfaz común) 2 | interface Archivo { 3 | mostrar(): void; 4 | } 5 | 6 | // Hoja (Leaf) 7 | class ArchivoSimple implements Archivo { 8 | constructor(private nombre: string) {} 9 | 10 | mostrar(): void { 11 | console.log(this.nombre); 12 | } 13 | } 14 | 15 | // Compuesto (Composite) 16 | class Carpeta implements Archivo { 17 | private elementos: Archivo[] = []; 18 | 19 | constructor(private nombre: string) {} 20 | 21 | agregar(elemento: Archivo): void { 22 | this.elementos.push(elemento); 23 | } 24 | 25 | mostrar(): void { 26 | console.log(`Carpeta: ${this.nombre}`); 27 | this.elementos.forEach(elemento => elemento.mostrar()); 28 | } 29 | } 30 | 31 | // Uso 32 | const archivo1 = new ArchivoSimple("archivo1.txt"); 33 | const archivo2 = new ArchivoSimple("archivo2.txt"); 34 | 35 | const carpeta = new Carpeta("Mis documentos"); 36 | carpeta.agregar(archivo1); 37 | carpeta.agregar(archivo2); 38 | 39 | const subCarpeta = new Carpeta("Fotos"); 40 | subCarpeta.agregar(new ArchivoSimple("vacaciones.jpg")); 41 | 42 | carpeta.agregar(subCarpeta); 43 | 44 | // Mostrar la estructura completa 45 | carpeta.mostrar(); 46 | 47 | 48 | -------------------------------------------------------------------------------- /Comportamiento/Iterator/Iterator.md: -------------------------------------------------------------------------------- 1 | # Iterator 2 | 3 | El patrón de diseño Iterator es un patrón de comportamiento que permite recorrer los elementos de una colección (como listas, pilas, arbol, etc.) sin exponer su representación interna. Este patrón abstrae la lógica de iteración en un objeto separado llamado iterador. 4 | 5 | 6 | ### Conceptos claves 7 | 8 | - Iterador: Una interfaz que define métodos para acceder a elementos en una colección, típicamente: 9 | - hasNext(): Indica si hay más elementos por iterar. 10 | - next(): Devuelve el siguiente elemento. 11 | 12 | - Colección: Una clase que implementa una interfaz para crear iteradores que recorren sus elementos. 13 | 14 | - Cliente: Utiliza el iterador para recorrer los elementos de la colección sin preocuparse por su implementación interna. 15 | 16 | ### Ventajas 17 | 18 | - Desacopla la lógica de recorrido de la colección. 19 | 20 | - Permite recorrer diferentes estructuras de datos de manera uniforme. 21 | 22 | - Facilita la implementación de diferentes tipos de iteración (por ejemplo, hacia adelante, hacia atrás). 23 | 24 | ### Ejemplo 25 | 26 | implementacion de un ejemplo simple donde recorremos una pila que almacena numeros 27 | 28 | 29 | **Codigo** [`Iterator`](./Iterator.ts) 30 | 31 | ![Diagrama de clases Iterator](../../assets/Iterator.jpg) 32 | -------------------------------------------------------------------------------- /Comportamiento/Strategy/Strategy.ts: -------------------------------------------------------------------------------- 1 | // strategy 2 | interface EnvioStrategy { 3 | calcularCosto(peso: number): number; 4 | } 5 | 6 | //concrete strategies 7 | class EnvioTerrestre implements EnvioStrategy { 8 | calcularCosto(peso: number): number { 9 | return peso * 1.5; 10 | } 11 | } 12 | 13 | class EnvioAereo implements EnvioStrategy { 14 | calcularCosto(peso: number): number { 15 | return peso * 3.0; 16 | } 17 | } 18 | 19 | class EnvioMaritimo implements EnvioStrategy { 20 | calcularCosto(peso: number): number { 21 | return peso * 0.8; 22 | } 23 | } 24 | 25 | class EnvioEspacial implements EnvioStrategy { 26 | calcularCosto(peso: number): number { 27 | return peso * 10.0; 28 | } 29 | } 30 | 31 | // context 32 | class CalculadoraCostoEnvio { 33 | private estrategia: EnvioStrategy; 34 | 35 | constructor(estrategia: EnvioStrategy) { 36 | this.estrategia = estrategia; 37 | } 38 | 39 | establecerEstrategia(estrategia: EnvioStrategy): void { 40 | this.estrategia = estrategia; 41 | } 42 | 43 | calcular(peso: number): number { 44 | return this.estrategia.calcularCosto(peso); 45 | } 46 | } 47 | 48 | // cliente 49 | const envioEspacial = new EnvioEspacial(); 50 | const calculadora = new CalculadoraCostoEnvio(envioEspacial); 51 | console.log("Costo de Envío Espacial:", calculadora.calcular(10)); 52 | -------------------------------------------------------------------------------- /Estructurales/Bridge/Bridge.ts: -------------------------------------------------------------------------------- 1 | // Implementor 2 | interface Dibujador { 3 | dibujarForma(): void; 4 | } 5 | 6 | // ConcreteImplementor A 7 | class DibujadorPantalla implements Dibujador { 8 | dibujarForma() { 9 | console.log("Dibujando en pantalla"); 10 | } 11 | } 12 | 13 | // ConcreteImplementor B 14 | class DibujadorImpresora implements Dibujador { 15 | dibujarForma() { 16 | console.log("Dibujando en impresora"); 17 | } 18 | } 19 | 20 | // Abstraction 21 | abstract class Forma { 22 | protected dibujador: Dibujador; 23 | 24 | constructor(dibujador: Dibujador) { 25 | this.dibujador = dibujador; 26 | } 27 | 28 | abstract dibujar(): void; 29 | } 30 | 31 | // RefinedAbstraction 32 | class Circulo extends Forma { 33 | dibujar() { 34 | console.log("Dibujando un círculo"); 35 | this.dibujador.dibujarForma(); 36 | } 37 | } 38 | 39 | class Cuadrado extends Forma { 40 | dibujar() { 41 | console.log("Dibujando un cuadrado"); 42 | this.dibujador.dibujarForma(); 43 | } 44 | } 45 | 46 | // uso 47 | const dibujadorPantalla = new DibujadorPantalla(); 48 | const circulo = new Circulo(dibujadorPantalla); 49 | circulo.dibujar(); 50 | 51 | const dibujadorImpresora = new DibujadorImpresora(); 52 | const cuadrado = new Cuadrado(dibujadorImpresora); 53 | cuadrado.dibujar(); 54 | -------------------------------------------------------------------------------- /Estructurales/Adapter/Adapter.md: -------------------------------------------------------------------------------- 1 | # Adapter 2 | 3 | El patrón de diseño Adapter pertenece a los patrones estructurales y se utiliza para permitir que dos interfaces incompatibles trabajen juntas. Su objetivo principal es "adaptar" la interfaz de una clase existente para que sea compatible con otra interfaz que el cliente espera. 4 | 5 | ### Concepto clave 6 | 7 | - Un Adapter actúa como un traductor entre dos clases o sistemas con interfaces distintas. 8 | 9 | - Se puede utilizar cuando quieres que una clase existente funcione con otras clases sin modificar su código. 10 | 11 | 12 | ### Componentes principales 13 | 14 | - Target (Objetivo): Define la interfaz esperada por el cliente. 15 | 16 | - Adaptee (Adaptado): La clase que tiene la funcionalidad que quieres reutilizar pero con una interfaz incompatible. 17 | 18 | - Adapter: Una clase que implementa la interfaz Target y traduce las llamadas del cliente al Adaptee 19 | 20 | 21 | ### Ejemplo práctico 22 | 23 | Imaginemos que tenemos un sistema que trabaja con una clase que representa un cargador de dispositivos. Pero ahora necesitamos usar una clase con una interfaz diferente (por ejemplo, un cargador europeo). Utilizamos un adaptador para que ambas interfaces sean compatibles. 24 | 25 | **Codigo** [`Adapter`](./Adapter.ts) 26 | 27 | ![Diagrama de clases Adapter](../../assets/AdapterDesignPattern.jpg) 28 | -------------------------------------------------------------------------------- /Estructurales/Facade/Facade.ts: -------------------------------------------------------------------------------- 1 | // Subsistema: Clases complejas que forman parte del sistema. 2 | class Luces { 3 | encender() { console.log("Luces encendidas"); } 4 | apagar() { console.log("Luces apagadas"); } 5 | } 6 | 7 | class Alarma { 8 | activar() { console.log("Alarma activada"); } 9 | desactivar() { console.log("Alarma desactivada"); } 10 | } 11 | 12 | class Termostato { 13 | setTemperatura(temp: number) { console.log(`Temperatura ajustada a ${temp}°C`); } 14 | } 15 | 16 | // Facade: interfaz simplificada al cliente 17 | class CasaFacade { 18 | private luces: Luces; 19 | private alarma: Alarma; 20 | private termostato: Termostato; 21 | 22 | constructor() { 23 | this.luces = new Luces(); 24 | this.alarma = new Alarma(); 25 | this.termostato = new Termostato(); 26 | } 27 | 28 | public salirDeCasa() { 29 | this.luces.apagar(); 30 | this.alarma.activar(); 31 | this.termostato.setTemperatura(18); 32 | console.log("Preparado para salir de casa."); 33 | } 34 | 35 | public LLegarACasa() { 36 | this.luces.encender(); 37 | this.alarma.desactivar(); 38 | this.termostato.setTemperatura(22); 39 | console.log("Bienvenido a casa."); 40 | } 41 | } 42 | 43 | // Uso del patrón Facade 44 | const miCasa = new CasaFacade(); 45 | miCasa.salirDeCasa(); 46 | miCasa.LLegarACasa(); 47 | -------------------------------------------------------------------------------- /Creacionales/FactoryMethod/FactoryMethod.md: -------------------------------------------------------------------------------- 1 | # Factory Method 2 | 3 | El patrón Factory es un patrón de diseño creacional que proporciona una forma de crear objetos sin especificar la clase exacta de objeto que se va a crear. En lugar de instanciar objetos directamente con el operador new, el patrón Factory delega esta tarea a un método o clase especial llamada "fábrica". Esto permite que el código sea más flexible y fácil de extender. 4 | 5 | ### ¿Por qué usar el patrón Factory? 6 | 7 | - Desacoplamiento: El patrón Factory permite que el código que usa los objetos no dependa de las clases específicas de esos objetos. Esto significa que puedes cambiar las implementaciones de esos objetos sin tener que modificar el código que los utiliza. 8 | 9 | - Facilidad para agregar nuevas clases: Si necesitas agregar una nueva clase que sigue el mismo contrato (interfaz o clase base), solo tienes que añadirla a la fábrica sin modificar el código que llama a la fábrica. 10 | 11 | - Organización: Agrupa en un solo lugar la lógica de creación de objetos complejos o basados en condiciones, haciendo el código más fácil de mantener y entender. 12 | 13 | - Control sobre la creación de objetos: Si la creación de ciertos objetos requiere lógica adicional, como configurar estados o inicializar parámetros, la fábrica encapsula estos pasos. 14 | 15 | ### Ejemplo 16 | 17 | **Codigo** [`FactoryMethod`](./FactoryMethod.ts) 18 | 19 | ![Diagrama de clases Factory method](../../assets/FactoryMethodClassDiagram.jpg) 20 | -------------------------------------------------------------------------------- /Comportamiento/State/State.md: -------------------------------------------------------------------------------- 1 | # State 2 | 3 | El patrón de diseño State es un patrón de comportamiento que permite a un objeto modificar su comportamiento dinámicamente en función de su estado interno. En lugar de utilizar estructuras condicionales como if o switch para manejar los diferentes estados, el patrón encapsula los comportamientos asociados a cada estado en clases separadas. El objeto principal delega sus operaciones a estas clases específicas de estado y puede cambiar entre ellas en tiempo de ejecución según su estado actual, proporcionando un diseño más flexible y mantenible. 4 | 5 | ### Conceptos clave 6 | 7 | - Contexto (context): 8 | 9 | - Es el objeto principal que contiene una referencia al estado actual. 10 | 11 | - Permite cambiar el estado actual en tiempo de ejecución. 12 | 13 | - Estado (State): 14 | 15 | - Una interfaz o clase base que define el comportamiento común de todos los estados. 16 | 17 | - Estados concretos (concrete states): 18 | 19 | - Implementaciones específicas de la interfaz del estado. 20 | 21 | - Cada clase concreta define un comportamiento particular asociado con un estado. 22 | 23 | 24 | ### Ejemplo 25 | 26 | - Vamos a modelar una máquina expendedora con tres estados: 27 | - Sin monedas 28 | - Con monedas 29 | - Producto entregado 30 | 31 | Cuando se inserta una moneda, cambia al estado "Con moneda". Luego, al presionar el botón, cambia al estado "Producto entregado" 32 | 33 | 34 | **Codigo** [`State`](./State.ts) 35 | 36 | ![Diagrama de clases State](../../assets/State.jpg) 37 | -------------------------------------------------------------------------------- /Comportamiento/Iterator/Iterator.ts: -------------------------------------------------------------------------------- 1 | // Iterator 2 | interface MyIterator { 3 | next(): T | null; 4 | hasNext(): boolean; 5 | } 6 | 7 | // IterableCollection 8 | interface MyIterableCollection { 9 | createIterator(): MyIterator; 10 | } 11 | 12 | // concrete iterator 13 | class StackIterator implements MyIterator { 14 | private stack: T[]; 15 | private position: number; 16 | 17 | constructor(stack: T[]) { 18 | this.stack = stack; 19 | this.position = stack.length - 1; 20 | } 21 | 22 | next(): T | null { 23 | if (this.hasNext()) { 24 | return this.stack[this.position--]; 25 | } 26 | return null; 27 | } 28 | 29 | hasNext(): boolean { 30 | return this.position >= 0; 31 | } 32 | } 33 | 34 | // concrete collection 35 | class Stack implements MyIterableCollection { 36 | private items: T[] = []; 37 | 38 | push(item: T): void { 39 | this.items.push(item); 40 | } 41 | 42 | pop(): T | undefined { 43 | return this.items.pop(); 44 | } 45 | 46 | isEmpty(): boolean { 47 | return this.items.length === 0; 48 | } 49 | 50 | createIterator(): MyIterator { 51 | return new StackIterator(this.items); 52 | } 53 | } 54 | 55 | // Cliente 56 | const stack = new Stack(); 57 | stack.push(10); 58 | stack.push(20); 59 | stack.push(30); 60 | 61 | console.log("Elementos en la pila:"); 62 | const iterator = stack.createIterator(); 63 | 64 | while (iterator.hasNext()) { 65 | console.log(iterator.next()); 66 | } 67 | -------------------------------------------------------------------------------- /Comportamiento/Mediator/Mediator.ts: -------------------------------------------------------------------------------- 1 | // Mediator 2 | interface ChatMediator { 3 | sendMessage(message: string, user: User): void; 4 | addUser(user: User): void; 5 | removeUser(user: User): void; 6 | } 7 | 8 | // Concrete mediator 9 | class ChatRoom implements ChatMediator { 10 | private users: User[] = []; 11 | 12 | public sendMessage(message: string, user: User): void { 13 | this.users.forEach((u) => { 14 | if (u !== user) { 15 | u.receiveMessage(message); 16 | } 17 | }); 18 | } 19 | 20 | public addUser(user: User): void { 21 | this.users.push(user); 22 | } 23 | 24 | public removeUser(user: User): void { 25 | this.users = this.users.filter((u) => u !== user); 26 | } 27 | } 28 | 29 | // Colleague 30 | interface User { 31 | receiveMessage(message: string): void; 32 | sendMessage(message: string): void; 33 | } 34 | 35 | // Componente 36 | class ChatUser implements User { 37 | private name: string; 38 | private chatRoom: ChatMediator; 39 | 40 | constructor(name: string, chatRoom: ChatMediator) { 41 | this.name = name; 42 | this.chatRoom = chatRoom; 43 | } 44 | 45 | public receiveMessage(message: string): void { 46 | console.log(`${this.name} recibio: ${message}`); 47 | } 48 | 49 | public sendMessage(message: string): void { 50 | console.log(`${this.name} envio: ${message}`); 51 | this.chatRoom.sendMessage(message, this); 52 | } 53 | } 54 | 55 | // Uso 56 | const chatRoom = new ChatRoom(); 57 | 58 | const user1 = new ChatUser("user1", chatRoom); 59 | const user2 = new ChatUser("user2", chatRoom); 60 | 61 | chatRoom.addUser(user1); 62 | chatRoom.addUser(user2); 63 | 64 | user1.sendMessage("Hola user2"); 65 | user2.sendMessage("Hola user1"); -------------------------------------------------------------------------------- /Comportamiento/Mediator/Mediator.md: -------------------------------------------------------------------------------- 1 | # Mediator 2 | 3 | Es un patron de diseño que define un objeto, el mediador, para centralizar la comunicacion entre varios componentes u objetos en un sistema. Esto desacopla las clases al evitar interacciones directas entre objetos/componentes, haciendo que se comuniquen a traves de el mediator lo que facilita la mantenibilidad y flexibilidad en la arquitectura del sistema 4 | 5 | El patron mediator permite: 6 | 7 | - Encapsular la lógica de comunicación en un solo lugar 8 | 9 | - Desarrollar componentes más independientes y autónomos 10 | 11 | - Facilitar la integración de nuevos componentes o funcionalidades 12 | 13 | - Mejorar la gestión de errores y excepciones 14 | 15 | Es especialmente util en sistemas con: 16 | 17 | - Muchos objetos interconectados 18 | 19 | - Comunicaciones complejas entre componentes 20 | 21 | - Requisitos de escalabilidad y flexibilidad 22 | 23 | - Necesidad de reducir el acoplamiento entre objetos 24 | 25 | ### Componentes 26 | 27 | - Mediator: Es el objeto intermediario que gestiona la comunicación entre los objetos Colleague. 28 | 29 | - Colleague: Son los objetos que se comunican entre sí a través del Mediator. 30 | 31 | ### Ventajas 32 | 33 | - Reduce el acoplamiento entre objetos. 34 | 35 | - Simplifica la comunicación entre objetos. 36 | 37 | - Facilita la escalabilidad y mantenimiento del sistema. 38 | 39 | ### Desventajas 40 | 41 | - Puede crear un punto único de fallo. 42 | 43 | - La complejidad del Mediator puede aumentar rápidamente. 44 | 45 | ### Ejemplo 46 | 47 | Supongamos que estamos creando un sistema de chat en tiempo real. Queremos que los usuarios puedan enviar mensajes y que estos se muestren en tiempo real para todos los usuarios conectados. 48 | 49 | 50 | **Codigo** [`Mediator`](./Mediator.ts) 51 | 52 | ![Diagrama de clases Mediator](../../assets/Mediator.jpg) 53 | -------------------------------------------------------------------------------- /Comportamiento/ChainOfResponsibility/ChainOfResponsibility.md: -------------------------------------------------------------------------------- 1 | # Chain of responsability 2 | 3 | es un patrón de diseño de comportamiento que permite pasar solicitudes a lo largo de una cadena de potenciales manejadores(handlers). 4 | Al recibir una solicitud, cada manejador decide si procesar la solicitud o pasarla al siguiente controlador de la cadena 5 | 6 | ### Proposito 7 | 8 | El propósito principal del patrón Chain of Responsibility (Cadena de Responsabilidad) es desacoplar al emisor de una solicitud de su(s) receptor(es), permitiendo que la solicitud pase por una cadena de manejadores hasta que alguno de ellos la procese. 9 | 10 | ### Estructura 11 | 12 | - Handler (manejador): Define una interfaz común para procesar una solicitud o pasarla al siguiente manejador. Puede tener una referencia al siguiente manejador de la cadena 13 | 14 | - Concrete Handler (manejador concreto): Implementan el procesamiento especifico para una solicitud. Decide si procesan la solicitud o la pasan al siguiente manejador en la cadena 15 | 16 | - Cliente: inicia la solicitud 17 | 18 | ### Ventajas 19 | 20 | - Flexibilidad para añadir o modificar manejadores en la cadena sin afectar a otros manejadores. 21 | 22 | - Reduce el acoplamiento entre el emisor y los receptores de una solicitud. 23 | 24 | 25 | ### Desventajas 26 | 27 | - Puede ser difícil seguir la lógica de ejecución si la cadena es larga. 28 | 29 | - Si no se define un manejador por defecto, la solicitud podría no ser procesada. 30 | 31 | 32 | ### Ejemplo 33 | 34 | Supongamos que tenemos un sistema para validar un formulario con varios campos. Cada campo requiere una validacion especifica, y queremos que cada validador sea responsable de su logica. 35 | 36 | 37 | **Codigo** [`Chain of responsibility`](ChainOfResponsibility.ts) 38 | 39 | ![Diagrama de clases Chain of responsibility](../../assets/ChainOfResponsibility.jpg) 40 | -------------------------------------------------------------------------------- /Creacionales/Prototype/Prototype.md: -------------------------------------------------------------------------------- 1 | # Prototype 2 | 3 | Prototype es un patron de diseño creacional que nos permite copiar objetos existentes sin que el codigo dependa de sus clases. 4 | 5 | Es útil cuando se necesita crear nuevas instancias de objetos que son muy similares o iguales a instancias existentes y cuando el proceso de creación de dichos objetos es costoso o complicado. Este patrón permite clonar objetos en lugar de crearlos desde cero, lo que puede mejorar el rendimiento y simplificar el código en situaciones específicas. 6 | 7 | ### ¿Por qué usar el patrón prototype? 8 | 9 | - Creación costosa: Si la creación de un objeto es costosa en términos de tiempo o recursos (por ejemplo, debido a configuraciones complejas o cálculos intensivos), el patrón Prototype permite clonar el objeto para evitar repetir el proceso de creación desde cero. 10 | 11 | - Variaciónes de configuración: Si se necesita crear múltiples instancias de objetos con configuraciones similares o que solo difieren ligeramente, el patrón Prototype permite clonar y luego modificar las copias según sea necesario. 12 | 13 | - Independencia de la clase concreta: Permite crear copias de objetos sin depender de la clase concreta de estos, lo que mejora la flexibilidad y reduce el acoplamiento. 14 | 15 | - Evitar constructores complejos: Si un objeto tiene un constructor complejo o una jerarquía de clases, el patrón Prototype facilita la creación de nuevos objetos simplemente clonando una instancia existente en lugar de usar constructores. 16 | 17 | Un ejemplo típico de uso del patrón Prototype es en programas gráficos o videojuegos, donde se crean múltiples instancias de personajes, objetos, o escenarios con configuraciones similares, pero personalizadas para cada instancia. 18 | 19 | ### Ejemplo 20 | 21 | **Codigo** [`Prototype`](./Prototype.ts) 22 | 23 | ![Diagrama de clases Prototype](../../assets/PrototypePattern.PNG) 24 | -------------------------------------------------------------------------------- /Comportamiento/Visitor/Visitor.md: -------------------------------------------------------------------------------- 1 | # Visitor 2 | 3 | El patrón de diseño Visitor pertenece a los patrones de comportamiento. Su propósito es separar un algoritmo de la estructura de datos en la que opera, lo que permite añadir nuevas operaciones sin cambiar las clases de los elementos sobre los que se aplica. 4 | Este patrón es útil cuando: 5 | 6 | - Frecuentemente se añaden nuevas operaciones a un conjunto de clases. 7 | 8 | - Quieres mantener la lógica de las operaciones separada de las estructuras de datos. 9 | 10 | 11 | ### Caracteristicas clave 12 | 13 | - Visitor (Visitador): Define una interfaz para todas las operaciones que pueden realizarse en los elementos de una estructura. 14 | 15 | - ConcreteVisitor (Visitador Concreto): Implementa las operaciones específicas. 16 | 17 | - Element (Elemento): Define una interfaz que acepta un objeto visitador. 18 | 19 | - ConcreteElement (Elemento Concreto): Implementa el método accept que delega la operación al visitador. 20 | 21 | - ObjectStructure (Estructura de Objetos): Mantiene una colección de elementos y permite que un visitador recorra todos ellos. 22 | 23 | ### Ventajas 24 | 25 | - Extensibilidad: Se pueden agregar nuevas operaciones (visitadores) sin modificar las clases de los elementos. 26 | 27 | - Separación de responsabilidades: La lógica de las operaciones está separada de las clases de los elementos. 28 | 29 | 30 | ### Desventajas 31 | 32 | - Dificultad para agregar nuevos elementos: Si necesitas agregar nuevas clases de elementos, todas las implementaciones de Visitor deben modificarse. 33 | 34 | - Puede hacer que el código sea más complejo si tienes muchos elementos y visitadores. 35 | 36 | 37 | ### Ejemplo 38 | 39 | Supongamos que estamos modelando una jerarquía de figuras geométricas (como Círculo y Cuadrado) y queremos calcular el área y perímetro de cada figura utilizando el patrón Visitor. 40 | 41 | 42 | **Codigo** [`Visitor`](./Visitor.ts) 43 | 44 | ![Diagrama de clases Visitor](../../assets/Visitor.jpg) 45 | -------------------------------------------------------------------------------- /Comportamiento/Memento/Memento.ts: -------------------------------------------------------------------------------- 1 | // Memento: Almacena el estado del texto. 2 | class Memento { 3 | private state: string; 4 | 5 | constructor(state: string) { 6 | this.state = state; 7 | } 8 | 9 | getState(): string { 10 | return this.state; 11 | } 12 | } 13 | 14 | // Originator: Representa el editor de texto. 15 | class TextEditor { 16 | private text: string = ''; 17 | 18 | setText(newText: string): void { 19 | this.text = newText; 20 | } 21 | 22 | getText(): string { 23 | return this.text; 24 | } 25 | 26 | save(): Memento { 27 | return new Memento(this.text); 28 | } 29 | 30 | restore(memento: Memento): void { 31 | this.text = memento.getState(); 32 | } 33 | } 34 | 35 | // Caretaker: Gestiona los mementos 36 | class Caretaker { 37 | private mementos: Memento[] = []; 38 | private originator: TextEditor; 39 | 40 | constructor(originator: TextEditor) { 41 | this.originator = originator; 42 | } 43 | 44 | save(): void { 45 | this.mementos.push(this.originator.save()); 46 | } 47 | 48 | undo(): void { 49 | if (this.mementos.length > 0) { 50 | const memento = this.mementos.pop(); 51 | if (memento) { 52 | this.originator.restore(memento); 53 | } 54 | } 55 | } 56 | } 57 | 58 | // Uso del patrón 59 | const editor = new TextEditor(); 60 | const caretaker = new Caretaker(editor); 61 | 62 | // Simulamos cambios de texto y deshacer 63 | editor.setText('Primer texto'); 64 | caretaker.save(); 65 | 66 | editor.setText('Segundo texto'); 67 | caretaker.save(); 68 | 69 | editor.setText('Tercer texto'); 70 | 71 | console.log('Texto actual:', editor.getText()); // "Tercer texto" 72 | 73 | caretaker.undo(); 74 | console.log('Después de deshacer:', editor.getText()); // "Segundo texto" 75 | 76 | caretaker.undo(); 77 | console.log('Después de deshacer nuevamente:', editor.getText()); // "Primer texto" 78 | -------------------------------------------------------------------------------- /Estructurales/Decorator/Decorator.md: -------------------------------------------------------------------------------- 1 | # Decorator 2 | 3 | El patrón Decorator nos permite extender funcionalidades de una clase de forma dinamica sin tener que recurrir a la herencia, lo hace envolviendo los objetos en objetos especiales llamados decorators/decoradores el cual contiene este nuevo comportamiento que va a ser añadido, puedes pensar en esto como si fueran capas de funcionalidades que se le van a ir añadiendo a la clase que esta en el nucleo 4 | 5 | ### ¿Cuando utilizar decorator sobre herencia? 6 | 7 | - Cuando se necesita añadir un comportamiento especifico a objetos en especificos y no a la clase entera. 8 | 9 | - Cuando quieres añadir un nuevo comportamiento sin modificar la herencia actual de la clase 10 | 11 | - Cuando necesitas que un comportamiento se modifique en tiempo de ejecución 12 | 13 | 14 | ### ¿Por qué usar el patrón Decorator? 15 | 16 | - Extension dinamica de funcionalidad 17 | 18 | - Adicion de comportamientos de manera incremental: Los decoradores se pueden "apilar" para construir un objeto con multiples funcionalidades sin necesidad de una jerarquia compleja de clases 19 | 20 | - Evitar la herencia excesiva: Si utilizamos herencia para extender funcionalidades podemos llegar al punto donde tendremos demaciadas subclases 21 | 22 | - Sustitución: es sencillo cambiar un decorador por otro sin cambiar la estructura original de la clase 23 | 24 | - Principio abierto/cerrado: Permite que las clases esten abiertas a la extensión pero cerrada a la modificación 25 | 26 | Ejemplo: 27 | Imagina que tienes una clase base llamada Bebida caliente que representa una bebida básica como café o té. Luego, en lugar de crear subclases para cada posible combinación de bebidas (como "café con leche", "té con miel y limón", etc.), puedes usar el patrón Decorator para agregar personalizaciones adicionales de forma flexible. Aquí está cómo podría funcionar: 28 | 29 | **Codigo** [`Decorator`](./Decorator.ts) 30 | 31 | ![Diagrama de clases Decorator](../../assets/DecoratorPattern.jpg) 32 | -------------------------------------------------------------------------------- /Comportamiento/TemplateMethod/TemplateMethod.ts: -------------------------------------------------------------------------------- 1 | // Clase base abstracta 2 | abstract class Bebida { 3 | // template method 4 | public prepararReceta(): void { 5 | this.hervirAgua(); 6 | this.preparar(); // Método abstracto 7 | this.servirEnTaza(); 8 | if (this.clienteQuiereCondimentos()) { // Metodo gancho 9 | this.agregarCondimentos(); // Metodo abstracto 10 | } 11 | } 12 | 13 | // Metodos comunes para todas las bebidas 14 | private hervirAgua(): void { 15 | console.log("Hirviendo agua"); 16 | } 17 | 18 | private servirEnTaza(): void { 19 | console.log("Sirviendo en la taza"); 20 | } 21 | 22 | // Metodos abstractos que las subclases deben implementar 23 | protected abstract preparar(): void; 24 | protected abstract agregarCondimentos(): void; 25 | 26 | // Gancho: las subclases pueden sobrescribirlo si es necesario 27 | protected clienteQuiereCondimentos(): boolean { 28 | return true; // Por defecto se añaden condimentos 29 | } 30 | } 31 | 32 | // Subclase 33 | class Te extends Bebida { 34 | protected preparar(): void { 35 | console.log("reposando el te"); 36 | } 37 | 38 | protected agregarCondimentos(): void { 39 | console.log("agregando limon"); 40 | } 41 | } 42 | 43 | // Subclase 44 | class Cafe extends Bebida { 45 | protected preparar(): void { 46 | console.log("Preparando cafe en prensa francesa"); 47 | } 48 | 49 | protected agregarCondimentos(): void { 50 | console.log("Agregando azucar"); 51 | } 52 | 53 | protected clienteQuiereCondimentos(): boolean { 54 | // Sobrescribimos el gancho 55 | return false; // En este caso, no queremos condimentos 56 | } 57 | } 58 | 59 | // Uso del patrón 60 | const te = new Te(); 61 | console.log("Preparando te..."); 62 | te.prepararReceta(); 63 | 64 | const cafe = new Cafe(); 65 | console.log("\nPreparando cafe..."); 66 | cafe.prepararReceta(); 67 | -------------------------------------------------------------------------------- /Comportamiento/TemplateMethod/TemplateMethod.md: -------------------------------------------------------------------------------- 1 | # Template Method 2 | 3 | El patrón de diseño Template Method es un patrón de comportamiento que define el esqueleto de un algoritmo en una clase base y permite que las subclases redefinan ciertos pasos del algoritmo sin cambiar su estructura general. 4 | 5 | 6 | ### Caracteristicas clave 7 | 8 | - Clase base con el esqueleto del algoritmo: La clase base contiene un método (el "template method") que define la secuencia de pasos del algoritmo. Este método puede llamar a otros métodos definidos en la clase base o ser implementados por las subclases. 9 | 10 | - Pasos del algoritmo: Algunos pasos del algoritmo se implementan en la clase base, mientras que otros se dejan como métodos abstractos o "ganchos" para que las subclases los personalicen. 11 | 12 | - Evita duplicación de código: Al definir la estructura general en la clase base, se reduce la duplicación de código al reutilizar la lógica común entre diferentes implementaciones. 13 | 14 | ### Ventajas 15 | 16 | - Reutilización de código: La estructura general del algoritmo se define una vez y puede reutilizarse con diferentes implementaciones. 17 | 18 | - Control de flujo: La clase base controla el flujo del algoritmo, asegurando consistencia. 19 | 20 | - Fácil personalización: Las subclases pueden personalizar pasos específicos sin alterar la lógica global. 21 | 22 | 23 | ### Desventajas 24 | 25 | - Complejidad inicial: Puede ser excesivo si el algoritmo es sencillo o si hay pocos pasos que varían. 26 | 27 | - Fuerte acoplamiento: Las subclases dependen de la clase base, lo que puede dificultar cambios en la estructura del algoritmo. 28 | 29 | 30 | ### Ejemplo 31 | 32 | Imaginemos que queremos implementar un sistema para preparar diferentes tipos de bebidas calientes como té y café. Ambas bebidas siguen un proceso similar, pero tienen pasos específicos que las distinguen. 33 | 34 | 35 | **Codigo** [`TemplateMethod`](./TemplateMethod.ts) 36 | 37 | ![Diagrama de clases TemplateMethod](../../assets/templateMethod.jpg) 38 | -------------------------------------------------------------------------------- /Comportamiento/Visitor/Visitor.ts: -------------------------------------------------------------------------------- 1 | // Visitor interface 2 | interface ShapeVisitor { 3 | visitCircle(circle: Circle): void; 4 | visitSquare(square: Square): void; 5 | } 6 | 7 | // Element interface 8 | interface Shape { 9 | accept(visitor: ShapeVisitor): void; 10 | } 11 | 12 | // Concrete Elements 13 | class Circle implements Shape { 14 | constructor(public radius: number) {} 15 | 16 | accept(visitor: ShapeVisitor): void { 17 | visitor.visitCircle(this); 18 | } 19 | } 20 | 21 | class Square implements Shape { 22 | constructor(public sideLength: number) {} 23 | 24 | accept(visitor: ShapeVisitor): void { 25 | visitor.visitSquare(this); 26 | } 27 | } 28 | 29 | // Concrete Visitor 1: Calcular el area 30 | class AreaCalculator implements ShapeVisitor { 31 | visitCircle(circle: Circle): void { 32 | const area = Math.PI * Math.pow(circle.radius, 2); 33 | console.log(`Circle area: ${area.toFixed(2)}`); 34 | } 35 | 36 | visitSquare(square: Square): void { 37 | const area = Math.pow(square.sideLength, 2); 38 | console.log(`Square area: ${area}`); 39 | } 40 | } 41 | 42 | // Concrete Visitor 2: Calcular el perimetro 43 | class PerimeterCalculator implements ShapeVisitor { 44 | visitCircle(circle: Circle): void { 45 | const perimeter = 2 * Math.PI * circle.radius; 46 | console.log(`Circle perimeter: ${perimeter.toFixed(2)}`); 47 | } 48 | 49 | visitSquare(square: Square): void { 50 | const perimeter = 4 * square.sideLength; 51 | console.log(`Square perimeter: ${perimeter}`); 52 | } 53 | } 54 | 55 | // Cliente 56 | const shapes: Shape[] = [ 57 | new Circle(5), 58 | new Square(4) 59 | ]; 60 | 61 | const areaCalculator = new AreaCalculator(); 62 | const perimeterCalculator = new PerimeterCalculator(); 63 | 64 | console.log("Calculating Area:"); 65 | shapes.forEach(shape => shape.accept(areaCalculator)); 66 | 67 | console.log("\nCalculating Perimeter:"); 68 | shapes.forEach(shape => shape.accept(perimeterCalculator)); 69 | -------------------------------------------------------------------------------- /Comportamiento/Observer/Observer.ts: -------------------------------------------------------------------------------- 1 | //observer 2 | interface Observer { 3 | actualizar(mensaje: string): void; 4 | } 5 | //Subject 6 | interface Subject { 7 | agregarMiembro(miembro: Observer): void; 8 | eliminarMiembro(miembro: Observer): void; 9 | notificarMiembros(mensaje: string): void; 10 | } 11 | 12 | // concreteSubject 13 | class GrupoWhatsApp implements Subject { 14 | private miembros: Observer[] = []; 15 | 16 | public agregarMiembro(miembro: Observer): void { 17 | console.log(`Nuevo miembro agregado al grupo.`); 18 | this.miembros.push(miembro); 19 | } 20 | 21 | public eliminarMiembro(miembro: Observer): void { 22 | const indice = this.miembros.indexOf(miembro); 23 | if (indice > -1) { 24 | this.miembros.splice(indice, 1); 25 | console.log(`Miembro eliminado del grupo.`); 26 | } 27 | } 28 | 29 | public notificarMiembros(mensaje: string): void { 30 | console.log(`Notificando a los miembros sobre un nuevo mensaje: "${mensaje}"`); 31 | this.miembros.forEach(miembro => miembro.actualizar(mensaje)); 32 | } 33 | } 34 | 35 | //concreteObservers 36 | class MiembroGrupo implements Observer { 37 | private nombre: string; 38 | 39 | constructor(nombre: string) { 40 | this.nombre = nombre; 41 | } 42 | 43 | public actualizar(mensaje: string): void { 44 | console.log(`${this.nombre} recibió el mensaje: "${mensaje}"`); 45 | } 46 | } 47 | 48 | 49 | const grupo = new GrupoWhatsApp(); 50 | 51 | const ana = new MiembroGrupo('Ana'); 52 | const juan = new MiembroGrupo('Juan'); 53 | const carlos = new MiembroGrupo('Carlos'); 54 | 55 | // agregar miembros al grupo 56 | grupo.agregarMiembro(ana); 57 | grupo.agregarMiembro(juan); 58 | grupo.agregarMiembro(carlos); 59 | 60 | // enviar un mensaje 61 | grupo.notificarMiembros('¡Hola a todos!'); 62 | 63 | // Eliminar un miembro y enviar otro mensaje 64 | grupo.eliminarMiembro(juan); 65 | grupo.notificarMiembros('Juan ha salido del grupo.'); 66 | -------------------------------------------------------------------------------- /Estructurales/Composite/Composite.md: -------------------------------------------------------------------------------- 1 | # Composite 2 | 3 | El patrón de diseño Composite es un patrón estructural que se utiliza para tratar de manera uniforme objetos individuales y composiciones de objetos. Es particularmente útil cuando tienes una estructura jerárquica de objetos que puede tener una relación de "parte-todo" en la que un objeto es siempre, o una parte de un todo, o un todo compuesto por varias partes y necesitas manipular tanto los objetos compuestos como los individuales de la misma manera. 4 | 5 | Basicamente se trata de establecer una jerarquia en forma de arbol, donde cada entidad puede estar formada por otras entidades del mismo tipo 6 | 7 | ### ¿Cuando utilizar el patron bridge? 8 | 9 | - Hay una estructura jerárquica de objetos (por ejemplo, un árbol) 10 | 11 | - Los clientes deben tratar los objetos individuales y los compuestos de forma uniforme. 12 | 13 | - Necesitas realizar operaciones en un grupo de objetos de manera recursiva. 14 | 15 | ### Componentes del patron bridge 16 | 17 | - Componente (Component): Es una interfaz común para todos los objetos de la composición. Define las operaciones que pueden realizar tanto los objetos individuales como los compuestos. 18 | 19 | - Hoja (Leaf): Representa los objetos individuales en la composición que no tienen elementos hijos. 20 | 21 | - Compuesto (Composite): Representa un objeto que tiene hijos. Implementa la interfaz del Componente y maneja los elementos hijos, delegando a ellos las operaciones. 22 | 23 | ### Ventajas 24 | 25 | - Facilidad de uso: Permite a los clientes tratar a los objetos compuestos y los simples de manera uniforme. 26 | 27 | - Flexibilidad: Agregar nuevos tipos de nodos o modificar la estructura es sencillo, ya que todos los elementos implementan la misma interfaz. 28 | 29 | ### Desventajas 30 | 31 | - Puede hacer más compleja la implementación si hay reglas de validación específicas o restricciones sobre cómo se pueden combinar los objetos. 32 | 33 | ### Ejemplo 34 | 35 | **Codigo** [`Composite`](./Composite.ts) 36 | 37 | ![Diagrama de clases Composite](../../assets/CompositePattern.jpg) 38 | -------------------------------------------------------------------------------- /Estructurales/Decorator/Decorator.ts: -------------------------------------------------------------------------------- 1 | //Abstraccion de toda nuestras clases (bebida) 2 | interface IBebida { 3 | obtenerDescripcion(): string; 4 | obtenerCosto(): number; 5 | } 6 | 7 | //Clase concreta 8 | class BebidaBase implements IBebida{ 9 | obtenerCosto(): number { 10 | return 10 11 | } 12 | obtenerDescripcion(): string { 13 | return "Agua caliente en un vaso" 14 | } 15 | } 16 | 17 | //Abstraccion decorador base nos sirve como puente entre la clase base (Bebida) 18 | //y los decoradores concretos 19 | //es abstracta para que no se pueda instanciar 20 | abstract class BebidaDecorator implements IBebida{ 21 | protected bebida: IBebida; 22 | 23 | constructor(bebidaToDecorate: IBebida){ 24 | this.bebida = bebidaToDecorate; 25 | } 26 | 27 | obtenerCosto(): number { 28 | return this.bebida.obtenerCosto() 29 | } 30 | obtenerDescripcion(): string { 31 | return this.bebida.obtenerDescripcion() 32 | } 33 | } 34 | 35 | //Abstraccion decorador concreto 36 | class Cafe extends BebidaDecorator{ 37 | obtenerCosto(): number { 38 | return this.bebida.obtenerCosto() + 5 39 | } 40 | obtenerDescripcion(): string { 41 | return this.bebida.obtenerDescripcion() + " con una cucharada de cafe" 42 | } 43 | } 44 | 45 | class Azucar extends BebidaDecorator{ 46 | obtenerCosto(): number { 47 | return this.bebida.obtenerCosto() + 2 48 | } 49 | obtenerDescripcion(): string { 50 | return this.bebida.obtenerDescripcion() + " y tres cucharadas de azucar" 51 | } 52 | } 53 | 54 | function mainDecorator(){ 55 | //las clases que heredan del decorador bebidaDecorador implementan su constructor de forma implicita por lo que podemos 56 | //ir pasando miBebida e ir incrementando sus funcionalidades con la misma instancia 57 | let miBebida = new BebidaBase(); 58 | miBebida = new Cafe(miBebida); 59 | miBebida = new Azucar(miBebida); 60 | 61 | console.log(miBebida.obtenerCosto()); 62 | console.log(miBebida.obtenerDescripcion()); 63 | } 64 | 65 | mainDecorator() -------------------------------------------------------------------------------- /Estructurales/Proxy/Proxy.md: -------------------------------------------------------------------------------- 1 | # Proxy 2 | 3 | El patron de diseño Proxy es un patron estructural que proporciona un sustituto o representante de otro objeto para controlar el acceso a este. Se utiliza comúnmente para agregar una capa de control sobre el objeto real, ya sea por razones de rendimiento, control de acceso, o para realizar alguna acción adicional antes o después de acceder al objeto real 4 | 5 | ### Estructura del patrón proxy 6 | 7 | - Interfaz común: Define los métodos que tanto el objeto real como el proxy deben implementar. 8 | 9 | - Sujeto real (Real Subject): Es el objeto principal que se quiere proteger o representar. 10 | 11 | - Proxy: Es la clase intermediaria que controla el acceso al sujeto real. 12 | 13 | ### Como funciona 14 | 15 | Se crea una clase proxy con la misma interfaz que el sujeto real. Despues actualizas tu aplicación para que pase el objeto proxy a todos los clientes del objeto real. Al recibir una solicitud de un cliente, el proxy crea un objeto de sujeto real y le delega todo el trabajo 16 | 17 | ### Ventajas 18 | 19 | - Control adicional: Permite añadir lógica antes y después de llamar al objeto real 20 | 21 | - Mejor rendimiento: Puedes diferir la creación o ejecución de operaciones costosas. 22 | 23 | - Organización: Permite implementar funcionalidades adicionales como caching, autenticacion o validación 24 | 25 | El patron Proxy es una herramienta poderosa para estructurar sistemas que requiren control sobre el acceso a objetos, especialmente cuando se manejan recursos costosos o necesitas una capa de seguridad. 26 | 27 | ### Desventajas 28 | 29 | - Mayor complejidad: introduce mas clases y abstracción 30 | 31 | - Posibles problemas de rendimiento: Si no se gestiona bien el proxy puede añadir una sobrecarga innecesaria 32 | 33 | ### Ejemplo práctico 34 | 35 | Supongamos que tenemos un sistema que carga imagenes y alguna imagenes son muy pesadas para volver a cargarlas. Podriamos utilizar un proxy para cargarlas cuando sea solamente necesario. 36 | 37 | **Codigo** [`Proxy`](./Proxy.ts) 38 | 39 | ![Diagrama de clases Proxy](../../assets/ProxyPattern.jpg) 40 | -------------------------------------------------------------------------------- /Estructurales/Flyweight/Flyweight.md: -------------------------------------------------------------------------------- 1 | # Flyweight 2 | 3 | El patrón Flyweight es un patrón estructural que busca minimizar el uso de memoria compartiendo tantos datos como sea posible entre los objetos que tienen estados similares o idénticos. Este patrón es ideal cuando necesitas manejar un gran número de objetos que comparten información común, pero también tienen datos únicos. 4 | 5 | ### Concepto clave 6 | 7 | - Un Adapter actúa como un traductor entre dos clases o sistemas con interfaces distintas. 8 | 9 | - Se puede utilizar cuando quieres que una clase existente funcione con otras clases sin modificar su código. 10 | 11 | 12 | ### Componentes principales 13 | 14 | - Estado Intrínseco: 15 | 1. Datos compartidos entre múltiples objetos, que son inmutables y no cambian. 16 | 2. Almacenados en el Flyweight. 17 | 18 | - Estado Extrínseco: 19 | 1. Datos específicos de cada objeto, que pueden cambiar. 20 | 2. Pasados desde el cliente al Flyweight cuando se realiza una operación. 21 | 22 | - Factory: 23 | 1. Responsable de administrar y reutilizar instancias de Flyweight. Evita crear múltiples objetos idénticos. 24 | 25 | 26 | ### Ejemplo práctico 27 | 28 | Imagina que estamos desarrollando un juego donde se representan árboles en un bosque. Cada árbol tiene un tipo (estado intrínseco) y una posición (estado extrínseco). 29 | 30 | Aquí usamos el patrón Flyweight para minimizar el uso de memoria cuando hay muchos árboles del mismo tipo. 31 | 32 | 33 | ### Cómo funciona el ejemplo 34 | 35 | - TipoArbolFactory: 36 | 1. Se asegura de que cada combinación única de ArbolTipo se cree solo una vez. 37 | 2. Si ya existe un ArbolTipo con el mismo nombre, color, y textura, lo reutiliza. 38 | 39 | - Arbol: 40 | 1. Contiene la posición específica (estado extrínseco) y una referencia a un ArbolTipo (estado intrínseco). 41 | 42 | - Memoria Optimizada 43 | 1. Aunque hay múltiples árboles (Arbol), los datos compartidos (ArbolTipo) se almacenan solo una vez 44 | 45 | **Codigo** [`Flyweight`](./Flyweight.ts) 46 | 47 | 48 | ![Diagrama de clases FlyWeight](../../assets/FlyweightPattern.jpg) 49 | -------------------------------------------------------------------------------- /Estructurales/Facade/Facade.md: -------------------------------------------------------------------------------- 1 | # Facade 2 | 3 | El patrón de diseño Facade es un patrón estructural cuyo propósito es simplificar la interfaz de una biblioteca, framework o cualquier otro grupo complejo de clases. Este patrón proporciona una interfaz simple y más fácil de usar para un conjunto de interfaces en un subsistema complejo que contiene muchas partes, ocultando su complejidad y permitiendo que el cliente interactúe con el sistema de manera simplificada para trabajar con la funciones realmente importantes para el cliente. 4 | 5 | 6 | ### Contexto y uso 7 | 8 | El patrón Facade es útil cuando un sistema tiene múltiples partes interdependientes que el usuario o cliente no necesita ver ni manipular directamente. Es común en sistemas grandes y complejos donde la interacción directa con todas las clases y módulos sería complicada o confusa. 9 | 10 | 11 | ### ¿Como funciona? 12 | 13 | - Fachada: Una clase Facade proporciona métodos simplificados y específicos para realizar ciertas acciones, encapsulando y delegando tareas a varias clases del sistema. 14 | 15 | - Subsistema: Las clases internas que forman parte del subsistema son complejas, y cada una tiene funcionalidades específicas y detalladas. La Facade se encarga de coordinar estas clases para ejecutar tareas complejas de forma sencilla. 16 | 17 | ### Beneficios 18 | 19 | - Simplicidad: Proporciona una interfaz simple y fácil de usar para sistemas complejos. 20 | 21 | - Desacoplamiento: Aísla el código cliente del subsistema, lo que facilita la modificación del sistema sin afectar al cliente 22 | 23 | - Organización: Ayuda a organizar el sistema, creando una capa de abstracción sobre el subsistema. 24 | 25 | ### Ejemplo 26 | Imagina que tienes un sistema para gestionar una casa inteligete y que cada elemento requiere su configuración y manejo. En lugar de que el cliente tenga que interactuar con el sistema por separado, puedes crear una clase centralizada que tenga métodos como play(), pause(), o stop(), que internamente llaman y coordinan a las clases individuales de audio, video y subtítulos. 27 | 28 | **Codigo** [`Facade`](./Facade.ts) 29 | 30 | ![Diagrama de clases Facade](../../assets/FacadePattern.jpg) 31 | -------------------------------------------------------------------------------- /Estructurales/Flyweight/Flyweight.ts: -------------------------------------------------------------------------------- 1 | // 1. Flyweight: Representa el estado compartido 2 | class ArbolTipo { 3 | constructor( 4 | public readonly nombre: string, 5 | public readonly color: string, 6 | public readonly textura: string 7 | ) {} 8 | 9 | dibujar(x: number, y: number): void { 10 | console.log( 11 | `Dibujando un árbol de tipo ${this.nombre} con color ${this.color} y textura ${this.textura} en la posición (${x}, ${y}).` 12 | ); 13 | } 14 | } 15 | 16 | // 2. Flyweight Factory: Gestiona los objetos compartidos 17 | class ArbolTipoFactory { 18 | private static tiposArboles: Map = new Map(); 19 | 20 | static getTipoArbol(name: string, color: string, texture: string): ArbolTipo { 21 | const key = `${name}-${color}-${texture}`; 22 | if (!this.tiposArboles.has(key)) { 23 | this.tiposArboles.set(key, new ArbolTipo(name, color, texture)); 24 | console.log(`Creado un nuevo tipo de árbol: ${key}`); 25 | } 26 | return this.tiposArboles.get(key)!; 27 | } 28 | } 29 | 30 | // 3. Contexto: Representa el estado extrínseco (posición del árbol) 31 | class Arbol { 32 | constructor( 33 | private x: number, 34 | private y: number, 35 | private tipo: ArbolTipo // Flyweight 36 | ) {} 37 | 38 | dibujar(): void { 39 | this.tipo.dibujar(this.x, this.y); 40 | } 41 | } 42 | 43 | // 4. Cliente: Usa los objetos Flyweight 44 | class Bosque { 45 | private arboles: Arbol[] = []; 46 | 47 | plantarArbol(x: number, y: number, name: string, color: string, texture: string) { 48 | const tipo = ArbolTipoFactory.getTipoArbol(name, color, texture); 49 | const arbol = new Arbol(x, y, tipo); 50 | this.arboles.push(arbol); 51 | } 52 | 53 | dibujar(): void { 54 | for (const arbol of this.arboles) { 55 | arbol.dibujar(); 56 | } 57 | } 58 | } 59 | 60 | // Uso del patrón Flyweight 61 | const bosque = new Bosque(); 62 | bosque.plantarArbol(10, 20, "Roble", "Verde", "Liso"); 63 | bosque.plantarArbol(15, 25, "Roble", "Verde", "Liso"); // Reutiliza el mismo tipo 64 | bosque.plantarArbol(30, 40, "Pino", "Verde oscuro", "Aspero"); 65 | 66 | bosque.dibujar(); -------------------------------------------------------------------------------- /Comportamiento/Command/Command.md: -------------------------------------------------------------------------------- 1 | # Command 2 | 3 | es uno de los patrones de comportamiento que permite encapsular una solicitud como un objeto, lo que facilita la parametrización de métodos con diferentes solicitudes, la encolación de solicitudes o el registro de las operaciones que se realizaron (historial de comandos). 4 | 5 | ### ¿Que problemas viene a solucionar? 6 | 7 | - Acoplamiento entre el invocador y el receptor: 8 | - Problema: En sistemas sin Command, el invocador (quien emite la solicitud) está directamente acoplado al receptor (quien la ejecuta). Esto dificulta el mantenimiento y la reutilización del código. 9 | 10 | - Solución: El patrón Command desacopla estos dos componentes al introducir una capa intermedia (el comando). Esto permite que el invocador no tenga conocimiento directo del receptor. 11 | 12 | - Flexibilidad en la ejecución de comandos: 13 | - Problema: En sistemas tradicionales, agregar nuevas solicitudes o modificar las existentes puede requerir cambios en múltiples partes del codigo. 14 | - Solución: El patrón Command encapsula cada acción en un objeto independiente, lo que facilita agregar o cambiar comandos sin afectar otras partes del sistema. 15 | 16 | - Ejecución diferida o encolada: 17 | - Problema: En algunos sistemas, las solicitudes necesitan ser almacenadas para ejecutarse mas tarde (por ejemplo, tareas programadas o trabajos en una cola). 18 | - Solucion: Los comandos se pueden serializar o almacenar en una cola para ejecutarse en el momento adecuado. 19 | 20 | ### Ventajas 21 | 22 | - Desacoplamiento: Separa el emisor (Invoker) del receptor (Receiver). 23 | 24 | - Extensibilidad: Es fácil añadir nuevos comandos sin cambiar el código existente. 25 | 26 | - Flexibilidad: Permite almacenar y ejecutar comandos de forma dinámica. 27 | 28 | - Historial: Habilita el registro de operaciones para permitir deshacer o rehacer. 29 | 30 | 31 | ### Desventajas 32 | 33 | - Puede incrementar la complejidad del sistema al introducir múltiples clases. 34 | 35 | - Requiere más código, especialmente si hay muchos comandos diferentes. 36 | 37 | ### Ejemplo 38 | 39 | Sistema de deshacer (undo) y rehacer (redo). Este ejemplo simula un editor de texto donde se pueden agregar y eliminar texto, con la posibilidad de deshacer y rehacer las acciones. 40 | 41 | 42 | **Codigo** [`Command`](./Command.ts) 43 | 44 | ![Diagrama de clases Command](../../assets/Command.jpg) 45 | -------------------------------------------------------------------------------- /Estructurales/Bridge/Bridge.md: -------------------------------------------------------------------------------- 1 | # Bridge 2 | 3 | El patrón de diseño Bridge (o Puente) es un patrón estructural que tiene como objetivo desacoplar una abstracción de su implementación, de manera que ambas puedan variar de forma independiente. Es particularmente útil cuando tienes dos dimensiones que pueden cambiar en un sistema y deseas que esas variaciones sean gestionadas de manera separada. 4 | 5 | 6 | ### ¿Cuando utilizar el patron bridge? 7 | 8 | - Quieres evitar una gran cantidad de subclases debido a combinaciones posibles de distintas variantes. 9 | 10 | - Necesitas dividir la implementación de una clase en clases independientes que puedan desarrollarse y evolucionar de forma separada. 11 | 12 | ### Componentes del patron bridge 13 | 14 | - Abstracción (Abstraction): Define la interfaz general de la abstracción y contiene una referencia a un objeto de Implementación. La abstracción actúa como puente que permite el acceso indirecto a la implementación. 15 | 16 | - Implementación (Implementor): Es una interfaz o clase abstracta que define métodos específicos que la Abstracción puede utilizar. Estas implementaciones suelen ser específicas de la plataforma o funcionalidad. 17 | 18 | - Refinación de la Abstracción (Refined Abstraction): Extiende la abstracción principal y puede agregar o modificar el comportamiento de la abstracción. Sin embargo, sigue usando la Implementación a través de la interfaz definida en Implementor. 19 | 20 | - Implementaciones Concretas (ConcreteImplementor): Estas son implementaciones específicas que heredan de la interfaz Implementor. La abstracción utiliza estas implementaciones concretas para llevar a cabo acciones específicas. 21 | 22 | ### Ventajas 23 | 24 | - Desacoplamiento: Permite que la abstracción y la implementación evolucionen de forma independiente 25 | 26 | - Reducción de Subclases: Evita la explosión de subclases al combinar jerarquías en un sistema 27 | 28 | - Mayor Flexibilidad: Puedes añadir nuevas implementaciones y abstracciones sin modificar el código existente 29 | 30 | ### Desventajas 31 | 32 | - Complejidad Incrementada: Agrega complejidad debido a la creación de varias interfaces y clases. 33 | 34 | - Dependencia en la Abstracción: Al depender de la abstracción para hacer el puente, hay que diseñarla adecuadamente para que soporte futuras implementaciones 35 | 36 | ### Ejemplo 37 | 38 | **Codigo** [`Bridge`](./Bridge.ts) 39 | 40 | ![Diagrama de clases Bridge](../../assets/BridgePattern.jpg) 41 | -------------------------------------------------------------------------------- /Creacionales/AbstractFactory/AbstractFactory.ts: -------------------------------------------------------------------------------- 1 | //abstracciones 2 | interface BloqueInterrogante{ 3 | spawnItem(); 4 | render(); 5 | } 6 | 7 | interface Moneda{ 8 | spawnItem(); 9 | render(); 10 | } 11 | 12 | interface AbstractFactory{ 13 | createMoneda(): Moneda; 14 | createBloqueInterrogante(): BloqueInterrogante 15 | } 16 | 17 | // Clases concretas para Gameboy 18 | class GameboyMoneda implements Moneda { 19 | spawnItem() { 20 | console.log("Gameboy: Moneda aparece."); 21 | } 22 | render() { 23 | console.log("Renderizando Moneda en estilo Gameboy."); 24 | } 25 | } 26 | 27 | class GameboyBloqueInterrogante implements BloqueInterrogante { 28 | spawnItem() { 29 | console.log("Gameboy: Bloque de interrogación aparece."); 30 | } 31 | render() { 32 | console.log("Renderizando Bloque de interrogación en estilo Gameboy."); 33 | } 34 | } 35 | 36 | // Clases concretas para Nintendo DS 37 | class NintendoDSMoneda implements Moneda { 38 | spawnItem() { 39 | console.log("Nintendo DS: Moneda aparece."); 40 | } 41 | render() { 42 | console.log("Renderizando Moneda en estilo Nintendo DS."); 43 | } 44 | } 45 | 46 | class NintendoDSBloqueInterrogante implements BloqueInterrogante { 47 | spawnItem() { 48 | console.log("Nintendo DS: Bloque de interrogación aparece."); 49 | } 50 | render() { 51 | console.log("Renderizando Bloque de interrogación en estilo Nintendo DS."); 52 | } 53 | } 54 | 55 | //fabricas de creacion 56 | class GameboyItemFactory implements AbstractFactory{ 57 | createMoneda(): Moneda { 58 | return new GameboyMoneda() 59 | } 60 | createBloqueInterrogante(): BloqueInterrogante { 61 | return new GameboyBloqueInterrogante() 62 | } 63 | } 64 | 65 | class NintendoDSItemFactory implements AbstractFactory{ 66 | createMoneda(): Moneda { 67 | return new NintendoDSMoneda() 68 | } 69 | createBloqueInterrogante(): BloqueInterrogante { 70 | return new NintendoDSBloqueInterrogante() 71 | } 72 | } 73 | 74 | function generarEntornoDeJuego(factory: AbstractFactory) { 75 | const moneda = factory.createMoneda(); 76 | const bloque = factory.createBloqueInterrogante(); 77 | 78 | moneda.spawnItem(); 79 | moneda.render(); 80 | 81 | bloque.spawnItem(); 82 | bloque.render(); 83 | } 84 | 85 | function main(){ 86 | const gameboyFactory = new GameboyItemFactory(); 87 | generarEntornoDeJuego(gameboyFactory); 88 | 89 | const nintendoDSFactory = new NintendoDSItemFactory(); 90 | generarEntornoDeJuego(nintendoDSFactory); 91 | } 92 | 93 | main(); 94 | -------------------------------------------------------------------------------- /Creacionales/FactoryMethod/FactoryMethod.ts: -------------------------------------------------------------------------------- 1 | interface Entity { 2 | updateLogic(): void; 3 | } 4 | 5 | class Boo implements Entity { 6 | updateLogic(): void { 7 | console.log("Boo: Subiendo 20 puntos de fuerza"); 8 | } 9 | } 10 | 11 | class Koopa implements Entity { 12 | updateLogic(): void { 13 | console.log("Koopa: Subiendo 40 puntos de fuerza"); 14 | } 15 | } 16 | 17 | class Goomba implements Entity { 18 | updateLogic(): void { 19 | console.log("Goomba: Subiendo 60 puntos de fuerza"); 20 | } 21 | } 22 | 23 | // Interfaz para crear enemigos 24 | interface EnemyFactory { 25 | createEnemy(): Entity; 26 | } 27 | 28 | // Fabrica de enemigos aleatorios 29 | class RandomEnemyFactory implements EnemyFactory { 30 | createEnemy(): Entity { 31 | const randomNum = Math.floor(Math.random() * 3); 32 | switch (randomNum) { 33 | case 0: return new Boo(); 34 | case 1: return new Koopa(); 35 | case 2: return new Goomba(); 36 | default: return new Goomba(); 37 | } 38 | } 39 | } 40 | 41 | // Fabrica de enemigos aleatorios dificiles 42 | class RandomDifficultEnemyFactory implements EnemyFactory { 43 | createEnemy(): Entity { 44 | const randomNum = Math.floor(Math.random() * 3); 45 | switch (randomNum) { 46 | case 0: 47 | console.log("Creando un Boo difícil."); 48 | return new Boo(); 49 | case 1: 50 | console.log("Creando un Koopa difícil."); 51 | return new Koopa(); 52 | case 2: 53 | console.log("Creando un Goomba difícil."); 54 | return new Goomba(); 55 | default: return new Goomba(); 56 | } 57 | } 58 | } 59 | 60 | class Game { 61 | private enemyFactory: EnemyFactory; 62 | private entities: Entity[] = []; 63 | 64 | constructor(enemyFactory: EnemyFactory) { 65 | this.enemyFactory = enemyFactory; 66 | } 67 | processGameLogic(entities: Entity[]) { 68 | for (let entity of entities) { 69 | entity.updateLogic(); 70 | } 71 | } 72 | // Genera nuevos enemigos y ejecuta la logica del juego 73 | gameLogic() { 74 | console.log("Generando enemigo..."); 75 | const newEnemy = this.enemyFactory.createEnemy(); 76 | this.entities.push(newEnemy); 77 | console.log("Ejecutando lógica del juego:"); 78 | this.processGameLogic(this.entities); 79 | } 80 | } 81 | 82 | // Simulación del juego 83 | const randomEnemyGame = new Game(new RandomEnemyFactory()); 84 | randomEnemyGame.gameLogic(); 85 | 86 | const difficultEnemyGame = new Game(new RandomDifficultEnemyFactory()); 87 | difficultEnemyGame.gameLogic(); 88 | -------------------------------------------------------------------------------- /Creacionales/Builder/Builder.ts: -------------------------------------------------------------------------------- 1 | interface Builder { 2 | setWeapon(weapon: string): Builder; 3 | setArmor(armor: string): Builder; 4 | setLevel(level: number): Builder; 5 | build(): Character; 6 | } 7 | 8 | class Character { 9 | private name: string; 10 | private race: string; 11 | private weapon: string; 12 | private armor: string; 13 | private level: number; 14 | 15 | constructor(builder: CharacterBuilder) { 16 | this.name = builder.name; 17 | this.race = builder.race; 18 | this.weapon = builder.weapon; 19 | this.armor = builder.armor; 20 | this.level = builder.level; 21 | } 22 | 23 | displayInfo() { 24 | console.log(`Character info: 25 | Name: ${this.name} 26 | Race: ${this.race} 27 | Weapon: ${this.weapon} 28 | Armor: ${this.armor} 29 | Level: ${this.level}`); 30 | } 31 | } 32 | 33 | class CharacterBuilder implements Builder { 34 | name: string; 35 | race: string; 36 | weapon: string = "Espada basica"; 37 | armor: string = "Armadura basica"; 38 | level: number = 1; 39 | 40 | constructor(name: string, race: string) { 41 | this.name = name; 42 | this.race = race; 43 | } 44 | 45 | setWeapon(weapon: string): Builder { 46 | this.weapon = weapon; 47 | return this; 48 | } 49 | 50 | setArmor(armor: string): Builder { 51 | this.armor = armor; 52 | return this; 53 | } 54 | 55 | setLevel(level: number): Builder { 56 | this.level = level; 57 | return this; 58 | } 59 | 60 | build(): Character { 61 | return new Character(this); 62 | } 63 | } 64 | 65 | 66 | class CharacterDirector { 67 | private builder: Builder; 68 | 69 | constructor(builder: Builder) { 70 | this.builder = builder; 71 | } 72 | 73 | // Construcción estándar para un guerrero 74 | buildWarrior(): Character { 75 | return this.builder 76 | .setWeapon("Espada rompemallas") 77 | .setArmor("Cota de mallas") 78 | .setLevel(10) 79 | .build(); 80 | } 81 | 82 | // construccion de un mago 83 | buildMage(): Character { 84 | return this.builder 85 | .setWeapon("Vara de sabiduria") 86 | .setArmor("Tunica oscura") 87 | .setLevel(12) 88 | .build(); 89 | } 90 | } 91 | 92 | const builder = new CharacterBuilder("Legolas", "Elfo"); 93 | const director = new CharacterDirector(builder); 94 | 95 | const warrior = director.buildWarrior(); 96 | warrior.displayInfo(); 97 | 98 | const mage = director.buildMage(); 99 | mage.displayInfo(); 100 | 101 | -------------------------------------------------------------------------------- /Comportamiento/Observer/Observer.md: -------------------------------------------------------------------------------- 1 | # Observer 2 | 3 | es un patrón de diseño de comportamiento que define una relación de dependencia uno a muchos entre objetos. Permite que cuando un objeto cambie de estado, todos sus dependientes (observadores) sean notificados automáticamente. 4 | 5 | ### Proposito 6 | 7 | Este patrón es ideal para aplicaciones donde un cambio en el estado de un objeto necesita reflejarse automáticamente en otros objetos relacionados. 8 | 9 | Por ejemplo: 10 | 11 | - Un sistema de notificaciones. 12 | 13 | - Actualización de la interfaz gráfica cuando cambian datos subyacentes. 14 | 15 | ### Estructura 16 | 17 | - Subject (Sujeto): Mantiene una lista de observadores y proporciona métodos para agregar, eliminar y notificar a los observadores. 18 | 19 | - Observer (Observador): Define una interfaz para recibir actualizaciones del sujeto. 20 | 21 | - ConcreteSubject (Sujeto Concreto): Implementa las funcionalidades del sujeto y almacena el estado que interesa a los observadores. 22 | 23 | - ConcreteObserver (Observador Concreto): Mantiene una referencia al sujeto e implementa la interfaz Observer para mantenerse sincronizado con el sujeto. 24 | 25 | ### Ventajas 26 | 27 | - Desacoplamiento entre el Subject y los Observers: El sujeto no necesita conocer los detalles de implementación de los observadores. Solo sabe que implementan la interfaz Observer. 28 | 29 | - Facilidad para añadir nuevos observadores: Se pueden agregar nuevos observadores sin modificar el código del sujeto, lo que mejora la extensibilidad del sistema. 30 | 31 | - Actualizaciones automáticas: Cuando el estado del sujeto cambia, todos los observadores relevantes se actualizan automáticamente, lo que reduce errores manuales. 32 | 33 | - Promueve el principio de diseño de "Open/Closed": El patrón permite que el sujeto esté abierto para extensiones (añadir observadores) pero cerrado para modificaciones. 34 | 35 | - Flexibilidad en la cantidad de observadores: Se pueden registrar múltiples observadores dinámicamente en tiempo de ejecución. 36 | 37 | ### Desventajas 38 | 39 | - Complejidad en sistemas grandes: Con muchos observadores, el sistema puede ser más difícil de rastrear y depurar, especialmente si ocurren bucles de notificaciones. 40 | 41 | - Rendimiento reducido: Si hay muchos observadores o las actualizaciones son frecuentes, el rendimiento del sistema puede degradarse debido a múltiples notificaciones. 42 | 43 | 44 | ### Ejemplo 45 | 46 | En un grupo de WhatsApp, cada miembro del grupo es un observador, mientras que el grupo en sí actúa como el sujeto. Cuando un miembro del grupo envía un mensaje, todos los demás miembros (observadores) son notificados automáticamente. 47 | 48 | 49 | **Codigo** [`Observer`](./Observer.ts) 50 | 51 | ![Diagrama de clases Observer](../../assets/ObserverPattern.jpg) 52 | -------------------------------------------------------------------------------- /Comportamiento/ChainOfResponsibility/ChainOfResponsibility.ts: -------------------------------------------------------------------------------- 1 | // Interfaz para los manejadores 2 | interface Handler { 3 | setNext(handler: Handler): Handler; 4 | handle(request: any): void; 5 | } 6 | 7 | // Clase base para los manejadores con logica para encadenar 8 | abstract class AbstractHandler implements Handler { 9 | private nextHandler: Handler | null = null; 10 | 11 | setNext(handler: Handler): Handler { 12 | this.nextHandler = handler; 13 | return handler; // Permite encadenar llamadas 14 | } 15 | 16 | handle(request: any): void { 17 | if (this.nextHandler) { 18 | this.nextHandler.handle(request); 19 | } 20 | } 21 | } 22 | 23 | // Manejador concreto para validar si un campo está vacío 24 | class NotEmptyHandler extends AbstractHandler { 25 | handle(request: any): void { 26 | if (!request.value) { 27 | console.error(`El campo "${request.field}" no puede estar vacío.`); 28 | return; // Detenemos la cadena si falla la validacion 29 | } 30 | super.handle(request); // Pasamos al siguiente manejador 31 | } 32 | } 33 | 34 | // Manejador concreto para validar la longitud minima 35 | class MinLengthHandler extends AbstractHandler { 36 | constructor(private minLength: number) { 37 | super(); 38 | } 39 | 40 | handle(request: any): void { 41 | if (request.value.length < this.minLength) { 42 | console.error( 43 | `El campo "${request.field}" debe tener al menos ${this.minLength} caracteres.` 44 | ); 45 | return; // Detenemos la cadena si falla la validacion 46 | } 47 | super.handle(request); // Pasamos al siguiente manejador 48 | } 49 | } 50 | 51 | // Manejador concreto para validar si es un email valido 52 | class EmailHandler extends AbstractHandler { 53 | handle(request: any): void { 54 | const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 55 | if (!emailRegex.test(request.value)) { 56 | console.error(`El campo "${request.field}" debe ser un correo válido.`); 57 | return; // Detenemos la cadena si falla la validación 58 | } 59 | super.handle(request); // Pasamos al siguiente manejador 60 | } 61 | } 62 | 63 | // cliente 64 | const emailValidation = new EmailHandler(); 65 | const lengthValidation = new MinLengthHandler(5); 66 | const emptyValidation = new NotEmptyHandler(); 67 | 68 | // seteamos la cadena de responsabilidad 69 | emptyValidation.setNext(lengthValidation).setNext(emailValidation); 70 | 71 | // ejemplo de validacion 72 | const request = { field: "email", value: "abc" }; 73 | emptyValidation.handle(request); 74 | 75 | // Otro ejemplo 76 | const validRequest = { field: "email", value: "user@example.com" }; 77 | emptyValidation.handle(validRequest); 78 | -------------------------------------------------------------------------------- /Creacionales/AbstractFactory/AbstractFactory.md: -------------------------------------------------------------------------------- 1 | # Abstract Factory 2 | 3 | Su definición: "Patrón de diseño que provee una interficie para crear familias de objetos relacionados o dependientes sin especificar su clase concreta" 4 | 5 | El patrón Abstract Factory es un patrón de diseño creacional que permite crear familias de objetos relacionados o dependientes sin especificar sus clases concretas. En lugar de instanciar los objetos directamente, el cliente interactúa con una interfaz de fábrica abstracta que se encarga de producir los objetos, lo cual permite que el cliente cambie fácilmente entre familias de productos sin alterar su propio código. 6 | 7 | ### Problema en el cual el patron factory no es la mejor opcion y abstract factory si 8 | 9 | Supongamos que estás desarrollando una aplicación multiplataforma que necesita diferentes componentes de interfaz de usuario para macOS y Windows. Estos componentes podrían incluir botones, ventanas, menús, etc., y cada sistema operativo tiene su propio estilo. 10 | 11 | Con Factory Method, puedes crear una fábrica que devuelva un tipo de botón (por ejemplo, MacButton o WindowsButton), pero no tienes una manera eficiente de agrupar y gestionar la creación de múltiples componentes relacionados de una misma familia (por ejemplo, MacButton, MacWindow, MacMenu para macOS, o WindowsButton, WindowsWindow, WindowsMenu para Windows). 12 | Cada vez que quieras añadir un nuevo tipo de componente (por ejemplo, un menú), necesitarás actualizar o crear nuevas fábricas para cada uno de los componentes en ambos sistemas operativos. 13 | 14 | ### ¿Por qué usar el patrón Abstract Factory? 15 | 16 | - Creación de Familias de Objetos Relacionados: Abstract Factory es ideal cuando necesitas crear grupos de objetos relacionados o dependientes (familias) sin especificar sus clases concretas. Esto es común en aplicaciones que funcionan en múltiples entornos o plataformas, como UI multiplataforma. 17 | 18 | - Consistencia entre Productos: Cuando los objetos en una familia deben funcionar juntos o seguir un estilo específico, Abstract Factory asegura que los productos sean compatibles y consistentes entre sí. Por ejemplo, los botones, menús y ventanas en un sistema operativo deben compartir un estilo visual. 19 | 20 | - Desacoplamiento del Código: Con Abstract Factory, el cliente no necesita saber qué clase específica está usando para crear un objeto; solo conoce la interfaz de la fábrica y los productos. Esto reduce la dependencia de las clases concretas, mejorando la modularidad y facilitando cambios de implementación. 21 | 22 | - Facilidad para Expandir y Mantener el Código: Agregar una nueva "familia" o grupo de objetos es sencillo; solo tienes que implementar una nueva fábrica sin alterar el código de los clientes. Esto es mucho más eficiente que actualizar múltiples métodos o clases cada vez que se necesita una nueva variante. 23 | 24 | ### Ejemplo 25 | 26 | **Codigo** [`AbstractFactory`](./AbstractFactory.ts) 27 | 28 | ![Diagrama de clases Abstract factory](../../assets/AbstractFactory.jpg) 29 | -------------------------------------------------------------------------------- /Comportamiento/Strategy/Strategy.md: -------------------------------------------------------------------------------- 1 | # Strategy 2 | 3 | El patrón Strategy es un patrón de diseño de comportamiento que te permite definir una familia de algoritmos, encapsularlos en clases separadas y hacer que sean intercambiables en tiempo de ejecución. Este patrón promueve el principio de "abierto/cerrado" ya que puedes agregar nuevas estrategias sin modificar el código que las utiliza. 4 | 5 | La idea principal detrás del patrón Strategy es separar el comportamiento que puede variar del resto del código que no cambia. Esto se logra encapsulando las distintas maneras de realizar una tarea en clases independientes (estrategias) y permitiendo que el cliente elija cuál usar en tiempo de ejecución. 6 | 7 | ### ¿Que es el principio abierto/cerrado? 8 | 9 | Es uno de los principios fundamentales de diseño de software dentro de los Principios SOLID. Este principio establece que: 10 | 11 | "Las entidades de software (clases, módulos, funciones) deben estar abiertas para extensión, pero cerradas para modificación." 12 | 13 | Esto significa que deberías poder extender el comportamiento de una clase o módulo sin tener que modificar su código fuente existente. Este enfoque ayuda a prevenir la introducción de errores en código ya probado y mejora la mantenibilidad del sistema. 14 | 15 | ### ¿Por que usar el patron strategy? 16 | 17 | En lugar de hacer que una clase tenga demaciados condicionales para manejar diferentes métodos, el patrón Strategy permite enviar el cálculo a una clase externa especializada haciendo el codigo mas legible y facil de escalar 18 | 19 | ### ¿Cuando utilizar el patron strategy? 20 | 21 | - Cuando tienes múltiples algoritmos, comportamientos o métodos para realizar una operación, como cálculos, validaciones, transformaciones, etc. 22 | 23 | - Cuando existen estructuras condicionales repetitivas 24 | 25 | - Cuando quieres cambiar el comportamiento de un objeto en tiempo de ejecución sin alterar su estructura interna. 26 | 27 | ### Ventajas 28 | 29 | - Flexibilidad: puedes agregar o cambiar estrategias sin modificar el contexto. 30 | 31 | - Reutilización: las estrategias son clases independientes que pueden reutilizarse en diferentes contextos. 32 | 33 | - Cumple con el principio de responsabilidad única: cada estrategia se encarga de un cálculo específico. 34 | 35 | ### Desventajas 36 | 37 | - Complejidad: aumenta el número de clases en el sistema. 38 | 39 | - Requiere diseño inicial claro: es más útil si se espera que haya múltiples algoritmos o comportamientos intercambiables. 40 | 41 | ### Ejemplo 42 | 43 | Imaginemos que queremos calcular el costo de envío dependiendo del método de transporte (terrestre, aéreo o marítimo), si implementamos esto sin el patron strategy nos quedaria un if === tipoTransporte por cada tipo de transporte que tengamos, lo que presentaria varios problemas principalmente la complejidad de escalar nuestro sistema, acoplamiento y violacion del principio abierto/cerrado. 44 | 45 | 46 | **Codigo** [`Strategy`](./Strategy.ts) 47 | 48 | ![Diagrama de clases Strategy](../../assets/StrategyPattern.jpg) 49 | -------------------------------------------------------------------------------- /Comportamiento/Command/Command.ts: -------------------------------------------------------------------------------- 1 | interface Command { 2 | execute(): void; 3 | undo(): void; 4 | } 5 | 6 | //receiver 7 | class TextEditor { 8 | private content: string = ""; 9 | 10 | addText(text: string) { 11 | this.content += text; 12 | console.log(`Content after add: "${this.content}"`); 13 | } 14 | 15 | removeText(count: number) { 16 | this.content = this.content.slice(0, -count); 17 | console.log(`Content after remove: "${this.content}"`); 18 | } 19 | 20 | getContent(): string { 21 | return this.content; 22 | } 23 | } 24 | 25 | 26 | //comandos concretos 27 | class AddTextCommand implements Command { 28 | private editor: TextEditor; 29 | private text: string; 30 | 31 | constructor(editor: TextEditor, text: string) { 32 | this.editor = editor; 33 | this.text = text; 34 | } 35 | 36 | execute() { 37 | this.editor.addText(this.text); 38 | } 39 | 40 | undo() { 41 | this.editor.removeText(this.text.length); 42 | } 43 | } 44 | 45 | class RemoveTextCommand implements Command { 46 | private removedText: string = ""; 47 | 48 | constructor( private editor: TextEditor, private count: number) {} 49 | 50 | execute() { 51 | this.removedText = this.editor.getContent().slice(-this.count); 52 | this.editor.removeText(this.count); 53 | } 54 | 55 | undo() { 56 | this.editor.addText(this.removedText); 57 | } 58 | } 59 | 60 | 61 | //clase invoker 62 | class CommandManager { 63 | private undoStack: Command[] = []; 64 | private redoStack: Command[] = []; 65 | 66 | executeCommand(command: Command) { 67 | command.execute(); 68 | this.undoStack.push(command); 69 | this.redoStack = []; // Limpiar la pila de rehacer cuando se ejecuta un nuevo comando 70 | } 71 | 72 | undo() { 73 | if (this.undoStack.length === 0) { 74 | console.log("Nothing to undo."); 75 | return; 76 | } 77 | const command = this.undoStack.pop()!; 78 | command.undo(); 79 | this.redoStack.push(command); 80 | } 81 | 82 | redo() { 83 | if (this.redoStack.length === 0) { 84 | console.log("Nothing to redo."); 85 | return; 86 | } 87 | const command = this.redoStack.pop()!; 88 | command.execute(); 89 | this.undoStack.push(command); 90 | } 91 | } 92 | 93 | 94 | //cliente 95 | const editor = new TextEditor(); 96 | const commandManager = new CommandManager(); 97 | 98 | // Ejecutar comandos 99 | commandManager.executeCommand(new AddTextCommand(editor, "Hello, ")); 100 | commandManager.executeCommand(new AddTextCommand(editor, "world!")); 101 | commandManager.executeCommand(new RemoveTextCommand(editor, 6)); 102 | 103 | // Deshacer acciones 104 | commandManager.undo(); // Rehacer "world!" 105 | commandManager.undo(); // Quitar "Hello, " 106 | commandManager.undo(); // Nada que deshacer 107 | 108 | // Rehacer acciones 109 | commandManager.redo(); // Rehacer "Hello, " 110 | commandManager.redo(); // Rehacer "world!" 111 | commandManager.redo(); // Nada que rehacer 112 | -------------------------------------------------------------------------------- /Comportamiento/State/State.ts: -------------------------------------------------------------------------------- 1 | // Interfaz del estado 2 | interface State { 3 | insertCoin(): void; 4 | pressButton(): void; 5 | dispense(): void; 6 | } 7 | 8 | // Contexto 9 | class VendingMachine { 10 | private state: State; 11 | 12 | // Estados concretos 13 | public noCoinState: State; 14 | public hasCoinState: State; 15 | public dispenseState: State; 16 | 17 | constructor() { 18 | this.noCoinState = new NoCoinState(this); 19 | this.hasCoinState = new HasCoinState(this); 20 | this.dispenseState = new DispenseState(this); 21 | 22 | // Estado inicial 23 | this.state = this.noCoinState; 24 | } 25 | 26 | setState(state: State): void { 27 | this.state = state; 28 | } 29 | 30 | getState(): State { 31 | return this.state; 32 | } 33 | 34 | insertCoin(): void { 35 | this.state.insertCoin(); 36 | } 37 | 38 | pressButton(): void { 39 | this.state.pressButton(); 40 | } 41 | 42 | dispense(): void { 43 | this.state.dispense(); 44 | } 45 | } 46 | 47 | // Estado concreto: no tiene monedas 48 | class NoCoinState implements State { 49 | constructor(private vendingMachine: VendingMachine) {} 50 | 51 | insertCoin(): void { 52 | console.log("Moneda insertada. Ahora puedes presionar el botón."); 53 | this.vendingMachine.setState(this.vendingMachine.hasCoinState); 54 | } 55 | 56 | pressButton(): void { 57 | console.log("Inserta una moneda primero."); 58 | } 59 | 60 | dispense(): void { 61 | console.log("Inserta una moneda primero."); 62 | } 63 | } 64 | 65 | // Estado concreto: tiene una moneda 66 | class HasCoinState implements State { 67 | constructor(private vendingMachine: VendingMachine) {} 68 | 69 | insertCoin(): void { 70 | console.log("Ya has insertado una moneda."); 71 | } 72 | 73 | pressButton(): void { 74 | console.log("Botón presionado. Dispensa en progreso."); 75 | this.vendingMachine.setState(this.vendingMachine.dispenseState); 76 | } 77 | 78 | dispense(): void { 79 | console.log("Presiona el boton para obtener el producto."); 80 | } 81 | } 82 | 83 | // Estado concreto: dispensa producto 84 | class DispenseState implements State { 85 | constructor(private vendingMachine: VendingMachine) {} 86 | 87 | insertCoin(): void { 88 | console.log("Espera a que termine el proceso de dispensa."); 89 | } 90 | 91 | pressButton(): void { 92 | console.log("Espera a que termine el proceso de dispensa."); 93 | } 94 | 95 | dispense(): void { 96 | console.log("Producto dispensado. Gracias por tu compra."); 97 | this.vendingMachine.setState(this.vendingMachine.noCoinState); 98 | } 99 | } 100 | 101 | // Uso 102 | const vendingMachine = new VendingMachine(); 103 | 104 | vendingMachine.pressButton(); // Inserta una moneda primero 105 | vendingMachine.insertCoin(); // Moneda insertada. Ahora puedes presionar el boton 106 | vendingMachine.insertCoin(); // Ya has insertado una moneda 107 | vendingMachine.pressButton(); // Boton presionado. en progreso 108 | vendingMachine.dispense(); // Producto entregado 109 | vendingMachine.dispense(); // Inserta una moneda primero 110 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Patrones de diseño en TypeScript 2 | 3 | Este repositorio contiene implementaciones de patrones de diseño utilizando TypeScript. Está organizado en tres categorías principales según el tipo de patrón: **Comportamiento**, **Creacionales** y **Estructurales**. El objetivo es proporcionar ejemplos claros y bien documentados de cada patrón para facilitar su comprensión y aplicación en proyectos TypeScript. 4 | 5 | ![PatronesDeDisenio](/assets/DesignPatterns.jpg) 6 | 7 | ## Estructura del Proyecto 8 | 9 | Actualmente, el repositorio está organizado en las siguientes carpetas: 10 | 11 | - **comportamiento**: Para patrones de diseño relacionados con cómo los objetos interactúan y se comunican entre ellos. 12 | - **creacionales**: Para patrones de diseño que se centran en la creación de objetos de manera flexible y reutilizable. 13 | - **estructurales**: Para patrones de diseño que se enfocan en cómo los objetos y clases se combinan para formar estructuras más grandes. 14 | 15 | ## Patrones Implementados 16 | 17 | ### Creacionales 18 | 19 | 1. **Factory Method** [`Creacionales/FactoryMethod`](./Creacionales/FactoryMethod/FactoryMethod.md) 20 | 21 | 2. **Abstract Factory** [`Creacionales/AbstractFactory`](./Creacionales/AbstractFactory/AbstractFactory.md) 22 | 23 | 3. **Prototype** [`Creacionales/Prototype`](./Creacionales/Prototype/Prototype.md) 24 | 25 | 4. **Builder** [`Creacionales/Builder`](./Creacionales/Builder/Builder.md) 26 | 27 | 5. **Singleton** [`Creacionales/Singleton`](./Creacionales/Singleton/Singleton.md) 28 | 29 | ### Estructurales 30 | 31 | 1. **Decorator** [`Estructurales/Decorator`](./Estructurales/Decorator/Decorator.md) 32 | 33 | 2. **Bridge** [`Estructurales/Bridge`](./Estructurales/Bridge/Bridge.md) 34 | 35 | 3. **Composite** [`Estructurales/Composite`](./Estructurales/Composite/Composite.md) 36 | 37 | 4. **Facade** [`Estructurales/Facade`](./Estructurales/Facade/Facade.md) 38 | 39 | 5. **Proxy** [`Estructurales/Proxy`](./Estructurales/Proxy/Proxy.md) 40 | 41 | 6. **Adapter** [`Estructurales/Adapter`](./Estructurales/Adapter/Adapter.md) 42 | 43 | 7. **Flyweight** [`Estructurales/Flyweight`](./Estructurales/Flyweight/Flyweight.md) 44 | 45 | ### Comportemiento 46 | 47 | 1. **Strategy** [`Comportamiento/Strategy`](./Comportamiento/Strategy/Strategy.md) 48 | 49 | 2. **Observer** [`Comportamiento/Observer`](./Comportamiento/Observer/Observer.md) 50 | 51 | 3. **TemplateMethod** [`Comportamiento/TemplateMethod`](./Comportamiento/TemplateMethod/TemplateMethod.md) 52 | 53 | 4. **Chain of responsability** [`Comportamiento/ChainOfResponsibility`](./Comportamiento/ChainOfResponsibility/ChainOfResponsibility.md) 54 | 55 | 5. **Command** [`Comportamiento/Command`](./Comportamiento/Command/Command.md) 56 | 57 | 6. **Iterator** [`Comportamiento/Iterator`](./Comportamiento/Iterator/Iterator.md) 58 | 59 | 7. **Mediator** [`Comportamiento/Mediator`](./Comportamiento/Mediator/Mediator.md) 60 | 61 | 8. **Memento** [`Comportamiento/Memento`](./Comportamiento/Memento/Memento.md) 62 | 63 | 9. **State** [`Comportamiento/State`](./Comportamiento/State/State.md) 64 | 65 | 10. **Visitor** [`Comportamiento/Visitor`](./Comportamiento/Visitor/Visitor.md) 66 | 67 | 68 | **Ejecutar codigo** 69 | ```bash 70 | # Navegar a la carpeta del patrón 71 | cd directorio 72 | 73 | # Ejecutar el código (asegúrate de tener TypeScript instalado) 74 | npx tsx archivo.ts 75 | ``` 76 | 77 | ## Requisitos 78 | 79 | - **Node.js** y **TypeScript** instalados 80 | 81 | --------------------------------------------------------------------------------