Introduccion

1

Patrones de Diseño Creacionales en Software

2

Patrones Creacionales: Singleton, Factory, Abstract Factory, Builder, Prototype

Singleton

3

Patrón Singleton: Implementación y Uso en Programación Orientada a Objetos

4

Diagrama de Clases del Patrón Singleton en JavaScript

5

Diferencias entre JavaScript y TypeScript en patrones de diseño

6

Ventajas y desventajas del patrón Singleton en diseño de software

Factory

7

Patrones de Diseño: Introducción al Patrón Factory

8

Patrón Factory: Implementación y Detalles Esenciales

9

Implementación del Patrón Factory Method en JavaScript

10

Comparación del Patrón Factory en JavaScript y TypeScript

11

Patrón Factory: Ventajas y Desventajas en Desarrollo de Software

Abstract Factory

12

Patrón Abstract Factory: Estrategia para Múltiples Fábricas de Coches

13

Patrones de Diseño: Abstract Factory en Producción de Coches

14

Implementación del patrón Abstract Factory en JavaScript

15

Diferencias entre JavaScript y TypeScript en el patrón Abstract Factory

16

Patrón Abstract Factory: Ventajas y Desventajas

Builder

17

Patrón Builder: Diseño y Aplicación en Producción de Vehículos

18

Patrón Builder: Análisis de Diagrama y Clases Relacionadas

19

Implementación del Patrón Builder en Producción de Coches

20

Comparación del Patrón Builder en JavaScript vs TypeScript

21

Patrón Builder: Ventajas, Desventajas y Aplicaciones Prácticas

Prototype

22

Patrón Prototype: Clonación de Objetos en Diseño de Software

23

Patrón Prototype en JavaScript y TypeScript

24

Implementación del Patrón Prototype en JavaScript

25

Comparación de Prototype en JavaScript y TypeScript

26

Patrón Prototype: Ventajas y Desafíos en Diseño de Software

Conclusiones

27

Patrones Creacionales en Diseño de Software

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Implementación del Patrón Factory Method en JavaScript

9/27
Recursos

¿Cómo implementar el Patrón Factory Method en JavaScript?

El Patrón Factory Method es una solución ideal para la creación de objetos cuando tienes una jerarquía de clases. Este patrón evita la necesidad de especificar la clase exacta de los objetos que se producen al delegar la responsabilidad de la creación a sus subclases. Te conduce a un código más limpio y flexible, permitiendo que las estructuras se adapten fácilmente a futuros cambios. Veamos cómo implementar este patrón en JavaScript paso a paso.

¿Cuál es el primer paso para implementar el patrón?

  1. Declaración de un producto base: Para comenzar, debes declarar una clase base o interfaz que será retornada por la clase Factory y sus subclases. En el ejemplo del curso, se usa una clase BaseCar que cuenta con un método que no está implementado.

    class BaseCar {
        showCost() {
            throw new Error('Method not implemented');
        }
    }
    

    Esta estructura alienta el uso de métodos abstractos, muy comunes en programación orientada a objetos, que definen la firma pero no la implementación del método.

¿Cómo se implementan los productos concretos?

  1. Definición de subclases concretas: Una vez creada la clase base, se procede a implementar productos concretos que heredan de esta clase. Estas subclases deben sobrescribir el método abstracto.

    class MastodonCar extends BaseCar {
        showCost() {
            console.log('Mastodon Car Cost: 300,000 pesos mexicanos');
        }
    }
    
    class RhinoCar extends BaseCar {
        showCost() {
            console.log('Rhino Car Cost: 100,000 pesos mexicanos');
        }
    }
    

    Esta etapa establece un enlace directo entre las clases específicas de los productos y la clase base.

¿Cuál es el papel de la clase Factory?

  1. Declaración de la clase Factory: Una clase Factory o interfaz debe crear objetos que coincidan con el producto base. Este es el esqueleto que obliga a sus subclases a implementar un método específico.

    class CarFactory {
        makeCar() {
            throw new Error('Method not implemented');
        }
    }
    

    Esto fortalece el concepto de polimorfismo, donde se espera que las subclases implementen este método con su lógica particular.

