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 Builder en Producción de Coches

19/27
Recursos

¿Qué es el patrón Builder y cómo se aplica a la producción de coches?

El patrón Builder es una de las técnicas más efectivas para manejar construcciones complejas en programación. En este contexto, implementamos el patrón Builder en la línea de producción de coches. Su objetivo principal es simplificar el proceso de creación de objetos complejos mediante la separación del proceso de creación en pasos pequeños y manejables. Aquí encontrarás los detalles de cómo se implementa este patrón en la producción de vehículos, utilizando específicamente JavaScript.

¿Cómo se define la clase base o interfaz Builder?

El primer paso para implementar el patrón Builder es definir una clase base o una interfaz que estipule los pasos generales para construir productos específicos. Para el contexto de producción de coches, definimos la clase CarProductionLine con métodos esenciales como la configuración de las bolsas de aire, el color y la edición del automóvil. Aquí un ejemplo de código:

class CarProductionLine {
    setAirbags(howMany) {
        throw new Error('Método no implementado');
    }
    setColor(color) {
        throw new Error('Método no implementado');
    }
    setEdition(edition) {
        throw new Error('Método no implementado');
    }
    resetProductionLine() {
        throw new Error('Método no implementado');
    }
}

Cada método en nuestra clase base arroja un error si no se implementa, asegurando que todas las clases constructoras deben definir estos métodos.

¿Cómo implementamos los builders concretos?

El segundo paso es implementar builders concretos para ofrecer diferentes implementaciones de los pasos definidos en la clase base. Por ejemplo, en la fábrica de sedanes creamos la clase SedanProductionLine que proporciona implementaciones concretas para el proceso de producción:

class SedanProductionLine extends CarProductionLine {
    setAirbags(howMany) {
        this.sedanCar.airbags = howMany;
        return this;
    }

    setColor(color) {
        this.sedanCar.color = color;
        return this;
    }

    setEdition(edition) {
        this.sedanCar.edition = edition;
        return this;
    }

    resetProductionLine() {
        const model = this.internalModel;
        this.sedanCar = model === 'Mastodon' ? new Mastodon() : new Rhino();
    }
}

Gracias al uso de this, podemos encadenar métodos de manera elegante y eficiente, facilitando la personalización del vehículo.

¿Cuál es la finalidad de la clase director y cómo se usa?

La clase director tiene la responsabilidad de conocer y definir el proceso exacto para construir las variaciones del producto. Así, se establece un orden en los pasos de construcción. Aquí se muestra cómo configuramos un director para gestionar la construcción de diferentes ediciones de coches:

class Director {
    setBuilder(builder) {
        this.productionLine = builder;
    }

    constructCVTEdition() {
        this.productionLine.setAirbags(4).setColor('Azul').setEdition('CVT');
    }

    constructSignatureEdition() {
        this.productionLine.setAirbags(8).setColor('Rojo').setEdition('Signature');
    }
}

El director garantiza que se sigan los pasos en un orden particular y permite la reutilización del mismo builder para diferentes configuraciones de productos.

¿Cómo se gestiona la creación de productos finales?

Impulsado por el director, el builder es capaz de ensamblar el producto y entregarlo ya configurado, manteniendo el estado del proceso y asegurando que el producto esté listo para ser utilizado:

const director = new Director();
const mastodonProductionLine = new SedanProductionLine('Mastodon');
director.setBuilder(mastodonProductionLine);
director.constructCVTEdition();

const mastodonCar = mastodonProductionLine.build();
console.log(mastodonCar);

El método build retorna el coche resultado de la configuración asignada, mostrando cómo los diversos métodos de construcción afectan al producto final.

¿Qué aporta el patrón Builder al desarrollo de software?

Implementar el patrón Builder no solo organiza el código sino que permite manejar de manera flexible la creación de objetos complejos, reduciendo el riesgo de errores y ofreciendo un código más mantenible. Mediante la separación de las acciones de construcción en varias clases, incluyendo los builders y el director, las responsabilidades están claramente definidas y desacopladas. Además, esta estructura es especialmente valiosa cuando se espera que los productos entren y salgan del proceso de producción de diferentes maneras en función de ciertos parámetros.

¡Ahora es tu turno de aplicar el patrón Builder y ver cómo se adapta a tus necesidades de desarrollo! Recuerda, la práctica es clave para dominar cualquier metodología de programación. ¡Sigue adelante y sigue construyendo!

Aportes 16

Preguntas 1

Ordenar por:

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

Super tediosa la implementación en JS

No termino de entender por qué al curso no le pusieron directamente "**Patrones de Diseño Creacionales en TypeScript**"... con toda la sinceridad del mundo, dejando aparte lo increíblemente retorcidos y poco aplicables que son los ejemplos y el tema autos (que me parece de plano una elección poco acertada y compleja al punto de haber tenido que googlear cada término para entender de qué estábamos hablando), las implementaciones en JavaScript van en contra de todo lo que uno quiere para su código: infinidad de líneas, cantidad de clases y código completamente genérico que no cumple ningún papel, y un largo etc. **POV:** Muy poca motivación para continuar cursando... pero está como obligatorio para la rama de JavaScript... asique a seguir sufriendo cada vez un poco más con cada clase... ya ni ganas tengo de abrir el editor de código.

Lo veo muy util para abstraer la complejidad de la construcción de objetos cuyo constructor requiere varios parámetros y no siempre son obligatorios. Una clase Builder, abstrae esta complejidad y facilita el uso del objeto. En este ejemplo más de la vida real he imaginado como pagar la liquidación de un empleado, en este caso hay varios factores que intervienen en el cálculo. Aquí es donde entra el patrón:

class Liquidation {
    private basicSalaryMontly: number;
    private monthsWorked: number;
    private pendingHolyDays: number;
    private premiumEndYear: number;
    private premiumMediumYear: number;
    private layoffs: number;

    /**
     *
     */
    constructor(
        basicSalaryMontly: number,
        monthsWorked: number,
        pendingHolyDays: number,
        premiumEndYear: number,
        premiumMediumYear: number,
        layoffs: number) {

        this.basicSalaryMontly = basicSalaryMontly;
        this.monthsWorked = monthsWorked;
        this.pendingHolyDays = pendingHolyDays;
        this.premiumEndYear = premiumEndYear;
        this.premiumMediumYear = premiumMediumYear;
        this.layoffs = layoffs;
    }

    Calculate() {
        const totalPendingHollyDays = ((this.basicSalaryMontly / 30) * 365) * this.pendingHolyDays;
        const total = (this.basicSalaryMontly * this.monthsWorked) + totalPendingHollyDays + this.premiumEndYear + this.premiumMediumYear + this.layoffs;
        console.log("Vacaciones pendientes: ", totalPendingHollyDays);
        console.log("Liquidación Total ", total);
    }
}

class LiquidationBuilder {
    private basicSalaryMontly: number;
    private monthsWorked: number;
    private pendingHolyDays: number;
    private premiumEndYear: number;
    private premiumMediumYear: number;
    private layoffs: number;


    setBasicSalaryMonth(basicSalaryMontly: number): LiquidationBuilder {
        this.basicSalaryMontly = basicSalaryMontly;
        return this;
    }

    setMothsWorked(monthsWorked: number): LiquidationBuilder {
        this.monthsWorked = monthsWorked;
        return this;
    }

    setPendingHollyDays(pendingHolyDays: number): LiquidationBuilder {
        this.pendingHolyDays = pendingHolyDays;
        return this;
    }

    setPremiumEndYear(premiumEndYear: number): LiquidationBuilder {
        this.premiumEndYear = premiumEndYear;
        return this;
    }

    setPremiumMediumYear(premiumMediumYear: number): LiquidationBuilder {
        this.premiumMediumYear = premiumMediumYear;
        return this;
    }

    setLayoffs(layoffs: number): LiquidationBuilder {
        this.layoffs = layoffs;
        return this;
    }

    build(): Liquidation {
        return new Liquidation(this.basicSalaryMontly, this.monthsWorked, this.pendingHolyDays,
            this.premiumEndYear, this.premiumMediumYear, this.layoffs);
    }
}

const total = new LiquidationBuilder()
    .setBasicSalaryMonth(4500)
    .setLayoffs(500)
    .setMothsWorked(15)
    .setPremiumEndYear(1000)
    .setPremiumMediumYear(0)
    .setPendingHollyDays(15)
    .build();

