* Typo corrections * bridge pattern translated to spanish * builder pattern translated to spanish * context-object pattern translated to spanish * converter pattern translated to spanish * dependency injection pattern translated to spanish * factory pattern translated to spanish * factory-kit pattern translated to spanish * factory-method pattern translated to spanish * monostate pattern translated to spanish * multiton pattern translated to spanish * object mother pattern translated to spanish * object pool pattern translated to spanish * property pattern translated to spanish * prototype pattern translated to spanish * registry pattern translated to spanish * step builder pattern translated to spanish * value object pattern translated to spanish * typo corrections and resources urls refactor * grammar corrections * Add image to each pattern --------- Co-authored-by: luismateoh <luismateohm@gmail.com> Co-authored-by: luis.hincapie <luis.hincapie@blankfactor.com>
@@ -29,7 +29,7 @@ programadores y arquitectos experimentados de la comunidad de código abierto. L
|
||||
Antes de sumergirte en el material deberías estar familiarizado con varios
|
||||
[Principios de diseño de software](https://java-design-patterns.com/principles/).
|
||||
|
||||
Todos los diseños deben ser lo más simples posible. Deberías comenzar con los principios KISS, YAGNI y hacer lo mas simple que funcione. La complejidad y los patrones solo deben introducirse cuando sean necesarios para una extensibilidad práctica.
|
||||
Todos los diseños deben ser lo más simples posible. Deberías comenzar con los principios KISS, YAGNI y hacer lo más simple que funcione. La complejidad y los patrones solo deben introducirse cuando sean necesarios para una extensibilidad práctica.
|
||||
|
||||
Una vez que esté familiarizado con estos conceptos, puedes comenzar a profundizar con los
|
||||
[patrones de diseño disponibles](https://java-design-patterns.com/patterns/) por cualquiera de los siguientes enfoques
|
||||
@@ -46,5 +46,5 @@ Si estás dispuesto a contribuir al proyecto encontrarás la información releva
|
||||
|
||||
# Licencia
|
||||
|
||||
Este proyecto esta licenciado de acuerdo con los términos de la licencia del MIT.
|
||||
Este proyecto está licenciado de acuerdo con los términos de la licencia del MIT.
|
||||
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Abstract Document
|
||||
folder: abstract-document
|
||||
permalink: /patterns/abstract-document/
|
||||
categories: Structural
|
||||
category: Structural
|
||||
language: es
|
||||
tag:
|
||||
- Extensibility
|
||||
tag:
|
||||
- Extensibility
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Usar propiedades dinámicas y conseguir la felexibilidad de los lenguajes no tipados manteniendo la seguridad de tipos.
|
||||
Usar propiedades dinámicas y conseguir la flexibilidad de los lenguajes no tipados manteniendo la seguridad de tipos.
|
||||
|
||||
## Explicación
|
||||
|
||||
El uso del patrón Abstract Document permite gestionar propiedades no estáticas adicionales. Este patrón usa el concepto de atributos para permitir seguridad de tipos y propiedades separadas de diferentes clases en un grupo de interfaces.
|
||||
El uso del patrón Abstract Document permite gestionar propiedades no estáticas adicionales. Este patrón usa el concepto
|
||||
de atributos para permitir seguridad de tipos y propiedades separadas de diferentes clases en un grupo de interfaces.
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Toma como ejemplo un coche que está formado por muchas partes. Sin embargo, no sabemos si el coche tiene todas las partes o solo una parte de ellas. Nuestros coches son dinámicos y extremadamente flexibles.
|
||||
> Toma como ejemplo un coche que está formado por muchas partes. Sin embargo, no sabemos si el coche tiene todas las
|
||||
> partes o solo una parte de ellas. Nuestros coches son dinámicos y extremadamente flexibles.
|
||||
|
||||
Dicho de otra forma
|
||||
|
||||
@@ -27,11 +26,16 @@ Dicho de otra forma
|
||||
|
||||
Según Wikipedia
|
||||
|
||||
> Un patrón de diseño estructural orientado a objetos para organizar objetos en contenedores clave-valor vagamente tipados y exponiendo los datos usando vistas tipadas. El propósito del patrón es conseguir un alto grado de flexibilidad entre componentes en un lenguaje de tipado fuerte donde nuevas propiedades pueden añadirse al arbol de objetos sobre la marcha sin perder el soporte de la seguridad de tipos. El patrón hace uso de atributos para separar diferentes propiedades de una clase en distintas interfaces.
|
||||
> Un patrón de diseño estructural orientado a objetos para organizar objetos en contenedores clave-valor vagamente
|
||||
> tipados y exponiendo los datos usando vistas tipadas. El propósito del patrón es conseguir un alto grado de flexibilidad
|
||||
> entre componentes en un lenguaje de tipado fuerte donde nuevas propiedades pueden añadirse al árbol de objetos sobre la
|
||||
> marcha sin perder el soporte de la seguridad de tipos. El patrón hace uso de atributos para separar diferentes
|
||||
> propiedades de una clase en distintas interfaces.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
Primero definamos las clases base `Document` y `AbstractDocument`. Básicamente hacen que el objeto contenga un mapa de propiedades y cualquier número de objetos hijo.
|
||||
Primero definamos las clases base `Document` y `AbstractDocument`. Básicamente, hacen que el objeto contenga un mapa de
|
||||
propiedades y cualquier número de objetos hijo.
|
||||
|
||||
```java
|
||||
public interface Document {
|
||||
@@ -76,7 +80,9 @@ public abstract class AbstractDocument implements Document {
|
||||
...
|
||||
}
|
||||
```
|
||||
A continuación definimos un enum `Property` y un grupo de interfaces para tipo, precio, modelo y partes. Esto nos permite crear interfaces de apariencia estática para nuestra clase `Car`.
|
||||
|
||||
A continuación definimos un enum `Property` y un grupo de interfaces para tipo, precio, modelo y partes. Esto nos
|
||||
permite crear interfaces de apariencia estática para nuestra clase `Car`.
|
||||
|
||||
```java
|
||||
public enum Property {
|
||||
@@ -166,14 +172,14 @@ Y finalmente asi es como construimos y usamos el Coche `Car` en un ejemplo compl
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicación
|
||||
|
||||
Usar el patrón Abstract Document cuando
|
||||
|
||||
* Existe la necesidad de añadir propiedades sobre la marcha.
|
||||
* Quieres una manera flexible de organizar el dominio en una estructura similar a un arbol.
|
||||
* Quieres una manera flexible de organizar el dominio en una estructura similar a un árbol.
|
||||
* Quieres un sistema menos acoplado.
|
||||
|
||||
## Créditos
|
||||
|
||||
|
After Width: | Height: | Size: 94 KiB |
@@ -1,9 +1,6 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Abstract Factory
|
||||
folder: abstract-factory
|
||||
permalink: /patterns/abstract-factory/
|
||||
categories: Creational
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Gang of Four
|
||||
@@ -21,11 +18,11 @@ Proveer de una interfaz para crear familias de objetos relacionados dependientes
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Para crear un reino necesitamos objetos con una temática común. El reino élfico necesita un rey elfo, un castillo élfico y un ejército élfico mientras que el reino orco necesita un rey orco, un castillo orco y un ejércico orco. Hay una dependencia entre los objetos del reino.
|
||||
> Para crear un reino necesitamos objetos con una temática común. El reino élfico necesita un rey elfo, un castillo élfico y un ejército élfico mientras que el reino orco necesita un rey orco, un castillo orco y un ejército orco. Hay una dependencia entre los objetos del reino.
|
||||
|
||||
Dicho de otra forma
|
||||
|
||||
> Una factoría de factorías; una factoría que agrupa otras factorias individuales pero relacionadas/dependientes sin especificar su clase concreta.
|
||||
> Una factoría de factorías; una factoría que agrupa otras factorías individuales pero relacionadas/dependientes sin especificar su clase concreta.
|
||||
|
||||
Según Wikipedia
|
||||
|
||||
@@ -33,7 +30,7 @@ Según Wikipedia
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
Traduciendo el ejemplo anterior sobre los reinos. Primero tenemos algunas interfaces e implementaciones de los objetos del reino.
|
||||
Traduciendo el ejemplo anterior sobre los reinos. Primero tenemos algunas interfaces e implementaciones de los objetos del `Castle`.
|
||||
|
||||
```java
|
||||
public interface Castle {
|
||||
@@ -75,7 +72,7 @@ public class ElfArmy implements Army {
|
||||
|
||||
```
|
||||
|
||||
Luego tenemos la abstracción e implementación de la factoría del reino.
|
||||
Luego tenemos la abstracción e implementación de la factoría del reino `KingdomFactory`.
|
||||
|
||||
```java
|
||||
public interface KingdomFactory {
|
||||
@@ -121,7 +118,7 @@ public class OrcKingdomFactory implements KingdomFactory {
|
||||
}
|
||||
```
|
||||
|
||||
Ahora tenemos la factoría abstracta que nos permite hacer familias de objetos relacionados por ejemplo la factoria del reino élfico crea el castillo, rey y ejercito élficos etc.
|
||||
Ahora tenemos la factoría abstracta que nos permite hacer familias de objetos relacionados por ejemplo la factoría del reino élfico `ElfKingdomFactory` crea el castillo `castle`, rey `king` y ejército `army` etc.
|
||||
|
||||
|
||||
```java
|
||||
@@ -135,7 +132,7 @@ king.getDescription();
|
||||
army.getDescription();
|
||||
```
|
||||
|
||||
Output del programa:
|
||||
Salida del programa:
|
||||
|
||||
```java
|
||||
This is the elven castle!
|
||||
@@ -180,7 +177,7 @@ public static class FactoryMaker {
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Aplicación
|
||||
@@ -191,24 +188,24 @@ Usar el patrón Abstract Factory cuando
|
||||
* El sistema debe ser configurado con una de las múltiples familias de productos.
|
||||
* La familia de objetos relacionados está diseñada para ser usada en conjunto y necesitas forzar esta premisa.
|
||||
* Quieres proveer de una librería de productos y solo quieres revelar sus interfaces, no su implementación.
|
||||
* El tiempo de vida de la dependencia es conceptualmente mas corte que el del cliente.
|
||||
* El tiempo de vida de la dependencia es conceptualmente más corto que el del cliente.
|
||||
* Necesitas un valor en tiempo de ejecución para construir una dependencia.
|
||||
* Quieres decidir que producto de una familia llamar en tiempo de ejecución.
|
||||
* Necesitas proveer de uno o mas parámetros solo conocidos en tiempo de ejecución antes de poder resolver la dependencia.
|
||||
* Necesitas proveer de uno o más parámetros solo conocidos en tiempo de ejecución antes de poder resolver la dependencia.
|
||||
* Necesitas consistencia entre productos.
|
||||
* No quieres cambiar el código existente al añadir nuevos productos o familias de productos al programa.
|
||||
|
||||
Ejemplos de casos de uso
|
||||
|
||||
* Elegir llamar a la implementación correcta de FileSystemAcmeService o DatabaseAcmeService o NetworkAcmeService en tiempo de ejecución.
|
||||
* Escribir test unitarios se hace mucho mas sencillo.
|
||||
* Escribir test unitarios se hace mucho más sencillo.
|
||||
* Herramientas UI (User Interface) para diferentes SO (Sistemas Operativos).
|
||||
|
||||
## Consecuencias
|
||||
|
||||
* La inyección de dependencias en java esconde las dependencias de la clase servicio lo que puede llevar a errores de ejecución que se podrian haber evitado al compilar.
|
||||
* La inyección de dependencias en java esconde las dependencias de la clase servicio lo que puede llevar a errores de ejecución que se podrían haber evitado al compilar.
|
||||
* Mientras que el patrón es muy bueno creando objetos predefinidos, añadir nuevos puede ser complicado.
|
||||
* El código es mas complicado de lo que deberia porque se añaden muchas interfaces y clases nuevas junto con el patrón.
|
||||
* El código es más complicado de lo que debería porque se añaden muchas interfaces y clases nuevas junto con el patrón.
|
||||
|
||||
## Tutoriales
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 80 KiB |
@@ -1,9 +1,6 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Active Object
|
||||
folder: active-object
|
||||
permalink: /patterns/active-object/
|
||||
categories: Concurrency
|
||||
category: Concurrency
|
||||
language: es
|
||||
tag:
|
||||
- Performance
|
||||
@@ -19,7 +16,7 @@ La clase que implementa el patrón de diseño de objeto activo contendrá un mec
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Los orcos son conocidos por su salvajismo y filosofía de no hacer equipo. Basandonos en este comportamiento se podría decir que tienen su propio hilo de control.
|
||||
> Los orcos son conocidos por su salvajismo y filosofía de no hacer equipo. Basándonos en este comportamiento se podría decir que tienen su propio hilo de control.
|
||||
|
||||
Podemos usar el patrón Active Object para implementar una criatura que tiene su propio hilo de control y exponer su API pero no la ejecución como tal.
|
||||
|
||||
@@ -123,7 +120,7 @@ Ahora podemos crear múltiples criaturas como los Orcos, diles que coman y deamb
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
## Tutoriales
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 19 KiB |
@@ -1,9 +1,6 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Acyclic Visitor
|
||||
folder: acyclic-visitor
|
||||
permalink: /patterns/acyclic-visitor/
|
||||
categories: Behavioral
|
||||
category: Behavioral
|
||||
language: es
|
||||
tag:
|
||||
- Extensibility
|
||||
@@ -25,7 +22,7 @@ En otras palabras
|
||||
|
||||
[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) dice
|
||||
|
||||
> El patrón Acyclic Visitor permite que nuevas funciones sean añadidas a jerarquías de clases existentes sin afectar a las mismas, y sin crear los círculos de dependencias que son inherentes al patrón Visitor Pattern de GangOfFour.
|
||||
> El patrón Acyclic Visitor permite que nuevas funciones sean añadidas a jerarquías de clases existentes sin afectar a las mismas, y sin crear los círculos de dependencias que son inherentes al patrón de visitante (Visitor Pattern) de GangOfFour.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
@@ -99,7 +96,7 @@ public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||
}
|
||||
```
|
||||
|
||||
Finalmente aquí están los "visitors" en acción.
|
||||
Finalmente, aquí están los "visitors" en acción.
|
||||
|
||||
```java
|
||||
var conUnix = new ConfigureForUnixVisitor();
|
||||
@@ -123,14 +120,14 @@ Output del programa:
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicación
|
||||
|
||||
Este patrón puede ser usado:
|
||||
|
||||
* Cuando necesitas añadir una nueva función a una jerarquía de clases sin que esta se vea afectada o alterada.
|
||||
* Cuando hay funciones que operan sobre la jerarquía pero no pertenecen a la jerarquía como tal. Las clases ConfigureForDOS / ConfigureForUnix / ConfigureForX por ejemplo.
|
||||
* Cuando hay funciones que operan sobre la jerarquía, pero no pertenecen a la jerarquía como tal. Las clases ConfigureForDOS / ConfigureForUnix / ConfigureForX por ejemplo.
|
||||
* Cuando necesitas ejecutar operaciones muy diferentes en un objeto dependiendo de su tipo.
|
||||
* Cuando la jerarquía visitada va a ser frecuentemente extendida con derivados de la clase elemento.
|
||||
* Cuando el proceso de volver a compilar, enlazar, probar o distribuir los derivados de la clase elemento es muy pesado.
|
||||
|
||||
|
After Width: | Height: | Size: 48 KiB |
@@ -18,11 +18,11 @@ Ejemplo del mundo real
|
||||
|
||||
> Imagina que tienes unas imágenes en una tarjeta de memoria y quieres transferirlas a tu ordenador. Para transferirlas necesitas algún tipo de adaptador compatible con los puertos de tu ordenador que te permita introducir tu tarjeta. En este caso el lector de tarjetas es un adaptador (adapter).
|
||||
> Otro ejemplo podría ser el famoso adaptador de corriente; un enchufe con tres patas no se puede conectar a una toma de corriente con dos agujeros, necesita un adaptador para hacerlo compatible con la toma de corriente.
|
||||
> Otro ejemplo mas seria un traductor traduciendo palabras de una persona para otra.
|
||||
> Otro ejemplo más sería un traductor traduciendo palabras de una persona para otra.
|
||||
|
||||
En otras palabras
|
||||
|
||||
> El patrón Adapter permite envolver un objeto en un adaptador para hacerlo compatible con una clase con la que seria incompatible de otra manera.
|
||||
> El patrón Adapter permite envolver un objeto en un adaptador para hacerlo compatible con una clase con la que sería incompatible de otra manera.
|
||||
|
||||
Según Wikipedia
|
||||
|
||||
@@ -64,7 +64,7 @@ public class Captain {
|
||||
}
|
||||
```
|
||||
|
||||
Ahora supongamos que viene un grupo de piratas y nuestro capitán tiene que escapar pero solo hay un bote de pesca. Necesitamos crear un adaptador que permita al capitán usar el bote de pesca con sus habilidades para usar botes de remo.
|
||||
Ahora supongamos que viene un grupo de piratas y nuestro capitán tiene que escapar, pero solo hay un bote de pesca. Necesitamos crear un adaptador que permita al capitán usar el bote de pesca con sus habilidades para usar botes de remo.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@@ -91,14 +91,14 @@ captain.row();
|
||||
```
|
||||
|
||||
## Diagrama de clases
|
||||

|
||||

|
||||
|
||||
## Aplicación
|
||||
Usa el patrón Adapter cuando
|
||||
|
||||
* Quieres usar una clase existente y su interfaz no coincide con la que necesitas.
|
||||
* Quieres crear una clase reutilizable que coopere con clases que no están relacionadas o con las que su cooperación no estaba planeada, esto es, clases que no necesariamente tienen interfaces compatibles.
|
||||
* Necesitas usar varias subclases existentes pero es impráctico adaptar su interfaz creando subclases para todas. Un adaptador puede adaptar la interfaz de la clase padre.
|
||||
* Necesitas usar varias subclases existentes, pero no es práctico adaptar su interfaz creando subclases para todas. Un adaptador puede adaptar la interfaz de la clase padre.
|
||||
* Muchas aplicaciones que usan librerías de terceros usan adaptadores como capas intermedias entre la aplicación y la librería para desacoplar la aplicación de la librería. Si es necesario usar otra librería solo hace falta crear un adaptador para la nueva librería sin necesidad de modificar el código de la aplicación.
|
||||
|
||||
## Tutoriales
|
||||
@@ -117,7 +117,7 @@ Los adaptadores de clases y objetos tienen distintas cualidades. Un adaptador de
|
||||
Un adaptador de objetos
|
||||
|
||||
* Permite a un solo adaptador trabajar con varias clases, esto es, con la clase adaptada y todas sus subclases (si tiene alguna). El adaptador también puede añadir funcionalidad a todas las clases adaptadas a la vez.
|
||||
* Hace mas complicado modificar el comportamiento de la clase adaptada. Sería necesario hacer una subclase de la clase a adaptar y hacer que el adaptador referencie la subclase en lugar de la clase a adaptar.
|
||||
* Hace más complicado modificar el comportamiento de la clase adaptada. Sería necesario hacer una subclase de la clase a adaptar y hacer que el adaptador referencie la subclase en lugar de la clase a adaptar.
|
||||
|
||||
|
||||
## Ejemplos del mundo real
|
||||
|
||||
|
After Width: | Height: | Size: 25 KiB |
@@ -8,13 +8,13 @@ tag:
|
||||
- Microservices
|
||||
---
|
||||
|
||||
## Intención
|
||||
## Propósito
|
||||
|
||||
El usuario realiza una sola llamada al servicio del agregador y, a continuación, el agregador llama a cada microservicio relevante.
|
||||
|
||||
## Explicación
|
||||
|
||||
ejemplo del mundo real
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Nuestro mercado web necesita información sobre los productos y su inventario actual. Hace una llamada a un agregador
|
||||
> servicio que a su vez llama al microservicio de información del producto y al microservicio de inventario del producto que devuelve la
|
||||
@@ -41,7 +41,7 @@ public class Product {
|
||||
}
|
||||
```
|
||||
|
||||
A continuación, podemos presentar nuestro microservicio `Aggregator` (Agregador de microservicios). Contiene el `ProductInformationClient` (Información del producto del cliente) y el
|
||||
A continuación, podemos presentar nuestro microservicio `Aggregator` (Agregador de microservicios). Contiene él `ProductInformationClient` (Información del producto del cliente) y él
|
||||
`ProductInventoryClient` (Inventario del producto del cliente) de los clientes para llamar a los respectivos microservicios.
|
||||
|
||||
```java
|
||||
|
||||
|
After Width: | Height: | Size: 40 KiB |
@@ -7,7 +7,7 @@ tag:
|
||||
- Cloud distributed
|
||||
---
|
||||
|
||||
## Motivo
|
||||
## Propósito
|
||||
|
||||
Proporcionar una instancia de servicio auxiliar a un cliente y delegar en ella las funcionalidades comunes de un recurso compartido.
|
||||
|
||||
@@ -170,7 +170,7 @@ Service result: -1
|
||||
|
||||
## Diagrama de clase
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicaciones
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 48 KiB |
@@ -8,16 +8,16 @@ tag:
|
||||
- Microservices
|
||||
---
|
||||
|
||||
## Motivo
|
||||
## Propósito
|
||||
|
||||
Agregar llamadas a los microservicios en un mismo lugar, la puerta de enlace API (API Gateway). El usuario
|
||||
hace un llamada simple al API Gateway, y la API Gateway hace la llamada a cada microservicio relevante.
|
||||
hace una llamada simple a la API Gateway, y la API Gateway hace la llamada a cada microservicio relevante.
|
||||
|
||||
## Explicaición
|
||||
## Explicación
|
||||
|
||||
Con el patrón de microservicios, el cliente puede necesitar datos de múltiples microservicios. Si el
|
||||
cliente llamara a cada microservicio de forma directe, podría ocasionar tiempos de carga largos, ya que
|
||||
el cliente tendría que hacer una solicitud de red para cada microservicio llamado. Además, tener la
|
||||
el cliente tendría que hacer una solicitud de red para cada microservicio llamado. Además, tener
|
||||
la llamada del cliente a cada microservicio vincula directamente al cliente con ese microservicio - si la
|
||||
implementacion interna del cambio de microservicios (por ejemplo, si dos microservicios se combinan en
|
||||
algún momento en el futuro) o si la ubicación (host y puerto) de un microservicio cambia, entonces cada
|
||||
@@ -26,7 +26,7 @@ cliente que hace uso de esos microservicios debe ser actualizado.
|
||||
La intención del patrón API Gateway es aliviar algunos de estos problemas. En el patrón API Gateway,
|
||||
se coloca una entidad adicional (la API Gateway) entre el cliente y los microservicios.
|
||||
El trabajo de API Gateway es agregar las llamadas a los microservicios. En lugar de que el cliente
|
||||
llame a cada microservicio individualmente, el cliente llama al API Gateway una sola vez. la API
|
||||
llame a cada microservicio individualmente, el cliente llama a la API Gateway una sola vez. La API
|
||||
Gateway luego llama a cada uno de los microservicios que necesita el cliente.
|
||||
|
||||
Ejemplo real
|
||||
@@ -146,13 +146,13 @@ public class ApiGateway {
|
||||
|
||||
## Diagrama de clase
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicaciones
|
||||
|
||||
Usa el patrón de API Gateway cuando
|
||||
|
||||
* Estés usando una arquitectura de microservicios y necesites un único punto de agregación para las llamadas de microservicios.
|
||||
* Estás usando una arquitectura de microservicios y necesites un único punto de agregación para las llamadas de microservicios.
|
||||
|
||||
## Tutoriales
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -10,7 +10,7 @@ tag:
|
||||
|
||||
Dado/Cuando/Entonces
|
||||
|
||||
## Intención
|
||||
## Propósito
|
||||
|
||||
Arrange/Act/Assert (AAA) es un patrón para organizar UnitTests.
|
||||
Divide las UnitTests en tres pasos claros y diferenciados:
|
||||
@@ -19,7 +19,7 @@ Divide las UnitTests en tres pasos claros y diferenciados:
|
||||
2. Act(Actuar): Toma las medidas necesarias para el test.
|
||||
3. Assert(Afirmar): Verifica los resultados del test.
|
||||
|
||||
## Explicacación
|
||||
## Explicación
|
||||
|
||||
Este patrón tiene varios beneficios significativos. Crea una clara separación entre la configuración, operaciones y resultados de un test. Esta estructura hace que el código sea más fácil de leer y comprender. Si
|
||||
colocas los pasos en orden y formateas su código para separarlos, puedes escanear un test y
|
||||
@@ -126,9 +126,9 @@ class CashAAATest {
|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Arrange/Act/Asert cuando
|
||||
Utilice el patrón Arrange/Act/Assert cuando
|
||||
|
||||
* Necesites estructurar tus UnitTests para que sean más fáciles de leer, mantener y mejorar.
|
||||
* Necesitas estructurar tus UnitTests para que sean más fáciles de leer, mantener y mejorar.
|
||||
|
||||
## Créditos
|
||||
|
||||
@@ -136,5 +136,5 @@ Utilice el patrón Arrange/Act/Asert cuando
|
||||
* [Bill Wake: 3A – Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/)
|
||||
* [Martin Fowler: DadoCuandoEntonces](https://martinfowler.com/bliki/GivenWhenThen.html)
|
||||
* [Patrones de prueba xUnit: Refactorizando Código de prueba](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f63d0bcf50)
|
||||
* [Principios, prácticas y patrones UnitTesting](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cfae3a5a)accae3a5a)
|
||||
* [Principios, prácticas y patrones UnitTesting](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cfae3a5aaccae3a5a)
|
||||
* [Desarrollo basado en pruebas: Ejemplo](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b47caef50875)
|
||||
|
||||
@@ -9,7 +9,7 @@ tag:
|
||||
## Propósito
|
||||
|
||||
Asynchronous method invocation (invocación de método asincrónico) es un patrón con el que el hilo o subproceso de llamada
|
||||
no se bloquea mientras espera resultados. El patrón proporciona pocesamiento en paralelo de múltiples tareas independientes y recupera los resultados a través de
|
||||
no se bloquea mientras espera resultados. El patrón proporciona procesamiento en paralelo de múltiples tareas independientes y recupera los resultados a través de
|
||||
devoluciones de llamada (callbacks) o esperando hasta que termine el procedimiento.
|
||||
|
||||
## Explicación
|
||||
@@ -22,7 +22,7 @@ Ejemplo cotidiano
|
||||
En otras palabras
|
||||
|
||||
> La invocación del método asíncrono inicia el procedimiento y vuelve inmediatamente antes de que la tarea termine
|
||||
> Los resultados del procedimiento se devuelven a la llamada posteriormente (callback).
|
||||
> Los resultados del procedimiento se devuelven a la llamada posteriormente (callback).
|
||||
|
||||
Según Wikipedia
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 36 KiB |
@@ -118,7 +118,7 @@ Aquí está la salida en consola de la aplicación.
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,223 @@
|
||||
---
|
||||
title: Bridge
|
||||
category: Structural
|
||||
language: es
|
||||
tag:
|
||||
- Gang of Four
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
|
||||
Handle/Body
|
||||
|
||||
## Intención
|
||||
|
||||
Desacoplar una abstracción de su implementación para que ambas puedan variar de forma independiente.
|
||||
|
||||
## Explicación
|
||||
|
||||
Real-world example
|
||||
|
||||
> Imagina que tienes un arma con diferentes encantamientos, y se supone que debes permitir la mezcla de diferentes armas
|
||||
> con diferentes encantamientos. ¿Qué harías? ¿Crearías múltiples copias de cada una de las armas para cada uno de los
|
||||
> encantamientos o simplemente crearías un encantamiento separado y lo establecerías para el arma según sea necesario?
|
||||
> El
|
||||
> patrón Bridge te permite hacer lo segundo.
|
||||
|
||||
En palabras sencillas
|
||||
|
||||
> El patrón Bridge se trata de preferir la composición sobre la herencia. Los detalles de implementación se empujan de
|
||||
> una jerarquía a otro objeto con una jerarquía separada.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> El patrón bridge es un patrón de diseño utilizado en ingeniería de software que tiene como objetivo "desacoplar una
|
||||
> abstracción de su implementación para que las dos puedan variar independientemente"
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Transladando nuestro ejemplo de arma de arriba. Aquí tenemos la interfaz arma `Weapon`:
|
||||
|
||||
```java
|
||||
public interface Weapon {
|
||||
void wield();
|
||||
void swing();
|
||||
void unwield();
|
||||
Enchantment getEnchantment();
|
||||
}
|
||||
|
||||
public class Sword implements Weapon {
|
||||
|
||||
private final Enchantment enchantment;
|
||||
|
||||
public Sword(Enchantment enchantment) {
|
||||
this.enchantment = enchantment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wield() {
|
||||
LOGGER.info("The sword is wielded.");
|
||||
enchantment.onActivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swing() {
|
||||
LOGGER.info("The sword is swinged.");
|
||||
enchantment.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unwield() {
|
||||
LOGGER.info("The sword is unwielded.");
|
||||
enchantment.onDeactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enchantment getEnchantment() {
|
||||
return enchantment;
|
||||
}
|
||||
}
|
||||
|
||||
public class Hammer implements Weapon {
|
||||
|
||||
private final Enchantment enchantment;
|
||||
|
||||
public Hammer(Enchantment enchantment) {
|
||||
this.enchantment = enchantment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wield() {
|
||||
LOGGER.info("The hammer is wielded.");
|
||||
enchantment.onActivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swing() {
|
||||
LOGGER.info("The hammer is swinged.");
|
||||
enchantment.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unwield() {
|
||||
LOGGER.info("The hammer is unwielded.");
|
||||
enchantment.onDeactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enchantment getEnchantment() {
|
||||
return enchantment;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Aquí está la interfaz de encantamientos `Enchantment` separada:
|
||||
|
||||
```java
|
||||
public interface Enchantment {
|
||||
void onActivate();
|
||||
void apply();
|
||||
void onDeactivate();
|
||||
}
|
||||
|
||||
public class FlyingEnchantment implements Enchantment {
|
||||
|
||||
@Override
|
||||
public void onActivate() {
|
||||
LOGGER.info("The item begins to glow faintly.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeactivate() {
|
||||
LOGGER.info("The item's glow fades.");
|
||||
}
|
||||
}
|
||||
|
||||
public class SoulEatingEnchantment implements Enchantment {
|
||||
|
||||
@Override
|
||||
public void onActivate() {
|
||||
LOGGER.info("The item spreads bloodlust.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
LOGGER.info("The item eats the soul of enemies.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeactivate() {
|
||||
LOGGER.info("Bloodlust slowly disappears.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Aquí están ambas interfaces en acción:
|
||||
|
||||
```java
|
||||
LOGGER.info("The knight receives an enchanted sword.");
|
||||
var enchantedSword = new Sword(new SoulEatingEnchantment());
|
||||
enchantedSword.wield();
|
||||
enchantedSword.swing();
|
||||
enchantedSword.unwield();
|
||||
|
||||
LOGGER.info("The valkyrie receives an enchanted hammer.");
|
||||
var hammer = new Hammer(new FlyingEnchantment());
|
||||
hammer.wield();
|
||||
hammer.swing();
|
||||
hammer.unwield();
|
||||
```
|
||||
|
||||
Aquí está la salida en consola.
|
||||
|
||||
```
|
||||
The knight receives an enchanted sword.
|
||||
The sword is wielded.
|
||||
The item spreads bloodlust.
|
||||
The sword is swung.
|
||||
The item eats the soul of enemies.
|
||||
The sword is unwielded.
|
||||
Bloodlust slowly disappears.
|
||||
The valkyrie receives an enchanted hammer.
|
||||
The hammer is wielded.
|
||||
The item begins to glow faintly.
|
||||
The hammer is swung.
|
||||
The item flies and strikes the enemies finally returning to owner's hand.
|
||||
The hammer is unwielded.
|
||||
The item's glow fades.
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Usa el patrón Bridge cuando
|
||||
|
||||
* Quieres evitar una vinculación permanente entre una abstracción y su implementación. Este podría ser el caso, por
|
||||
ejemplo, cuando la implementación debe ser seleccionada o cambiada en tiempo de ejecución.
|
||||
* Tanto las abstracciones como sus implementaciones deberían ser extensibles mediante la herencia. En este caso, el
|
||||
patrón Bridge te permite combinar las diferentes abstracciones e implementaciones y extenderlas de forma
|
||||
independiente.
|
||||
* Los cambios en la implementación de una abstracción no deberían tener impacto en los clientes; es decir, su código no
|
||||
debería tener que ser recompilado.
|
||||
* Tienes una proliferación de clases. Tal jerarquía de clases indica la necesidad de dividir un objeto en dos partes.
|
||||
Rumbaugh usa el término "generalizaciones anidadas" para referirse a tales jerarquías de clases.
|
||||
* Quieres compartir una implementación entre varios objetos (quizás usando conteo de referencias), y este hecho debería
|
||||
ser ocultado al cliente. Un ejemplo simple es la clase String de Coplien, en la que varios objetos pueden compartir la
|
||||
misma representación de cadena.
|
||||
|
||||
## Tutoriales
|
||||
|
||||
* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||
|
After Width: | Height: | Size: 43 KiB |
@@ -0,0 +1,158 @@
|
||||
---
|
||||
title: Builder
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Gang of Four
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Separar la construcción de un objeto complejo de su representación para que el mismo proceso de
|
||||
construcción pueda crear diferentes representaciones.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo real
|
||||
|
||||
> Imagina un generador de personajes para un juego de rol. La opción más fácil es dejar que el ordenador
|
||||
> cree el personaje por ti. Si quieres seleccionar manualmente los detalles del personaje como
|
||||
> profesión, sexo, color de pelo, etc. la generación del personaje se convierte en un proceso paso a paso que
|
||||
> se completa cuando todas las selecciones están listas.
|
||||
|
||||
En pocas palabras
|
||||
|
||||
> Permite crear diferentes sabores de un objeto evitando la contaminación del constructor. Útil
|
||||
> cuando puede haber varios sabores de un objeto. O cuando hay muchos pasos involucrados en la creación de un objeto.
|
||||
> creación de un objeto.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> El patrón constructor es un patrón de diseño de software de creación de objetos con la intención de encontrar
|
||||
> una solución al anti-patrón del constructor telescópico.
|
||||
|
||||
|
||||
Dicho esto, permíteme agregar un poco sobre qué es el anti-patrón del constructor telescópico. En algún momento
|
||||
u otro, todos hemos visto un constructor como el siguiente:
|
||||
|
||||
```java
|
||||
public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) {
|
||||
}
|
||||
```
|
||||
|
||||
Como puedes ver, el número de parámetros del constructor puede salirse rápidamente de control, y puede volverse difícil
|
||||
entender la disposición de los parámetros. Además, esta lista de parámetros podría seguir creciendo si quisieras agregar
|
||||
más opciones en el futuro. A esto se le llama anti-patrón del constructor telescópico.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
La alternativa sensata es utilizar el patrón Builder. En primer lugar, tenemos a nuestro héroe `Hero` que queremos
|
||||
crear:
|
||||
|
||||
```java
|
||||
public final class Hero {
|
||||
private final Profession profession;
|
||||
private final String name;
|
||||
private final HairType hairType;
|
||||
private final HairColor hairColor;
|
||||
private final Armor armor;
|
||||
private final Weapon weapon;
|
||||
|
||||
private Hero(Builder builder) {
|
||||
this.profession = builder.profession;
|
||||
this.name = builder.name;
|
||||
this.hairColor = builder.hairColor;
|
||||
this.hairType = builder.hairType;
|
||||
this.weapon = builder.weapon;
|
||||
this.armor = builder.armor;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Luego tenemos al constructor:
|
||||
|
||||
```java
|
||||
public static class Builder {
|
||||
private final Profession profession;
|
||||
private final String name;
|
||||
private HairType hairType;
|
||||
private HairColor hairColor;
|
||||
private Armor armor;
|
||||
private Weapon weapon;
|
||||
|
||||
public Builder(Profession profession, String name) {
|
||||
if (profession == null || name == null) {
|
||||
throw new IllegalArgumentException("profession and name can not be null");
|
||||
}
|
||||
this.profession = profession;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Builder withHairType(HairType hairType) {
|
||||
this.hairType = hairType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withHairColor(HairColor hairColor) {
|
||||
this.hairColor = hairColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withArmor(Armor armor) {
|
||||
this.armor = armor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withWeapon(Weapon weapon) {
|
||||
this.weapon = weapon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Hero build() {
|
||||
return new Hero(this);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Entonces se puede utilizar como:
|
||||
|
||||
```java
|
||||
var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();
|
||||
```
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utiliza el patrón Builder cuando
|
||||
|
||||
* El algoritmo para crear un objeto complejo debe ser independiente de las partes que componen el objeto y cómo se
|
||||
ensamblan.
|
||||
* El proceso de construcción debe permitir diferentes representaciones para el objeto que se construye.
|
||||
|
||||
## Tutoriales
|
||||
|
||||
* [Refactoring Guru](https://refactoring.guru/design-patterns/builder)
|
||||
* [Oracle Blog](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java)
|
||||
* [Journal Dev](https://www.journaldev.com/1425/builder-design-pattern-in-java)
|
||||
|
||||
## Usos en el mundo real
|
||||
|
||||
* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
|
||||
* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) así como otros
|
||||
buffers
|
||||
como FloatBuffer, IntBuffer, etc.
|
||||
* [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-)
|
||||
* Todas las implementaciones
|
||||
de [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html)
|
||||
* [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder)
|
||||
* [Apache Commons Option.Builder](https://commons.apache.org/proper/commons-cli/apidocs/org/apache/commons/cli/Option.Builder.html)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||
* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb)
|
||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
|
||||
|
After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1,187 @@
|
||||
---
|
||||
title: Context object
|
||||
category: Creational
|
||||
language: es
|
||||
tags:
|
||||
- Data access
|
||||
---
|
||||
|
||||
## Nombre / Clasificación
|
||||
|
||||
Context Object
|
||||
|
||||
## También conocido como
|
||||
|
||||
Context, Encapsulate Context
|
||||
|
||||
## Propósito
|
||||
|
||||
Desacoplar los datos de las clases específicas del protocolo y almacenar los datos del ámbito en un objeto independiente
|
||||
de la tecnología del protocolo subyacente.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Esta aplicación tiene diferentes capas etiquetadas como A, B y C, cada una extrayendo información específica de un
|
||||
> contexto similar para su uso posterior en el software. Pasar cada pieza de información individualmente sería
|
||||
> ineficiente, se necesita un método para almacenar y pasar información de manera eficiente.
|
||||
> En palabras sencillas
|
||||
|
||||
> Crea un objeto y almacena los datos allí y pasa este objeto a donde se necesita.
|
||||
|
||||
[Core J2EE Patterns](http://corej2eepatterns.com/ContextObject.htm) dice
|
||||
|
||||
> Utilice un objeto de contexto (Context Object) para encapsular el estado de una manera independiente del protocolo para ser compartido
|
||||
> en toda tu aplicación.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Definimos qué datos contiene un objeto de contexto (Context Object) de servicio `ServiceContext`.
|
||||
|
||||
```Java
|
||||
public class ServiceContext {
|
||||
|
||||
String ACCOUNT_SERVICE, SESSION_SERVICE, SEARCH_SERVICE;
|
||||
|
||||
public void setACCOUNT_SERVICE(String ACCOUNT_SERVICE) {
|
||||
this.ACCOUNT_SERVICE = ACCOUNT_SERVICE;
|
||||
}
|
||||
|
||||
public void setSESSION_SERVICE(String SESSION_SERVICE) {
|
||||
this.SESSION_SERVICE = SESSION_SERVICE;
|
||||
}
|
||||
|
||||
public void setSEARCH_SERVICE(String SEARCH_SERVICE) {
|
||||
this.SEARCH_SERVICE = SEARCH_SERVICE;
|
||||
}
|
||||
|
||||
public String getACCOUNT_SERVICE() {
|
||||
return ACCOUNT_SERVICE;
|
||||
}
|
||||
|
||||
public String getSESSION_SERVICE() {
|
||||
return SESSION_SERVICE;
|
||||
}
|
||||
|
||||
public String getSEARCH_SERVICE() {
|
||||
return SEARCH_SERVICE;
|
||||
}
|
||||
|
||||
public String toString() { return ACCOUNT_SERVICE + " " + SESSION_SERVICE + " " + SEARCH_SERVICE;}
|
||||
}
|
||||
```
|
||||
|
||||
Se crea una interfaz `ServiceContextFactory` utilizada en partes de la aplicación para crear objetos de contexto.
|
||||
|
||||
```Java
|
||||
public class ServiceContextFactory {
|
||||
|
||||
public static ServiceContext createContext() {
|
||||
return new ServiceContext();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Instanciar el objeto de contexto en la primera capa `LayerA` y la capa contigua `LayerB` hasta llamar al contexto en la capa actual `LayerC`,
|
||||
que estructura el objeto.
|
||||
|
||||
```Java
|
||||
public class LayerA {
|
||||
|
||||
private static ServiceContext context;
|
||||
|
||||
public LayerA() {
|
||||
context = ServiceContextFactory.createContext();
|
||||
}
|
||||
|
||||
public static ServiceContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void addAccountInfo(String accountService) {
|
||||
context.setACCOUNT_SERVICE(accountService);
|
||||
}
|
||||
}
|
||||
|
||||
public class LayerB {
|
||||
|
||||
private static ServiceContext context;
|
||||
|
||||
public LayerB(LayerA layerA) {
|
||||
this.context = layerA.getContext();
|
||||
}
|
||||
|
||||
public static ServiceContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void addSessionInfo(String sessionService) {
|
||||
context.setSESSION_SERVICE(sessionService);
|
||||
}
|
||||
}
|
||||
|
||||
public class LayerC {
|
||||
|
||||
public static ServiceContext context;
|
||||
|
||||
public LayerC(LayerB layerB) {
|
||||
this.context = layerB.getContext();
|
||||
}
|
||||
|
||||
public static ServiceContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void addSearchInfo(String searchService) {
|
||||
context.setSEARCH_SERVICE(searchService);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
He aquí el objeto de contexto y las capas en acción.
|
||||
|
||||
```Java
|
||||
var layerA = new LayerA();
|
||||
layerA.addAccountInfo(SERVICE);
|
||||
LOGGER.info("Context = {}",layerA.getContext());
|
||||
var layerB = new LayerB(layerA);
|
||||
layerB.addSessionInfo(SERVICE);
|
||||
LOGGER.info("Context = {}",layerB.getContext());
|
||||
var layerC = new LayerC(layerB);
|
||||
layerC.addSearchInfo(SERVICE);
|
||||
LOGGER.info("Context = {}",layerC.getContext());
|
||||
```
|
||||
|
||||
Salida del programa:
|
||||
|
||||
```Java
|
||||
Context = SERVICE null null
|
||||
Context = SERVICE SERVICE null
|
||||
Context = SERVICE SERVICE SERVICE
|
||||
```
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilizar el patrón Objeto Contexto (Context Object) para:
|
||||
|
||||
* Compartir información entre diferentes capas del sistema.
|
||||
* Desacoplar datos de software de contextos específicos de protocolo.
|
||||
* Exponer solo las API relevantes dentro del contexto.
|
||||
|
||||
## Usos conocidos
|
||||
|
||||
* [Spring: ApplicationContext](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html)
|
||||
* [Oracle: SecurityContext](https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/SecurityContext.html)
|
||||
* [Oracle: ServletContext](https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Core J2EE Design Patterns](https://amzn.to/3IhcY9w)
|
||||
* [Core J2EE Design Patterns website - Context Object](http://corej2eepatterns.com/ContextObject.htm)
|
||||
* [Allan Kelly - The Encapsulate Context Pattern](https://accu.org/journals/overload/12/63/kelly_246/)
|
||||
* [Arvid S. Krishna et al. - Context Object](https://www.dre.vanderbilt.edu/~schmidt/PDF/Context-Object-Pattern.pdf)
|
||||
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: Converter
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Decoupling
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
El propósito del patrón Conversor (Converter) es proporcionar una forma genérica y común de conversión bidireccional
|
||||
entre tipos correspondientes, permitiendo una implementación limpia en la que los tipos no
|
||||
tienen que conocerse entre sí. Además, el patrón Converter introduce la asignación bidireccional de colecciones
|
||||
bidireccional, reduciendo al mínimo el código repetitivo.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> En las aplicaciones del mundo real, a menudo se da el caso de que la capa de base de datos consta de entidades que
|
||||
> necesitan ser mapeadas en DTO para su uso en la capa de lógica de negocio. Un mapeo similar se realiza para
|
||||
> potencialmente enorme cantidad de clases y necesitamos una forma genérica de lograrlo.
|
||||
|
||||
En palabras sencillas
|
||||
|
||||
> El patrón de conversión (Converter) facilita la asignación de instancias de una clase a instancias de otra clase.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Necesitamos una solución genérica para el problema del mapeo. Para ello, introduzcamos un convertidor genérico.
|
||||
|
||||
```java
|
||||
public class Converter<T, U> {
|
||||
|
||||
private final Function<T, U> fromDto;
|
||||
private final Function<U, T> fromEntity;
|
||||
|
||||
public Converter(final Function<T, U> fromDto, final Function<U, T> fromEntity) {
|
||||
this.fromDto = fromDto;
|
||||
this.fromEntity = fromEntity;
|
||||
}
|
||||
|
||||
public final U convertFromDto(final T dto) {
|
||||
return fromDto.apply(dto);
|
||||
}
|
||||
|
||||
public final T convertFromEntity(final U entity) {
|
||||
return fromEntity.apply(entity);
|
||||
}
|
||||
|
||||
public final List<U> createFromDtos(final Collection<T> dtos) {
|
||||
return dtos.stream().map(this::convertFromDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public final List<T> createFromEntities(final Collection<U> entities) {
|
||||
return entities.stream().map(this::convertFromEntity).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Los convertidores especializados heredan de esta clase base de la siguiente manera.
|
||||
|
||||
```java
|
||||
public class UserConverter extends Converter<UserDto, User> {
|
||||
|
||||
public UserConverter() {
|
||||
super(UserConverter::convertToEntity, UserConverter::convertToDto);
|
||||
}
|
||||
|
||||
private static UserDto convertToDto(User user) {
|
||||
return new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getUserId());
|
||||
}
|
||||
|
||||
private static User convertToEntity(UserDto dto) {
|
||||
return new User(dto.getFirstName(), dto.getLastName(), dto.isActive(), dto.getEmail());
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Ahora el mapeo entre `User` y `UserDto` se vuelve trivial.
|
||||
|
||||
```java
|
||||
var userConverter = new UserConverter();
|
||||
var dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com");
|
||||
var user = userConverter.convertFromDto(dtoUser);
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón de conversión en las siguientes situaciones:
|
||||
|
||||
* Cuando tiene tipos que lógicamente se corresponden entre sí y necesita convertir entidades
|
||||
entre ellos.
|
||||
* Cuando quieras proporcionar diferentes formas de conversión de tipos dependiendo del contexto.
|
||||
* Siempre que introduzca un DTO (Data transfer object), probablemente necesitará convertirlo en la
|
||||
equivalencia de dominio.
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Converter Pattern in Java 8](http://www.xsolve.pl/blog/converter-pattern-in-java-8/)
|
||||
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: Dependency Injection
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Decoupling
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
La inyección de dependencias es un patrón de diseño de software en el que una o más dependencias (o servicios)
|
||||
se inyectan, o se pasan por referencia, a un objeto dependiente (o cliente) y pasan a formar parte del estado del
|
||||
cliente. El patrón separa la creación de las dependencias de un cliente de su propio comportamiento,
|
||||
lo que permite que los diseños de los programas estén poco acoplados y sigan los principios de inversión de control y
|
||||
responsabilidad única.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Al viejo mago le gusta llenar su pipa y fumar tabaco de vez en cuando. Sin embargo, no quiere depender de una sola
|
||||
> marca de tabaco, sino que le gusta poder disfrutar de todas ellas de manera intercambiable.
|
||||
|
||||
En palabras sencillas
|
||||
|
||||
> La Inyección de Dependencias separa la creación de las dependencias del cliente de su propio comportamiento.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> En ingeniería de software, la inyección de dependencias es una técnica en la que un objeto recibe otros objetos de los
|
||||
> que depende. Estos otros objetos se llaman dependencias.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Presentemos primero la interfaz tabaco `Tobacco` y las marcas concretas.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public abstract class Tobacco {
|
||||
|
||||
public void smoke(Wizard wizard) {
|
||||
LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
|
||||
this.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
public class SecondBreakfastTobacco extends Tobacco {
|
||||
}
|
||||
|
||||
public class RivendellTobacco extends Tobacco {
|
||||
}
|
||||
|
||||
public class OldTobyTobacco extends Tobacco {
|
||||
}
|
||||
```
|
||||
|
||||
A continuación se muestra la interfaz `Wizard` y su implementación.
|
||||
|
||||
```java
|
||||
public interface Wizard {
|
||||
|
||||
void smoke();
|
||||
}
|
||||
|
||||
public class AdvancedWizard implements Wizard {
|
||||
|
||||
private final Tobacco tobacco;
|
||||
|
||||
public AdvancedWizard(Tobacco tobacco) {
|
||||
this.tobacco = tobacco;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void smoke() {
|
||||
tobacco.smoke(this);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Y por último podemos demostrar lo fácil que es darle al viejo mago cualquier marca de tabaco `Tobacco`.
|
||||
|
||||
```java
|
||||
var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
|
||||
advancedWizard.smoke();
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón de Inyección de Dependencia cuando:
|
||||
|
||||
* Cuando necesites eliminar el conocimiento de la implementación concreta del objeto.
|
||||
* Para permitir pruebas unitarias de clases de forma aislada utilizando objetos simulados o stubs.
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd)
|
||||
* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871)
|
||||
* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1)
|
||||
* [Google Guice: Agile Lightweight Dependency Injection Framework](https://www.amazon.com/gp/product/1590599977/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1590599977&linkId=3b10c90b7ba480a1b7777ff38000f956)
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,132 @@
|
||||
---
|
||||
title: Factory Kit
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Extensibility
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
|
||||
Abstract-Factory
|
||||
|
||||
## Propósito
|
||||
|
||||
Define una fábrica de contenido inmutable con interfaces de constructor y fábrica separadas.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Imagina una fábrica de armas mágicas que puede crear cualquier tipo de arma que se desee. Cuando la fábrica se
|
||||
> desempaqueta, el maestro recita los tipos de armas necesarios para prepararla. Después de eso, cualquiera de esos
|
||||
> tipos
|
||||
> de armas pueden ser invocados en un instante.
|
||||
|
||||
En palabras sencillas
|
||||
|
||||
> El kit de fábrica (Kit Factory) es un constructor de objetos configurable, una fábrica para crear fábricas.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Definamos primero la interfaz simple arma `Weapon`.
|
||||
|
||||
```java
|
||||
public interface Weapon {
|
||||
}
|
||||
|
||||
public enum WeaponType {
|
||||
SWORD,
|
||||
AXE,
|
||||
BOW,
|
||||
SPEAR
|
||||
}
|
||||
|
||||
public class Sword implements Weapon {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sword";
|
||||
}
|
||||
}
|
||||
|
||||
// Hacha `Axe`, Arco `Bow` y Lanza `Spear` se definen de forma similar
|
||||
```
|
||||
|
||||
A continuación, definimos una interfaz funcional que permite añadir un constructor con un nombre a la fábrica.
|
||||
|
||||
```java
|
||||
public interface Builder {
|
||||
void add(WeaponType name, Supplier<Weapon> supplier);
|
||||
}
|
||||
```
|
||||
|
||||
El núcleo del ejemplo es la interfaz `WeaponFactory` que implementa el patrón de fábrica. El método `#factory` se
|
||||
utiliza para configurar la fábrica con las clases que necesita para ser capaz de construir. El método `#create` se
|
||||
utiliza para crear instancias del objeto.
|
||||
|
||||
```java
|
||||
public interface WeaponFactory {
|
||||
|
||||
static WeaponFactory factory(Consumer<Builder> consumer) {
|
||||
var map = new HashMap<WeaponType, Supplier<Weapon>>();
|
||||
consumer.accept(map::put);
|
||||
return name -> map.get(name).get();
|
||||
}
|
||||
|
||||
Weapon create(WeaponType name);
|
||||
}
|
||||
```
|
||||
|
||||
Ahora, podemos mostrar cómo se puede utilizar `WeaponFactory`.
|
||||
|
||||
```java
|
||||
var factory = WeaponFactory.factory(builder -> {
|
||||
builder.add(WeaponType.SWORD, Sword::new);
|
||||
builder.add(WeaponType.AXE, Axe::new);
|
||||
builder.add(WeaponType.SPEAR, Spear::new);
|
||||
builder.add(WeaponType.BOW, Bow::new);
|
||||
});
|
||||
var list = new ArrayList<Weapon>();
|
||||
list.add(factory.create(WeaponType.AXE));
|
||||
list.add(factory.create(WeaponType.SPEAR));
|
||||
list.add(factory.create(WeaponType.SWORD));
|
||||
list.add(factory.create(WeaponType.BOW));
|
||||
list.stream().forEach(weapon -> LOGGER.info("{}", weapon.toString()));
|
||||
```
|
||||
|
||||
Esta es la salida de la consola cuando se ejecuta el ejemplo.
|
||||
|
||||
```
|
||||
21:15:49.709 [main] INFO com.iluwatar.factorykit.App - Axe
|
||||
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Spear
|
||||
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Sword
|
||||
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Bow
|
||||
```
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Factory Kit cuando
|
||||
|
||||
* La clase de fábrica no puede anticipar los tipos de objetos que debe crear.
|
||||
* Se necesita una nueva instancia de un constructor personalizado en lugar de uno global.
|
||||
* Los tipos de objetos que la fábrica puede construir necesitan ser definidos fuera de la clase.
|
||||
* Es necesario separar las interfaces del constructor y del creador.
|
||||
* Desarrollos de juegos y otras aplicaciones que tienen personalización del usuario
|
||||
|
||||
## Patrones relacionados
|
||||
|
||||
* [Builder](https://java-design-patterns.com/patterns/builder/)
|
||||
* [Factory](https://java-design-patterns.com/patterns/factory/)
|
||||
* [Abstract-Factory](https://java-design-patterns.com/patterns/abstract-factory/)
|
||||
|
||||
## Tutoriales
|
||||
|
||||
* [Factory kit implementation tutorial](https://diego-pacheco.medium.com/factory-kit-pattern-66d5ccb0c405)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Design Pattern Reloaded by Remi Forax](https://www.youtube.com/watch?v=-k2X7guaArU)
|
||||
|
After Width: | Height: | Size: 37 KiB |
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Factory Method
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Extensibility
|
||||
- Gang of Four
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
|
||||
Virtual Constructor
|
||||
|
||||
## Propósito
|
||||
|
||||
Definir una interfaz para crear un objeto, pero dejar que las subclases decidan qué clase instanciar. El método de
|
||||
fábrica permite que una clase difiera la instanciación a las subclases.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> El herrero fabrica armas. Los elfos requieren armas élficas y los orcos requieren armas orcas. Dependiendo del cliente
|
||||
> en cuestión, se convoca al tipo correcto de herrero.
|
||||
|
||||
En palabras sencillas
|
||||
|
||||
> Proporciona una forma de delegar la lógica de instanciación a las clases hijas.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> En la programación basada en clases, el patrón de método de fábrica es un patrón de creación que utiliza métodos de
|
||||
> fábrica para lidiar con el problema de crear objetos sin tener que especificar la clase exacta del objeto que se
|
||||
> creará.
|
||||
> Esto se hace creando objetos llamando a un método de fábrica — ya sea especificado en una interfaz e implementado por
|
||||
> clases hijas, o implementado en una clase base y opcionalmente sobrescrito por clases derivadas — en lugar de llamar a
|
||||
> un constructor.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Tomando nuestro ejemplo del herrero. En primer lugar, tenemos una interfaz `Blacksmith` y algunas implementaciones para
|
||||
ello:
|
||||
|
||||
```java
|
||||
public interface Blacksmith {
|
||||
Weapon manufactureWeapon(WeaponType weaponType);
|
||||
}
|
||||
|
||||
public class ElfBlacksmith implements Blacksmith {
|
||||
public Weapon manufactureWeapon(WeaponType weaponType) {
|
||||
return ELFARSENAL.get(weaponType);
|
||||
}
|
||||
}
|
||||
|
||||
public class OrcBlacksmith implements Blacksmith {
|
||||
public Weapon manufactureWeapon(WeaponType weaponType) {
|
||||
return ORCARSENAL.get(weaponType);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Cuando llegan los clientes, se llama al herrero adecuado y se fabrican las armas solicitadas:
|
||||
|
||||
```java
|
||||
Blacksmith blacksmith = new OrcBlacksmith();
|
||||
Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
|
||||
blacksmith = new ElfBlacksmith();
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
```
|
||||
|
||||
Salida del programa:
|
||||
|
||||
```
|
||||
The orc blacksmith manufactured an orcish spear
|
||||
The orc blacksmith manufactured an orcish axe
|
||||
The elf blacksmith manufactured an elven spear
|
||||
The elf blacksmith manufactured an elven axe
|
||||
```
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Método de Fábrica cuando:
|
||||
|
||||
* La clase no puede anticipar la clase de objetos que debe crear.
|
||||
* La clase quiere que sus subclases especifiquen los objetos que crea.
|
||||
* Las clases delegan la responsabilidad a una de varias subclases ayudantes, y desea localizar el conocimiento de qué
|
||||
subclase ayudante es el delegado. conocimiento de qué subclase ayudante es el delegado.
|
||||
|
||||
## Usos conocidos
|
||||
|
||||
* [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
|
||||
* [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
|
||||
* [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
|
||||
* [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
|
||||
* [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-)
|
||||
* [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-)
|
||||
* [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
|
||||
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,143 @@
|
||||
---
|
||||
title: Factory
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Gang of Four
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
|
||||
* Simple Factory
|
||||
* Static Factory Method
|
||||
|
||||
## Propósito
|
||||
|
||||
Proporcionar un método estático encapsulado en una clase llamada fábrica (Factory), para ocultar la lógica de
|
||||
implementación y
|
||||
hacer que el código del cliente se centre en el uso en lugar de inicializar nuevos objetos.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Imagina un alquimista que está a punto de fabricar monedas. El alquimista debe ser capaz de crear tanto monedas de oro
|
||||
> como de cobre y cambiar entre ellas debe ser posible sin modificar el código fuente existente. El patrón de fábrica lo
|
||||
> hace posible proporcionando un método de construcción estático que puede ser llamado con los parámetros relevantes.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> La fábrica (Factory) es un objeto para crear otros objetos: formalmente, una fábrica es una función o método que
|
||||
> devuelve objetos de un prototipo o clase variable.
|
||||
|
||||
**Ejemplo programático**
|
||||
|
||||
Tenemos una interfaz moneda `Coin` y dos implementaciones moneda de oro `GoldCoin` y moneda de cobre `CopperCoin`.
|
||||
|
||||
```java
|
||||
public interface Coin {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
public class GoldCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is a gold coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
|
||||
public class CopperCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is a copper coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
La siguiente enumeración representa los tipos de monedas que admitimos (`GoldCoin` y `CopperCoin`).
|
||||
|
||||
```java
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CoinType {
|
||||
|
||||
COPPER(CopperCoin::new),
|
||||
GOLD(GoldCoin::new);
|
||||
|
||||
private final Supplier<Coin> constructor;
|
||||
}
|
||||
```
|
||||
|
||||
Luego tenemos el método estático obtener moneda `getCoin` para crear objetos moneda encapsulados en la clase fábrica
|
||||
`CoinFactory`.
|
||||
|
||||
```java
|
||||
public class CoinFactory {
|
||||
|
||||
public static Coin getCoin(CoinType type) {
|
||||
return type.getConstructor().get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ahora en el código cliente podemos crear diferentes tipos de monedas utilizando la clase fábrica.
|
||||
|
||||
```java
|
||||
LOGGER.info("The alchemist begins his work.");
|
||||
var coin1 = CoinFactory.getCoin(CoinType.COPPER);
|
||||
var coin2 = CoinFactory.getCoin(CoinType.GOLD);
|
||||
LOGGER.info(coin1.getDescription());
|
||||
LOGGER.info(coin2.getDescription());
|
||||
```
|
||||
|
||||
Salida del programa:
|
||||
|
||||
```java
|
||||
The alchemist begins his work.
|
||||
This is a copper coin.
|
||||
This is a gold coin.
|
||||
```
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón de fábrica cuando solo se preocupe por la creación de un objeto, no de cómo crearlo
|
||||
y gestionarlo.
|
||||
|
||||
Ventajas
|
||||
|
||||
* Permite mantener toda la creación de objetos en un solo lugar y evitar la propagación de la palabra clave 'new' a
|
||||
través de la base de código.
|
||||
* Permite escribir código poco acoplado. Algunas de sus principales ventajas incluyen mejor testabilidad, código fácil
|
||||
de entender, componentes intercambiables, escalabilidad y características aisladas.
|
||||
|
||||
Contras
|
||||
|
||||
* El código se vuelve más complicado de lo que debería.
|
||||
|
||||
## Usos conocidos
|
||||
|
||||
* [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
|
||||
* [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
|
||||
* [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
|
||||
* [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
|
||||
* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (
|
||||
devuelve diferentes objetos singleton, en función de un protocolo)
|
||||
* [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E))
|
||||
* [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--)
|
||||
y otros métodos similares.
|
||||
|
||||
## Patrones relacionados
|
||||
|
||||
* [Factory Method](https://java-design-patterns.com/patterns/factory-method/)
|
||||
* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
|
||||
* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/)
|
||||
|
After Width: | Height: | Size: 29 KiB |
@@ -27,7 +27,7 @@ En otras palabras
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> En ingeniería de software, la arquitectura multitier (a menudo referida como arquitectura n-tier) o
|
||||
> En ingeniería de software, la arquitectura de varios niveles _multitier_ (a menudo referida como arquitectura n-tier) o
|
||||
> arquitectura multicapa es una arquitectura cliente-servidor en la que las funciones de presentación, procesamiento de aplicaciones
|
||||
> y gestión de datos están físicamente separadas.
|
||||
|
||||
@@ -81,7 +81,7 @@ public class CakeViewImpl implements View {
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 95 KiB |
@@ -12,16 +12,16 @@ la inicialización de un objeto hasta el punto en que se necesita. Puede
|
||||
contribuir a la eficiencia en la operación del programa si se usa de manera adecuada.
|
||||
|
||||
## Diagrama de clases
|
||||

|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
Utilice el modelo de Carga Diferida cuando:
|
||||
|
||||
* la carga anticipada es costosa o el objeto a cargar podría no ser necesario en absoluto
|
||||
* La carga anticipada es costosa o el objeto a cargar podría no ser necesario en absoluto
|
||||
|
||||
## Ejemplos del mundo real
|
||||
|
||||
* Anotaciones JPA @OneToOne, @OneToMany, @ManyToOne, @ManyToMany y fetch = FetchType.LAZY
|
||||
* Anotaciones JPA `@OneToOne`, `@OneToMany`, `@ManyToOne`, `@ManyToMany` y `fetch = FetchType.LAZY`
|
||||
|
||||
## Créditos
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: MonoState
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
Borg
|
||||
|
||||
## Propósito
|
||||
Impone un comportamiento como compartir el mismo estado entre todas las instancias.
|
||||
|
||||
## Diagrama de Clases
|
||||

|
||||
|
||||
## Applicability
|
||||
Utilice el patrón Monostate cuando
|
||||
|
||||
* El mismo estado debe ser compartido por todas las instancias de una clase.
|
||||
* Típicamente, este patrón puede ser usado en cualquier lugar donde un Singleton pueda ser usado. Sin embargo, el uso de Singleton no es transparente, el uso de Monostate sí lo es.
|
||||
* Monostate tiene una gran ventaja sobre Singleton. Las subclases pueden decorar el estado compartido como deseen y, por lo tanto, pueden proporcionar dinámicamente un comportamiento diferente de la clase base.
|
||||
|
||||
## Casos de uso típicos
|
||||
|
||||
* La clase de registro
|
||||
* Gestión de una conexión a una base de datos
|
||||
* Gestor de archivos
|
||||
|
||||
## Ejemplos del mundo real
|
||||
|
||||
Aún no lo he visto.
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,140 @@
|
||||
---
|
||||
title: Multiton
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
|
||||
Registry
|
||||
|
||||
## Propósito
|
||||
|
||||
Asegúrese de que una clase solo tiene un número limitado de instancias y proporcione un punto de acceso global a las
|
||||
mismas.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Los Nazgûl, también llamados espectros del anillo o los Nueve Jinetes, son los sirvientes más terribles de Sauron. Por
|
||||
> definición, siempre hay nueve de ellos.
|
||||
|
||||
En palabras simples
|
||||
|
||||
> El patrón Multiton asegura que hay una cantidad predefinida de instancias disponibles globalmente.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> En ingeniería de software, el patrón multiton es un patrón de diseño que generaliza el patrón singleton. Mientras que
|
||||
> el singleton permite que solo se cree una instancia de una clase, el patrón multiton permite la creación controlada de
|
||||
> múltiples instancias, las cuales gestiona mediante el uso de un mapa.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
`Nazgul` es la clase multiton.
|
||||
|
||||
```java
|
||||
public enum NazgulName {
|
||||
|
||||
KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
|
||||
}
|
||||
|
||||
public final class Nazgul {
|
||||
|
||||
private static final Map<NazgulName, Nazgul> nazguls;
|
||||
|
||||
private final NazgulName name;
|
||||
|
||||
static {
|
||||
nazguls = new ConcurrentHashMap<>();
|
||||
nazguls.put(NazgulName.KHAMUL, new Nazgul(NazgulName.KHAMUL));
|
||||
nazguls.put(NazgulName.MURAZOR, new Nazgul(NazgulName.MURAZOR));
|
||||
nazguls.put(NazgulName.DWAR, new Nazgul(NazgulName.DWAR));
|
||||
nazguls.put(NazgulName.JI_INDUR, new Nazgul(NazgulName.JI_INDUR));
|
||||
nazguls.put(NazgulName.AKHORAHIL, new Nazgul(NazgulName.AKHORAHIL));
|
||||
nazguls.put(NazgulName.HOARMURATH, new Nazgul(NazgulName.HOARMURATH));
|
||||
nazguls.put(NazgulName.ADUNAPHEL, new Nazgul(NazgulName.ADUNAPHEL));
|
||||
nazguls.put(NazgulName.REN, new Nazgul(NazgulName.REN));
|
||||
nazguls.put(NazgulName.UVATHA, new Nazgul(NazgulName.UVATHA));
|
||||
}
|
||||
|
||||
private Nazgul(NazgulName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Nazgul getInstance(NazgulName name) {
|
||||
return nazguls.get(name);
|
||||
}
|
||||
|
||||
public NazgulName getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Y así es como accedemos a las instancias `Nazgul`.
|
||||
|
||||
```java
|
||||
// eagerly initialized multiton
|
||||
LOGGER.info("Printing out eagerly initialized multiton contents");
|
||||
LOGGER.info("KHAMUL={}", Nazgul.getInstance(NazgulName.KHAMUL));
|
||||
LOGGER.info("MURAZOR={}", Nazgul.getInstance(NazgulName.MURAZOR));
|
||||
LOGGER.info("DWAR={}", Nazgul.getInstance(NazgulName.DWAR));
|
||||
LOGGER.info("JI_INDUR={}", Nazgul.getInstance(NazgulName.JI_INDUR));
|
||||
LOGGER.info("AKHORAHIL={}", Nazgul.getInstance(NazgulName.AKHORAHIL));
|
||||
LOGGER.info("HOARMURATH={}", Nazgul.getInstance(NazgulName.HOARMURATH));
|
||||
LOGGER.info("ADUNAPHEL={}", Nazgul.getInstance(NazgulName.ADUNAPHEL));
|
||||
LOGGER.info("REN={}", Nazgul.getInstance(NazgulName.REN));
|
||||
LOGGER.info("UVATHA={}", Nazgul.getInstance(NazgulName.UVATHA));
|
||||
|
||||
// enum multiton
|
||||
LOGGER.info("Printing out enum-based multiton contents");
|
||||
LOGGER.info("KHAMUL={}", NazgulEnum.KHAMUL);
|
||||
LOGGER.info("MURAZOR={}", NazgulEnum.MURAZOR);
|
||||
LOGGER.info("DWAR={}", NazgulEnum.DWAR);
|
||||
LOGGER.info("JI_INDUR={}", NazgulEnum.JI_INDUR);
|
||||
LOGGER.info("AKHORAHIL={}", NazgulEnum.AKHORAHIL);
|
||||
LOGGER.info("HOARMURATH={}", NazgulEnum.HOARMURATH);
|
||||
LOGGER.info("ADUNAPHEL={}", NazgulEnum.ADUNAPHEL);
|
||||
LOGGER.info("REN={}", NazgulEnum.REN);
|
||||
LOGGER.info("UVATHA={}", NazgulEnum.UVATHA);
|
||||
```
|
||||
|
||||
Salida del programa:
|
||||
|
||||
```
|
||||
20:35:07.413 [main] INFO com.iluwatar.multiton.App - Printing out eagerly initialized multiton contents
|
||||
20:35:07.417 [main] INFO com.iluwatar.multiton.App - KHAMUL=com.iluwatar.multiton.Nazgul@48cf768c
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - MURAZOR=com.iluwatar.multiton.Nazgul@7960847b
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - DWAR=com.iluwatar.multiton.Nazgul@6a6824be
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - JI_INDUR=com.iluwatar.multiton.Nazgul@5c8da962
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - AKHORAHIL=com.iluwatar.multiton.Nazgul@512ddf17
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - HOARMURATH=com.iluwatar.multiton.Nazgul@2c13da15
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - ADUNAPHEL=com.iluwatar.multiton.Nazgul@77556fd
|
||||
20:35:07.419 [main] INFO com.iluwatar.multiton.App - REN=com.iluwatar.multiton.Nazgul@368239c8
|
||||
20:35:07.420 [main] INFO com.iluwatar.multiton.App - UVATHA=com.iluwatar.multiton.Nazgul@9e89d68
|
||||
20:35:07.420 [main] INFO com.iluwatar.multiton.App - Printing out enum-based multiton contents
|
||||
20:35:07.420 [main] INFO com.iluwatar.multiton.App - KHAMUL=KHAMUL
|
||||
20:35:07.420 [main] INFO com.iluwatar.multiton.App - MURAZOR=MURAZOR
|
||||
20:35:07.420 [main] INFO com.iluwatar.multiton.App - DWAR=DWAR
|
||||
20:35:07.420 [main] INFO com.iluwatar.multiton.App - JI_INDUR=JI_INDUR
|
||||
20:35:07.421 [main] INFO com.iluwatar.multiton.App - AKHORAHIL=AKHORAHIL
|
||||
20:35:07.421 [main] INFO com.iluwatar.multiton.App - HOARMURATH=HOARMURATH
|
||||
20:35:07.421 [main] INFO com.iluwatar.multiton.App - ADUNAPHEL=ADUNAPHEL
|
||||
20:35:07.421 [main] INFO com.iluwatar.multiton.App - REN=REN
|
||||
20:35:07.421 [main] INFO com.iluwatar.multiton.App - UVATHA=UVATHA
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Multiton cuando
|
||||
|
||||
* Debe haber un número determinado de instancias de una clase, y deben ser accesibles a los clientes desde un punto de
|
||||
acceso conocido.
|
||||
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Object Mother
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Se utiliza para definir una fábrica de contenido inmutable con interfaces de constructor y fábrica separadas.
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Object Mother cuando
|
||||
|
||||
* Quieres objetos consistentes a lo largo de varias pruebas
|
||||
* Desea reducir el código para la creación de objetos en las pruebas.
|
||||
* Cada prueba debe ejecutarse con datos nuevos
|
||||
|
||||
## Comprender el patrón madre objeto (Object Mother)
|
||||
|
||||
### Escenario real
|
||||
|
||||
Imagine que está desarrollando una aplicación Java para una agencia de viajes. En su sistema, hay diferentes tipos de
|
||||
viajeros, como turistas, viajeros de negocios y agentes de viajes, cada uno con atributos y comportamientos específicos.
|
||||
Para realizar pruebas exhaustivas, necesita crear y manipular estos objetos viajeros en varios contextos. El patrón
|
||||
Object Mother puede ayudarle a generar objetos viajeros coherentes y predefinidos para las pruebas, garantizando que
|
||||
estas se basen en datos conocidos y fiables.
|
||||
|
||||
### En palabras simples
|
||||
|
||||
El Patrón Objeto Madre (Object Mother) es un patrón de diseño utilizado en Java para simplificar la creación de objetos
|
||||
con configuraciones específicas, especialmente para pruebas. En lugar de construir manualmente objetos con propiedades
|
||||
variables para cada caso de prueba, se crea una clase o método "Objeto Madre" dedicado que produce estos objetos con
|
||||
configuraciones predefinidas. De este modo se garantiza la coherencia y previsibilidad de los datos de las pruebas, lo
|
||||
que las hace más fiables y fáciles de gestionar.
|
||||
|
||||
### Visión general desde el punto de vista de las pruebas
|
||||
|
||||
El patrón Objeto Madre (Object Mother) es un patrón de diseño relacionado con las pruebas que ayuda a mantener un
|
||||
entorno de pruebas coherente y fiable. Permite definir y crear objetos con atributos específicos, lo que ayuda a
|
||||
garantizar que las pruebas produzcan resultados coherentes y predecibles, lo que facilita la detección de problemas y el
|
||||
mantenimiento del conjunto de pruebas.
|
||||
|
||||
### Uso práctico en pruebas
|
||||
|
||||
En las pruebas de software, sobre todo en las unitarias, el Patrón Objeto Madre tiene un valor incalculable. Ayuda a
|
||||
asegurar que sus pruebas no están influenciadas por datos impredecibles, haciendo así sus pruebas más robustas y
|
||||
repetibles. Al centralizar la creación de objetos de prueba en un Objeto Madre, puede adaptar fácilmente sus datos de
|
||||
prueba a diferentes escenarios.
|
||||
|
||||
### Ejemplo en Java
|
||||
|
||||
He aquí un ejemplo ilustrativo en Java del Patrón Objeto Madre (Object Mother) en el contexto de una aplicación de
|
||||
agencia de viajes:
|
||||
|
||||
```java
|
||||
class Traveler {
|
||||
private String name;
|
||||
private int age;
|
||||
private boolean isBusinessTraveler;
|
||||
|
||||
// Constructor and methods for the traveler
|
||||
// ...
|
||||
|
||||
// Getter and setter methods
|
||||
// ...
|
||||
}
|
||||
|
||||
class TravelerMother {
|
||||
public static Traveler createTourist(String name, int age) {
|
||||
Traveler traveler = new Traveler();
|
||||
traveler.setName(name);
|
||||
traveler.setAge(age);
|
||||
traveler.setBusinessTraveler(false);
|
||||
return traveler;
|
||||
}
|
||||
|
||||
public static Traveler createBusinessTraveler(String name, int age) {
|
||||
Traveler traveler = new Traveler();
|
||||
traveler.setName(name);
|
||||
traveler.setAge(age);
|
||||
traveler.setBusinessTraveler(true);
|
||||
return traveler;
|
||||
}
|
||||
}
|
||||
|
||||
public class TravelAgency {
|
||||
public static void main(String[] args) {
|
||||
// Using the Object Mother to create traveler objects for testing
|
||||
Traveler tourist = TravelerMother.createTourist("Alice", 28);
|
||||
Traveler businessTraveler = TravelerMother.createBusinessTraveler("Bob", 35);
|
||||
|
||||
// Now you have consistent traveler objects for testing.
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
En este ejemplo, TravelerMother es la clase Object Mother responsable de generar objetos Traveler predefinidos con
|
||||
configuraciones específicas. Este enfoque garantiza que disponga de datos de prueba coherentes para diversos escenarios
|
||||
en una aplicación de agencia de viajes, lo que mejora la fiabilidad y la eficacia de sus esfuerzos de prueba.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Answer by David Brown](http://stackoverflow.com/questions/923319/what-is-an-objectmother) a la pregunta de
|
||||
stackoverflow: [What is an ObjectMother?](http://stackoverflow.com/questions/923319/what-is-an-objectmother)
|
||||
* [c2wiki - Object Mother](http://c2.com/cgi/wiki?ObjectMother)
|
||||
* [Nat Pryce - Test Data Builders: an alternative to the Object Mother pattern](http://www.natpryce.com/articles/000714.html)
|
||||
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: Object Pool
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Game programming
|
||||
- Performance
|
||||
---
|
||||
|
||||
## También conocido como
|
||||
|
||||
Resource Pool
|
||||
|
||||
## Propósito
|
||||
|
||||
Cuando los objetos son costosos de crear y solo se necesitan durante cortos períodos de tiempo, es ventajoso utilizar el
|
||||
patrón de Object Pool. El Object Pool proporciona una caché para objetos instanciados, rastreando cuáles están en uso y
|
||||
cuáles están disponibles.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> En nuestro juego de guerra necesitamos usar olifantes, bestias masivas y míticas, pero el problema es que son
|
||||
> extremadamente costosos de crear. La solución es crear un grupo de ellos, rastrear cuáles están en uso y, en lugar de
|
||||
> desecharlos, reutilizar las instancias.
|
||||
|
||||
En palabras simples
|
||||
|
||||
> Object Pool gestiona un conjunto de instancias en lugar de crearlas y destruirlas bajo demanda.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> El patrón de object pool es un patrón de diseño de creación de software que utiliza un conjunto de objetos
|
||||
> inicializados listos para usar, un "pool", en lugar de asignar y destruirlos a demanda.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
Aquí está la clase básica olifante `Oliphaunt`. Estos gigantes son muy caros de crear.
|
||||
|
||||
```java
|
||||
public class Oliphaunt {
|
||||
|
||||
private static final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
private final int id;
|
||||
|
||||
public Oliphaunt() {
|
||||
id = counter.incrementAndGet();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Oliphaunt id=%d", id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A continuación se muestra el `ObjectPool` y más concretamente el `OliphauntPool`.
|
||||
|
||||
```java
|
||||
public abstract class ObjectPool<T> {
|
||||
|
||||
private final Set<T> available = new HashSet<>();
|
||||
private final Set<T> inUse = new HashSet<>();
|
||||
|
||||
protected abstract T create();
|
||||
|
||||
public synchronized T checkOut() {
|
||||
if (available.isEmpty()) {
|
||||
available.add(create());
|
||||
}
|
||||
var instance = available.iterator().next();
|
||||
available.remove(instance);
|
||||
inUse.add(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public synchronized void checkIn(T instance) {
|
||||
inUse.remove(instance);
|
||||
available.add(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return String.format("Pool available=%d inUse=%d", available.size(), inUse.size());
|
||||
}
|
||||
}
|
||||
|
||||
public class OliphauntPool extends ObjectPool<Oliphaunt> {
|
||||
|
||||
@Override
|
||||
protected Oliphaunt create() {
|
||||
return new Oliphaunt();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Por último, así es como utilizamos la piscina.
|
||||
|
||||
```java
|
||||
var pool = new OliphauntPool();
|
||||
var oliphaunt1 = pool.checkOut();
|
||||
var oliphaunt2 = pool.checkOut();
|
||||
var oliphaunt3 = pool.checkOut();
|
||||
pool.checkIn(oliphaunt1);
|
||||
pool.checkIn(oliphaunt2);
|
||||
var oliphaunt4 = pool.checkOut();
|
||||
var oliphaunt5 = pool.checkOut();
|
||||
```
|
||||
|
||||
Salida del programa:
|
||||
|
||||
```
|
||||
Pool available=0 inUse=0
|
||||
Checked out Oliphaunt id=1
|
||||
Pool available=0 inUse=1
|
||||
Checked out Oliphaunt id=2
|
||||
Checked out Oliphaunt id=3
|
||||
Pool available=0 inUse=3
|
||||
Checking in Oliphaunt id=1
|
||||
Checking in Oliphaunt id=2
|
||||
Pool available=2 inUse=1
|
||||
Checked out Oliphaunt id=2
|
||||
Checked out Oliphaunt id=1
|
||||
Pool available=0 inUse=3
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Object Pool cuando
|
||||
|
||||
* Los objetos son caros de crear (coste de asignación).
|
||||
* Necesitas un gran número de objetos de vida corta (fragmentación de memoria).
|
||||
|
After Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,144 @@
|
||||
---
|
||||
title: Property
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Crear jerarquía de objetos y nuevos objetos utilizando objetos existentes como padres.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> En la mística tierra de _"Elandria"_, los aventureros pueden aprovechar el poder de las reliquias antiguas para
|
||||
> personalizar sus habilidades. Cada reliquia representa una propiedad o habilidad única. A medida que los aventureros
|
||||
> exploran, descubren e integran nuevas reliquias, mejorando dinámicamente sus habilidades en función de las reliquias
|
||||
> que
|
||||
> poseen.
|
||||
|
||||
> Considera un software moderno utilizado en el diseño y personalización de teléfonos inteligentes. Los diseñadores
|
||||
> pueden elegir entre una variedad de componentes como el tipo de procesador, las especificaciones de la cámara, la
|
||||
> capacidad de la batería y más. Cada componente representa una propiedad del teléfono inteligente. A medida que la
|
||||
> tecnología evoluciona y se disponen de nuevos componentes, los diseñadores pueden agregar o reemplazar propiedades sin
|
||||
> problemas para crear una configuración de teléfono inteligente única sin redefinir la estructura de diseño central.
|
||||
|
||||
En palabras simples
|
||||
|
||||
> Define y gestiona un conjunto dinámico de propiedades para un objeto, permitiendo la personalización sin alterar su
|
||||
> estructura.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
```java
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// Enumeration for possible properties or statistics a character can have
|
||||
enum Stats {
|
||||
AGILITY, ATTACK_POWER, ARMOR, INTELLECT, SPIRIT, FURY, RAGE;
|
||||
}
|
||||
|
||||
// Enumeration for different types or classes of characters
|
||||
enum Type {
|
||||
WARRIOR, MAGE, ROGUE;
|
||||
}
|
||||
|
||||
// Interface defining prototype operations on a character
|
||||
interface Prototype {
|
||||
Integer get(Stats stat);
|
||||
boolean has(Stats stat);
|
||||
void set(Stats stat, Integer value);
|
||||
void remove(Stats stat);
|
||||
}
|
||||
|
||||
// Implementation of the Character class
|
||||
class Character implements Prototype {
|
||||
private String name;
|
||||
private Type type;
|
||||
private Map<Stats, Integer> properties = new HashMap<>();
|
||||
|
||||
public Character() {}
|
||||
|
||||
public Character(Type type, Prototype prototype) {
|
||||
this.type = type;
|
||||
for (Stats stat : Stats.values()) {
|
||||
if (prototype.has(stat)) {
|
||||
this.set(stat, prototype.get(stat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Character(String name, Type type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(Stats stat) {
|
||||
return properties.get(stat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(Stats stat) {
|
||||
return properties.containsKey(stat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Stats stat, Integer value) {
|
||||
properties.put(stat, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Stats stat) {
|
||||
properties.remove(stat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Character{name='" + name + "', type=" + type + ", properties=" + properties + '}';
|
||||
}
|
||||
}
|
||||
|
||||
// Main class to demonstrate the pattern
|
||||
public class PropertyPatternDemo {
|
||||
public static void main(String[] args) {
|
||||
// Create a prototype character
|
||||
Character prototypeWarrior = new Character("Proto Warrior", Type.WARRIOR);
|
||||
prototypeWarrior.set(Stats.ATTACK_POWER, 10);
|
||||
prototypeWarrior.set(Stats.ARMOR, 15);
|
||||
|
||||
// Create a new character using the prototype
|
||||
Character newWarrior = new Character(Type.WARRIOR, prototypeWarrior);
|
||||
newWarrior.set(Stats.AGILITY, 5);
|
||||
|
||||
System.out.println(prototypeWarrior);
|
||||
System.out.println(newWarrior);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Salida del programa:
|
||||
|
||||
```
|
||||
Character{name='Proto Warrior', type=WARRIOR, properties={ARMOR=15, ATTACK_POWER=10}}
|
||||
Character{name='null', type=WARRIOR, properties={ARMOR=15, AGILITY=5, ATTACK_POWER=10}}
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Property cuando
|
||||
|
||||
* Cuando desee tener objetos con un conjunto dinámico de campos y herencia de prototipos
|
||||
|
||||
## Ejemplo del mundo real
|
||||
|
||||
* [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototipo
|
||||
herencia
|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,180 @@
|
||||
---
|
||||
title: Prototype
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Gang Of Four
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Especificar los tipos de objetos a crear utilizando una instancia prototípica, y crear nuevos objetos copiando este
|
||||
prototipo
|
||||
|
||||
## Explicación
|
||||
|
||||
Primero, debe notarse que el patrón Prototype no se utiliza para obtener beneficios de rendimiento. Solo se utiliza para
|
||||
crear nuevos objetos a partir de instancias prototipo.
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> ¿Recuerdas a Dolly? ¡La oveja que fue clonada! No entremos en detalles, pero el punto clave aquí es que todo se trata
|
||||
> de clonación.
|
||||
|
||||
En palabras simples
|
||||
|
||||
> Crea un objeto basado en un objeto existente a través de la clonación.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> El patrón de prototipo es un patrón de diseño de creación en el desarrollo de software. Se utiliza cuando el tipo de
|
||||
> objetos a crear está determinado por una instancia prototípica, que se clona para producir nuevos objetos.
|
||||
|
||||
En resumen, te permite crear una copia de un objeto existente y modificarla según tus necesidades, en lugar de pasar por
|
||||
el problema de crear un objeto desde cero y configurarlo.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
En Java, se recomienda implementar el patrón prototipo de la siguiente manera. En primer lugar, cree una interfaz con un
|
||||
método para clonar objetos. En este ejemplo, la interfaz `Prototype` logra esto con su método `copy`.
|
||||
|
||||
```java
|
||||
public abstract class Prototype<T> implements Cloneable {
|
||||
@SneakyThrows
|
||||
public T copy() {
|
||||
return (T) super.clone();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Nuestro ejemplo contiene una jerarquía de diferentes criaturas. Por ejemplo, veamos las clases `Beast` y `OrcBeast`.
|
||||
|
||||
```java
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@NoArgsConstructor
|
||||
public abstract class Beast extends Prototype<Beast> {
|
||||
|
||||
public Beast(Beast source) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@RequiredArgsConstructor
|
||||
public class OrcBeast extends Beast {
|
||||
|
||||
private final String weapon;
|
||||
|
||||
public OrcBeast(OrcBeast orcBeast) {
|
||||
super(orcBeast);
|
||||
this.weapon = orcBeast.weapon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Orcish wolf attacks with " + weapon;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
No queremos entrar en demasiados detalles, pero el ejemplo completo contiene también las clases base `Mage` y `Warlord`
|
||||
y hay implementaciones especializadas para los elfos además de para los orcos.
|
||||
|
||||
Para aprovechar al máximo el patrón prototipo, creamos las clases `HeroFactory` y `HeroFactoryImpl` para producir
|
||||
diferentes tipos de criaturas a partir de prototipos.
|
||||
|
||||
```java
|
||||
public interface HeroFactory {
|
||||
|
||||
Mage createMage();
|
||||
Warlord createWarlord();
|
||||
Beast createBeast();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class HeroFactoryImpl implements HeroFactory {
|
||||
|
||||
private final Mage mage;
|
||||
private final Warlord warlord;
|
||||
private final Beast beast;
|
||||
|
||||
public Mage createMage() {
|
||||
return mage.copy();
|
||||
}
|
||||
|
||||
public Warlord createWarlord() {
|
||||
return warlord.copy();
|
||||
}
|
||||
|
||||
public Beast createBeast() {
|
||||
return beast.copy();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ahora, somos capaces de mostrar el patrón prototipo completo en acción produciendo nuevas criaturas clonando instancias
|
||||
existentes.
|
||||
|
||||
```java
|
||||
var factory = new HeroFactoryImpl(
|
||||
new ElfMage("cooking"),
|
||||
new ElfWarlord("cleaning"),
|
||||
new ElfBeast("protecting")
|
||||
);
|
||||
var mage = factory.createMage();
|
||||
var warlord = factory.createWarlord();
|
||||
var beast = factory.createBeast();
|
||||
LOGGER.info(mage.toString());
|
||||
LOGGER.info(warlord.toString());
|
||||
LOGGER.info(beast.toString());
|
||||
|
||||
factory = new HeroFactoryImpl(
|
||||
new OrcMage("axe"),
|
||||
new OrcWarlord("sword"),
|
||||
new OrcBeast("laser")
|
||||
);
|
||||
mage = factory.createMage();
|
||||
warlord = factory.createWarlord();
|
||||
beast = factory.createBeast();
|
||||
LOGGER.info(mage.toString());
|
||||
LOGGER.info(warlord.toString());
|
||||
LOGGER.info(beast.toString());
|
||||
```
|
||||
|
||||
Esta es la salida de la consola al ejecutar el ejemplo.
|
||||
|
||||
```
|
||||
Elven mage helps in cooking
|
||||
Elven warlord helps in cleaning
|
||||
Elven eagle helps in protecting
|
||||
Orcish mage attacks with axe
|
||||
Orcish warlord attacks with sword
|
||||
Orcish wolf attacks with laser
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Prototipo cuando un sistema deba ser independiente de cómo se crean, componen, representan sus
|
||||
productos y
|
||||
|
||||
* Cuando las clases a instanciar se especifican en tiempo de ejecución, por ejemplo, mediante carga dinámica.
|
||||
* Para evitar construir una jerarquía de clases de fábricas paralela a la jerarquía de clases de productos.
|
||||
* Cuando las instancias de una clase solo pueden tener una de unas pocas combinaciones diferentes de estado. Puede ser
|
||||
más conveniente instalar un número correspondiente de prototipos y clonarlos en lugar de instanciar la clase
|
||||
manualmente, cada vez con el estado apropiado.
|
||||
* Cuando la creación de objetos es costosa en comparación con la clonación.
|
||||
|
||||
## Usos conocidos
|
||||
|
||||
* [java.lang.Object#clone()](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||
|
After Width: | Height: | Size: 79 KiB |
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: Registry
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Almacena los objetos de una única clase y proporciona un punto de acceso global a los mismos.
|
||||
Similar al patrón Multiton, la única diferencia es que en un registro no hay restricción en el número de objetos.
|
||||
|
||||
## Explicación
|
||||
|
||||
En pocas palabras
|
||||
|
||||
> El registro es un objeto bien conocido que otros objetos pueden utilizar para encontrar objetos y servicios comunes.
|
||||
|
||||
**Ejemplo Programático**
|
||||
A continuación se muestra una clase `Cliente
|
||||
|
||||
```java
|
||||
public class Customer {
|
||||
|
||||
private final String id;
|
||||
private final String name;
|
||||
|
||||
public Customer(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Este registro de los objetos `Customer` es `CustomerRegistry`.
|
||||
|
||||
```java
|
||||
public final class CustomerRegistry {
|
||||
|
||||
private static final CustomerRegistry instance = new CustomerRegistry();
|
||||
|
||||
public static CustomerRegistry getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final Map<String, Customer> customerMap;
|
||||
|
||||
private CustomerRegistry() {
|
||||
customerMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public Customer addCustomer(Customer customer) {
|
||||
return customerMap.put(customer.getId(), customer);
|
||||
}
|
||||
|
||||
public Customer getCustomer(String id) {
|
||||
return customerMap.get(id);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Usar el patrón Registry cuando
|
||||
|
||||
* El cliente quiere una referencia de algún objeto, por lo que el cliente puede buscar ese objeto en el registro del
|
||||
objeto.
|
||||
|
||||
## Consecuencias
|
||||
|
||||
Un gran número de objetos voluminosos añadidos al registro daría lugar a un gran consumo de memoria, ya que los objetos
|
||||
del registro no se recogen de la basura.
|
||||
|
||||
## Créditos
|
||||
|
||||
* https://www.martinfowler.com/eaaCatalog/registry.html
|
||||
* https://wiki.c2.com/?RegistryPattern
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -58,7 +58,7 @@ enumIvoryTower2=com.iluwatar.singleton.EnumIvoryTower@1221555852
|
||||
|
||||
## Diagrama de clases
|
||||
|
||||

|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: Step Builder
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
# Step Builder Pattern
|
||||
|
||||
## Explicación
|
||||
|
||||
El patrón Step Builder es un patrón de diseño de creación utilizado para construir un objeto complejo paso a paso.
|
||||
Proporciona una interfaz fluida para crear un objeto con un gran número de configuraciones posibles, haciendo el código
|
||||
más legible y reduciendo la necesidad de múltiples constructores o métodos setter.
|
||||
|
||||
## Propósito
|
||||
|
||||
Una extensión del patrón Builder que guía completamente al usuario a través de la creación del objeto sin posibilidades
|
||||
de confusión.
|
||||
La experiencia del usuario será mucho más mejorada por el hecho de que solo verá los métodos del siguiente paso
|
||||
disponibles, NINGÚN método constructor hasta que sea el momento adecuado para construir el objeto.
|
||||
|
||||
## Ejemplo del mundo real
|
||||
|
||||
Imagine que está construyendo un objeto de configuración para una conexión a una base de datos. La conexión tiene varios
|
||||
parámetros opcionales como host, puerto, nombre de usuario, contraseña y otros. Usando el patrón Step Builder, puedes
|
||||
establecer estos parámetros de una forma limpia y legible:
|
||||
|
||||
```java
|
||||
DatabaseConnection connection = new DatabaseConnection.Builder()
|
||||
.setHost("localhost")
|
||||
.setPort(3306)
|
||||
.setUsername("user")
|
||||
.setPassword("password")
|
||||
.setSSL(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
## En pocas palabras
|
||||
|
||||
El patrón Step Builder permite construir objetos complejos dividiendo el proceso de construcción en una serie de pasos.
|
||||
Cada paso corresponde a la configuración de un atributo particular u opción de configuración del objeto. Esto resulta en
|
||||
un código más legible y mantenible, especialmente cuando se trata de objetos que tienen numerosas opciones de
|
||||
configuración.
|
||||
|
||||
## Wikipedia dice
|
||||
|
||||
Según Wikipedia, el patrón Step Builder es un patrón de diseño de creación en el que un objeto se construye paso a paso.
|
||||
Implica una clase 'director' dedicada, que orquesta el proceso de construcción a través de una serie de clases '
|
||||
constructoras', cada una responsable de un aspecto específico de la configuración del objeto. Este patrón es
|
||||
particularmente útil cuando se trata de objetos que tienen un gran número de parámetros opcionales.
|
||||
|
||||
## Ejemplo programático
|
||||
|
||||
Suponiendo que tienes una clase `Producto` con varios atributos configurables, un Step Builder para ella podría tener
|
||||
este aspecto:
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String name;
|
||||
private double price;
|
||||
private int quantity;
|
||||
|
||||
// private constructor to force the use of the builder
|
||||
private Product(String name, double price, int quantity) {
|
||||
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
this.quantity = quantity;
|
||||
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String name;
|
||||
private double price;
|
||||
private int quantity;
|
||||
|
||||
public Builder setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPrice(double price) {
|
||||
this.price = price;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setQuantity(int quantity) {
|
||||
this.quantity = quantity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product build() {
|
||||
return new Product(name, price, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
Product product = new Product.Builder()
|
||||
.setName("Example Product")
|
||||
.setPrice(29.99)
|
||||
.setQuantity(100)
|
||||
.build();
|
||||
```
|
||||
|
||||
Este ejemplo muestra cómo utilizar el patrón Constructor por pasos para crear un objeto `Producto` con un conjunto de
|
||||
atributos personalizables. Cada método del constructor corresponde a un paso del proceso de construcción.
|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el patrón Step Builder cuando el algoritmo para crear un objeto complejo debe ser independiente de las partes
|
||||
que componen el objeto y de cómo se ensamblan el proceso de construcción debe permitir diferentes representaciones para
|
||||
el objeto que se construye cuando en el proceso de construcción el orden es importante.
|
||||
|
||||
## Otro ejemplo con diagrama de clases
|
||||
|
||||

|
||||
|
||||
## Créditos
|
||||
|
||||
* [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html)
|
||||
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Value Object
|
||||
category: Creational
|
||||
language: es
|
||||
tag:
|
||||
- Instantiation
|
||||
---
|
||||
|
||||
## Propósito
|
||||
|
||||
Proporcionar objetos que siguen la semántica de valor en lugar de la semántica de referencia. Esto significa que la
|
||||
igualdad de los objetos de valor no se basa en la identidad. Dos objetos de valor son iguales cuando tienen el mismo
|
||||
valor, no necesariamente siendo el mismo objeto.
|
||||
|
||||
## Explicación
|
||||
|
||||
Ejemplo del mundo real
|
||||
|
||||
> Existe una clase para las estadísticas de héroes en un juego de rol. Las estadísticas contienen atributos como fuerza,
|
||||
> inteligencia y suerte. Las estadísticas de diferentes héroes deben ser iguales cuando todos los atributos son iguales.
|
||||
|
||||
En palabras simples
|
||||
|
||||
> Los objetos de valor son iguales cuando sus atributos tienen el mismo valor.
|
||||
|
||||
Wikipedia dice
|
||||
|
||||
> En informática, un objeto de valor es un objeto pequeño que representa una entidad simple cuya igualdad no se basa en
|
||||
> la identidad: es decir, dos objetos de valor son iguales cuando tienen el mismo valor, no necesariamente siendo el mismo
|
||||
> objeto.
|
||||
|
||||
**Ejemplo Programático**
|
||||
|
||||
Aquí está la clase `HeroStat` que es el objeto valor. Fíjate en el uso de la
|
||||
anotación [Lombok's `@Value`](https://projectlombok.org/features/Value).
|
||||
|
||||
```java
|
||||
@Value(staticConstructor = "valueOf")
|
||||
class HeroStat {
|
||||
|
||||
int strength;
|
||||
int intelligence;
|
||||
int luck;
|
||||
}
|
||||
```
|
||||
|
||||
El ejemplo crea tres `HeroStat` diferentes y compara su igualdad.
|
||||
|
||||
```java
|
||||
var statA = HeroStat.valueOf(10, 5, 0);
|
||||
var statB = HeroStat.valueOf(10, 5, 0);
|
||||
var statC = HeroStat.valueOf(5, 1, 8);
|
||||
|
||||
LOGGER.info(statA.toString());
|
||||
LOGGER.info(statB.toString());
|
||||
LOGGER.info(statC.toString());
|
||||
|
||||
LOGGER.info("Is statA and statB equal : {}", statA.equals(statB));
|
||||
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
|
||||
```
|
||||
|
||||
Aquí está la salida de la consola.
|
||||
|
||||
```
|
||||
20:11:12.199 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
|
||||
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
|
||||
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=5, intelligence=1, luck=8)
|
||||
20:11:12.202 [main] INFO com.iluwatar.value.object.App - Is statA and statB equal : true
|
||||
20:11:12.203 [main] INFO com.iluwatar.value.object.App - Is statA and statC equal : false
|
||||
```
|
||||
|
||||
## Diagrama de Clases
|
||||
|
||||

|
||||
|
||||
## Aplicabilidad
|
||||
|
||||
Utilice el objeto Valor cuando
|
||||
|
||||
* La igualdad del objeto debe basarse en su valor.
|
||||
|
||||
## Usos conocidos
|
||||
|
||||
* [java.util.Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html)
|
||||
* [java.time.LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html)
|
||||
* [joda-time, money, beans](http://www.joda.org/)
|
||||
|
||||
## Créditos
|
||||
|
||||
* [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.html)
|
||||
* [ValueObject](https://martinfowler.com/bliki/ValueObject.html)
|
||||
* [VALJOs - Value Java Objects : Stephen Colebourne's blog](http://blog.joda.org/2014/03/valjos-value-java-objects.html)
|
||||
* [Value Object : Wikipedia](https://en.wikipedia.org/wiki/Value_object)
|
||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
|
||||
|
After Width: | Height: | Size: 4.9 KiB |