GoF
Última actualización
¿Te fue útil?
Última actualización
¿Te fue útil?
En esta publicación se utilizarán los 23 patrones de diseño del libro "Patrones de Diseño: Elementos de software orientado a objetos reutilizable" escrito por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. El término GoF proviene de los autores del libro que son conocidos por la comunidad como Gang of Four (La Banda de los Cuatro).
En el libro "Patrones de Diseño" los autores hacen la siguiente aclaración respecto de los lenguajes utilizados para documentar los 23 patrones: "Aunque los patrones describen diseños orientados a objetos, están basados en soluciones prácticas que han sido implementadas en los lenguajes de programación orientados a objetos más usuales, como Smalltalk y C++, en vez de mediante lenguajes procedimentales (Pascal, C, Ada) u otros lenguajes orientados a objetos más dinámicos (CLOS, Dylan, Self). Nosotros hemos elegido Smalltalk y C++ por una cuestión pragmática: nuestra experiencia diaria ha sido con estos lenguajes, y estos cada vez son más populares". "La elección del lenguaje de programación es importante, ya que influye en el punto de vista. Nuestros patrones presuponen características de Smalltalk y C++, y esa elección determina lo que puede implementarse o no fácilmente. Si hubiéramos supuesto lenguajes procedimentales, tal vez, hubiéramos incluido patrones llamados 'Herencia', 'Encapsulación' y 'Polimorfismo'. De manera similar, algunos de nuestros patrones están incluidos directamente en lenguajes orientados a objetos menos corrientes. CLOS, por ejemplo, tiene multi-métodos que reducen la necesidad de patrones como Visitor. De hecho, hay suficientes diferencias entre Smalltalk y C++ como para que algunos patrones puedan expresarse más fácilmente en un lenguaje que en otro (por ejemplo, el Iterator)"
Es importante remarcar que este libro fue publicado en 1994 - (Java 1 recién se publicó en 1996)
También es importante entender que este trabajo intenta demostrar cómo pueden aplicarse los patrones de diseño en Go, aunque no es necesariamente imperativo su uso ni se lo promueve. Tal como exponen los autores, cada lenguaje tiene sus particularidades y en necesario entender el real problema a resolver, y no intentar adaptar formas de trabajo de un lenguaje a otro, sino entender esas particularidades que hacen diferente a un lenguaje respecto del otro para potenciar sus características.
A pesar de que parezca desalentador lo anteriormente dicho es importante remarcarlo. Un error muy común cuando aprendemos algo nuevo es querer utilizarlo en cualquier contexto, sin analizar realmente la conveniencia de su uso. Cuando uno aprende un patrón de diseño nuevo se ve tentado a utilizarlo. Los patrones de diseño resuelven problemas conocidos, y solo deben usarse si se está en presencia de un problema apropiado.
Un error que veo muy seguido es la adaptación de un patrón de un lenguaje a otro (como si se tratase de una traducción literal) cuando en realidad no se tienen en cuenta sus características específicas, que hacen a cada lenguaje de programación único, ni el objetivo que intenta resolver el patrón de diseño. Intentaré no caer yo mismo en este error.
En Go pueden aprovecharse algunas de sus características particulares para implementar también otros tipos de patrones distintos a los del libro "Patrones de Diseño" . Por ejemplo hay una gran cantidad de patrones de concurrencia.
Los patrones de diseño se organizan en tres familias de acuerdo a su propósito:
Creacionales: tienen que ver con el proceso de creación de objetos.
Estructurales: tratan con la composición de clases u objetos.
Comportamiento: caracterizan el modo en el que las clases y objetos interactúan y se reparten responsabilidades.
Los autores del libro "Patrones de Diseño" , también proponen otro criterio de clasificación denominado ámbito: "especifica si el patrón se aplica principalmente a clases o a objetos. Los patrones de clases se ocupan de relaciones entre las clases y sus subclases. Estas relaciones se establecen a través de la herencia, de modo que son relaciones estáticas - fijadas en tiempo de compilación -. Los patrones de objetos tratan con las relaciones entre objetos, que pueden cambiarse en tiempo de ejecución y son más dinámicas".
Al no existir en Go ni clases, ni objetos, ni herencia, la implementación de los patrones se verán muy diferentes. El desafío de esta publicación es respetar el propósito de cada patrón y su posible implementación en Go basándose en las características particulares del lenguaje.
Los patrones de diseño se catalogan de la siguiente forma:
Según su Propósito:
Creacionales: resuelven problemas relativos a la creación de objetos.
Estructurales: resuelven problemas relativos a composición de objetos.
Comportamiento: resuelven problemas relativos a la interacción de objetos.
Según su Ámbito:
Clases: respecto de las relaciones estáticas entre clases.
Objetos: respecto de las relaciones dinámicas entre objetos.
Creación
Estructurales
Comportamiento
Factory Method
Adapter
Interpreter
Template Method
Creación
Estructurales
Comportamiento
Abstract Factory
Adapter
Chain of Responsibility
Builder
Bridge
Command
Propotype
Composite
Iterator
Singleton
Decorator
Mediator
Facade
Memento
Flyweight
Observer
Proxy
State
Strategy
Visitor
Sección
Detalle
Nombre del patrón y clasificación
El nombre del patrón transmite su esencia. El nombre es vital porque pasa a formar parte de nuestro vocabulario de diseño. Por ejemplo al decir Singleton todos entenderán de que se habla, sin necesidad de explicar el objetivo y los participantes del patrón
Propósito
Es una frase breve que responde a las siguientes cuestiones: ¿Qué hace este patrón de diseño?, ¿En qué se basa? ¿Cuál es el problema concreto de diseño que resuelve?
También conocido como
Son otros nombres, si existen, por los que también se conoce al patrón
Motivación
Un escenario que ilustra un problema de diseño y cómo las estructuras de clases y objetos del patrón resuelven el problema
Aplicabilidad
¿En qué situaciones se puede aplicar el patrón de diseño? ¿Qué ejemplos hay de malos diseños que el patrón puede resolver? ¿Cómo se puede reconocer dichas situaciones?
Estructura
Una representación gráfica de las clases del patrón
Participantes
Las clases y objetos participantes en el patrón de diseño, junto con sus responsabilidades
Colaboradores
Cómo colaboran los participantes para llevar a cabo sus responsabilidades
Consecuencias
¿Cómo consigue el patrón sus objetivos? ¿Cuáles son las ventajas, desventajas y resultados de usar el patrón?
Implementación
¿Cuáles son las dificultades, trucos o técnicas que deberíamos tener en cuenta a la hora de aplicar el patrón? ¿Hay cuestiones específicas del lenguaje?
Código de ejemplo
Fragmentos de código que muestran cómo se puede implementar el patrón
Usos conocidos
Ejemplos del patrón en sistemas reales
Patrones relacionados
¿Qué patrones de diseño están estrechamente relacionados con este? ¿Cuáles son las principales diferencias? ¿Con qué otros patrones debería usarse?
En esta publicación utilizaremos la misma estructura pero con las siguientes observaciones:
Se unificará la motivación junto con el código de ejemplo.
Se analizarán adicionalmente, solo si corresponden, las alternativas de implementación desde el punto de vista de la concurrencia que caracteriza al lenguaje Go.
Se utilizarán códigos de ejemplo en el lenguaje Go.
Se utilizará UML en reemplazo de OMT.
Paradójicamente se utilizarán diagramas de clases de UML cuando en Go no existen clases. Sin embargo, al ser UML una de las notaciones más extendidas, considero que la traducción de las clases a tipos de datos de Go no presentará dificultades adicionales al lector.
Extracto de "Patrones de Diseño" - Tabla 1.1 - Patrones de diseño -
Extracto de "Patrones de Diseño" - Tabla 1.1 - Patrones de diseño -
Los autores del libro "Patrones de Diseño" utilizan la siguiente plantilla para especificar un Patrón.
Se reemplazarán los escenarios por ejemplos más simples ya que los del libro están basados en un caso de estudio complejo (creación de un editor de texto) y no pueden ser ejecutados para el aprendizaje del lector. Los escenarios serán triviales y muy simples, la idea es orientar al lector en cómo se implementa el patrón de diseño y no en como resolver un problema puntual. Se utilizarán escenarios de alguno de los siguientes recursos de interés: , , , .
Se omitirá las secciones aplicabilidad, colaboradores, consecuencias, usos conocidos y patrones relacionados ya que no es el objetivo de esta publicación el explicar cada patrón de diseño. Se insta al lector a referirse al libro original para mayor información - .
En las explicaciones de cada patrón de diseño del libro "Patrones de Diseño" utilizan constantemente las palabras objeto y clase. Parte de la comunidad asume que en Go la palabra objeto es válida ya que se interpreta que es sinónimo de un tipo de dato con comportamiento. Sin embargo, a fines de esta publicación cuando se requiera hablar de un objeto utilizaré la frase "variable" (considero que se ajusta más al lenguaje). Para la palabra clase no existe una terminología comparable, por lo que utilizaré simplemente la frase "tipo de dato" o la palabra "tipo". En cuanto a la palabra método, si bien es válida en Go dado que en definitiva los métodos son funciones que reciben un argumento receptor, también utilizaré la frase "comportamiento de un tipo".
Dado que el libro original "Patrones de Diseño" utiliza OMT en lugar de UML, se hará el mayor esfuerzo en respetar la estructura original de cada patrón dado que cada lenguaje permite implementaciones levemente distintas basándose en sus características particulares. Dicho esto se han observado pequeñas alteraciones/concesiones en implementaciones donde se reemplazan clases abstractas por interfaces y viceversa. Este tema es justamente una de las principales diferencias que pueden encontrarse en las implementaciones de un patrón de diseño GoF en Go, por lo que será dificultoso al lector diferenciar si una clase abstracta fue implementada como interface por a) una necesidad exclusiva dada las limitaciones del lenguaje Go en sus características orientadas a objetos; o b) simplemente por una concesión válida entre los desarrolladores de otros lenguajes. Lo invito en esos caso a buscar implementaciones de código en otros lenguajes como Java o C#.
Atención: Esta publicación se encuentra abandonada. Puede acceder a la versión vigente en