translation: Translate to Spanish (#2894)

* Translate Iterator pattern to Spanish

* Translate to Spanish:
Servant pattern
Sharding pattern
Spatial-partition pattern
Special-case pattern
specification pattern
State pattern
Strategy pattern
Subclass-case pattern

* Update language to es

* Fixing Missing translation

* Translate to Spanish:
template method pattern
throttling pattern
trampoline pattern
transaction-script pattern
type object pattern
Update method pattern
visitor pattern

* Fixing Missing translation
This commit is contained in:
David Medina Orozco
2024-04-09 12:16:21 -05:00
committed by GitHub
parent 1a50353b49
commit d45dcb1a63
15 changed files with 1113 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
---
title: Template method
category: Behavioral
language: es
tag:
- Gang of Four
---
## Propósito
Define el esqueleto de un algoritmo en una operación, difiriendo algunos pasos a subclases. Plantilla
Método que permite a las subclases redefinir ciertos pasos de un algoritmo sin cambiar la estructura del algoritmo.
del algoritmo.
## Explicación
Ejemplo del mundo real
> Los pasos generales para robar un objeto son los mismos. Primero, eliges al objetivo, luego lo confundes...
> y finalmente, robas el objeto. Sin embargo, hay muchas maneras de implementar estos
> pasos.
En palabras sencillas
> El patrón Template Method esboza los pasos generales en la clase padre y deja que las implementaciones hijas concretas definan los detalles.
Wikipedia dice
> En programación orientada a objetos, el método de plantillas es uno de los patrones de diseño de comportamiento
> identificados por Gamma et al. en el libro Design Patterns. El método de plantilla es un método en una
> superclase, normalmente una superclase abstracta, y define el esqueleto de una operación en términos de
> una serie de pasos de alto nivel. Estos pasos son a su vez implementados por métodos de ayuda adicionales
> en la misma clase que el método de plantilla.
**Ejemplo programático**
Presentemos primero la clase de método de plantilla junto con sus implementaciones concretas.
Para asegurarse de que las subclases no sobrescriben el método de plantilla, el método de plantilla (en nuestro caso
método `steal`) debe ser declarado `final`, de lo contrario el esqueleto definido en la clase base podría
ser sobreescrito en subclases.
```java
@Slf4j
public abstract class StealingMethod {
protected abstract String pickTarget();
protected abstract void confuseTarget(String target);
protected abstract void stealTheItem(String target);
public final void steal() {
var target = pickTarget();
LOGGER.info("The target has been chosen as {}.", target);
confuseTarget(target);
stealTheItem(target);
}
}
@Slf4j
public class SubtleMethod extends StealingMethod {
@Override
protected String pickTarget() {
return "shop keeper";
}
@Override
protected void confuseTarget(String target) {
LOGGER.info("Approach the {} with tears running and hug him!", target);
}
@Override
protected void stealTheItem(String target) {
LOGGER.info("While in close contact grab the {}'s wallet.", target);
}
}
@Slf4j
public class HitAndRunMethod extends StealingMethod {
@Override
protected String pickTarget() {
return "old goblin woman";
}
@Override
protected void confuseTarget(String target) {
LOGGER.info("Approach the {} from behind.", target);
}
@Override
protected void stealTheItem(String target) {
LOGGER.info("Grab the handbag and run away fast!");
}
}
```
Aquí está la clase ladrón halfling que contiene el método de plantilla.
```java
public class HalflingThief {
private StealingMethod method;
public HalflingThief(StealingMethod method) {
this.method = method;
}
public void steal() {
method.steal();
}
public void changeMethod(StealingMethod method) {
this.method = method;
}
}
```
Y por último, mostramos cómo el ladrón halfling utiliza los diferentes métodos de robo.
```java
var thief = new HalflingThief(new HitAndRunMethod());
thief.steal();
thief.changeMethod(new SubtleMethod());
thief.steal();
```
## Diagrama de clases
![alt text](./etc/template_method_urm.png "Template Method")
## Aplicabilidad
El patrón Template Method debería utilizarse
* Para implementar las partes invariantes de un algoritmo una vez y dejar que las subclases implementen el comportamiento que puede variar.
* Cuando el comportamiento común entre subclases debe ser factorizado y localizado en una clase común para evitar la duplicación de código. Este es un buen ejemplo de "refactorizar para generalizar", tal y como lo describen Opdyke y Johnson. Primero se identifican las diferencias en el código existente y luego se separan las diferencias en nuevas operaciones. Por último, se sustituye el código diferente por un método de plantilla que llama a una de estas nuevas operaciones
* Para controlar las extensiones de las subclases. Puede definir un método de plantilla que llame a operaciones "gancho" en puntos específicos, permitiendo así extensiones sólo en esos puntos
## Tutoriales
* [Template-method Pattern Tutorial](https://www.journaldev.com/1763/template-method-design-pattern-in-java)
## Usos conocidos
* [javax.servlet.GenericServlet.init](https://jakarta.ee/specifications/servlet/4.0/apidocs/javax/servlet/GenericServlet.html#init--):
El método `GenericServlet.init(ServletConfig config)` llama al método sin parámetros `GenericServlet.init()` que está pensado para ser sobreescrito en subclases.
El método `GenericServlet.init(ServletConfig config)` es el método plantilla en este ejemplo.
## 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)
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+218
View File
@@ -0,0 +1,218 @@
---
title: Throttling
category: Behavioral
language: es
tag:
- Performance
- Cloud distributed
---
## Propósito
Garantizar que un cliente determinado no pueda acceder a los recursos del servicio más allá del límite asignado.
## Explicación
Ejemplo del mundo real
> Un joven humano y un viejo enano entran en un bar. Empiezan a pedir cervezas al camarero.
> El camarero se da cuenta inmediatamente de que el joven humano no debe consumir demasiadas bebidas demasiado rápido
> y se niega a servir si no ha pasado suficiente tiempo. Para el viejo enano, el ritmo de servicio puede ser mayor.
> ser mayor.
En palabras sencillas
> El patrón de Throttling se utiliza para limitar la velocidad de acceso a un recurso.
[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling) dice
> Controlar el consumo de recursos utilizados por una instancia de una aplicación, un tenant individual,
> o un servicio completo. Esto puede permitir que el sistema continúe funcionando y cumpla con los acuerdos de nivel de servicio, incluso cuando un aumento de la demanda impone una carga extrema sobre los recursos.
**Ejemplo programático**
La clase `BarCustomer` presenta los clientes de la API `Bartender`. La clase `CallsCount` registra el número de
llamadas por `BarCustomer`.
```java
public class BarCustomer {
@Getter
private final String name;
@Getter
private final int allowedCallsPerSecond;
public BarCustomer(String name, int allowedCallsPerSecond, CallsCount callsCount) {
if (allowedCallsPerSecond < 0) {
throw new InvalidParameterException("Number of calls less than 0 not allowed");
}
this.name = name;
this.allowedCallsPerSecond = allowedCallsPerSecond;
callsCount.addTenant(name);
}
}
@Slf4j
public final class CallsCount {
private final Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();
public void addTenant(String tenantName) {
tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
}
public void incrementCount(String tenantName) {
tenantCallsCount.get(tenantName).incrementAndGet();
}
public long getCount(String tenantName) {
return tenantCallsCount.get(tenantName).get();
}
public void reset() {
tenantCallsCount.replaceAll((k, v) -> new AtomicLong(0));
LOGGER.info("reset counters");
}
}
```
A continuación, se introduce el servicio al que llaman los inquilinos. Para realizar un seguimiento del número de llamadas, se utiliza un temporizador de estrangulamiento.
```java
public interface Throttler {
void start();
}
public class ThrottleTimerImpl implements Throttler {
private final int throttlePeriod;
private final CallsCount callsCount;
public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
this.throttlePeriod = throttlePeriod;
this.callsCount = callsCount;
}
@Override
public void start() {
new Timer(true).schedule(new TimerTask() {
@Override
public void run() {
callsCount.reset();
}
}, 0, throttlePeriod);
}
}
```
El `Bartender` ofrece el servicio `orderDrink` a los `BarCustomer`s. Los clientes probablemente no
saben que la tasa de servicio de cerveza está limitada por su apariencia.
```java
class Bartender {
private static final Logger LOGGER = LoggerFactory.getLogger(Bartender.class);
private final CallsCount callsCount;
public Bartender(Throttler timer, CallsCount callsCount) {
this.callsCount = callsCount;
timer.start();
}
public int orderDrink(BarCustomer barCustomer) {
var tenantName = barCustomer.getName();
var count = callsCount.getCount(tenantName);
if (count >= barCustomer.getAllowedCallsPerSecond()) {
LOGGER.error("I'm sorry {}, you've had enough for today!", tenantName);
return -1;
}
callsCount.incrementCount(tenantName);
LOGGER.debug("Serving beer to {} : [{} consumed] ", barCustomer.getName(), count+1);
return getRandomCustomerId();
}
private int getRandomCustomerId() {
return ThreadLocalRandom.current().nextInt(1, 10000);
}
}
```
Ahora es posible ver el ejemplo completo en acción. BarCustomer` el joven humano está limitado a 2
llamadas por segundo y el viejo enano a 4.
```java
public static void main(String[] args) {
var callsCount = new CallsCount();
var human = new BarCustomer("young human", 2, callsCount);
var dwarf = new BarCustomer("dwarf soldier", 4, callsCount);
var executorService = Executors.newFixedThreadPool(2);
executorService.execute(() -> makeServiceCalls(human, callsCount));
executorService.execute(() -> makeServiceCalls(dwarf, callsCount));
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
LOGGER.error("Executor service terminated: {}", e.getMessage());
}
}
private static void makeServiceCalls(BarCustomer barCustomer, CallsCount callsCount) {
var timer = new ThrottleTimerImpl(1000, callsCount);
var service = new Bartender(timer, callsCount);
// Sleep is introduced to keep the output in check and easy to view and analyze the results.
IntStream.range(0, 50).forEach(i -> {
service.orderDrink(barCustomer);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
LOGGER.error("Thread interrupted: {}", e.getMessage());
}
});
}
```
Un extracto de la salida de consola del ejemplo:
```
18:46:36.218 [Timer-0] INFO com.iluwatar.throttling.CallsCount - reset counters
18:46:36.218 [Timer-1] INFO com.iluwatar.throttling.CallsCount - reset counters
18:46:36.242 [pool-1-thread-2] DEBUG com.iluwatar.throttling.Bartender - Serving beer to dwarf soldier : [1 consumed]
18:46:36.242 [pool-1-thread-1] DEBUG com.iluwatar.throttling.Bartender - Serving beer to young human : [1 consumed]
18:46:36.342 [pool-1-thread-2] DEBUG com.iluwatar.throttling.Bartender - Serving beer to dwarf soldier : [2 consumed]
18:46:36.342 [pool-1-thread-1] DEBUG com.iluwatar.throttling.Bartender - Serving beer to young human : [2 consumed]
18:46:36.443 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:36.443 [pool-1-thread-2] DEBUG com.iluwatar.throttling.Bartender - Serving beer to dwarf soldier : [3 consumed]
18:46:36.544 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:36.544 [pool-1-thread-2] DEBUG com.iluwatar.throttling.Bartender - Serving beer to dwarf soldier : [4 consumed]
18:46:36.645 [pool-1-thread-2] ERROR com.iluwatar.throttling.Bartender - I'm sorry dwarf soldier, you've had enough for today!
18:46:36.645 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:36.745 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:36.745 [pool-1-thread-2] ERROR com.iluwatar.throttling.Bartender - I'm sorry dwarf soldier, you've had enough for today!
18:46:36.846 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:36.846 [pool-1-thread-2] ERROR com.iluwatar.throttling.Bartender - I'm sorry dwarf soldier, you've had enough for today!
18:46:36.947 [pool-1-thread-2] ERROR com.iluwatar.throttling.Bartender - I'm sorry dwarf soldier, you've had enough for today!
18:46:36.947 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:37.048 [pool-1-thread-2] ERROR com.iluwatar.throttling.Bartender - I'm sorry dwarf soldier, you've had enough for today!
18:46:37.048 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:37.148 [pool-1-thread-1] ERROR com.iluwatar.throttling.Bartender - I'm sorry young human, you've had enough for today!
18:46:37.148 [pool-1-thread-2] ERROR com.iluwatar.throttling.Bartender - I'm sorry dwarf soldier, you've had enough for today!
```
## Diagrama de clases
![alt text](./etc/throttling_urm.png "Throttling pattern class diagram")
## Aplicabilidad
El patrón Throttling debe utilizarse:
* Cuando se necesita restringir el acceso al servicio para no tener un alto impacto en el rendimiento del mismo.
* Cuando varios clientes consumen los mismos recursos del servicio y la restricción debe hacerse en función del uso por cliente.
## Créditos
* [Throttling pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling)
* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications (Microsoft patterns & practices)](https://www.amazon.com/gp/product/B00ITGHBBS/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B00ITGHBBS&linkId=12aacdd0cec04f372e7152689525631a)
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

+149
View File
@@ -0,0 +1,149 @@
---
title: Trampoline
category: Behavioral
language: es
tag:
- Performance
---
## Propósito
El patrón Trampoline se utiliza para implementar algoritmos recursivamente en Java sin volar la pila
y para intercalar la ejecución de funciones sin codificarlas juntas.
## Explicación
La recursión es una técnica frecuentemente adoptada para resolver problemas algorítmicos en un estilo de divide y vencerás.
Por ejemplo, el cálculo de la suma acumulativa de Fibonacci y los factoriales. En este tipo de
problemas, la recursividad es más directa que su homóloga de bucle. Además, la recursividad puede
necesitar menos código y parecer más concisa. Hay un dicho que dice que todo problema de recursión puede resolverse
utilizando un bucle a costa de escribir código más difícil de entender.
Sin embargo, las soluciones de tipo recursivo tienen una gran advertencia. Para cada llamada recursiva, normalmente se necesita
un valor intermedio almacenado y hay una cantidad limitada de memoria de pila disponible. Quedarse sin
memoria de pila crea un error de desbordamiento de pila y detiene la ejecución del programa.
Trampoline pattern es un truco que permite definir algoritmos recursivos en Java sin desbordar la
pila.
Ejemplo del mundo real
> Un cálculo Fibonacci recursivo sin el problema de desbordamiento de pila utilizando el patrón Trampoline.
En palabras sencillas
> El patrón Trampoline permite la recursión sin agotar la memoria de la pila.
Wikipedia dice
> En Java, trampoline se refiere al uso de reflection para evitar el uso de clases internas, por ejemplo en
> eventos. La sobrecarga de tiempo de una llamada a reflection se intercambia por la sobrecarga de espacio de una clase interna.
> Trampolines en Java generalmente implican la creación de un GenericListener para pasar eventos a una clase externa.
**Ejemplo programático**
Esta es la implementación de `Trampoline` en Java.
Cuando se llama a `get` sobre el Trampoline devuelto, internamente se itera llamando a `jump` sobre el
siempre que la instancia concreta devuelta sea `Trampoline`, deteniéndose una vez que la instancia
instancia devuelta sea `done`.
```java
public interface Trampoline<T> {
T get();
default Trampoline<T> jump() {
return this;
}
default T result() {
return get();
}
default boolean complete() {
return true;
}
static <T> Trampoline<T> done(final T result) {
return () -> result;
}
static <T> Trampoline<T> more(final Trampoline<Trampoline<T>> trampoline) {
return new Trampoline<T>() {
@Override
public boolean complete() {
return false;
}
@Override
public Trampoline<T> jump() {
return trampoline.result();
}
@Override
public T get() {
return trampoline(this);
}
T trampoline(final Trampoline<T> trampoline) {
return Stream.iterate(trampoline, Trampoline::jump)
.filter(Trampoline::complete)
.findFirst()
.map(Trampoline::result)
.orElseThrow();
}
};
}
}
```
Uso del `Trampoline` para obtener valores Fibonacci.
```java
public static void main(String[] args) {
LOGGER.info("Start calculating war casualties");
var result = loop(10, 1).result();
LOGGER.info("The number of orcs perished in the war: {}", result);
}
public static Trampoline<Integer> loop(int times, int prod) {
if (times == 0) {
return Trampoline.done(prod);
} else {
return Trampoline.more(() -> loop(times - 1, prod * times));
}
}
```
Salida del programa:
```
19:22:24.462 [main] INFO com.iluwatar.trampoline.TrampolineApp - Start calculating war casualties
19:22:24.472 [main] INFO com.iluwatar.trampoline.TrampolineApp - The number of orcs perished in the war: 3628800
```
## Diagrama de clases
![alt text](./etc/trampoline.urm.png "Trampoline pattern class diagram")
## Aplicabilidad
Utilice el patrón Trampoline cuando:
* Para implementar funciones recursivas de cola. Este patrón permite encender una operación sin pila.
* Para intercalar la ejecución de dos o más funciones en el mismo hilo.
## Usos conocidos
* [cyclops-react](https://github.com/aol/cyclops-react)
## Créditos
* [Trampolining: a practical guide for awesome Java Developers](https://medium.com/@johnmcclean/trampolining-a-practical-guide-for-awesome-java-developers-4b657d9c3076)
* [Trampoline in java ](http://mindprod.com/jgloss/trampoline.html)
* [Laziness, trampolines, monoids and other functional amenities: this is not your father's Java](https://www.slideshare.net/mariofusco/lazine)
* [Trampoline implementation](https://github.com/bodar/totallylazy/blob/master/src/com/googlecode/totallylazy/Trampoline.java)
* [What is a trampoline function?](https://stackoverflow.com/questions/189725/what-is-a-trampoline-function)
* [Modern Java in Action: Lambdas, streams, functional and reactive programming](https://www.amazon.com/gp/product/1617293563/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617293563&linkId=ad53ae6f9f7c0982e759c3527bd2595c)
* [Java 8 in Action: Lambdas, Streams, and functional-style programming](https://www.amazon.com/gp/product/1617291994/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617291994&linkId=e3e5665b0732c59c9d884896ffe54f4f)
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,117 @@
---
title: Transaction Script
category: Behavioral
language: es
tag:
- Data access
---
## Propósito
Transaction Script organiza la lógica de negocio por procedimientos donde cada procedimiento maneja una única
solicitud de la presentación.
## Explicación
Ejemplo del mundo real
> Necesitas crear un sistema de reservas de habitaciones de hotel. Dado que los requisitos son bastante simples
> utilizar el patrón Transaction Script.
En palabras sencillas
> Transaction Script organiza la lógica de negocio en transacciones que el sistema necesita llevar a cabo.
Ejemplo programático
La clase `Hotel` se encarga de reservar y cancelar las reservas de habitaciones.
```java
@Slf4j
public class Hotel {
private final HotelDaoImpl hotelDao;
public Hotel(HotelDaoImpl hotelDao) {
this.hotelDao = hotelDao;
}
public void bookRoom(int roomNumber) throws Exception {
Optional<Room> room = hotelDao.getById(roomNumber);
if (room.isEmpty()) {
throw new Exception("Room number: " + roomNumber + " does not exist");
} else {
if (room.get().isBooked()) {
throw new Exception("Room already booked!");
} else {
Room updateRoomBooking = room.get();
updateRoomBooking.setBooked(true);
hotelDao.update(updateRoomBooking);
}
}
}
public void cancelRoomBooking(int roomNumber) throws Exception {
Optional<Room> room = hotelDao.getById(roomNumber);
if (room.isEmpty()) {
throw new Exception("Room number: " + roomNumber + " does not exist");
} else {
if (room.get().isBooked()) {
Room updateRoomBooking = room.get();
updateRoomBooking.setBooked(false);
int refundAmount = updateRoomBooking.getPrice();
hotelDao.update(updateRoomBooking);
LOGGER.info("Booking cancelled for room number: " + roomNumber);
LOGGER.info(refundAmount + " is refunded");
} else {
throw new Exception("No booking for the room exists");
}
}
}
}
```
La clase `Hotel` tiene dos métodos, uno para reservar y otro para cancelar una habitación respectivamente. Cada uno de ellos
transacción en el sistema, haciendo que `Hotel` implemente el patrón Transaction Script
Transaction Script.
El método `bookRoom` consolida todos los pasos necesarios como comprobar si la habitación ya está reservada
o no, si no está reservada entonces reserva la habitación y actualiza la base de datos utilizando el DAO.
El método `cancelRoom` consolida pasos como comprobar si la habitación está reservada o no,
si está reservada, calcula el importe del reembolso y actualiza la base de datos utilizando el DAO.
## Diagrama de clases
![alt text](./etc/transaction-script.png "Transaction script model")
## Aplicabilidad
Utilice el patrón Transaction Script cuando la aplicación tenga sólo una pequeña cantidad de lógica y esa
lógica no será extendida en el futuro.
## Consecuencias
* A medida que la lógica de negocio se complica,
se hace progresivamente más difícil mantener el script de transacción
en un estado bien diseñado.
* Puede ocurrir duplicación de código entre scripts de transacciones.
* Normalmente no es fácil refactorizar el script de transacciones a otros patrones de lógica de dominio.
del dominio.
## Patrones relacionados
* Domain Model
* Table Module
* Service Layer
## Créditos
* [Transaction Script Pattern](https://dzone.com/articles/transaction-script-pattern#:~:text=Transaction%20Script%20(TS)%20is%20the,need%20big%20architecture%20behind%20them.)
* [Transaction Script](https://www.informit.com/articles/article.aspx?p=1398617)
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=18acc13ba60d66690009505577c45c04)
Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+209
View File
@@ -0,0 +1,209 @@
---
title: Type-Object
category: Behavioral
language: es
tag:
- Game programming
- Extensibility
---
## Propósito
Como se explica en el libro Game Programming Patterns de Robert Nystrom, el patrón objeto tipo ayuda a
> Permitir la creación flexible de nuevas "clases" mediante la creación de una única clase, cada instancia de la cual representa un tipo diferente de objeto
## Explicación
Ejemplo del mundo real
> Estás trabajando en un juego con muchas razas diferentes de monstruos. Cada raza de monstruo tiene diferentes valores para los atributos, como ataque, salud, inteligencia, etc. Quieres crear nuevas razas de monstruos, o modificar los atributos de una raza existente, sin necesidad de modificar el código y recompilar el juego.
En palabras sencillas
> Definimos una clase de objeto de tipo y una clase de objeto tipado. Damos a cada instancia de objeto de tipo una referencia a un objeto tipado, que contiene la información para ese tipo.
**Ejemplo programático**
Supongamos que estamos desarrollando un juego de Candy Crush. Hay muchos tipos de caramelos diferentes, y es posible que queramos editar o crear nuevos con el tiempo a medida que desarrollamos el juego.
En primer lugar, tenemos un tipo para los caramelos, con un nombre de campo, padre, puntos y Tipo.
```java
@Getter(AccessLevel.PACKAGE)
public class Candy {
enum Type {
CRUSHABLE_CANDY,
REWARD_FRUIT
}
String name;
Candy parent;
String parentName;
@Setter
private int points;
private final Type type;
Candy(String name, String parentName, Type type, int points) {
this.name = name;
this.parent = null;
this.type = type;
this.points = points;
this.parentName = parentName;
}
}
```
Los datos de campo de los tipos de caramelos se almacenan en el archivo JSON ``candy.json``. Se pueden añadir nuevos caramelos simplemente añadiéndolos a este archivo.
```json
{"candies" : [
{
"name" : "fruit",
"parent" : "null",
"type" : "rewardFruit",
"points" : 20
},
{
"name" : "candy",
"parent" : "null",
"type" : "crushableCandy",
"points" : 10
},
{
"name" : "cherry",
"parent" : "fruit",
"type" : "rewardFruit",
"points" : 0
},
{
"name" : "mango",
"parent" : "fruit",
"type" : "rewardFruit",
"points" : 0
},
{
"name" : "purple popsicle",
"parent" : "candy",
"type" : "crushableCandy",
"points" : 0
},
{
"name" : "green jellybean",
"parent" : "candy",
"type" : "crushableCandy",
"points" : 0
},
{
"name" : "orange gum",
"parent" : "candy",
"type" : "crushableCandy",
"points" : 0
}
]
}
```
El archivo JSON se analiza, instanciando cada tipo de caramelo y almacenándolo en una tabla hash. El campo ``type`` se compara con el enum ``Type`` definido en la clase Candy.
```java
public class JsonParser {
Hashtable<String, Candy> candies;
JsonParser() {
this.candies = new Hashtable<>();
}
void parse() throws JsonParseException {
var is = this.getClass().getClassLoader().getResourceAsStream("candy.json");
var reader = new InputStreamReader(is);
var json = (JsonObject) com.google.gson.JsonParser.parseReader(reader);
var array = (JsonArray) json.get("candies");
for (var item : array) {
var candy = (JsonObject) item;
var name = candy.get("name").getAsString();
var parentName = candy.get("parent").getAsString();
var t = candy.get("type").getAsString();
var type = Type.CRUSHABLE_CANDY;
if (t.equals("rewardFruit")) {
type = Type.REWARD_FRUIT;
}
var points = candy.get("points").getAsInt();
var c = new Candy(name, parentName, type, points);
this.candies.put(name, c);
}
setParentAndPoints();
}
void setParentAndPoints() {
for (var e = this.candies.keys(); e.hasMoreElements(); ) {
var c = this.candies.get(e.nextElement());
if (c.parentName == null) {
c.parent = null;
} else {
c.parent = this.candies.get(c.parentName);
}
if (c.getPoints() == 0 && c.parent != null) {
c.setPoints(c.parent.getPoints());
}
}
}
}
```
## En palabras sencillas
El patrón Tipo-Objeto en Java es un método para encapsular propiedades y comportamientos específicos de un tipo dentro de un objeto. Este patrón de diseño facilita la adición de nuevos tipos sin necesidad de realizar cambios en el código existente, mejorando así la expansión y el mantenimiento de la base de código.
## Wikipedia dice
Aunque no existe una entrada específica en Wikipedia para el patrón Tipo-Objeto, se trata de una técnica de uso común en la programación orientada a objetos. Este patrón ayuda a gestionar objetos que comparten características similares pero tienen valores diferentes para esas características. Su uso está muy extendido en el desarrollo de juegos, donde numerosos tipos de objetos (como los enemigos) comparten un comportamiento común pero tienen propiedades diferentes.
## Ejemplo programático
Consideremos un ejemplo en el que intervienen distintos tipos de enemigos en un juego. Cada tipo de enemigo tiene propiedades distintas, como velocidad, salud y daño.
```java
public class EnemyType {
private String name;
private int speed;
private int health;
private int damage;
public EnemyType(String name, int speed, int health, int damage) {
this.name = name;
this.speed = speed;
this.health = health;
this.damage = damage;
}
// getters and setters
}
public class Enemy {
private EnemyType type;
// Encapsulating type information in an object
public Enemy(EnemyType type) {
this.type = type;
}
// other methods
}
```
En el ejemplo anterior, `EnemyType` encapsula propiedades específicas del tipo (nombre, velocidad, salud, daño), y `Enemy` utiliza una instancia de `EnemyType` para definir su tipo. De esta forma, puedes añadir tantos tipos de enemigos como quieras sin modificar la clase "Enemigo".
## Aplicabilidad
Este patrón puede utilizarse cuando:
* No sabemos de antemano qué tipos vamos a necesitar.
* Queremos ser capaces de modificar o añadir nuevos tipos sin tener que recompilar o cambiar el código.
* La única diferencia entre los diferentes "tipos" de objetos son los datos, no el comportamiento.
## Otro ejemplo con diagrama de clases
![alt text](./etc/typeobjectpattern.urm.png "Type-Object pattern class diagram")
## Créditos
* [Game Programming Patterns - Type Object](http://gameprogrammingpatterns.com/type-object.html)
* [Types as Objects Pattern](http://www.cs.sjsu.edu/~pearce/modules/patterns/analysis/top.htm)
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

+33
View File
@@ -0,0 +1,33 @@
---
title: Update Method
category: Behavioral
language: es
tag:
- Game programming
---
## Propósito
El patrón de método de actualización simula una colección de objetos independientes indicando a cada uno que procese un fotograma de comportamiento a la vez.
## Explicación
El mundo del juego mantiene una colección de objetos. Cada objeto implementa un método de actualización que simula un fotograma del comportamiento del objeto. En cada fotograma, el juego actualiza cada objeto de la colección.
Para obtener más información sobre cómo se ejecuta el bucle de juego y cuándo se invocan los métodos de actualización, consulte Patrón de bucle de juego.
## Diagrama de clases
![alt text](./etc/update-method.urm.png "Update Method pattern class diagram")
## Aplicabilidad
Si el patrón Game Loop es lo mejor desde el pan rebanado, entonces el patrón Update Method es su mantequilla. Una amplia gama de juegos con entidades vivas con las que el jugador interactúa utilizan este patrón de una forma u otra. Si el juego tiene marines espaciales, dragones, marcianos, fantasmas o atletas, es muy probable que utilice este patrón.
Sin embargo, si el juego es más abstracto y las piezas móviles se parecen menos a actores vivos y más a piezas de un tablero de ajedrez, este patrón no suele encajar. En un juego como el ajedrez, no necesitas simular todas las piezas concurrentemente, y probablemente no necesites decirle a los peones que se actualicen a sí mismos en cada frame.
Los métodos de actualización funcionan bien cuando:
- Su juego tiene un número de objetos o sistemas que necesitan ejecutarse simultáneamente.
- El comportamiento de cada objeto es independiente de los demás.
- Los objetos necesitan ser simulados en el tiempo.
## Créditos
* [Game Programming Patterns - Update Method](http://gameprogrammingpatterns.com/update-method.html)
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+232
View File
@@ -0,0 +1,232 @@
---
title: Visitor
category: Behavioral
language: es
tag:
- Gang of Four
---
## Propósito
Representar una operación a realizar sobre los elementos de una estructura de objetos. Visitante permite
definir una nueva operación sin cambiar las clases de los elementos sobre los que opera.
## Explicación
Ejemplo del mundo real
> Considere una estructura de árbol con unidades del ejército. El comandante tiene dos sargentos bajo él y cada sargento
> tiene tres soldados bajo él. Dado que la jerarquía implementa el patrón visitante, podemos
> crear fácilmente nuevos objetos que interactúen con el comandante, los sargentos, los soldados, o todos ellos.
Ejemplo del mundo real
> El patrón Visitante define las operaciones que se pueden realizar en los nodos de la estructura de datos.
Wikipedia dice
> En programación orientada a objetos e ingeniería de software, el patrón de diseño visitante es una forma de
> separar un algoritmo de una estructura de objetos sobre la que opera. Un resultado práctico de esta
> separación es la capacidad de añadir nuevas operaciones a estructuras de objetos existentes sin modificarlas.
> las estructuras.
**Ejemplo programático**
Dado el ejemplo anterior de la unidad del ejército, primero tenemos los tipos básicos Unit y UnitVisitor.
```java
public abstract class Unit {
private final Unit[] children;
public Unit(Unit... children) {
this.children = children;
}
public void accept(UnitVisitor visitor) {
Arrays.stream(children).forEach(child -> child.accept(visitor));
}
}
public interface UnitVisitor {
void visit(Soldier soldier);
void visit(Sergeant sergeant);
void visit(Commander commander);
}
```
Luego tenemos las unidades de hormigón.
```java
public class Commander extends Unit {
public Commander(Unit... children) {
super(children);
}
@Override
public void accept(UnitVisitor visitor) {
visitor.visit(this);
super.accept(visitor);
}
@Override
public String toString() {
return "commander";
}
}
public class Sergeant extends Unit {
public Sergeant(Unit... children) {
super(children);
}
@Override
public void accept(UnitVisitor visitor) {
visitor.visit(this);
super.accept(visitor);
}
@Override
public String toString() {
return "sergeant";
}
}
public class Soldier extends Unit {
public Soldier(Unit... children) {
super(children);
}
@Override
public void accept(UnitVisitor visitor) {
visitor.visit(this);
super.accept(visitor);
}
@Override
public String toString() {
return "soldier";
}
}
```
He aquí, pues, algunos visitantes concretos.
```java
@Slf4j
public class CommanderVisitor implements UnitVisitor {
@Override
public void visit(Soldier soldier) {
// Do nothing
}
@Override
public void visit(Sergeant sergeant) {
// Do nothing
}
@Override
public void visit(Commander commander) {
LOGGER.info("Good to see you {}", commander);
}
}
@Slf4j
public class SergeantVisitor implements UnitVisitor {
@Override
public void visit(Soldier soldier) {
// Do nothing
}
@Override
public void visit(Sergeant sergeant) {
LOGGER.info("Hello {}", sergeant);
}
@Override
public void visit(Commander commander) {
// Do nothing
}
}
@Slf4j
public class SoldierVisitor implements UnitVisitor {
@Override
public void visit(Soldier soldier) {
LOGGER.info("Greetings {}", soldier);
}
@Override
public void visit(Sergeant sergeant) {
// Do nothing
}
@Override
public void visit(Commander commander) {
// Do nothing
}
}
```
Por último, podemos mostrar el poder de los visitantes en acción.
```java
commander.accept(new SoldierVisitor());
commander.accept(new SergeantVisitor());
commander.accept(new CommanderVisitor());
```
Salida del programa:
```
Greetings soldier
Greetings soldier
Greetings soldier
Greetings soldier
Greetings soldier
Greetings soldier
Hello sergeant
Hello sergeant
Good to see you commander
```
## Diagrama de clases
![alt text](./etc/visitor_1.png "Visitor")
## Aplicabilidad
Utilice el patrón Visitor cuando
* Una estructura de objetos contiene muchas clases de objetos con diferentes interfaces, y desea realizar operaciones en estos objetos que dependen de sus clases concretas.
* Es necesario realizar muchas operaciones distintas y no relacionadas en los objetos de una estructura de objetos, y se desea evitar "contaminar" sus clases con estas operaciones. Visitor permite mantener juntas las operaciones relacionadas definiéndolas en una clase. Cuando la estructura de objetos es compartida por muchas aplicaciones, utilice Visitor para poner las operaciones sólo en aquellas aplicaciones que las necesiten.
* Las clases que definen la estructura del objeto raramente cambian, pero a menudo se quieren definir nuevas operaciones sobre la estructura. Cambiar las clases de la estructura del objeto requiere redefinir la interfaz para todos los visitantes, lo que es potencialmente costoso. Si las clases de la estructura del objeto cambian a menudo, probablemente sea mejor definir las operaciones en esas clases.
## Tutoriales
* [Refactoring Guru](https://refactoring.guru/design-patterns/visitor)
* [Dzone](https://dzone.com/articles/design-patterns-visitor)
* [Sourcemaking](https://sourcemaking.com/design_patterns/visitor)
## Usos conocidos
* [Apache Wicket](https://github.com/apache/wicket) component tree, Mire [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
* [javax.lang.model.element.AnnotationValue](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/AnnotationValue.html) y [AnnotationValueVisitor](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/AnnotationValueVisitor.html)
* [javax.lang.model.element.Element](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/Element.html) y [Element Visitor](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/ElementVisitor.html)
* [java.nio.file.FileVisitor](http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileVisitor.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)
* [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)
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB