Categorías
Desarrollo y Programación

Patrón de Diseño: Fábrica Abstracta (Abstract Factory)

Este patrón es parte de los patrones de diseño creacionales.

Estos patrones se tratan de instancias clases. Los patrones de diseño creacionales pueden ser divididos en 2 tipos, por creación de clase (que utiliza la magia de la herencia) y por creación de objetos (que delega las responsabilidades como un profesional).

Fábrica Abstracta (Abstract Factory)

  • Brinda una interface para la creación de familias relacionadas u objetos dependientes sin especificar una clase concreta.
  • Una jerarquía que encapsula: las posibles plataformas, y la construcción de un conjunto de productos.
  • El operador new es nocivo para este tipo de patrón.

Problemática

Cuando una aplicación necesita portabilidad, es necesario encapsular las dependencias por plataforma. Estas plataformas pueden incluir, Sistema de ventanas, el sistema operativo, el tipo de dispositivo, las bases de datos, etc.

Por lo general si esta encapsulación no es pensada a futuro, llegarán a existir muchos condicionales (if, elseif) que le dan soporte a los distintos tipos de plataformas, que se van multiplicando a lo largo del proyecto cada vez que se necesita una nueva plataforma.

Estructura

El patrón de Fábrica Abstracta define un método (factory) por producto. Cada método encapsula el operador “new” y las clases de los productos por plataforma. Cada plataforma debe ser modelada con una clase derivada de la Factory.

Ejemplo

El propósito de la Fábrica Abstracta es proveer una interface para la creación de familias de objetos relacionados, sin especificar clases concretas.

Este patrón se encuentra en una fábrica de moldeado de autopartes. El equipo de corte y moldeo es la Fábrica Abstracta la cual crea las autopartes. La misma maquinaria es utilizada para cortar las puertas, los cofres, las cajuelas, etc. Para diferentes modelos de coches. A través del uso de rodillos que cambian el tipo de acabado, las clases concretas son producidas por la maquinaria que puede ser cambiada en menos de 3 minutos.

Consideraciones para elegir la fábrica abstracta

  • Decidir si la independencia de la plataforma y los servicios de creación son el principal problema.
  • Crear una matriz de plataformas contra productos.
  • Definir una interface factory que consista de  un método factory por producto.
  • Definir una clase factory derivada por cada plataforma que encapsule todas las referencias al operador new.
  • El cliente debería quitar todas las referencias a new, y utilizar los métodos factory para crear los productos.

Reglas

Algunas veces los patrones creacionales con competencia, y en toros casos con complementarios. Una Fábrica Abstracta puede tener un conjunto de Prototipos de los cuales clonar y retornar objetos de productos.

Los constructores pueden utilizar otros patrones para implementar los componentes a construir. Fabrica Abstracta, Constructor y Prototipo pueden utilizarse como Singleton en sus implementaciones.

Los tres definen un objeto factory que es el responsable de crear las clases para los objetos de producto.

  • Fábrica Abstracta; se encarga de la creación de objetos produciéndolos desde distintas clases.
  • Builder (Construsctor): es un objeto Factory que construye un producto complejo utilizando un protocolo definido.
  • Prototipo: es un objeto factory que construye el producto copiando un objeto prototipo.

El builder se enfoca en construir un objeto complejo paso a paso. La Fábrica Abstracta se enfatiza en una familia de productos. Al final el Builder retorna ese producto.

A menudo los diseños empiezan utilizados un Método Factory (poca complejidad, personalizable, lleno de subclases) y evoluciona en torno a Prototype, o Builder (a veces mas flexible, a veces más complejo) según como el diseñador infiera donde esa flexibilidad es necesaria.

Fábrica Abstracta en Typescript

El código de ejemplo esta en: https://github.com/elporfirio/design-patterns-typescript/tree/master/abstract_factor

Supongamos que tengo una fábrica de productos de videojuegos, donde grabo los discos e imprimo portadas. Para ello tengo una serie de clases definidas para los productos:

/**
 * Game Products Classes
 */
export abstract class AbstractDisc {
    abstract getTitle();

    abstract getGenre();
}

export abstract class AbstractCover {
    abstract getSize();

    abstract getPaperType();
}

abstract class AbstractCallOfDuty {
    private gameSeries = 'Call of Duty';

    getGameSeries() {
        return this.gameSeries;
    }
}

export class CallOfDutyDisc extends AbstractCallOfDuty implements AbstractDisc {
    private title = 'Modern Warfare';
    private genre = 'FPS';

    getTitle() {
        return this.title;
    }