¿Cómo se crean las fábricas concretas?

  1. Implementación de fábricas concretas: Las fábricas concretas extienden la clase base de la fábrica, retornando productos específicos.

    class MastodonCarFactory extends CarFactory {
        makeCar() {
            return new MastodonCar();
        }
    }
    
    class RhinoCarFactory extends CarFactory {
        makeCar() {
            return new RhinoCar();
        }
    }
    

    Así se establece el puente entre las clases productoras y los productos concretos, dentro del patrón Method Factory.

¿Cómo se probó el patrón en la práctica?

Para demostrar el funcionamiento de esta estructura, se mostró cómo crear una aplicación que recibe una fábrica y produce el producto correspondiente, sin conocer de antemano qué tipo de fábrica utiliza.

function appFactory(factory) {
   const car = factory.makeCar();
   car.showCost();
}

appFactory(new MastodonCarFactory()); // Mastodon Car Cost: 300,000 pesos mexicanos
appFactory(new RhinoCarFactory()); // Rhino Car Cost: 100,000 pesos mexicanos

Aquí, la función appFactory es capaz de trabajar con cualquier variación de la fábrica, gracias a la uniformidad en la interfaz que provee el patrón.

¿Es posible una mejora creativa dentro del patrón Factory Method?

El instructor sugiere una sofisticación más, creando una función createFactory que extienda la versatilidad para crear fábricas basadas en strings.

function createFactory(type) {
   const factories = {
       Mastodon: MastodonCarFactory,
       Rhino: RhinoCarFactory
   };
   const Factory = factories[type];
   return new Factory();
}

appFactory(createFactory('Mastodon')); // Mastodon Car Cost: 300,000 pesos mexicanos
appFactory(createFactory('Rhino')); // Rhino Car Cost: 100,000 pesos mexicanos

Esta abstracción permite expandir el código sin dificultad, simplemente añadiendo más tipos al objeto factories.

Reflexión final: ¿Qué aprendiste?

Implementar el Patrón Factory Method no solo refuerza los conceptos de programación orientada a objetos como la herencia y el polimorfismo, sino que también promueve la creatividad en el diseño de software. Añade una herramienta poderosa a tu repertorio, lista para usarse en problemas que requieran la creación flexible y extensible de objetos. ¿Qué otras aplicaciones creativas imaginas que podría tener este patrón en tus futuros proyectos?

Aportes 11

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

¡Hola! Creería que a pesar que una clase abstracta pura y una interfaz puedan llegar a ser similares, hay algo importante a tener en cuenta y es que una clase abstracta pura se utiliza para definir una clase base de la cuál cada una de las subclases tienen relación, por otro lado, una interfaz se utiliza para definir un conjunto de métodos que deben ser implementados por diferentes clases y puede que exista una relación entre las clases que implementen esta interfaz como puede que sean clases no relacionadas de alguna forma, por lo que si usamos una clase abstracta pura o una interfaz variaría en el diseño y requerimientos de la aplicación.

class Animal {
  comer() {}
  dormir() {}
}

class Ave extends Animal {
  comer() {
    console.log("El ave está comiendo");
  }
  dormir() {
    console.log("El ave está durmiendo");
  }
}

const ave1 = new Ave();
ave1.comer();
/*la clase "Ave" extiende la clase base "Animal" y redefine los métodos "comer" y "dormir" para que muestren un mensaje específico para las aves. Luego, se crea una instancia de "Ave" y se llama al método "comer"*/

¡Hola!

Creería que al crear la función createFactory estamos aplicando el principio O de SOLID, en el que estamos abiertos a la extensión y cerrados a la modificación, en la que si queremos añadir un tipo de carro, solamente se debe de modificar la función createFactory sin modificar el código base de cada una de las clases de los carros, ¡Gracias por el ejemplo, Dani!

Agregué propiedades a la clase BaseCar las cuales se establecen desde cada uno de los productos concretos: ````js /** STEP 1 */ class BaseCar { constructor(name, year) { this.name = name; this.year = year; } showCost() { throw new Error("Method not implemented"); } } /** STEP 2 */ class MastodonCar extends BaseCar { constructor() { super("mastodon", 2024); } showCost() { console.log("Mastodon Car cost: 300,000 MXN"); } } class RhinoCar extends BaseCar { constructor () { super("rhino", 2024); } showCost() { console.log("Rhino Car cost: 100,000 MXN"); } } ```/\*\* STEP 1 \*/class BaseCar {  constructor(name, year) {    this.name = name;    this.year = year;  }   showCost() {    throw new Error("Method not implemented");  }} /\*\* STEP 2 \*/class MastodonCar extends BaseCar {  constructor() {    super("mastodon", 2024);  }   showCost() {    console.log("Mastodon Car cost: 300,000 MXN");  }} class RhinoCar extends BaseCar {  constructor () {    super("rhino", 2024);  }   showCost() {    console.log("Rhino Car cost: 100,000 MXN");  }} ````
interface BaseCar {
    showCost(): void
}

interface CarFactory {
    makeCar(): BaseCar
}

class RhinoCar implements BaseCar {
    public showCost(): void{
        console.log('Rhino Car Cost: $ 15.000')
    }
}

class MastodonCar implements BaseCar {
    public showCost(): void {
        console.log('Mastodon Car Cost: $ 20.000')
    }
}

class RhinoFactory implements CarFactory {
    public makeCar(): BaseCar {
        return new RhinoCar()
    }
}

class MastodonFactory implements CarFactory {
    public makeCar(): BaseCar {
        return new MastodonCar()
    }
}

function appFactory(factory: CarFactory): void {
    const car = factory.makeCar()
    car.showCost()
}

function createFactory(type: 'rhino' | 'mastodon'): CarFactory {
    const factories = {
        rhino: RhinoFactory,
        mastodon: MastodonFactory
    }

    const Factory = new factories[type]
    return Factory
}

appFactory(createFactory('rhino'))
appFactory(createFactory('mastodon'))
Usar objetos para almacenar funciones o métodos es muy útil para no usar tantos anidamientos if o switch
Agregué propiedades a la clase BaseCar las cuales se establecen desde cada uno de los productos concretos: /\*\* STEP 1 \*/class BaseCar {  constructor(name, year) {    this.name = name;    this.year = year;  }   showCost() {    throw new Error("Method not implemented");  }} /\*\* STEP 2 \*/class MastodonCar extends BaseCar {  constructor() {    super("mastodon", 2024);  }   showCost() {    console.log("Mastodon Car cost: 300,000 MXN");  }} class RhinoCar extends BaseCar {  constructor () {    super("rhino", 2024);  }   showCost() {    console.log("Rhino Car cost: 100,000 MXN");  }}```js /** STEP 1 */ class BaseCar { constructor(name, year) { this.name = name; this.year = year; } showCost() { throw new Error("Method not implemented"); } } /** STEP 2 */ class MastodonCar extends BaseCar { constructor() { super("mastodon", 2024); } showCost() { console.log("Mastodon Car cost: 300,000 MXN"); } } class RhinoCar extends BaseCar { constructor () { super("rhino", 2024); } showCost() { console.log("Rhino Car cost: 100,000 MXN"); } } ```
lo de las referencias me parecio un detalle muy elegante, lo seguire usando en mis codigos.
\#### Factory \> Este patrón consiste en definir clases tanto para las (fabricas especificas para instanciar productos específicos::fabricas) como para los productos las cuales implementan interfaces que son contratos genéricos para cada uno de las fabricas y productos. ```java public class Main {     public static void main(String\[] args) {         Factory factoryA = new ConcreteFactoryA();         Factory factoryB = new ConcreteFactoryB();         Product productA = factoryA.makeProduct();         Product productB = factoryB.makeProduct();         System.out.println(productA.doProductOperation());         System.out.println(productB.doProductOperation());     } } interface Product {     String doProductOperation(); } interface Factory {     Product makeProduct(); } class ProductA implements Product {     @Override     public String doProductOperation() {         return "making a ProductA product...";     } } class ProductB implements Product {     @Override     public String doProductOperation() {         return "making a ProductB product...";     } } class ConcreteFactoryA implements Factory {     @Override     public Product makeProduct() {         return new ProductA();     } } class ConcreteFactoryB implements Factory {     @Override     public Product makeProduct() {         return new ProductB();     } } ```

Estas clases están geniales! Hace meses estuve leyendo sobre patrones de diseño, y en ese momemto, me pareciaron temas muy crípticos. Pero con los ejemplos y las explicaciones, me están resultando muy digeribles.

Emocionado por continuar con las siguientes clases-.

La abstracción createFactory nos ofrece ambos beneficios de extensibilidad y reusabilidad. Depende de nosotros si vale la pena implementarlo dados nuestros requerimientos 🧐