console.log(total);
console.log(total.Calculate());

¡Hola!

Considero que sería bueno para el curso darnos un ejemplo de aplicar este patrón de diseño no tan complejo, algo más corto y ahí si complementar con el ejemplo de los carros que se lleva trabajando en los anteriores patrones de diseño y ahondar un poco más en los requerimientos, con más diagramas y un puntero explicando la historia de usuario, considero que en esta clase se agregó un nivel de complejidad para aplicar el patrón a este ejemplo que quizás se puede ver un poco forzado, sería tener una introducción al patrón Builder más corta y ahí pasar a este ejemplo, algo más sencillo podría ser el proceso de creación de una pizza con Builder como el siguiente:

// Clase Pizza
class Pizza {
  private dough: string;
  private sauce: string;
  private cheese: string;
  private toppings: string[];

  constructor(
    dough: string,
    sauce: string,
    cheese: string,
    toppings: string[]
  ) {
    this.dough = dough;
    this.sauce = sauce;
    this.cheese = cheese;
    this.toppings = toppings;
  }

  public getDough(): string {
    return this.dough;
  }

  public getSauce(): string {
    return this.sauce;
  }

  public getCheese(): string {
    return this.cheese;
  }

  public getToppings(): string[] {
    return this.toppings;
  }
}

// Builder
class PizzaBuilder {
  private dough: string;
  private sauce: string;
  private cheese: string;
  private toppings: string[];

  constructor() {
    this.toppings = [];
  }

  public setDough(dough: string): PizzaBuilder {
    this.dough = dough;
    return this;
  }

  public setSauce(sauce: string): PizzaBuilder {
    this.sauce = sauce;
    return this;
  }

  public setCheese(cheese: string): PizzaBuilder {
    this.cheese = cheese;
    return this;
  }

  public addTopping(topping: string): PizzaBuilder {
    this.toppings.push(topping);
    return this;
  }

  public build(): Pizza {
    return new Pizza(this.dough, this.sauce, this.cheese, this.toppings);
  }
}

// Uso
const pizza = new PizzaBuilder()
  .setDough('thin')
  .setSauce('tomato')
  .setCheese('mozzarella')
  .addTopping('mushrooms')
  .addTopping('olives')
  .addTopping('onions')
  .build();

console.log(pizza.getDough()); // thin
console.log(pizza.getSauce()); // tomato
console.log(pizza.getCheese()); // mozzarella
console.log(pizza.getToppings()); // ['mushrooms', 'olives', 'onions']

En el anterior ejemplo, no se dejó una clase Director ya que según refactoring.guru una clase Director no es estrictamente necesaria (aunque recomendada), también recomiendo écharle un vistazo al link para mayor entendimiento de este patrón de diseño.

¡Gracias por la clase!

Recomiendo el uso de ejemplos más cortos, más sencillos, más explicables. O también podríamos tener otro curso que sea exclusivamente práctico por ejemplo que tenga 20 proyectos. 5 proyectos por cada tipo de patrón de diseño creacional en Javascript. Pienso que de esa forma podríamos estar más conformes.
<https://www.youtube.com/watch?v=5et6PxMDVXo&ab_channel=MarluanEspiritusanto> Un ejemplo👆 un poco diferente que me ayudo a entender.

Otro ejemplo diferente en python

class Car:
    def __init__(self):
        self.brand = None
        self.model = None
        self.color = None
        self.engine = None
        self.transmission = None

    def __str__(self):
        return f"Coche: {self.brand} {self.model}, Color: {self.color}, Motor: {self.engine}, Transmisión: {self.transmission}"

class CarBuilder:
    def __init__(self):
        self.car = Car()

    def set_brand(self, brand):
        self.car.brand = brand
        return self

    def set_model(self, model):
        self.car.model = model
        return self

    def set_color(self, color):
        self.car.color = color
        return self

    def set_engine(self, engine):
        self.car.engine = engine
        return self

    def set_transmission(self, transmission):
        self.car.transmission = transmission
        return self

    def build(self):
        return self.car