    getGenre() {
        return this.genre;
    }
}

export class CallOfDutyCover extends AbstractCallOfDuty implements AbstractCover {
    private size = '4x6';
    private paperType = 'couche';

    getSize() {
        return this.size;
    }

    getPaperType() {
        return this.paperType;
    }
}

Esos productos son producidos para 2 plataformas, PlayStation y Xbox para lo cual defino mis clases fabrica:

import { CallOfDutyCover, CallOfDutyDisc} from "./product_classes";

/**
 * Game Factory Classes
 */
export abstract class AbstractGameFactory {
    abstract makeDisc();

    abstract makeCover();
}

export class PS4GameFactory extends AbstractGameFactory {
    private brand = 'Sony';

    makeDisc() {
        return new CallOfDutyDisc();
    }

    makeCover() {
        return new CallOfDutyCover();
    }
}

export class XBOXGameFactory extends AbstractGameFactory {
    private brand = 'Microsoft';

    makeDisc() {
        return new CallOfDutyDisc;
    }

    makeCover() {
        return new CallOfDutyCover;
    }
}

Por último lo que tengo que hacer es echar a andar mi fábrica, tan fácil como solo correr mis distintos tipos:

import {PS4GameFactory, XBOXGameFactory} from "./factory_clases";

export class GameMaker {
    public constructor() {
        const ps4Game = new PS4GameFactory();
        this.tester(ps4Game);

        const xboxGame = new XBOXGameFactory();
        this.tester(xboxGame);
    }

    tester(game) {
        const cover = game.makeCover();
        const disc = game.makeDisc();

        console.log('==============');

        console.log(cover.getPaperType());
        console.log(cover.getSize());

        console.log(disc.getGenre());
        console.log(disc.getTitle());

        console.log('==============');
    }
}

Por cierto si quieres correrlo no uno que se haría es un new GameMaker();

Y eso es todo, ¿qué pasaría si necesito otro juego, como el Dragon Ball FighterZ?, simplemente tendríamos que agregar ese nuevo producto a nuestra clase producto.

¿Y si ahora queremos Nintendo Switch?, 🤯 bueno pues hay que agregarlo a nuestras fabricas. Y así se logra la combinación de fábrica abstracta con sus productos, por supuesto al inicio parece no tener mucha utilidad.

Sin embargo imaginen hacer una fábrica en base a módulos nuevos o simples archivos .json. Agregar y quitar fábricas en desuso sería tan fácil como agregar y eliminar archivos.
Y ya está, felices arquitecturas 😬

Categorías
Desarrollo y Programación

Importar y Exportar con Javascript ES6

Bienvenidos a otra valiosa información en internet totalmente en español, en esta ocasión vamos a ver cómo importar y exportar variables, funciones, expresiones y clases con JavaScript.

Actualizaciones:
– Elimine paréntesis de la declaración de clases

Exports Default

Cuando se utiliza un default para exportar, se puede utilizar cualquier nombre para importar.

Función Anónima

// helpers.js
export default function() {
  // Do something
}

// index.js
import Awesomeness from './helpers'

console.log(Awesomeness); // ƒ(){}

Función

// helpers.js
export default function hiDude() {
  // Do something
}

// index.js
import Awesomeness from './helpers'

console.log(Awesomeness); // ƒ hiDude(){}

No es posible tener más de un “export default” en un archivo, así que no lo intentes en casa.

– La comunidad PRO de JavaScript

Clase Anónima

Recordar que las clases son un tipo de objeto con superpoderes.

// classes.js
export default class {
  // rest of class
}

// index.js
import ImportantClass from './classes'

console.log(ImportantClass); // ƒ _default(){}

Clase

// classes.js
export default class Person {
  // rest of class
}

// index.js
import ImportantClass from './classes'

console.log(ImportantClass); // ƒ Person(){}

Variables

// constants.js
const PI = 3.1416;
export default PI;

// index.js
import PIValue from './constants'

console.log(PIValue); // 3.1416

Otro método para exportar variables:

// constants.js
const PI = 3.1416;
export {PI as default};

// index.js
import PIValue from './constants'

console.log(PIValue); // 3.1416

Este último también sirve para las funciones:

// constants.js
function getPI(){
  return 3.1416
}
export {getPI as default};

// index.js
import PIValue from './constants'

console.log(PIValue); // ƒ getPI(){}

Named Exports

A diferencia de los default, en este tipo si es necesario dar un nombre a nuestra variable, método, etc.

Exportar por separado

export function add(){
  // add something
}

