Skip to content

Instantly share code, notes, and snippets.

@Whistler092
Last active May 19, 2020 11:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Whistler092/7875141e89a2cefb8326984776a9a5fd to your computer and use it in GitHub Desktop.
Save Whistler092/7875141e89a2cefb8326984776a9a5fd to your computer and use it in GitHub Desktop.
Ejemplos de código para el curso de patrones de diseño para UNIAJC
'use strict';
class HotDrink {
consume() {
/* abstract */
}
}
class Tea extends HotDrink {
consume() {
console.log(`Este té es rico con limón!`);
}
}
class Coffee extends HotDrink {
consume() {
console.log(`Este café es delicioso!`);
}
}
class HotDrinkFactory {
prepare(amount) {
/* abstract */
}
}
// Construyendo los factories para el Tea y el Coffee
class TeaFactory extends HotDrinkFactory {
prepare(amount) {
console.log(`Pon en la bolsa de té, hervir agua, verter ${amount}ml`);
return new Tea(); // Se retorna el objeto con fines de personalización.
}
}
class CoffeeFactory extends HotDrinkFactory {
prepare(amount) {
console.log(`Muele algunos granos, hervir agua, verter ${amount}ml`);
return new Coffee(); // Se retorna el objeto para personalización.
}
}
/*
// NOTA: Versión sin Abstract Factory
class HotDrinkMachine {
makeDrink(type) {
switch (type) {
case "tea":
return new TeaFactory().prepare(200);
case "coffee":
return new CoffeeFactory().prepare(50);
default:
throw new Error("");
}
}
}
let machine = new HotDrinkMachine();
let drink = machine.makeDrink("tea");
drink.consume();
*/
let AvailableDrink = Object.freeze({
coffee: CoffeeFactory,
tea: TeaFactory,
});
class HotDrinkMachine {
constructor() {
this.factories = {};
// Instanciamos todas las factories
for (let drink in AvailableDrink) {
this.factories[drink] = new AvailableDrink[drink]();
}
}
makeDrink(type, amount) {
console.log(`Ingresando parametros para preparar ${type}, en ${amount}ml`);
return this.factories[type].prepare(amount); //Retorna Objeto Tea o Coffee
}
}
// Ahora para poder usar la maquina correctamente.
let machine = new HotDrinkMachine();
// TÉ
let drinkTea = machine.makeDrink("tea", 200);
drinkTea.consume();
// CAFÉ
let drinkCoffee = machine.makeDrink("coffee", 50);
drinkCoffee.consume();
// Ingresando parametros para preparar tea, en 200ml
// Pon en la bolsa de té, hervir agua, verter 200ml
// Este té es rico con limón!
// Ingresando parametros para preparar coffee, en 50ml
// Muele algunos granos, hervir agua, verter 50ml
// Este café es delicioso!
class House {
/* Espacio para el objeto casa */
constructor() {
this.walls = this.floor = this.floor = `Sin definir`;
this.doors = 0;
}
}
class HouseBuilder {
constructor(house = new House()) {
this.house = house;
}
walls(walls) {
this.house.walls = walls;
return this; // Fluent Interface
}
floor(floor) {
this.house.floor = floor;
return this; // Fluent Interface
}
roof(roof) {
this.house.roof = roof;
return this; // Fluent Interface
}
doors(doors) {
this.house.doors = doors;
return this; // Fluent Interface
}
garage(garage) {
this.house.garage = garage;
return this; // Fluent Interface
}
swimmingPool(swimmingPool) {
this.house.swimmingPool = swimmingPool;
return this;
}
garden(garden) {
this.house.garden = garden;
return this;
}
build() {
return this.house;
}
}
let houseBuilder = new HouseBuilder();
let house = houseBuilder
.floor("piso de marmol")
.roof("techo en plancha")
.doors(3)
.garage("con garaje doble")
.swimmingPool("Con piscina de 30x30")
.build();
console.log(house);
/*
House {
floor: 'piso de marmol',
walls: 'Sin definir',
doors: 3,
roof: 'techo en plancha',
garage: 'con garaje doble',
swimmingPool: 'Con piscina de 30x30'
}
*/
'use strict';
class Builder
{
buildPart() { /* abstract */ }
buildWalls() { /* abstract */ }
buildFloor() { /* abstract */ }
buildRoof() { /* abstract */ }
buildDoors() { /* abstract */ }
}
class House
{
/* Espacio para el objeto casa */
constructor(){
this.walls = `Sin definir`;
this.floor = `Sin definir`;
this.floor = `Sin definir`;
this.doors = 0;
}
}
class HouseWithGarageBuilders extends Builder
{
constructor()
{
super();
}
buildPart()
{
this.house = new House();
this.buildWalls();
this.buildFloor();
this.buildRoof();
this.buildDoors();
// Paso en especifico para la implementación
this.buildGarage();
}
buildWalls() {
this.house.walls = `paredes blancas`;
}
buildFloor() {
this.house.floor = `piso de madera`;
}
buildRoof() {
this.house.floor = `techo en flecha`;
}
buildDoors() {
this.house.doors = 2;
}
buildGarage(){
this.house.garage = `con garaje`;
}
getResults()
{
return this.house;
}
}
class HouseLuxuryBuilders extends Builder
{
constructor()
{
super();
}
buildPart()
{
this.house = new House();
this.buildWalls();
this.buildFloor();
this.buildRoof();
this.buildDoors();
// Paso en especifico para la implementación
this.buildGarage();
this.buildSwimmingPool();
this.buildGarden();
}
buildWalls() {
this.house.walls = `paredes blancas en veneciano`;
}
buildFloor() {
this.house.floor = `piso de marmol`;
}
buildRoof() {
this.house.floor = `techo en flecha con atico`;
}
buildDoors() {
this.house.doors = 4;
}
buildGarage(){
this.house.garage = `con garaje doble`;
}
buildSwimmingPool(){
this.house.swimmingPool = `con piscina`;
}
buildGarden(){
this.house.garden = `con jardin`;
}
getResults()
{
return this.house;
}
}
class Director
{
construct(builder)
{
console.log(`Orquestando las operaciones de construcción`);
builder.buildPart();
return builder.getResults();
}
}
// Use the Builder
let luxHouse = new HouseLuxuryBuilders();
let withGarageHouse = new HouseWithGarageBuilders();
let director = new Director();
let newLuxHouse = director.construct(luxHouse);
// Orquestando las operaciones de construcción
let newWithGarageHouse = director.construct(withGarageHouse);
// Orquestando las operaciones de construcción
console.log(`Casa Lujosa:: ${JSON.stringify(newLuxHouse)}`);
/*
Casa Lujosa::
{
"walls": "paredes blancas en veneciano",
"floor": "techo en flecha con atico",
"doors": 4,
"garage": "con garaje doble",
"swimmingPool": "con piscina",
"garden": "con jardin"
}
*/
console.log(`Casa con Garaje:: ${JSON.stringify(newWithGarageHouse)}`);
/*
Casa con Garaje::
{
"walls": "paredes blancas",
"floor": "techo en flecha",
"doors": 2,
"garage": "con garaje"
}
*/
'use strict';
class LogisticalPackage {
Operation() {
/* abstract */
}
Add(Component) {
/* abstract */
}
Remove(Component) {
/* abstract */
}
GetChild(key) {
/* abstract */
}
}
class BoxContainer extends LogisticalPackage {
constructor(name) {
super();
this.name = name;
this.children = [];
console.log(`Creada un nuevo BoxContainer: ${this.name}`);
}
Operation() {
console.log("Ejecutando las operaciones de BoxContainer: " + this.name);
for (var i in this.children) this.children[i].Operation();
}
Add(Component) {
this.children.push(Component);
}
Remove(Component) {
for (var i in this.children)
if (this.children[i] === Component) this.children.splice(i, 1);
}
GetChild(key) {
let child = this.children[key];
console.log(`${this.name}: Obteniendo hijos ${child}`);
return child;
}
}
class Item extends LogisticalPackage {
constructor(name, price) {
super();
this.name = name;
this.price = price;
console.log(`Creado nuevo articulo ${this.name} $${this.price}`);
}
Operation() {
console.log(
`Ejecutando Operación para el Item: ${this.name} $${this.price}`
);
return this.price;
}
}
let caja1 = new BoxContainer("Caja de Celular");
// Creada un nuevo BoxContainer: Caja de Celular
caja1.Add(new Item("Celular", 800));
// Creado nuevo articulo Celular $800
caja1.Add(new Item("Audifonos", 100));
// Creado nuevo articulo Audifonos $100
let caja2 = new BoxContainer("Caja de Accesorios");
// Creada un nuevo BoxContainer: Caja de Accesorios
caja2.Add(new Item("Cargador Celular", 80));
// Creado nuevo articulo Cargador Celular $80
caja2.Add(new Item("Powerbank", 200));
// Creado nuevo articulo Powerbank $200
let cajaPrincipal = new BoxContainer("Envio #12345");
// Creada un nuevo BoxContainer: Envio #12345
cajaPrincipal.Add(caja1);
cajaPrincipal.Add(caja2);
cajaPrincipal.Operation();
/*
Ejecutando las operaciones de BoxContainer: Envio #12345
Ejecutando las operaciones de BoxContainer: Caja de Celular
Ejecutando Operación para el Item: Celular $800
Ejecutando Operación para el Item: Audifonos $100
Ejecutando las operaciones de BoxContainer: Caja de Accesorios
Ejecutando Operación para el Item: Cargador Celular $80
Ejecutando Operación para el Item: Powerbank $200
*/
"use strict";
class Shape {
/* abstract */
}
class Circle extends Shape {
constructor(radius = 0) {
super();
this.radius = radius;
}
resize(factor) {
this.radius *= factor;
}
toString() {
return `Un circulo de radio ${this.radius}`;
}
}
class ColoredShape extends Shape {
constructor(shape, color) {
super();
this.shape = shape;
this.color = color;
}
toString() {
return `${this.shape.toString()} tiene el color ${this.color}`;
}
}
class TransparentShape extends Shape {
constructor(shape, transparency) {
super();
this.shape = shape;
this.transparency = transparency;
}
toString() {
return `${this.shape.toString()} y una transparencia de ${
this.transparency * 100.0
}%`;
}
}
let circle = new Circle(2);
console.log(circle.toString());
// Un circulo de radio 2
// Decorador
let redCircle = new ColoredShape(circle, "rojo");
console.log(redCircle.toString());
// Un circulo de radio 2 tiene el color rojo
let redHalfCircle = new TransparentShape(redCircle, 0.5);
console.log(redHalfCircle.toString());
// Un circulo de radio 2 tiene el color rojo y una transparencia de 50%
"use strict";
//Integraciones con otros subsistemas
class BankHistory {
verify(name, amount) {
return 200;
}
}
class CreditHistory {
get(name) {
return [];
}
}
class PersonalProfile {
check(name) {
return [];
}
}
// Implementación del patrón façade
class Loans {
constructor(name) {
this.name = name;
}
ApplyFor(amount) {
let result = "APROVADO";
// Punto de acceso a multiples subsistemas
let bankScore = new BankHistory().verify(this.name, amount);
if (bankScore < 500) {
result = "RECHAZADO";
}
let negativeReports = new CreditHistory().get(this.name);
if (negativeReports.length > 0) {
result = "RECHAZADO";
}
let criminalRecords = new PersonalProfile().check(this.name);
if (criminalRecords.length > 0) {
result = "RECHAZADO";
}
return `${this.name}, su préstamo por valor de ${amount} ha sido ${result}`;
}
}
let prestamos = new Loans("Juanito Alimaña");
console.log(prestamos.ApplyFor(1000000));
// Juanito Alimaña, su préstamo por valor de 1000000 ha sido RECHAZADO
'use strict';
class Point {
// Constructor por defecto.
constructor(x, y) {
this.x = x;
this.y = y;
}
static factory() {
return PointFactory;
}
}
class PointFactory {
// Factory Method para coordenadas Cartesianas
static newCartesianPoint(x, y) {
return new Point(x, y);
}
// Factory Method para coordenadas Polares
static newPolarPoint(radio, angulo) {
return new Point(radio * Math.cos(angulo), radio * Math.sin(angulo));
}
}
// Generación de la instancia usando el método factory
let cartesianPoint = Point.factory().newCartesianPoint(4, 5);
console.log(cartesianPoint);
/*
Point
{
"x": 4,
"y": 5
}
*/
let polarPoint = Point.factory().newPolarPoint(5, Math.PI / 2);
console.log(polarPoint);
/*
Point
{
"x": 3.061616997868383e-16,
"y": 5
}
*/
"use strict";
class Event {
constructor() {
this.handlers = new Map();
this.count = 0;
}
subscribe(handler) {
this.handlers.set(++this.count, handler);
return this.count;
}
unsubscribe(idx) {
this.handlers.delete(idx);
}
// (sender) Quien ejecutó los eventos?
// (args) Argumentos adicionales (event args)
notify(sender, args) {
this.handlers.forEach((func, idx) => func(sender, args));
}
}
class MarketStore extends Event {
constructor(initInventory) {
super();
this.inventory = initInventory;
}
newInventoryArrived(newInventory) {
this.inventory = newInventory;
console.log(`MarketStore: Nuevo Inventario ha llegado:`, this.inventory);
let iPhoneArrived = this.inventory.filter((i) => i === "iPhone 1k");
if (iPhoneArrived.length > 0) {
this.notifyIphoneUsers();
}
}
notifyIphoneUsers() {
this.notify(
this,
`El nuevo iPhone ha llegado, ` +
`acercate a nuestras tiendas para llevártelo`
);
}
}
class Person {
constructor(name) {
this.name = name;
}
update = (sender, args) => {
console.log(`Una notificación de ${sender.name} ha llegado!`);
console.log(`${this.name}: ${args}`);
};
}
// Observador
let paul = new Person("Paul McCartney");
// Subject
let store = new MarketStore([]);
store.name = "Los Magníficos Store";
let paulId = store.subscribe(paul.update);
//let paulId = store.subscribe(paul.update);
// Nuevo Suscriptor Map { 1 => [Function: update] }
store.newInventoryArrived(["iPhone 1k", "iPad pro"]);
// MarketStore: Nuevo Inventario ha llegado: [ 'iPhone 1k', 'iPad pro' ]
/* Llega la notificación */
// Una notificación de Los Magníficos Store ha llegado!
// Paul McCartney: El nuevo iPhone ha llegado, acercate a nuestras tiendas para llevártelo
store.unsubscribe(paulId);
store.newInventoryArrived(["iPhone 1k", "Magic Mouse"]);
// MarketStore: Nuevo Inventario ha llegado: [ 'iPhone 1k', 'Magic Mouse' ]
/* No han llegado más notificaciones */
"use strict";
class TrafficLightState {
go() {
/* Abstract method */
}
}
class Red extends TrafficLightState {
constructor(context) {
super();
this.context = context;
}
go() {
console.log(`Red for 1 minute`);
this.context.change(new Yellow(this.context));
}
}
class Yellow extends TrafficLightState {
constructor(context) {
super();
this.context = context;
}
go() {
console.log(`Yellow for 10 seconds`);
this.context.change(new Green(this.context));
}
}
class Green extends TrafficLightState {
constructor(context) {
super();
this.context = context;
}
go() {
console.log(`Green for 1 minute`);
this.context.change(new Red(this.context));
}
}
/* Clase Contexto */
class TrafficLight {
constructor() {
this.count = 0;
this.currentState = null;
}
change(newState) {
if (this.count++ >= 10) return;
this.currentState = newState;
this.currentState.go();
}
start(initialState) {
this.currentState = initialState;
this.currentState.go();
}
}
let light = new TrafficLight();
let initialState = new Red(light);
light.start(initialState);
/*
Red for 1 minute
Yellow for 10 seconds
Green for 1 minute
Red for 1 minute
Yellow for 10 seconds
Green for 1 minute
Red for 1 minute
Yellow for 10 seconds
Green for 1 minute
Red for 1 minute
Yellow for 10 seconds
*/
"use strict";
let OutputFormat = Object.freeze({
markdown: 0,
html: 1,
});
class ListStrategy {
start(buffer) {}
end(buffer) {}
addListItem(buffer, item) {}
}
class MarkdownListStrategy extends ListStrategy {
addListItem(buffer, item) {
buffer.push(` * ${item}`);
}
}
class HtmlListStrategy extends ListStrategy {
start(buffer) {
buffer.push(`<ul>`);
}
end(buffer) {
buffer.push(`</ul>`);
}
addListItem(buffer, item) {
buffer.push(` <li>${item}</li>`);
}
}
class TextProcessor {
constructor(ouputFormat) {
this.buffer = [];
this.setOutputFormat(ouputFormat);
}
setOutputFormat(format) {
switch (format) {
case OutputFormat.markdown:
this.listStrategy = new MarkdownListStrategy();
break;
case OutputFormat.html:
this.listStrategy = new HtmlListStrategy();
break;
}
}
appendList(items) {
this.listStrategy.start(this.buffer);
for (let item of items) this.listStrategy.addListItem(this.buffer, item);
this.listStrategy.end(this.buffer);
}
// Métodos de útilidad.
clear() {
this.buffer = [];
}
toString() {
return this.buffer.join("\n");
}
}
let tp = new TextProcessor(OutputFormat.markdown);
tp.appendList([`factory`, `bridge`, `façade`]);
console.log(tp.toString());
// * factory
// * bridge
// * façade
tp.clear();
// Cambiamos a otro formato
tp.setOutputFormat(OutputFormat.html);
tp.appendList(["composite", "decorator", "state"]);
console.log(tp.toString());
// <ul>
// <li>composite</li>
// <li>decorator</li>
// <li>state</li>
// </ul>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment