No tienes acceso a esta clase

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

Implementación de Builder en JS

19/27
Recursos

Aportes 14

Preguntas 1

Ordenar por:

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

Super tediosa la implementación en JS

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());
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.

¡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)
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()