export class Person {
  // class definition
}

export const PI = 3.1416;

export let car = {
  paintColor: 'red'
}

Exportar todo en una sentencia

function add(){
  // add something
}

class Person {
  // class definition
}

const PI = 3.1416;

let car = {
  paintColor: 'red'
}

export { add, Person, PI, car };

Para importar estos elementos (cualquiera de las 2 formas anteriores) es necesario utilizar el nombre que se les dio al momento de exportar:

import { add, Person, PI, car } from './helpers'

console.log(add); // ƒ add(){}
console.log(Person); // ƒ Person(){}
console.log(PI); // 3.1416
console.log(car); // { paintColor: 'red' }

Exportar named y default

En el caso de las named, deben importarse entre los corchetes y el default queda fuera de los corchetes.

// important.js
export add() {
  // do add
}

export const maxValue = 999;

export default class Calculator {
  // Calculator class
}
// index.js
import Calc, { maxValue, add } from './important'

// Recordar que el default no importa el nombre
console.log(Calc); // ƒ Calculator() {}
console.log(maxValue); // 999
console.log(add); // ƒ add() {}

No es posible hacer un “named export” con una función anónima o una expresión. Siempre es necesario que tenga un nombre.

– La comunidad PRO de JavaScript

Exportar con un nombre diferente (alias)

En algunos casos nos puede ayudar darle un nombre diferente a nuestros exports.

function add(){
  // add something
}

function divide(){
  // divide something
}

export { add as plus, divide as split };

Al momento de importar es necesario importar con ese nuevo nombre que le asignamos, sin embargo nuestros métodos conservaran la referencia a su nombre original.

import { plus, split } from './calculator.js'

console.log(plus); // ƒ add() {} <-- add en vez de plus
console.log(split); // ƒ divide() {}

Exportar desde otros archivos

Si aunque el uso de este tipo no es muy común, es posible hacerlo. Supongamos que tenmos un archivo pruncipal:

export default add() {
  // add something
}

export multiply() {
  // multiply something
}

ahora podemos tener un exportador que agrupe de uno o diferentes archivos:

export {
  default,
  multiply
} from './calculator'

Ahora podemos importar del nuevo archivo:

import add, { multiply } from './operations'

console.log(add); // ƒ add() {}
console.log(multiply): // ƒ multiply {}

Exportar desde otros archivos con alias

De igual forma que antes podemos utilizar alias para exportar y renombrar.

export {
  default as plus,
  multiply
} from './calculator'

Ahora que nuestros default pasaron a ser named, es necesario importarlos con ese nuevo nombre:

import { plus, multiply } from './operations-alias'

console.log(plus); // ƒ add() {}
console.log(multiply): // ƒ multiply {}

Importar con alias

Es posible también agregar un alias al momento de importar.

import { plus as suma, multiply as multiplicar } from './operations-alias'

Esto es útil cuando importamos métodos con el mismo nombre que vengan de distintos archivos. A continuación 2 métodos con el mismo nombre pero en distintos archivos:

export getAge() {}
export getAge() {}

Ahora si queremos utilizarlos podemos asignarles un alias:

import { getAge as grandFatherAge } from './grandfather';
import { getAge as fatherAge } from './father';

console.log(grandFatherAge);
console.log(fatherAge);

Exportar todo

Es posible utilizar el comodín “*” para exportar todos los elementos, tomemos como ejemplo el siguiente archivo.

export function add(){
  // add something
}

export class Person {
  // class definition
}

export const PI = 3.1416;

export let car = {
  paintColor: 'red'
}

export default helloWorld(){
  // say hello
}

Y al momento de exportar solo necesitamos lo siguiente:

export * from './examples';

Al hacer un export con * , el método default no se exporta por lo que debe exportarse por separado.

– La comunidad PRO de JavaScript

Para exportar además el método default necesitamos lo siguiente:

export { default } from './examples';
export * from './examples';

En caso de existir más de un default es necesario utilizar los alias.

Importar todo

Al importar con * es necesario asignar un alias, este alias ahora será un objeto con todo lo importado (incluido el default):

import * as exampleMethods from './examples';

console.log(exampleMethods.add); // ƒ add(){}
console.log(exampleMethods.Person); // ƒ Person(){}
console.log(exampleMethods.PI); // 3.1416
console.log(exampleMethods.car); // { paintColor: 'red' }
console.log(exampleMethods.default); // ƒ helloWorld() {}

Es posible importar el default por separado, aunque de igual forma existirá en nuestro objeto:

import exampleDefault, * as exampleMethods from './examples';

console.log(exampleMethods.default); // ƒ helloWorld() {}
console.log(exampleDefault); // ƒ helloWorld() {}

Ahora si a andar desnudos por la casa

Ahora que sabes todas las formas de importar y exportar modulos, variables, etc. es hora de mostrarle al mundo que estas a punto de ser un ninja del Javascript o que ya eres un ninja avanzado.

Si te gusto el post o tienes alguna duda deja tu comentario y no olvides seguirme por el resto de redes sociales.

Un saludo 😀 y nos vemos en la siguiente publicación.

Categorías
Desarrollo y Programación

React dar formato a números

Hola, bienvenidos a otro tutorial en esta ocasión con React a dar formato a un número para mostrarlo en pantalla.

Vamos a trabajar en el aspecto visual deseado sin necesidad de cambiar el dato original, es decir meramente vamos a trabajar con la estética del número.

Este material está basado en la información que encontré en este hilo de Stackoverflow.

Para esto dejo el siguiente videotutorial, espero que les sea útil como material de apoyo.

Además dejo el código final en la parte de abajo para que revisen si algo no funciona como debe.

import React from "react";
import "./App.css";
function FormatNumber({ number }) {
return (
<span style={{ color: "red" }}>
{new Intl.NumberFormat("ES-MX", {
style: "currency",
currency: "MXN"
}).format(number)}
</span>
);
}
class App extends React.Component {
state = {
number: 0
};
handleChange = event => {
this.setState({
number: event.target.value > 999999999 ? 999999999 : event.target.value,
});
};
render() {
const { number } = this.state;
return (
<div className="App">
<h1>
Hola dinero <FormatNumber number={number} />
</h1>
<input type="number" onChange={this.handleChange} />
</div>
);
}
}
export default App;

Pueden dejar sus dudas o comentarios en está publicación o en el video, nos leemos en el siguiente tutorial.

Feliz día a todos 😄

Referencias

Categorías
Desarrollo y Programación

Sumar Radio button con Javascript

Este problema lo obtuve de los foros de cristalab del usuario mariassssss, el usuario busca sumar los valores de unos input radio con javascript:

Aquí el post original: http://foros.cristalab.com/javascrip-t122822/

Me tomé la libertad de corregir el codigo, quitar las funciones que no estaban en uso y hacer la operación que necesita sin moverle mucho.

