Super tediosa la implementaci贸n en JS
Introduccion
D贸nde estamos y hacia d贸nde vamos
Patrones creacionales
Singleton
Singleton 101
Implementaci贸n de Singleton en JS
Contrastemos: Singleton con TS
Singleton: pros y contras
Factory
Factory 101
Diagrama de implementaci贸n de Factory
Implementaci贸n de Factory en JS
Contrastemos: Factory en TS
Factory: pros y contras
Abstract Factory
Abstract Factory 101
Diagrama de implementaci贸n de Abstract Factory
Implementaci贸n de Abstract Factory en JS
Contrastemos: Abstract Factory en TS
Abstract Factory: pros y contras
Builder
Builder 101
Diagrama de implementaci贸n de Builder
Implementaci贸n de Builder en JS
Contrastemos: Builder en TS
Builder: pros y contras
Prototype
Prototype 101
Diagrama de implementaci贸n de Prototype
Implementaci贸n de Prototype en JS
Contrastemos: Prototype en TS
Prototype: pros y contras
Conclusiones
驴Qu茅 sigue sobre patrones de dise帽o?
You don't have access to this class
Keep learning! Join and start boosting your career
The Builder pattern is one of the most effective techniques for handling complex constructions in programming. In this context, we implemented the Builder pattern in the car production line. Its main goal is to simplify the process of creating complex objects by separating the creation process into small and manageable steps. Here you will find the details of how this pattern is implemented in car production, specifically using JavaScript.
The first step in implementing the Builder pattern is to define a base class or interface that stipulates the general steps for building specific products. For the car production context, we define the CarProductionLine
class with essential methods such as airbag configuration, color, and car editing. Here is a code example:
class CarProductionLine { setAirbags(howMany) { throw new Error('Method not implemented'); } setColor(color) { throw new Error('Method not implemented'); } setEdition(edition) { throw new Error('Method not implemented'); } resetProductionLine() { throw new Error('Method not implemented'); } }}
Each method in our base class throws an error if it is not implemented, ensuring that all builder classes must define these methods.
The second step is to implement concrete builders to provide different implementations of the steps defined in the base class. For example, in the sedan factory we create the SedanProductionLine
class that provides concrete implementations for the production process:
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(); } }}
Thanks to the use of this
, we can chain methods in an elegant and efficient way, facilitating the customization of the vehicle.
The director class is responsible for knowing and defining the exact process to build the variations of the product. Thus, it establishes an order in the construction steps. Here is how we set up a director to manage the build of different car editions:
class Director { setBuilder(builder) { this.productionLine = builder; } }
constructCVTEdition() { this.productionLine.setAirbags(4).setColor('Blue').setEdition('CVT'); } }
constructSignatureEdition() { this.productionLine.setAirbags(8).setColor('Red').setEdition('Signature'); } }}
The director ensures that the steps are followed in a particular order and allows reuse of the same builder for different product configurations.
Driven by the director, the builder is able to assemble the product and deliver it already configured, maintaining the state of the process and ensuring that the product is ready to be used:
const director = new Director();const mastodonProductionLine = new SedanProductionLine('Mastodon');director.setBuilder(mastodonProductionLine);director.constructCVTEdition();
const mastodonCar = mastodonProductionLine.build();console.log(mastodonCar);
The build
method returns the car resulting from the assigned configuration, showing how the various build methods affect the final product.
Implementing the Builder pattern not only organizes the code but also allows flexible handling of the creation of complex objects, reducing the risk of errors and providing more maintainable code. By separating build actions into several classes, including builders and the manager, responsibilities are clearly defined and decoupled. In addition, this structure is especially valuable when products are expected to enter and exit the production process in different ways based on certain parameters.
Now it's your turn to apply the Builder pattern and see how it fits your development needs! Remember, practice is key to mastering any programming methodology - go ahead and keep building!
Contributions 16
Questions 1
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());
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!
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)
Se me ocurren dos formas de variar la implementaci贸n de la clase Director:
Director.setProductionLine(mastodonSedanProductionLine).constructCvtEdition()
Want to see more contributions, questions and answers from the community?