class CarDirector:
    def __init__(self, builder):
        self.builder = builder

    def construct_sports_car(self):
        return self.builder.set_brand("Ferrari") \
                          .set_model("488 GTB") \
                          .set_color("Rojo") \
                          .set_engine("V8") \
                          .set_transmission("Automática") \
                          .build()

    def construct_suv(self):
        return self.builder.set_brand("BMW") \
                          .set_model("X5") \
                          .set_color("Negro") \
                          .set_engine("V6") \
                          .set_transmission("Automática") \
                          .build()

# Uso del Builder y el Director para construir diferentes tipos de coches
builder = CarBuilder()
director = CarDirector(builder)

sports_car = director.construct_sports_car()
suv = director.construct_suv()

print(sports_car)
print(suv)
Complicada
No entiendo la necesidad de ser críptico en la explicación. Estoy intentando hacer un paso a paso en mis notas de la clase y alrededor del minuto 10 el instructor empieza a colocar variables que se supone debo adivinar. Si me pareció errado colocar la palabra reservada super sin estar heredando nada de la clase base, pero como se supone que voy a adivinarlo si quien tiene el código en la cabeza es el? No me gusta este profesor la verdad. Siento que se enreda solo en su explicación.
he visto lo primera parte del video unas 3 veces y no entiendo el porque de la funcion resetbuilder¡ alguien me lo puede explicar porfa.
este codigo me esta volando la cabeza, creo que necesitare tiempo extra para entenderlo e interiorisarlo
Interesante saber que se pudo implementar este patrón en JS. Sin embargo, fue demasiado tedioso, demasiadas clases... JS esta muy enfocado en programación funcional ? O Es lo que siempre he visto, ha sido tedioso pero divertido ver estas implementaciones en JS.
Tengo unas dudas...  Primero: por qué crear 2 métodos "construct" específicos, en vez de 1 que reciba parámetros como la cantidad de airbags, color y edición? Algo así dentro de la clase Director: ```txt construct(airbags, color, edition) { this.productionLine .setAirBags(airbags) .setColor(color) .setEdition(edition); } ``` Segundo: por qué si el Director es quien "construye" el carro, no es el mismo Director el que "arme" (build). De esa manera no es necesario manejar la instancia de la línea de producción que se esté trabajando, sino que el Director se encarga de eso. Nuevamente dentro de la clase Director: ```js build(){ return this.productionLine.build() } ```Entonces en el appBuilder, se puede llamar de esta manera: ```js const mastodonSedanProductionLine = new SedanProductionLine({ modelToCustomizeInLine: 'mastodon', }); director.construct(airbags=4, color='blue', edition='CVT'); const mastodnSedanCvt = director.build(); console.log('--- Mastodon Sedan CVT ---\n', mastodnSedanCvt); ```En la explicación, hay un pequeño error creo: ```js * 2. Implement concrete builders subclasses that offer different * versions of the build steps. These builders could create * concrete products or base ones. Depends on what we need. * * SedanProductionLine: build() -> {Mastodon|Rhino}Car | Car * RhinoProductionLine: build() -> {Mastodon|Rhino}Car | Car ```Dice RhinoProductionLine, cuando entiendo debería ser HatchbackProductionLine, porque hace referencia al Tipo de vehículo y no al modelo.
🟢 La verdad con el ejemplo de los carros tomo mas complejidad, después de revisar paso por paso las líneas de código y con el diagrama, pude entender la explicación de las clases anteriores, <u>la división de pasos para la creación de un objeto</u> y **además con la anidación de funciones**.
ufff patron builder agregado mentalmente al terminar el ejercicio completo y revisarlo una hora jajaja, pero quedó entendido.... la idea basica es devolver un objeto que esta construido por pequeñas partes de una clase llamada "Builder". Si estoy mal me corrijen... sino a seguir aprendiendo !

Se me ocurren dos formas de variar la implementación de la clase Director:

  1. Un director por cada línea de producción
    No sé si estoy equivocado, pero se me ocurre que es buena idea tener varios directores, cada uno encargado de una línea de producción y que la reciba por el método constructor al instanciarse.
  2. Director basado en métodos estáticos
    El ejemplo del profesor podría funcionar perfecto sin tener que instanciar un director. Si asumimos que todos los métodos mostrados en clase fueras estáticos, podríamos hacer esto:
    Director.setProductionLine(mastodonSedanProductionLine).constructCvtEdition()