<html>
<head>
<title>CAFETERIA</title>
<meta charset="utf-8" />
<style>
body {
background-color: #e1e637;
}
h1 {
color: #ff090e;
}
legend {
margin-top: 20px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<h1>CAFETERIA</h1>
<form>
<legend>SELECCIONE EL PLATO PRINCIPAL</legend>
<input type="radio" id="n1" name="principal" value="12" /> Caldo de pollo
Q12.00 <br /><br />
<input type="radio" id="n2" name="principal" value="20" /> pescado frito
Q20.00<br /><br />
<input type="radio" id="n3" name="principal" value="25" /> revolcado
Q25.00<br /><br />
<legend>SELECCIONE SU BEBIDA</legend>
<input type="radio" id="n4" name="bebida" value="7" /> CocaCola Q7.OO<br /><br />
<input type="radio" id="n5" name="bebida" value="4" /> Jamaica Q4.00<br /><br />
<input type="radio" id="n6" name="bebida" value="5" /> Sprite Q5.00<br /><br />
<legend>SELECCIONE SU POSTRE</legend>
<input type="radio" id="n7" name="postre" value="7" /> Pastel de fresa
Q7.oo<br /><br />
<input type="radio" id="n8" name="postre" value="5" /> Helado de Chocolate
Q5<br /><br />
<input type="radio" id="n9" name="postre" value="9" /> Coctel de frutas
Q9.00<br /><br />
<button>Obtener TOTAL</button>
</form>
<script>
// buscar el <form> y guardarlo en una variable
const form = document.querySelector('form');
// decir que en el evento enviar se sume el total
form.addEventListener('submit', obtenerTotal);
function obtenerTotal(event) {
// evitar enviar el formulario que ocasiona que se refresque la pagina
event.preventDefault();
// obtener todos los input radio
const formData = new FormData(event.target);
// convertir los valores a String, o colocar un 0 si no elegieron algo
const principal = parseInt(formData.get('principal') || '0', 10);
const bebida = parseInt(formData.get('bebida') || '0', 10);
const postre = parseInt(formData.get('postre') || '0', 10);
const result = principal + bebida + postre;
alert("la suma es:" + result);
}
</script>
</body>
</html>

A diferencia del código original no es necesario ir a recuperar el valor por input, si no obtener todo el formulario y sacar los valores necesarios.

Es algo primitivo pero este formData estaría listo para enviar a en una request y obtener los datos a partir de este elemento y sus correspondientes names.

Entre las mejoras se puede poner un array para obtener los datos requeridos, pero como no estaba la problemática descrita, pues decidí omitir.

Categorías
Desarrollo y Programación

WebStorm Color Themes – base16 [2019]

Que tal coders, en esta ocasión voy a compartir mi tema de color para el editor WebStorm, reciente el editor entró en la versión 2019.2 cambiando ajustes.

Estos ajustes ahora permiten establecer colores para otras variables, sintaxis y palabras reservadas.

Javascript Class

Mi tema esta basado en los colores de Base16 que pueden encontrar aquí http://chriskempson.com/projects/base16/ y he cambiado mayormente los colores para trabajar con Javascript y react.js

ReactJS Component

Quizá no se vea tan bien como otros temas o schemes pero está listo para trabajar con pantallas muy brillantes, donde a veces el color parece que va a incendiar las pupilas

Node JS

Sin más aquí dejo el enlace al archivo:

Si por alguna razón no funciona, también lo dejo en Google drive:

https://drive.google.com/file/d/1Ef9_o5d2yXP5n7XCncKZs_u5BHs0qfUP/view?usp=sharing

Cómo importar Webstorm color themes

Para importar este o cualquier otro tema, necesitan un archivo *.icls para poder importarlo. Después ir a Archivo > Preferencias > Editor > Color Scheme

Webstorm 2019.x Preferences

Elegir la opción Import Scheme… del icono de configuración, para finalizar elegir el archivo, aplicar y aceptar los cambios. Y listo 😄

Si tienen algún ajuste para cambiar o mejorar el tema compartanlo en los comentarios. Muchas gracias y nos vemos en el siguiente post.

Categorías
Desarrollo y Programación

jQuery mostrar y ocultar div con animación

En esta ocasión vamos a mostrar y ocultar div con jQuery para practicar el funcionamiento base de la librería. vamos a asignar eventos a dos botones que nos permitan interactuar con la visualización de un componente.

En esta ocasión traigo la actualización de un código que hice hace unos siete años para este blog, el cual hice un tutorial en youtube:

El código completo y funcional está aquí:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tutorial jQuery Remasterizado</title>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script>
var pagina = $(document);
pagina.on("ready", animar);
function animar() {
var x = $("#mostrar_elemento");
x.on("click", mostrar);
var y = $("#ocultar_elemento");
y.on("click", ocultar);
}
function mostrar() {
var x = $("div");
x.show("slow");
}
function ocultar() {
var x = $("div");
x.hide("slow");
}
</script>
<style>
.ocultado {
display: none;
background-color: #9c0;
border-color: #063;
border-style: dotted;
border: thin;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<input id="mostrar_elemento" type="button" value="Mostrar mensaje" />
<input id="ocultar_elemento" type="button" value="Ocultar" />
<div class="ocultado">
Esta div se esta mostrando sin embargo puede ser cualquier elemento
</div>
</body>
</html>
view raw jquery01.html hosted with ❤ by GitHub

Refactorizar código Javascript

Ahora también tenemos una actualización de un refactor que pueden ver en el siguiente video:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tutorial jQuery Remasterizado</title>
<link href="style.css" rel="stylesheet">
</head>
<body>
<button id="showContainer" type="button">Mostrar mensaje</button>
<button id="hideContainer" type="button">Ocultar mensaje</button>
<div class="container hidden">
Esta div se esta mostrando sin embargo puede ser cualquier elemento
</div>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"
></script>
<script>
$(window).on("load", assignEvents);
function assignEvents() {
$("#showContainer").on("click", mostrar);
$("#hideContainer").on("click", ocultar);
}
function mostrar() {
$("div").show("slow");
}
function ocultar() {
$("div").hide("slow");
}
</script>
</body>
</html>
view raw index.html hosted with ❤ by GitHub
.container {
background-color: #9c0;
border-color: #063;
border-style: dotted;
border: thin;
width: 200px;
height: 200px;
}
.hidden {
display: none;
}
view raw style.css hosted with ❤ by GitHub

Este último video trata de seguir buenas prácticas para evitar el uso innecesario de variables y agregar nombres legibles a las clases e identificadores de HTML y Javascript.

Si tienen alguna duda ponganla en los comentarios 😎