El patrón de diseño del decorador es como una galleta

El patrón decorador consiste en agregar características adicionales a un objeto existente.

¿Suena eso a francés?

Sin preocupaciones.

Vamos a volver a esto más adelante.

¡Veamos primero algunos gofres!

La parte genial de los waffles es que comienzan de manera simple. Como son simples, casi todo sabe bien con ellos.

Algunos ingredientes comunes para los waffles son las fresas, arándanos, moras, plátanos, almendras y jarabes.

Intentemos crear una colección de diferentes objetos de gofres.

Habrá StrawberryWaffle, BlueberryWaffle, BlackberryWaffle, BananaWaffle, AlmondWaffle y SyrupWaffle.

Espera, podemos tener fresas y arándanos en el mismo gofre. Esto nos da un StrawberryBlueberryWaffle.

También podemos tener fresas y moras en el mismo gofre. Esto nos da un StrawberryBlackberryWaffle.

Nadie nos prohíbe poner tres ingredientes en el mismo gofre. Esto nos da un StrawberryBlueberryBlackberryWaffle.

Para simplificar las cosas, consideremos las fresas, los arándanos y las moras como coberturas potenciales. Hay ocho combinaciones diferentes [1].

¿Significa esto que necesitamos crear ocho objetos diferentes para nuestra colección de gofres?

Si agregamos plátanos a nuestra lista potencial de ingredientes, hay 16 combinaciones diferentes [2].

Es obvio que agregar un solo topping a nuestra lista de toppings provoca una explosión en nuestra colección de waffles.

No es factible crear una clase de waffle diferente para cada combinación posible de coberturas. Debe haber una mejor manera de hacer esto.

¿Qué pasa si, cuando queremos un StrawberryWaffle en lugar de crear un StrawberryWaffle, creamos un Waffle y le agregamos fresas?

¿Qué pasa con StrawberryBlueberryWaffle entonces?

¡Podemos crear un Waffle, agregarle fresas y agregar arándanos!

Crear clases de gofres

Echemos un vistazo a la clase de gofres simples:

Puedes crear un gofre, servirlo y comerlo así:

Y aquí está la clase StrawberryWaffle:

Observe que pasamos un objeto waffle dentro del constructor StrawberryWaffle para crear un StrawberryWaffle.

La clase StrawberryWaffle tiene:

  1. El gofre pasado
  2. Fresas como aderezo
  3. Un método de servicio que llama al método de servicio del waffle pasado. Luego impresiones cubiertas con fresas
  4. Un método de comer que llama al método de comer del waffle pasado y luego imprime y luego come algunas fresas

Puedes crear un waffle de fresa, servirlo y comerlo así:

Estas son las clases de BlueberryWaffle y BlackberryWaffle:

Y puedes usarlos así:

Sacando la parte común

Al notar que la clase StrawberryWaffle, la clase BlueberryWaffle y la clase BlackberryWaffle son casi idénticas, excepto por su cobertura, podemos extraer las partes comunes como una clase principal.

En WaffleDecorator, el relleno ya no es un atributo del objeto. En cambio, es un método que puede ser anulado por una clase secundaria.

Ahora podemos reescribir StrawberryWaffle, BlueberryWaffle y BlackberryWaffle para heredar WaffleDecorator y obtener estas funcionalidades comunes:

Y aún deberían funcionar igual que antes:

Aquí están las clases que creamos:

Crear un gofre BlueberryStrawberry

Ahora tenemos Waffle, StrawberryWaffle, BlueberryWaffle y BlackberryWaffle.

Es hora de lograr el objetivo que originalmente establecimos:

cree un Waffle, agréguele fresas y arándanos.

Solo así:

Y podemos:

¡¿Que esta pasando?!

Veamos más de cerca cómo creamos blueberry_strawberry_waffle:

Primero, creamos un plain_waffle con Waffle: plain_waffle = Waffle.new

Luego creamos strawberry_waffle pasando el plain_waffle al constructor StrawberryWaffle. strawberry_waffle = StrawberryWaffle.new (plain_waffle)

Vale la pena señalar que cuando creamos el strawberry_waffle, mantenemos el plain_waffle pasado como una variable de instancia de strawberry_waffle:

Como podemos ver, strawberry_waffle.waffle y plain_waffle son el mismo objeto:

En este punto, cuando llamamos strawberry_waffle.serve. Primero llamamos plain_waffle.serve y luego imprimimos con fresas.

Para strawberry_waffle.eat, primero llamamos plain_waffle.eat, luego imprimimos y luego comemos algunas fresas.

Creamos blueberry_strawberry_waffle pasando el strawberry_waffle al constructor BlueberryWaffle. blueberry_strawberry_waffle = BlueberryStrawberryWaffle.new (strawberry_waffle)

Cuando creamos blueberry_strawberry_waffle, mantenemos el strawberry_waffle pasado como una variable de instancia de blueberry_strawberry_waffle:

Cuando llamamos a blueberry_strawberry_waffle.serve, primero llamamos a strawberry_waffle.serve. Que llama plain_waffle.serve y luego imprime rematado con fresas. Luego imprima cubierto con arándanos.

Cuando llamamos a blueberry_strawberry_waffle.eat, primero llamamos a strawberry_waffle.eat. Que llama plain_waffle.eat, luego imprime y luego come algunas fresas. Luego imprime y luego come algunos arándanos.

La llave de la magia:

strawberry_waffle está construido encima de plain_waffle. Y blueberry_strawberry_waffle está construido encima de strawberry_waffle.

La clave para poder construir waffles uno encima del otro es que todos los waffles deben obedecer la misma interfaz.

Todos los waffles tienen un método de servir y un método de comer.

Es por eso que dentro de las clases StrawberryWaffle / BlueberryWaffle / BlackberryWaffle, estamos seguros de que el waffle pasado tiene un método de servir y un método de comer.

Y podemos aprovechar el método de servir y el método de comer del waffle pasado al definir un nuevo método de servir y un nuevo método de comer.

A WaffleDecorator no le importa el tipo de waffle. Puede ser un waffle simple, un waffle de fresa o un waffle alienígena.

Lo único que importa es que un WaffleDecorator toma un waffle y devuelve un waffle mejorado. El gofre que toma y el gofre que devuelve obedecen a la misma interfaz.

Como todos los decoradores que toman y devuelven waffles obedecen a la misma interfaz, el resultado de un decorador se puede pasar a otro decorador.

Solo así:

o esto:

Ahora con Waffle, StrawberryWaffle, BlueberryWaffle y BlackberryWaffle, podemos crear los ocho waffles diferentes.

Agregar banana a nuestra lista de topping es tan fácil como:

¡Acabas de aprender el patrón decorador!

Aquí está su definición:

El decorador asigna responsabilidades adicionales a un objeto de forma dinámica.

Comida para llevar:

  1. El patrón decorador consiste en agregar características adicionales a un objeto existente fácilmente.
  2. El objeto a decorar (el que se pasa a todos los decoradores) y los objetos devueltos por los decoradores deben obedecer la misma interfaz.

¡Gracias por leer! Espero que disfrutes el artículo.

Publico semanalmente en sihui.io.

Suscríbase para no perderse el próximo artículo de la serie.

La próxima vez veremos ...

[1] PlainWaffle, StrawberryWaffle, BlueberryWaffle, BlackberryWaffle, StrawberryBlueberryWaffle, StrawberryBlackberryWaffle, BlueberryBlackberryWaffle y StrawberryBlueberryBlackberryWaffle.

[2] C (4, 0) + C (4, 1) + C (4, 2) + C (4, 3) + C (4, 4) = 16