Designpatternsingo
Designpatternsingo
Designpatternsingo
Daniel M. Spiridione
Este libro está a la venta en http://leanpub.com/designpatternsingo
Éste es un libro de Leanpub. Leanpub anima a los autores y publicadoras con el proceso de
publicación. Lean Publishing es el acto de publicar un libro en progreso usando herramientas
sencillas y muchas iteraciones para obtener retroalimentación del lector hasta conseguir el libro
adecuado.
Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Organización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Parte I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Sobre Go . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
POO en Go . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Herencia / Composición . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
S.O.L.I.D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Parte II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Patrones de Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
GoF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Patrones de Comportamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Chain of Responsibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Template Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Memento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Interpreter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Visitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Mediator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Patrones Creacionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Builder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Factory Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
ÍNDICE GENERAL
Abstract Factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Patrones Estructurales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Composite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Flyweight . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Acerca De . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Glosario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Sobre esta publicación
Esta publicación se distribuye como un e-book gratuito y se encuentra en constante evolución.
Puede acceder a la versión más actualizada desde la siguiente dirección:
http://www.designpatternsingo.com/
Los códigos fuentes de ejemplo de los patrones de diseño utilizados en este e-book se encuentran
en el siguiente repositorio público:
https://github.com/danielspk/designpatternsingo
Asimismo, el código fuente de este e-book se encuentra en el siguiente repositorio público:
https://github.com/danielspk/designpatternsingoebook
Última actualización: 20 de Agosto de 2020 a las 20:55 hs.
Introducción
Este trabajo tiene como objetivo discutir sobre la programación orientada a objetos en el lenguaje
de programación Go, y como pueden implementarse los 23 Patrones de Diseño GoF.
Organización
La primera parte del trabajo está destinada a la presentación del lenguaje Go y a como se puede
aplicar el paradigma orientado a objetos.
En la segunda parte se expone como pueden implementarse los 23 patrones de diseño GoF.
La tercera y última parte está destinada a las conclusiones generales y a los motivos que me
llevaron a realizar esta publicación.
¹Fuente: https://golang.org/s/logos
Parte I
Presentación del Lenguaje Go y sus características Orientadas
a Objetos
Sobre Go
“Go es un lenguaje de programación de código abierto que facilita la creación de software simple,
confiable y eficiente”. [1]
“Go es expresivo, conciso, limpio y eficiente. Sus mecanismos de concurrencia facilitan la
escritura de programas que aprovechan al máximo las máquinas multinúcleo, y de red, mientras
que su novedoso sistema de tipo permite la construcción de programas flexibles y modulares.
Go compila rápidamente el código de máquina y tiene la comodidad de la recolección de basura
y el poder de la reflexión en tiempo de ejecución. Es un lenguaje compilado, rápido, de tipado
estático, que se siente como un lenguaje interpretado de tipado dinámico”. [2]
Orígenes
Go fue creado en Google en el año 2007 por Robert Griesemer, Rob Pike, y Ken Thomson.
Su lanzamiento oficial fue en noviembre del año 2009, pero su primera versión estable - 1.0 -
recién se publicó en marzo de 2012.
²Fuente: https://golang.org/doc/gopher
³Fuente: https://github.com/golang-samples/gopher-vector
Sobre Go 5
Sobre su nombre
Dado que la palabra Go es parte del idioma ingles el lenguaje también es conocido como Golang.
Características
Go está inspirado en la sintaxis de C como otros lenguajes: C++, C#, Java, PHP, Javascript, etc.
Su elección fue ser afín a la gran comunidad de desarrolladores de C++ de Google.
Por sus características suele clasificarse como un lenguaje compilado que tiene características de
lenguajes interpretados.
Sobre Go 6
• compilado,
• concurrente,
• de tipado estático,
• con recolector de basura,
• con uso de punteros - pero sin aritmética
• con cortos tiempos de compilación
Ejemplo
1 package main
2
3 import "fmt"
4
5 func main() {
6 fmt.Println("www.designpatternsingo.com")
7 }
Para Mark Summerfield [36] “Go es bastante parecido a C en su espíritu, ya que es un lenguaje
pequeño y eficiente con convenientes facilidades de bajo nivel, como punteros. Sin embargo, Go
también ofrece muchas características asociadas con lenguajes de alto o muy alto nivel, como
cadenas Unicode, potentes estructuras de datos integradas, duck typing, recolección de basura y
soporte de concurrencia de alto nivel que utiliza comunicaciones en lugar de datos compartidos
y bloqueos. Go también tiene una gran biblioteca estándar de amplio rango”.
Para Shiju Varghese [28] “El lenguaje de programación Go se puede describir simplemente en
tres palabras: simple, mínimo y pragmático. El objetivo del diseño de Go es ser un lenguaje
de programación simple, minimalista y expresivo que proporcione todas las características
esenciales para crear sistemas de software confiables y eficientes. Cada idioma tiene su propio
objetivo de diseño y una filosofía única. La simplicidad no se puede agregar más adelante en el
idioma, por lo que debe ser construida con la simplicidad en mente. Go está diseñado para ser
⁴Fuente: Vladimir Vivien, Mario Castro Contreras, Mat Ryer, “Go: Design Patterns for Real-World Projects” - Packt, 2017
Sobre Go 7
Controversias
Go como todos los lenguajes de programación presenta ciertas controversias. Sus detractores por
ejemplo manifiestan que el lenguaje carece de:
• genéricos
• manejo de excepciones
• sobrecarga de operadores
de un error sin sobrecargar el valor de retorno. Un tipo de error canónico, junto con otras
características de Go, hace que el manejo de errores sea agradable, pero bastante diferente del de
otros lenguajes.” [3]
Esta filosofía para algunos controvertida es la que creo en mi opinión que hace a Go tan
interesante. En vez incorporar constantemente nuevas características y/o copiar otras de otros
lenguajes de programación, Go intenta mantener un lenguaje simple, mínimo y conciso.
Proverbios de Go
Los proverbios de Go invitan a los desarrolladores a reflexionar sobre la filosofía de Go y a la
enseñanza sobre el lenguaje.
Se invita a los lectores a profundizar más sobre esta filosofía con base en la charla de Rob Pike
en el Gopherfest del año 2015: “Go Proverbs”. [44]
A continuación se exponen solo algunos de estos proverbios:
Este apartado tratará de dar respuesta a la siguiente pregunta: ¿Es Go un lenguaje orientado a
objetos?.
Contenido
• Objetos en Go
• Herencia vs Composición en Go
• Principios S.O.L.I.D en Go
⁵Fuente: https://golang.org/doc/gopher
POO en Go 10
Objetos
A diferencia de lenguajes explícitamente orientados a objetos como C++, Java, Smalltalk, y
Python entre otros, en Go no existen las clases, ni los objetos, ni las excepciones, ni la herencia
de clases.
Algunos, rápidamente podrían inferir que Go no es un lenguaje orientado a objetos. ¿Cómo puede
existir un lenguaje orientado a objetos que no disponga de clases?. La pregunta que realmente
debemos hacernos es: ¿Qué es la programación orientada a objetos?.
Los desarrolladores tenemos una tendencia natural a comparar las cosas. Entonces, por ejemplo,
algunos podrían decir que dado que Java es académicamente reconocido como un lenguaje
estrictamente orientado a objetos, y dado que ese lenguaje tiene entre otras características clases,
objetos y herencia; como Go no las tiene, entonces no podría ser un lenguaje orientado a objetos.
¿Alguien alguna vez escuchó decir que Javascript es un lenguaje orientado a objetos?. Existe una
gran discusión sobre si lo es o no lo es - a fin de cuentas en Javascript tampoco hay clases ni
herencia de la forma como la que la hay en Java. No obstante Javascript suele ser considerado
un lenguaje orientado a objetos. ¿Por qué?. Porque permite implementar ciertas características
de la programación orientada a objetos.
En ES6 se incorporan las clases en Javascript aunque con un soporte muy limitado en
comparación con otros lenguajes orientados a objetos clásicos.
• Herencia de clase
– Simple
* Scala
* Smalltalk
– Múltiple
* Eifell
* C++
• Herencia de Interfaces
– Explícitas
* C++ (mediante clases abstractas y métodos virtuales)
* Scala (mediante herencia simple de clase y/o traits)
POO en Go 11
Como se puede apreciar lenguajes como Scala, Eiffel, C++ y Smalltalk son muy distintos entre
sí, pero todos ellos respetan el paradigma orientado a objetos.
Al analizar a Go, debemos comparar qué características propias de la programación orientada a
objetos se pueden implementar y no simplemente hacer una comparación de un lenguaje respecto
de otro solamente por la falta o no de ciertos atributos o características individuales.
Cómo es la POO en Go
Clases y Objetos
En Go no existen clases ni objetos. Existen tipos de datos definidos por el usuario a los cuales se
les pueden incorporar comportamientos. En una analogía con una clase, las propiedades pudieran
ser los tipos de datos de una estructura, y los métodos las funciones o comportamientos asociados
al tipo de dato.
Ejemplo sobre una estructura:
Interfaces
“La interfaz de un objeto no dice nada acerca de su implementación - distintos objetos son
libres de implementar las peticiones de forma diferente -. Eso significa que dos objetos con
implementaciones completamente diferentes pueden tener interfaces idénticas”. [38]. Go cumple
con esta característica de interfaces sin implementación. Lenguajes de programación tales como
Visual Basic .Net o Kotlin definen sus interfaces de forma explícita. En Go las interfaces son
implícitas ya que no existe ninguna palabra reservada o símbolo para tal fin (tal como implements
en Groovy o : en C#). En Go cualquier tipo de dato que implemente todos los métodos de una
interfaz, implícitamente la implementa. Este comportamiento es análogo al de algunos lenguajes
de tipado dinámico, como Python o Boo, donde a esto se lo conoce como Duck typing (“si camina
como un pato y grazna como un pato, entonces debe ser un pato” [54]). En Go el compilador
chequea forzosamente que se si referencia a un tipo de dato como una interface, este debe
implementar todos sus comportamientos sin excepción.
Ejemplo:
Herencia
Encapsulamiento
1 // estructura pública
2 type CuentaCorriente struct {
3 //...
4 }
5
6 // método privado
7 func (cc CuentaCorriente) calcularIntereses() double {
8 //...
9 }
Polimorfismo
Método Estáticos
1 package Modelos
2
3 // estructura
4 type CuentaCorriente struct {
5 //...
6 }
7
8 // emular propiedad estática
9 // utilizando variable de paquete
10 var banco = "Banco S.A."
11
12 // emular método estático de CuentaCorriente
13 // utilizando una función de paquete
14 func CuentaCorrienteGetBanco() string {
15 return banco
16 }
Mi punto de vista
Ya que existen otros lenguajes que permiten programar orientado a objetos, sin ser realmente
orientados a objetos, puedo decir que “Go es un lenguaje no orientado a objetos que permite
la programación orientada a objetos - aunque no de la forma tradicional”.
POO en Go 17
Herencia / Composición
Como se indicó previamente en Go no existe el concepto de herencia de implementación típico
de lenguajes orientados a objetos como Java, C++ y Smalltalk entre otros.
En Go existe otro concepto complementario que es la composición.
Tal como menciona Steve Francia [8] “Existen varios enfoques diferentes para definir relaciones
entre objetos. Si bien difieren bastante entre sí, todos comparten un propósito común como
mecanismo para la reutilización de código”:
• Herencia
• Herencia múltiple
• Polimorfismo
• Composición de objetos
Herencia
La herencia se puede expresar de dos maneras: herencia de clases y herencia de interfaces. “La
herencia de clases define la implementación de un objeto en términos de la implementación
de otro objeto. En resumen, es un mecanismo para compartir código y representación. Por el
contrario, la herencia de interfaces (o subtipado) describe cuándo se puede usar un objeto en el
lugar de otro.” [38]
No todos los lenguajes de programación implementan la herencia de la misma manera. En
algunos lenguajes la herencia de clases y la de interfaces existen como un mismo mecanismo
(Eiffel por ejemplo), mientras que en otros están separados (Java por ejemplo). Algunos
solamente permiten heredar de un único objeto, esto se denomina herencia simple; mientras
otros permiten heredar de varios objetos y a esto se lo denomina herencia múltiple.
Asimismo los comportamientos y datos heredados pueden estar limitados al acceso con el que el
objeto padre los definió, esto se denomina visibilidad.
Se expresa a la herencia como una relación es-un/a.
Composición
La composición es una manera de definir objetos dentro de otros objetos. De esta forma un objeto
puede adquirir los comportamientos y datos de los otros objetos por los que está compuesto.
Esto en cierta medida es más similar al concepto de herencia múltiple que al de simple.
Herencia
POO en Go 19
1 class Fruta {
2 public void pelar() {
3 System.out.println("Pelando una fruta");
4 }
5 }
6
7 class Manzana extends Fruta {
8 public void pelar() {
9 System.out.println("Pelando una manzana");
10 }
11 }
Pros:
• Reutilización de código: todo código definido en la clase Fruta puede ser reutilizado por
cualquiera de sus subclases.
• Polimorfismo: una variable de tipo Fruta puede contener una referencia a un objeto de tipo
superclase o cualquiera de sus subclases.
• Enlace dinámico: en tiempo de ejecución se decidirá que método invocar en función del
tipo de clase del objeto.
• Facilidad para agregar una nueva subclase: simplemente se debe agregar una subclase
que heredé de la superclase.
Contras:
Composición
1 class Fruta {
2 public void pelar() {
3 System.out.println("Pelando una fruta");
4 }
5 }
6
7 class Manzana {
8 private Fruta fruta = new Fruta();
9
10 public void pelar() {
11 fruta.pelar();
12 }
13 }
POO en Go 20
Pros:
Contras:
• Es más difícil agregar una nueva clase: sintácticamente requiere de más código.
• Costo de rendimiento: el método explícito de reenvío de llamadas tiene un costo de
rendimiento en comparación con la invocación directa de la herencia.
Ejemplo de Composición en Go
Como veremos la composición en Go se logra embebiendo tipos de datos unos dentro de otros:
Composición e interfaces en Go
POO en Go 21
• la composición cuando exista un comportamiento que deba ser compartido entre tipos de
datos
• mediante interfaces cuando se deba asegurar que una estructura es parte de una relación
es-un y/o requiera implementar ciertos comportamientos.
Estrategia implementada en Go
Conclusión
Go permite la composición y la herencia de interfaz. El uso de interfaces (es-un) y de la
composición (tiene-un) posibilitan la reutilización de código en Go y la adopción de técnicas
y de patrones orientados a objetos.
POO en Go 23
S.O.L.I.D
SOLID es un acrónimo introducido por Robert C. Martin en su libro “Agile Software Develop-
ment, Principles, Patterns and Practices” [40] y hace referencia a los siguientes cinco principios:
El objetivo de aplicar estos principios es obtener sistemas orientados a objetos con código de
mayor calidad, facilidad de mantenimiento y mejores oportunidades de reuso de código.
Una clase debe tener una, y sólo una, razón para cambiar, lo que significa que una clase
debe tener un solo trabajo.
La primera observación respecto de este principio es que en Go no existen clases. Sin embargo,
como vimos mediante la incorporación de comportamientos a tipos de datos, podemos llegar a
un concepto equivalente.
Este principio hace foco en que un objeto debe tener únicamente una responsabilidad encapsu-
lada por la clase. Cuando se hace referencia a una responsabilidad es para referirse a una razón
para cambiar.
Mantener una clase que tiene múltiples objetivos o responsabilidades es mucho más complejo
que una clase enfocada en una única responsabilidad.
El siguiente ejemplo no cumple con este principio porque otorga a una estructura dos responsa-
bilidades bien diferenciadas: guardar en un archivo local y guardar en una base de datos.
1 package main
2
3 type Documento struct {
4 Nombre string
5 }
6
7 func (d *Documento) GuardarEnArchivo() {
8 // ...
9 }
10
11 func (d *Documento) GuardarEnBaseDatos() {
12 // ...
13 }
POO en Go 24
1 package model
2
3 type Documento struct {
4 Nombre string
5 }
1 package store
2
3 import "model"
4
5 type GuardadorDocumento interface {
6 Guardar(d model.Documento)
7 }
8
9 type GuardadorDocumentoArchivo struct {
10 Path string
11 }
12
13 func (gda GuardadorDocumentoArchivo) Guardar(d model.Documento) {
14 // ...
15 }
16
17 type GuardadorDocumentoBaseDatos struct {
18 StringConnection string
19 }
20
21 func (gdbd GuardadorDocumentoBaseDatos) Guardar(d model.Documento) {
22 // ...
23 }
Los objetos o entidades deberían estar abiertos para la extensión, pero cerrados para su
modificación.
POO en Go 25
Este principio propone que una entidad esté cerrada, lista para ser usada y estable en su calidad
e interfaces, y al mismo tiempo abierta, es decir, que permita extender su comportamiento (pero
sin modificar su código fuente).
Imaginemos que se requiere cambiar el comportamiento de la siguiente estructura únicamente
en uno de sus métodos:
Cada clase que herede de otra debe poder utilizarse como su clase padre sin necesidad
de conocer las diferencias que pudieran existir entre ellas.
Este principio propone que el contrato de una clase base debe ser honrado por sus clases derivadas
para que instancias de las clases derivadas puedan reemplazar a instancias de la clase base.
Veamos el siguiente código:
POO en Go 26
Este principio hace foco en como deben definirse las interfaces. Las mismas deben ser pequeñas
y específicas.
Grandes y complejas interfaces obligan al cliente a implementar métodos que no necesita.
Veamos la siguiente interface:
12 // ...
13 }
14
15 type BotonIcono struct {}
16
17 func (b BotonIcono) OnDobleClick() {
18 // ...
19 }
Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deberían
depender de abstracciones. Las abstracciones no deben depender de los detalles. Los
detalles deben depender de las abstracciones.
Este principio esta basado en reducir las dependencias entre los módulos del código para atacar
el alto acoplamiento.
Veamos la siguiente ejemplo:
1 type B struct {}
2
3 func (b B) Saludar() {
4 // ...
5 }
6
7 type A struct {
8 B
9 }
Conclusión
Si bien el libro de Robert C. Martin [40] tiene más de una década y media y hace referencia
a lenguajes propiamente orientados a objetos, vimos como también pueden aplicarse esos
principios en Go.
Como se vio en el apartado anterior, el poder de la composición y de las interfaces implícitas le
permiten a Go implementar buenas prácticas y conceptos propios de la programación orientada
a objetos.
Parte II
Patrones de Diseño
En el libro de Erich Gamma et al - Patrones de Diseño [38] - exponen la importancia y usos de
los patrones de diseño en conceptos como:
• “Diseñar software orientado a objetos es difícil, y aún lo es más diseñar software orientado
a objetos reutilizable”.
• “Algo que los expertos saben que no hay que hacer es resolver cada problema partiendo de
cero. Por el contrario, reutilizan soluciones que ya les han sido útiles en el pasado. Cuando
encuentran una solución buena, la usan una y otra vez”.
• “Los patrones de diseño hacen que sea más fácil reutilizar buenos diseños y arquitecturas”.
• “Los patrones de diseño nos ayudan a elegir las alternativas de diseño que hacen que un
sistema sea reutilizable, y a evitar aquellas que dificultan dicha reutilización. Pueden incluso
mejorar la documentación y el mantenimiento de los sistemas existentes al proporcionar
una especificación explícita de las interacciones entre clases y objetos y de cuál es su
intención. En definitiva los patrones de diseño ayudan a un diseñador a lograr un buen
diseño más rápidamente”.
Como se puede observar se utilizan términos como clases y objetos, ya que los patrones de diseño
están enfocados al desarrollo orientado a objetos siendo los ejemplos de su libro implementados
en C++.
En las siguientes secciones se detallará como es posible implementar dichos patrones de diseño
en Go.
Contenido
• Patrones de Diseño GoF
• Patrones de Comportamiento
• Patrones Creacionales
• Patrones Estructurales
⁶Fuente: https://golang.org/doc/gopher
GoF
¿Qué es Gof?
En esta publicación se utilizan los 23 patrones de diseño del libro “Patrones de Diseño: Elementos
de software orientado a objetos reutilizable” [38] 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).
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
GoF 33
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. Intento no caer yo mismo en este error.
Los autores del libro Patrones de Diseño [38], 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”.
Catálogo de patrones
Los patrones de diseño se catalogan de la siguiente forma:
Según su Propósito:
Según su Ámbito:
Patrones de Clase
Patrones de Objeto
Sección Detalle
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 se utiliza la misma estructura pero con las siguientes observaciones:
• Se reemplazan 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 son 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 utilizan escenarios de alguno de los siguientes recursos de interés: [10], [11],
[12], [13].
• Se omiten 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 Patrones de Diseño [38] para mayor información
- [38].
• Se unifica la motivación junto con el código de ejemplo.
• Se analiza adicionalmente, solo si corresponden, las alternativas de implementación desde
el punto de vista de la concurrencia que caracteriza al lenguaje Go.
• Se utiliza código de ejemplo en el lenguaje Go.
• Se utiliza UML en reemplazo de OMT.
GoF 36
Implicancias
En las explicaciones de cada patrón de diseño del libro Patrones de Diseño [38] 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 Patrones de Diseño [38] 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#.
Patrones de Comportamiento
Según el libro Patrones de Diseño [38] los patrones de comportamiento “tienen que ver con
algoritmos y con la asignación de responsabilidades a objetos. Los patrones de comportamiento
describen no solo patrones de clases y objetos, sino también patrones de comunicación entre
ellos.”
Contenido
• Strategy
• Chain of Responsibility
• Command
• Template Method
• Memento
• Interpreter
• Iterator
• Visitor
• State
• Mediator
• Observer
⁷Fuente: https://golang.org/doc/gopher
Patrones de Comportamiento 38
Strategy
Propósito
Según el libro Patrones de Diseño [38] el patrón Strategy “define una familia de algoritmos,
encapsula cada uno de ellos y los hace intercambiables. Permite que un algoritmo varíe
independientemente de los clientes que lo usan”.
Estructura
Participantes
• Estrategia:
– declara la interfaz común a todos los algoritmos permitidos. El Contexto usa esta
interfaz para llamar al algoritmo definido por una EstrategiaConcreta.
• EstrategiaConcreta:
– implementa el algoritmo usando la interfaz Estrategia.
• Contexto:
– se configura con una variable EstrategiaConcreta.
– mantiene una referencia a una variable Estrategia.
– puede definir una interfaz que permita a la Estrategia acceder a sus datos.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos definir tres estrategias concretas que pueden realizar distintas
operaciones matemáticas. Cuando se crea el contexto se establece que estrategia deberá utilizar.
Implementación:
Patrones de Comportamiento 39
1 // Interface
2 type Estrategia interface {
3 RealizarOperacion(int, int) int
4 }
5
6 // Estrategia Suma
7 type EstrategiaSuma struct{}
8
9 func (e EstrategiaSuma) RealizarOperacion(num1 int, num2 int) int {
10 return num1 + num2
11 }
12
13 // Estrategia Resta
14 type EstrategiaResta struct{}
15
16 func (e EstrategiaResta) RealizarOperacion(num1 int, num2 int) int {
17 return num1 - num2
18 }
19
20 // Estrategia Multiplica
21 type EstrategiaMultiplica struct{}
22
23 func (e EstrategiaMultiplica) RealizarOperacion(num1 int, num2 int) int {
24 return num1 * num2
25 }
26
27 // Contexto
28 type Contexto struct {
29 estrategia Estrategia
30 }
31
32 func (c *Contexto) EjecutarOperacion(num1 int, num2 int) int {
33 return c.estrategia.RealizarOperacion(num1, num2)
34 }
Chain of Responsibility
Propósito
Según el libro Patrones de Diseño [38] el patrón Chain of Responsibility “evita acoplar el emisor
de una petición a su receptor, dando a más de un objeto la posibilidad de responder a la petición.
Encadena los objetos receptores y pasa la petición a través de la cadena hasta que es procesada
por algún objeto”.
Estructura
Participantes
• Manejador:
– define una interfaz para tratar las peticiones.
– (opcional) implementa el enlace al sucesor.
• ManejadorConcreto:
– trata las peticiones de las que es responsable.
– puede acceder a su sucesor.
– si el ManejadorConcreto puede manejar la petición, lo hace; en caso contrario la
reenvía a su sucesor.
• Cliente:
– inicializa la petición a una variable ManejadorConcreto de la cadena.
Patrones de Comportamiento 42
Implementación
• No se observan impedimentos para su implementación en Go.
• La implementación de la clase abstracta Manejador debe reemplazarse por una interface
dado que no existe la herencia de clase en Go.
• Si fuese necesario que Manejador implementase código común a los ManejadoresConcretos
se podrá definir un tipo de dato adicional (ManejadorComun por ejemplo) y el mismo
deberá implementarse en cada ManejadorConcreto mediante el uso de la composición.
Código de ejemplo
En este ejemplo se definen dos receptores distintos de mensajes. Uno para mensajes de alta
prioridad y otro para mensajes de baja prioridad. El mensaje enviado por el cliente es transmitido
a través de la cadena de receptores y cada receptor trata o no el mensaje de acuerdo a su prioridad.
Implementación:
1 // Interface
2 type Receptor interface {
3 ProcesarMensaje(int, string) string
4 }
5
6 // Receptor de Alta Prioridad
7 type ReceptorAltaPrioridad struct{
8 siguiente Receptor
9 }
10
11 func (rap ReceptorAltaPrioridad) ProcesarMensaje(prioridad int, mensaje string) string {
12 if prioridad >= 5 {
13 return "Procesando mensaje de alta prioridad: " + mensaje
14 }
15
16 if rap.siguiente != nil {
17 return rap.siguiente.ProcesarMensaje(prioridad, mensaje)
18 }
19
20 return ""
21 }
22
23 // Receptor de Baja Prioridad
24 type ReceptorBajaPrioridad struct{
25 siguiente Receptor
26 }
27
28 func (rbp ReceptorBajaPrioridad) ProcesarMensaje(prioridad int, mensaje string) string {
29 if prioridad < 5 {
30 return "Procesando mensaje de baja prioridad: " + mensaje
31 }
32
33 if rbp.siguiente != nil {
Patrones de Comportamiento 43
1 manejadores := ReceptorBajaPrioridad {
2 siguiente: ReceptorAltaPrioridad {},
3 }
4
5 fmt.Println(manejadores.ProcesarMensaje(4, "Mensaje 1 - Prioridad 4"))
6 fmt.Println(manejadores.ProcesarMensaje(5, "Mensaje 2 - Prioridad 5"))
7 fmt.Println(manejadores.ProcesarMensaje(10, "Mensaje 3 - Prioridad 10"))
Command
Propósito
Según el libro Patrones de Diseño [38] el patrón Command “encapsula una petición en un objeto,
permitiendo así parametrizar a los clientes con diferentes peticiones, hacer cola o llevar registro
de las peticiones, y poder deshacer las operaciones”.
Estructura
Participantes
• Orden:
– declara una interfaz para ejecutar una operación.
• Orden Concreta:
– define un enlace entre una variable Receptor y una acción.
– implementa Ejecutar invocando la correspondiente operación u operaciones del Re-
ceptor.
• Cliente:
– crea una variable OrdenConcreta y establece su receptor.
• Invocador:
– le pide a la orden que ejecute la petición.
• Receptor:
– sabe cómo llevar a cabo las operaciones asociadas a una petición. Cualquier clase puede
actuar como Receptor.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Patrones de Comportamiento 45
Código de ejemplo
En este ejemplo queremos poder prender y apagar un televisor mediante la invocación de
comandos mediante un control remoto.
Implementación:
45
46 for _, comando := range i.comandos {
47 resultados += comando.Ejecutar() + "\n"
48 }
49
50 return resultados
51 }
52
53 // Receptor
54 type Receptor struct{}
55
56 func (r Receptor) Prender() string {
57 return "- Prender Televisor"
58 }
59
60 func (r Receptor) Apagar() string {
61 return "- Apagar Televisor"
62 }
Template Method
Propósito
Según el libro Patrones de Diseño [38] el patrón Template Method “define en una operación el
esqueleto de un algoritmo, delegando en las subclases algunos de sus pasos. Permite que las
subclases redefinan ciertos pasos de un algoritmo sin cambiar su estructura”.
Estructura
Participantes
• ClaseAbstracta:
– define operaciones primitivas abstractas que son definidas por los subtipos de datos
para implementar los pasos de un algoritmo.
– implementa una función plantilla que define el esqueleto de un algoritmo. La función
plantilla llama a las operaciones primitivas así como a operaciones definidas en
ClaseAbstracta o a las de otras variables.
• ClaseConcreta:
– implementa las operaciones primitivas para realizar los pasos del algoritmo específicos
de los subtipos de datos.
Implementación
• No se observan impedimentos para su implementación en Go.
Patrones de Comportamiento 48
• En este caso, dado que no existe la herencia de clase en Go, la ClaseAbstracta sugerida por
el patrón debe implementarse en dos partes: a) por un lado los comportamientos abstractos
deben definirse en una Interface, y b) por otro lado los comportamientos concretos (el
método plantilla) dentro del propio tipo ClaseAbstracta.
• Las ClasesConcretas se componen (en vez de heredar) de una ClaseConcreta.
• Las ClasesConcretas implementan los comportamientos de la Interface.
• La principal dificultad de implementar este patrón en Go es que el comportamiento
del método plantilla de la ClaseAbstracta invoca a otros comportamientos que no están
definidos dentro de la propia ClaseAbstracta sino dentro de la ClaseConcreta. Esto obliga
a que cuando se invoca el método plantilla desde una ClaseConcreta se deba pasar una
referencia de si misma para que el método plantilla pueda invocar los comportamientos
definidos en la Interface.
Dada esta complejidad adicional léase esta forma de implementación junto al código de
ejemplo del patrón.
Código de ejemplo
En este ejemplo queremos cumplir con una serie de pasos formales (método plantilla) para
desplegar diferentes aplicaciones móviles.
Implementación:
24
25 func (d DeployAndroid) Testear() {
26 fmt.Println("Android: Testeando")
27 }
28
29 func (d DeployAndroid) Compilar() {
30 fmt.Println("Android: Compilando")
31 }
32
33 func (d DeployAndroid) Publicar() {
34 fmt.Println("Android: Publicando")
35 }
36
37 // Clase Concreta - iOS
38 type DeployiOS struct {
39 Deploy
40 }
41
42 func (d DeployiOS) Testear() {
43 fmt.Println("iOS: Testeando")
44 }
45
46 func (d DeployiOS) Compilar() {
47 fmt.Println("iOS: Compilando")
48 }
49
50 func (d DeployiOS) Publicar() {
51 fmt.Println("iOS: Publicando")
52 }
1 deployAndroid := DeployAndroid{Deploy{}}
2 deployAndroid.Construir(&deployAndroid)
3
4 deployiOS := DeployiOS{Deploy{}}
5 deployiOS.Construir(&deployiOS)
1 deployAndroid := DeployAndroid{Deploy{DeployAndroid{}}}
2 deployAndroid.Construir()
Memento
Propósito
Según el libro Patrones de Diseño [38] el patrón Memento “representa y externaliza el estado
interno de un objeto sin violar la encapsulación, de forma que este puede volver a dicho estado
más tarde”.
Estructura
Participantes
• Memento:
– guarda el estado interno de la variable Creador. El memento puede guardar tanta
información del estado interno del creador como sea necesario a discreción del creador.
– protege frente a accesos de otras variables que no sean el creador. Los mementos
tienen realmente dos interfaces. El Conserje va una interfaz reducida del memento
- solo puede pasar el memento a otras variables -. El Creador, por el contrario, ve una
interfaz amplia, que le permite acceder a todos los datos necesarios para volver a su
estado anterior. Idealmente, solo el creador que produjo el memento estaría autorizado
a acceder al estado interno de este.
• Creador:
– crea un memento que contiene una instantánea de su estado interno actual.
– usa el memento para volver a su estado anterior.
• Conserje:
– es responsable de guardar en lugar seguro el memento.
– nunca examina los contenidos del memento, ni opera sobre ellos.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Patrones de Comportamiento 52
Código de ejemplo
En este ejemplo queremos que un editor de texto tenga la posibilidad de volver atrás su estado
luego de una actualización de contenido.
Implementación:
1 // Interface
2 type Memento interface {
3 SetContenido(string)
4 GetContenido() string
5 }
6
7 // Memento
8 type EditorMemento struct {
9 contenido string
10 }
11
12 func (em *EditorMemento) SetContenido(contenido string) {
13 em.contenido = contenido
14 }
15
16 func (em *EditorMemento) GetContenido() string {
17 return em.contenido
18 }
19
20 // Originador
21 type Editor struct {
22 contenido string
23 }
24
25 func (e *Editor) VerContenido() string {
26 return e.contenido
27 }
28
29 func (e *Editor) Escribir(texto string) {
30 e.contenido = e.contenido + " " + texto
31 }
32
33 func (e *Editor) Guardar() Memento {
34 editorMemento := &EditorMemento{}
35 editorMemento.SetContenido(e.contenido)
36
37 return editorMemento
38 }
39
40 func (e *Editor) Restaurar(memento Memento) {
41 e.contenido = memento.GetContenido()
42 }
1 editor := &Editor{}
2 editor.Escribir("TextoA")
3 editor.Escribir("TextoB")
4 fmt.Printf("El editor contiene:%s\n", editor.VerContenido())
5
6 fmt.Println("Se guarda el estado actual")
7 memento := editor.Guardar()
8
9 fmt.Println("Se escribe unnuevo contenido")
10 editor.Escribir("TextoC")
11
12 fmt.Printf("El editor ahora contiene:%s\n", editor.VerContenido())
13
14 fmt.Println("Se restaura el contenido guardado")
15 editor.Restaurar(memento)
16
17 fmt.Printf("El editor nuevamente contiene:%s\n", editor.VerContenido())
Interpreter
Propósito
Según el libro Patrones de Diseño [38] el patrón Interpreter “dado un lenguaje, define una
representación de su gramática junto con un intérprete que usa dicha representación para
interpretar sentencias del lenguaje”.
Estructura
Participantes
• ExpresionAbstracta:
– declara una operación abstracta interpretar que es común a todos los nodos del árbol
de sintaxis abstracto.
• ExpresionTerminal:
– implementa una operación interpretar asociada con los símbolos terminales de la
gramática.
– se necesita una variable de este tipo de dato para cada símbolo terminal de la sentencia.
• ExpresionNoTerminal:
– por cada regla de la gramática debe haber uno de estos tipos de datos.
– mantiene variables de tipo ExpresionAbstracta para cada uno de los símbolos de cada
regla.
Patrones de Comportamiento 55
• Contexto:
– contiene información que es global al intérprete.
• Cliente:
– construye (o recibe) un árbol sintáctico abstracto que representa una determinada
sentencia del lenguaje definido por la gramática. Este árbol sintáctico abstracto está
formado por variables del tipo de dato ExpresionNoTerminal y ExpresionTerminal.
– invoca a la operación interpretar.
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• La ExpresionAbstracta se define como una interfaz por simplificación.
Código de ejemplo
En este ejemplo queremos interpretar distintas expresiones lógicas: AND y OR en base a palabras
definidas en un contexto.
Implementación:
1 // Contexto
2 type Contexto struct {
3 Palabra string
4 }
5
6 // Interface
7 type ExpresionAbstracta interface {
8 Interpretar(Contexto) bool
9 }
10
11 // Expresion Terminal
12 type ExpresionTerminal struct {
13 Palabra string
14 }
15
16 func (et *ExpresionTerminal) Interpretar(contexto Contexto) bool {
17 return contexto.Palabra == et.Palabra
18 }
19
20 // Expresion No Terminal
21 type ExpresionOR struct {
22 expresionA ExpresionAbstracta
23 expresionB ExpresionAbstracta
24 }
25
26 func (eo *ExpresionOR) Interpretar(contexto Contexto) bool {
27 return eo.expresionA.Interpretar(contexto) || eo.expresionB.Interpretar(contexto)
Patrones de Comportamiento 56
28 }
29
30 // Expresion No Terminal
31 type ExpresionAND struct {
32 expresionA ExpresionAbstracta
33 expresionB ExpresionAbstracta
34 }
35
36 func (ea *ExpresionAND) Interpretar(contexto Contexto) bool {
37 return ea.expresionA.Interpretar(contexto) && ea.expresionB.Interpretar(contexto)
38 }
1 expresionA := &ExpresionTerminal{"Perro"}
2 expresionB := &ExpresionTerminal{"Gato"}
3 expresionC := &ExpresionTerminal{"Perro"}
4
5 contextoOR := Contexto{"Perro"}
6 expresionOR := &ExpresionOR{expresionA, expresionB}
7 fmt.Printf("La expresion OR contiene la palabra perro: %v\n", expresionOR.Interpretar(conte\
8 xtoOR))
9
10 contextoAND := Contexto{"Perro"}
11 expresionAND := &ExpresionAND{expresionA, expresionC}
12 fmt.Printf("La expresion AND contiene dos palabras perro: %v\n", expresionAND.Interpretar(c\
13 ontextoAND))
Iterator
Propósito
Según el libro Patrones de Diseño [38] el patrón Iterator “proporciona un modo de acceder
secuencialmente a los elementos de un objeto agregado sin exponer su representación interna”.
Estructura
Participantes
• Iterador:
– define una interfaz para recorrer los elementos y acceder a ellos.
• IteradorConcreto:
– implementa la interfaz Iterador.
– mantiene la posición actual en el recorrido del agregado.
• Agregado:
– define una interfaz para crear una variable Iterador.
• AgregadoConcreto:
– implementa la interfaz de creación de Iterador para devolver una variable del Iterador-
Concreto apropiado.
Patrones de Comportamiento 58
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• El Iterador y Agregado se definen como interfaces por simplificación.
Código de ejemplo
En este ejemplo queremos recorrer las distintas estaciones de radio preseteadas de un estéreo de
audio.
Implementación:
1 // Iterador Interface
2 type Iterador interface {
3 Valor() string
4 Siguiente()
5 Anterior()
6 }
7
8 // Agregado Interface
9 type Agregado interface {
10 CrearIterador() Iterador
11 }
12
13 // Agregado Concreto
14 type Radio struct {
15 Estaciones []string
16 }
17
18 func (r *Radio) CrearIterador() Iterador {
19 return &RadioIterador{radio: r}
20 }
21
22 func (r *Radio) Registrar(estacion string) {
23 r.Estaciones = append(r.Estaciones, estacion)
24 }
25
26 // Iterador Concreto
27 type RadioIterador struct {
28 radio *Radio
29 indice int
30 }
31
32 func (ri *RadioIterador) Valor() string {
33 return ri.radio.Estaciones[ri.indice]
34 }
35
36 func (ri *RadioIterador) Siguiente() {
37 ri.indice++
Patrones de Comportamiento 59
38 }
39
40 func (ri *RadioIterador) Anterior() {
41 ri.indice--
42 }
1 radio := &Radio{}
2 radio.Registrar("FM100")
3 radio.Registrar("FM200")
4 radio.Registrar("FM300")
5
6 iterador := radio.CrearIterador()
7
8 fmt.Printf("Escuhando la radio %s\n", iterador.Valor())
9
10 iterador.Siguiente()
11 fmt.Printf("Escuhando la radio %s\n", iterador.Valor())
12
13 iterador.Siguiente()
14 fmt.Printf("Escuhando la radio %s\n", iterador.Valor())
15
16 iterador.Anterior()
17 fmt.Printf("Escuhando nuevamente la radio %s\n", iterador.Valor())
Visitor
Propósito
Según el libro Patrones de Diseño [38] el patrón Visitor “representa una operación sobre los
elementos de una estructura de objetos. Permite definir una nueva operación sin cambiar las
clases de los elementos sobre los que opera”.
Estructura
Participantes
• Visitante:
– declara una operación visitar para cada tipo de dato de operación de ElementoConcreto
de la estructura de variables. El nombre y signatura de la operación identifican al tipo
de dato que envía la petición visitar al visitante. Eso permite al visitante determinar el
tipo de dato concreto de elemento que está siendo visitada. A continuación el visitante
puede acceder al elemento directamente a través de su interfaz particular.
• VisitanteConcreto:
Patrones de Comportamiento 61
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• Dado que Go no soporta sobrecarga de método, y a fin de facilitar el ejemplo sin hacer
uso de la reflexión (https://golang.org/pkg/reflect/), los visitantes dispondan de diferentes
comportamientos para cada tipo de elemento variando los nombres de sus funciones.
• Se omite del código de ejemplo EstructuraDeObjeto dado que solo sería una colección que
acepta elementos.
Código de ejemplo
En este ejemplo queremos recrear un juego de rol en donde algunos personajes tengan superpo-
deres y otros armas de batalla.
Implementación:
1 // Visitante
2 type Visitante interface {
3 VisitarSuperpoder(*ElementoSuperpoder)
4 VisitarArma(*ElementoArma)
5 }
6
7 // Visitante Concreto
8 type VisitanteNivel1 struct{}
9
10 func (v *VisitanteNivel1) VisitarSuperpoder(elementoSuperpoder *ElementoSuperpoder) {
11 elementoSuperpoder.Poder = "Rayo superpoderoso"
12 }
13
14 func (v *VisitanteNivel1) VisitarArma(elementoArma *ElementoArma) {
15 elementoArma.Arma = "Espada de dos manos"
16 }
Patrones de Comportamiento 62
17
18 // Visitante Concreto
19 type VisitanteNivel0 struct{}
20
21 func (v *VisitanteNivel0) VisitarSuperpoder(elementoSuperpoder *ElementoSuperpoder) {
22 elementoSuperpoder.Poder = "Rayo simple"
23 }
24
25 func (v *VisitanteNivel0) VisitarArma(elementoArma *ElementoArma) {
26 elementoArma.Arma = "Espada de una mano"
27 }
28
29 // Elemento
30 type Elemento interface {
31 Aceptar(Visitante)
32 }
33
34 // Elemento Concreto
35 type ElementoSuperpoder struct {
36 Poder string
37 }
38
39 func (e *ElementoSuperpoder) Aceptar(visitante Visitante) {
40 visitante.VisitarSuperpoder(e)
41 }
42
43 // Elemento Concreto
44 type ElementoArma struct {
45 Arma string
46 }
47
48 func (e *ElementoArma) Aceptar(visitante Visitante) {
49 visitante.VisitarArma(e)
50 }
1 // desde visitar
2 elementoArma0 := &ElementoArma{}
3 elementoSuperpoder0 := &ElementoSuperpoder{}
4
5 visitanteNivel0 := &VisitanteNivel0{}
6 visitanteNivel0.VisitarArma(elementoArma0)
7 visitanteNivel0.VisitarSuperpoder(elementoSuperpoder0)
8
9 fmt.Printf("El visitante Nivel 0 tiene la siguiente arma de batalla: %s\n", elementoArma0.A\
10 rma)
11 fmt.Printf("El visitante Nivel 0 tiene el siguiente superpoder: %s\n", elementoSuperpoder0.\
12 Poder)
13
14 elementoArma1 := &ElementoArma{}
Patrones de Comportamiento 63
15 elementoSuperpoder1 := &ElementoSuperpoder{}
16
17 visitanteNivel1 := &VisitanteNivel1{}
18 visitanteNivel1.VisitarArma(elementoArma1) visitanteNivel1.VisitarSuperpoder(elementoSup\
19 erpoder1)
20
21 fmt.Printf("El visitante Nivel 1 tiene la siguiente arma de batalla: %s\n", elementoArma1.A\
22 rma)
23 fmt.Printf("El visitante Nivel 1 tiene el siguiente superpoder: %s\n", elementoSuperpoder1.\
24 Poder)
25
26 // desde aceptar
27 visitanteNivel0 = &VisitanteNivel0{}
28 elementoArma0 = &ElementoArma{}
29 elementoArma0.Aceptar(visitanteNivel0)
30
31 fmt.Printf("El elemento Arma aceptada por un visitante Nivel 0 es: %s\n", elementoArma0.Arm\
32 a)
State
Propósito
Según el libro Patrones de Diseño [38] el patrón State “permite que un objeto modifique su
comportamiento cada vez que cambie su estado interno. Parecerá que cambia la clase del objeto”.
Estructura
Participantes
• Contexto:
– define la interfaz de interés para los clientes.
– mantiene una variable de un subtipo de dato de EstadoConcreto que define el estado
actual.
• Estado:
– define una interfaz para encapsular el comportamiento asociado con un determinado
estado del Contexto.
• Subtipos de Datos de EstadoConcreto:
– cada subtipo de dato implementa un comportamiento asociado con un estado del
Contexto.
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• El Estado se define como interface por simplificación.
Patrones de Comportamiento 65
Código de ejemplo
En este ejemplo queremos escribir texto en base al estado de una botonera de estilos, pudiendo
ser estos estados “negrita” o “cursiva”.
Implementación:
1 // Interface Estado
2 type Estado interface {
3 Escribir(string) string
4 }
5
6 // Estado Concreto
7 type EstadoNegrita struct{}
8
9 func (en *EstadoNegrita) Escribir(texto string) string {
10 return "*" + texto + "*"
11 }
12
13 // Estado Concreto
14 type EstadoCursiva struct{}
15
16 func (ec *EstadoCursiva) Escribir(texto string) string {
17 return "_" + texto + "_"
18 }
19
20 // Contexto
21 type EditorMarkdown struct {
22 estado Estado
23 }
24
25 func (em *EditorMarkdown) SetEstado(estado Estado) {
26 em.estado = estado
27 }
28
29 func (em *EditorMarkdown) Redactar(texto string) string {
30 if em.estado == nil {
31 return texto
32 }
33
34 return em.estado.Escribir(texto)
35 }
1 editor := &EditorMarkdown{}
2 fmt.Printf("Texto redactado sin estado: %s\n", editor.Redactar("Lorem ipsum"))
3
4 editor.SetEstado(&EstadoNegrita{})
5 fmt.Printf("Texto redactado en negrita: %s\n", editor.Redactar("Lorem ipsum"))
6
7 editor.SetEstado(&EstadoCursiva{})
8 fmt.Printf("Texto redactado en cursiva: %s\n", editor.Redactar("Lorem ipsum"))
Mediator
Propósito
Según el libro Patrones de Diseño [38] el patrón Mediator “define un objeto que encapsula
cómo interactúan una serie de objetos. Promueve un bajo acoplamiento al evitar que los objetos
se refieran unos a otros explícitamente, y permite variar la interacción entre ellos de forma
independiente”.
Estructura
Participantes
• Mediador:
– define una interfaz para comunicarse con sus variables Colega.
• MediadorConcreto:
– implementa el comportamiento cooperativo coordinando variables Colega.
– conoce a sus Colegas.
• Colega:
– cada tipo de dato Colega conoce a su variable Mediador.
– cada Colega se comunica con su mediador cada vez que, de no existir éste, se hubiera
comunicado con otro Colega.
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• El Mediador y Colega se definen como interfaces por simplificación.
Patrones de Comportamiento 68
Código de ejemplo
En este ejemplo queremos montar una sala de chat en donde los usuarios puedan comunicarse
entre sí. La sala de chat actúa como mediador entre los usuarios.
Implementación:
1 // Interface Mediador
2 type Mediador interface {
3 MostrarMensaje(Usuario, string)
4 }
5
6 // Mediador Concreto
7 type ChatRoom struct{}
8
9 func (cr *ChatRoom) MostrarMensaje(usuario Usuario, mensaje string) {
10 fmt.Printf("El mensaje de %s es: %s\n", usuario.GetNombre(), mensaje)
11 }
12
13 // Interface Colega
14 type Usuario interface {
15 EnviarMensaje(string)
16 GetNombre() string
17 }
18
19 // Colega Concreto
20 type UsuarioChat struct {
21 nombre string
22 mediador Mediador
23 }
24
25 func (u *UsuarioChat) GetNombre() string {
26 return u.nombre
27 }
28
29 func (u *UsuarioChat) EnviarMensaje(mensaje string) {
30 u.mediador.MostrarMensaje(u, mensaje)
31 }
1 mediador := &ChatRoom{}
2
3 usuarioA := &UsuarioChat{"Daniel", mediador}
4 usuarioB := &UsuarioChat{"Pedro", mediador}
5
6 usuarioA.EnviarMensaje("Hola como estas?")
7 usuarioB.EnviarMensaje("Muy bien y vos?")
Observer
Propósito
Según el libro Patrones de Diseño [38] el patrón Observer “define una dependencia de uno-
a-muchos entre objetos, de forma que cuando un objeto cambie de estado se notifique y se
actualicen automáticamente todos los objetos que depende de él”.
Estructura
Participantes
• Sujeto:
– conoce a sus observadores. Un sujeto puede ser observado por cualquier número de
variables Observador.
– proporciona una interfaz para asignar y quitar variables Observador.
• Observador:
– define una interfaz para actualizar las variables que deben ser notificadas ante cambios
en un sujeto.
• SujetoConcreto:
Patrones de Comportamiento 71
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• El Sujeto y Observador se definen como interfaces por simplificación.
Código de ejemplo
En este ejemplo queremos que postulantes a empleos sean notificados cuando se creen ofertas
laborales.
Implementación:
1 // Interface Sujeto
2 type Sujeto interface {
3 Adquirir(Observador)
4 notificar()
5 }
6
7 // Sujeto Concreto
8 type AgenciaEmpleo struct {
9 observadores []Observador
10 }
11
12 func (ae *AgenciaEmpleo) Adquirir(observador Observador) {
13 ae.observadores = append(ae.observadores, observador)
14 }
15
16 func (ae *AgenciaEmpleo) notificar(oferta string) {
17 for _, observador := range ae.observadores {
18 observador.Actualizar(oferta)
19 }
20 }
21
22 func (ae *AgenciaEmpleo) IngresarOfertaLaboral(oferta string) {
23 ae.notificar(oferta)
24 }
25
26 // Interface Observador
27 type Observador interface {
Patrones de Comportamiento 72
28 Actualizar(string)
29 }
30
31 // Observador Concreto
32 type ObservadorEmpleo struct {
33 nombre string
34 }
35
36 func (o *ObservadorEmpleo) Actualizar(oferta string) {
37 fmt.Printf("Hola %s, existe la siguiente oferta de empleo: %s\n", o.nombre, oferta)
38 }
1 observadorA := &ObservadorEmpleo{"Juan"}
2 observadorB := &ObservadorEmpleo{"Maria"}
3
4 agencia := &AgenciaEmpleo{}
5 agencia.Adquirir(observadorA)
6 agencia.Adquirir(observadorB)
7
8 agencia.IngresarOfertaLaboral("Programador JAVA Senior")
9 fmt.Printf("\n")
10 agencia.IngresarOfertaLaboral("Programador C# Junior")
Según el libro Patrones de Diseño [38] los patrones de creación “abstraen el proceso de creación
de instancias. Ayudan a hacer un sistema independiente de cómo se crean, se componen y se
representan sus objetos. Un patrón de creación de clases usa la herencia para cambiar la clase
de la instancia a crear, mientras que un patrón de creación de objetos delega la creación de la
instancia en otro objeto.”
Esta definición de Gamma et al es un desafío de representar en Go ya que como hemos visto
no existen ni clases, ni sus instancias, ni objetos y ni la herencia de clase. Sin embargo veremos
como todo encaja en su lugar en cada patrón y cómo pueden implementarse en Go.
Concurrencia
Go es un lenguaje que permite la programación concurrente y los patrones de diseño creacionales
asumen que se trabaja sobre un único hilo de ejecución.
Dada la cantidad de estrategias y patrones de concurrencia existentes, sería muy dificultoso
detallar como pueden verse afectadas las variables transmitidas por canales en desarrollos
concurrentes.
Sin embargo, se realizará una mención especial en la explicación del patrón Singleton dado
que como su propósito es crear una única variable de un tipo de dato, será interesante ver que
estrategia permite implementar el lenguaje Go para cumplir con el propósito del patrón.
Contenido
• Singleton
• Builder
• Factory Method
• Abstract Factory
• Prototype
⁸Fuente: https://golang.org/doc/gopher
Patrones Creacionales 74
Singleton
Propósito
Según el libro Patrones de Diseño [38] el patrón Singleton “garantiza que una clase solo tenga
una instancia, y proporciona un punto de acceso global a ella”.
Estructura
Participantes
• Singleton:
– define una operación instancia que permite que los clientes accedan a su única variable.
– puede ser responsable de crear su única variable en memoria.
Implementación
• No se observan impedimentos para la implementación del patrón en Go.
• Al no existir método y propiedades estáticas en Go es necesario utilizar programación
funcional para poder implementar el patrón.
• Dado que Go permite la programación concurrente en diferentes subprocesos de ejecución,
no es posible garantizar una única variable del tipo de dato si no se toman recaudos
adicionales. Para asegurar que solo existirá una variable del tipo de dato se deberá hacer uso
de la librería estándar sync (https://golang.org/pkg/sync/) de Go. Concretamente el método
Do (https://golang.org/pkg/sync/#Once.Do) de la estructura Once (https://golang.org/pkg/
sync/#Once) garantiza que la función pasada como parámetro puede ser ejecutada una
única vez mientras dure la ejecución del programa. Esta función será la encargada de crear
la única variable del tipo de dato Singleton.
Código de ejemplo
Implementación:
Patrones Creacionales 75
1 // Singleton
2 type Singleton struct {
3 Tiempo int64
4 }
5
6 // Creador "estático"
7 var instancia *Singleton
8 var once sync.Once
9
10 func GetInstancia() *Singleton {
11 once.Do(func() {
12 instancia = &Singleton{
13 time.Now().Unix(),
14 }
15 })
16
17 return instancia
18 }
Builder
Propósito
Según el libro Patrones de Diseño [38] el patrón Builder “separa la construcción de un objeto
complejo de su representación, de forma que el mismo proceso de construcción pueda crear
diferentes representaciones”.
Estructura
Participantes
• Constructor:
– especifica una interfaz abstracta para crear las partes de una variable Producto.
• ConstructorConcreto:
– implementa la interfaz de Constructor para construir y ensamblar las partes del
producto.
– proporciona una interfaz para devolver el producto.
• Director:
– construye una variable usando la interfaz Constructor.
• Producto:
– representa una variable compleja en construcción. El ConstructorConcreto construye
la representación interna del producto y define el proceso de ensamble.
– incluye los tipos de datos que definen sus partes constituyentes, incluyendo interfaces
para ensamblar las partes en el resultado final.
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• El Constructor se define como interface por simplificación.
Patrones Creacionales 77
Código de ejemplo
En este ejemplo queremos que un local de comida pueda entregar distintos tipos de hamburguesas
(simples y dobles) para lo que será necesario generar distintos constructores de hamburguesas.
Implementación:
1 // Interface Constructor
2 type Constructor interface {
3 EstablecerTamanio()
4 Construir() *Hamburguesa
5 }
6
7 // Constructor Concreto
8 type ConstructorHamburguesaSimple struct {
9 tamanio string
10 }
11
12 func (chs *ConstructorHamburguesaSimple) EstablecerTamanio() {
13 chs.tamanio = "Simple"
14 }
15
16 func (chs *ConstructorHamburguesaSimple) Construir() *Hamburguesa {
17 return &Hamburguesa{chs.tamanio}
18 }
19
20 // Constructor Concreto
21 type ConstructorHamburguesaDoble struct {
22 tamanio string
23 }
24
25 func (chd *ConstructorHamburguesaDoble) EstablecerTamanio() {
26 chd.tamanio = "Doble"
27 }
28
29 func (chd *ConstructorHamburguesaDoble) Construir() *Hamburguesa {
30 return &Hamburguesa{chd.tamanio}
31 }
32
33 // Producto
34 type Hamburguesa struct {
35 Tamanio string
36 }
37
38 // Director
39 type LocalComida struct{}
40
41 func (lc *LocalComida) ConstruirHamburguesa(constructor Constructor) *Hamburguesa {
42 constructor.EstablecerTamanio()
43
44 return constructor.Construir()
Patrones Creacionales 78
45 }
1 localComida := &LocalComida{}
2
3 hamburguesaA := localComida.ConstruirHamburguesa(&ConstructorHamburguesaSimple{})
4 hamburguesaB := localComida.ConstruirHamburguesa(&ConstructorHamburguesaDoble{})
5
6 fmt.Printf("Se solicito una hamburguesa: %s\n", hamburguesaA.Tamanio)
7 fmt.Printf("Se solicito una hamburguesa: %s\n", hamburguesaB.Tamanio)
Factory Method
Propósito
Según el libro Patrones de Diseño [38] el patrón Factory Method “define una interfaz para crear
un objeto, pero deja que sean las subclases quienes decidan qué clase instanciar. Permite que una
clase delegue en sus subclases la creación de objetos”.
Estructura
Participantes
• Producto:
– define la interfaz de las variables que crea el método de fabricación.
• ProductoConcreto:
– implementa la interfaz Producto.
• Creador:
– declara el método de fabricación, el cual devuelve una variable de tipo Producto.
También puede definir una implementación predeterminada del método de fabricación
que devuelva una variable ProductoConcreto.
– puede llamar al método de fabricación para crear una variable Producto.
• CreadorConcreto:
– redefine el método de fabricación para devolver una variable de un ProductoConcreto.
Patrones Creacionales 80
Implementación
• No se observan impedimentos para su implementación en Go.
• En este caso, dado que no existe la herencia de clase en Go, el Creador sugerido por el patrón
debe implementarse en dos partes: a) por un lado los comportamientos abstractos deben
definirse en una Interface, y b) por otro lado los comportamientos concretos (el método una
operación) dentro del propio tipo de dato Creador.
• Los CreadoresConcretos se componen (en vez de heredar) de un Creador.
• Los CreadoresConcretos implementan los comportamientos de la InterfaceCreador.
• La principal dificultad de implementar este patrón en Go es que existe un comportamiento
concreto en Creador que invoca a otros comportamientos que no están definidos dentro del
propio Creador sino que están dentro del CreadorConcreto que implementa la Interface-
Creador. Esto obliga a que cuando se invoca el comportamiento concreto de Creador desde
un CreadorConcreto se deba pasar una referencia de si mismo para que el comportamiento
concreto pueda invocar los comportamientos definidos en la InterfaceCreador.
Código de ejemplo
En este ejemplo queremos contratar personas con diferentes perfiles profesionales. A medida que
los postulantes lleguen a la oficina de recursos humanos serán entrevistados (construidos) por
diferentes reclutadores especializados.
Implementación:
1 // Interface Producto
2 type Entrevistador interface {
3 RealizarPreguntas()
4 }
5
6 // Producto Concreto
7 type EntrevistadorIT struct{}
8
9 func (e *EntrevistadorIT) RealizarPreguntas() {
10 fmt.Println("¿Nombre 5 patrones de diseño?")
11 }
12
13 // Producto Concreto
14 type EntrevistadorFinanzas struct{}
15
16 func (e *EntrevistadorFinanzas) RealizarPreguntas() {
17 fmt.Println("¿Cuál es la alicuota del IVA?")
18 }
19
20 // Creador Interface
21 type RecursosHumanosInterface interface {
22 LlamarEntrevistador() Entrevistador
23 }
24
25 // Creador Abstracto
Patrones Creacionales 81
Abstract Factory
Propósito
Según el libro Patrones de Diseño [38] el patrón Abstract Factory “proporciona una interfaz
para crear familias de objetos relacionados o que dependen entre sí, sin especificar sus clases
concretas”.
Estructura
Participantes
• FabricaAbstracta:
– declara una interfaz para operaciones que crean variables producto abstractas.
• FabricaConcreta:
– implementa las operaciones para crear variables producto concretos.
• ProductoAbstracto:
– declara una interfaz para un tipo de variable producto.
• ProductoConcreto:
– define una variable producto para que sea creado por la fábrica correspondiente.
– implementa la interfaz ProductoAbstracto.
• Cliente:
– solo usa interfaces declaradas por los tipos de datos FabricaAbstracta y ProductoAbs-
tracto.
Patrones Creacionales 83
Implementación
• No se observan impedimentos y/o modificaciones de la estructura original del patrón para
su implementación en Go.
• La FabricaAbstracta y ProductoAbstracto se definen como interfaces por simplificación.
Código de ejemplo
En este ejemplo queremos comprar distintos tipos de puertas de madera (madera o metal). Al
realizar el pedido el local de venta debe encargar cada puerta a distintos fabricantes, ya que
quien realiza la puerta de madera no la hace de metal y viceversa.
Implementación:
1 fabricaPuertaMadera := &FabricaPuertaMadera{}
2 puertaMadera := fabricaPuertaMadera.ConstruirPuerta()
3 fmt.Printf("Se construyo un puerta de: %s\n", puertaMadera.VerMaterial())
4
5 fabricaPuertaMetal := &FabricaPuertaMetal{}
6 puertaMetal := fabricaPuertaMetal.ConstruirPuerta()
7 fmt.Printf("Se construyo un puerta de: %s\n", puertaMetal.VerMaterial())
Prototype
Propósito
Según el libro Patrones de Diseño [38] el patrón Prototype “especifica los tipos de objetos a crear
por medio de una instancia prototípica, y crea nuevos objetos copiando dicho prototipo”.
Estructura
Participantes
• Prototipo:
– declara la interfaz para clonarse.
• PrototipoConcreto:
– implementa una operación para clonarse.
• Cliente:
– crea una variable pidiéndole a un prototipo que se clone.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos que un elemento químico sea capaz de clonarse a sí mismo indicando
cuantas veces fue clonado.
Implementación:
Patrones Creacionales 86
1 // Prototipo Interface
2 type Prototipo interface {
3 Clonar() *Elemento
4 }
5
6 // Prototipo Concreto
7 type Elemento struct {
8 Material string
9 Copias int
10 }
11
12 func (e *Elemento) Clonar() *Elemento {
13 return &Elemento{
14 Material: e.Material,
15 Copias: e.Copias + 1,
16 }
17 }
1 elementoA := &Elemento{"Azufre", 1}
2
3 elementoB := elementoA.Clonar()
4 elementoB.Material = elementoB.Material + " (fortificado)"
5
6 elementoC := elementoB.Clonar()
7
8 fmt.Printf("El elemento A es de %s y se clono %d veces\n", elementoA.Material, elementoA.Co\
9 pias)
10 fmt.Printf("El elemento B es de %s y se clono %d veces\n", elementoB.Material, elementoB.Co\
11 pias)
12 fmt.Printf("El elemento C es de %s y se clono %d veces\n", elementoC.Material, elementoC.Co\
13 pias)
Según el libro Patrones de Diseño [38] los patrones estructurales “se ocupan de cómo se combinan
las clases y los objetos para formar estructuras más grandes. Los patrones estructurales de clases
hacen uso de la herencia para componer interfaces o implementaciones.”
Contenido
• Composite
• Adapter
• Bridge
• Proxy
• Decorator
• Facade
• Flyweight
⁹Fuente: https://golang.org/doc/gopher
Patrones Estructurales 88
Composite
Propósito
Según el libro Patrones de Diseño [38] el patrón Composite “compone objetos en estructuras
de árbol para representar jerarquías de parte-todo. Permite que los clientes traten de manera
uniforme a los objetos individuales y a los compuestos”.
Estructura
Participantes
• Componente:
– declara la interfaz de las variables de la composición.
– implementa el comportamiento predeterminado de la interfaz que es común a todos
los tipos de datos.
– declara una interfaz para acceder a sus componentes hijos y gestionarlos.
– (opcional) define una interfaz para acceder al padre de un componente en la jerarquía
recursiva y, si es necesario, la implementa.
• Hoja:
– representa variables hoja en la composición. Una hoja no tiene hijos.
– define el comportamiento de las variables primitivas de la composición.
• Compuesto:
– define el comportamiento de los componentes que tienen hijos.
– almacena componentes hijos.
– implementa las operaciones de la interfaz Componente relacionadas con los hijos.
• Cliente:
– manipula variables en la composición a través de la interfaz Componente.
Patrones Estructurales 89
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos acceder a los salarios de los empleados de una gerencia tanto de forma
individual como grupal. De esta forma la compañía podría analizar el impacto de futuros bonos
de productividad tanto para una gerencia completa o para alguno de sus empleados.
Implementación:
1 // Componente Interface
2 type Empleado interface {
3 ObtenerSalario() int
4 }
5
6 // Hoja
7 type DesarrolladorSenior struct{}
8
9 func (ds *DesarrolladorSenior) ObtenerSalario() int {
10 return 1000
11 }
12
13 // Hoja
14 type DesarrolladorJunior struct{}
15
16 func (dj *DesarrolladorJunior) ObtenerSalario() int {
17 return 750
18 }
19
20 // Compuesto
21 type GerenciaIT struct {
22 empleados []Empleado
23 }
24
25 func (g *GerenciaIT) AgregarEmpleado(empleado Empleado) {
26 g.empleados = append(g.empleados, empleado)
27 }
28
29 func (g *GerenciaIT) ObtenerSalario() int {
30 sumaSalarios := 0
31
32 for _, empleado := range g.empleados {
33 sumaSalarios = sumaSalarios + empleado.ObtenerSalario()
34 }
35
36 return sumaSalarios
37 }
Patrones Estructurales 90
1 empleadoA := &DesarrolladorJunior{}
2 empleadoB := &DesarrolladorJunior{}
3 empleadoC := &DesarrolladorSenior{}
4
5 gerenciaIT := &GerenciaIT{}
6 gerenciaIT.AgregarEmpleado(empleadoA)
7 gerenciaIT.AgregarEmpleado(empleadoB)
8 gerenciaIT.AgregarEmpleado(empleadoC)
9
10 fmt.Printf("El salario individual del desarrollador A es de $%d\n", empleadoA.ObtenerSalari\
11 o())
12 fmt.Printf("El salario individual del desarrollador B es de $%d\n", empleadoB.ObtenerSalari\
13 o())
14 fmt.Printf("El salario individual del desarrollador C es de $%d\n", empleadoC.ObtenerSalari\
15 o())
16 fmt.Printf("Los salarios de todos los desarrolladores de la Gerencia es de $%d\n", gerencia\
17 IT.ObtenerSalario())
Adapter
Propósito
Según el libro Patrones de Diseño [38] el patrón Adapter “convierte la interfaz de una clase en
otra interfaz que es la que esperan los clientes. Permite que cooperen clases que de otra forma
no podrían por tener interfaces incompatibles”.
Estructura
Participantes
• Objetivo:
– define la interfaz específica del dominio que usa el Cliente.
• Cliente:
– colabora con variables que se ajustan a la interfaz Objetivo.
• Adaptable:
– define una interfaz existente que necesita ser adaptada.
• Adaptador:
– adapta la interfaz de Adaptable a la interfaz Objetivo.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Patrones Estructurales 92
Código de ejemplo
En este ejemplo queremos que un juego de RPG se pueda adaptar a un nuevo tipo de personaje
(Magos) que no comparte las mismas características que los guerreros originales (Elfos). Para
esto es necesario realizar un adaptador para que un Mago pueda atacar como un Elfo.
Implementación:
1 // Objetivo
2 type Gerrero interface {
3 UsarArma() string
4 }
5
6 type Elfo struct{}
7
8 func (e *Elfo) UsarArma() string {
9 return "atacando con arco y flecha"
10 }
11
12 // Adaptable
13 type GerreroMagico interface {
14 UsarMagia() string
15 }
16
17 type Mago struct{}
18
19 func (m *Mago) UsarMagia() string {
20 return "atacando con magia"
21 }
22
23 // Adaptador
24 type MagoAdaptador struct {
25 gerrero GerreroMagico
26 }
27
28 func (ma *MagoAdaptador) UsarArma() string {
29 return ma.gerrero.UsarMagia()
30 }
31
32 // Cliente
33 type Jugador struct {
34 guerrero Gerrero
35 }
36
37 func (j *Jugador) Atacar() string {
38 return j.guerrero.UsarArma()
39 }
1 jugadorA := &Jugador{&Elfo{}}
2 fmt.Printf("Jugador A: %s\n", jugadorA.Atacar())
3
4 jugadorB := &Jugador{&MagoAdaptador{&Mago{}}}
5 fmt.Printf("Jugador B: %s\n", jugadorB.Atacar())
Bridge
Propósito
Según el libro Patrones de Diseño [38] el patrón Bridge “desacopla una abstracción de su
implementación, de modo que ambas puedan variar de forma independiente”.
Estructura
Participantes
• Abstraccion:
– define la interfaz de la abstracción.
– mantiene una referencia a una variable de tipo Implementador.
• AbstraccionRefinada:
– extiende la interfaz definida por Abstraccion.
• Implementador:
– define la interfaz de los tipos de datos de implementación. Esta interfaz no tiene por
qué corresponderse exactamente con la de Abstracción; de hecho, ambas interfaces
pueden ser muy distintas. Normalmente la interfaz Implementador solo proporciona
operaciones primitivas, y Abstraccion define operaciones de más alto nivel basadas en
dichas primitivas.
• ImplementadorConcreto:
– implementa la interfaz Implementador y define su implementación concreta.
Patrones Estructurales 95
Implementación
• No se observan impedimentos para su implementación en Go.
• En este caso, dado que Abstraccion se define como una interface pero a la vez también
implementando comportamiento concreto para mantener la referencia del tipo de dato
Implementador, se separará en dos partes en dos partes: a) por un lado los comportamientos
abstractos deben definirse en una interface Abstraccion Interface, y b) por otro lado los
comportamientos concretos (el que mantiene una referencia del Implementador) dentro de
un tipo de dato Abstraccion Abstracta.
• Las Abstracciones Refinadas se componen (en vez de heredar) de Abstraccion Abstracta.
Código de ejemplo
En este ejemplo queremos desacoplar el protocolo de conexión a internet que pueden implemen-
tar distintos dispositivos.
Implementación:
1 // Abstraccion Interface
2 type DispositivoInterface interface {
3 ConectarInternet() string
4 SetConexion(Conexion)
5 }
6
7 // Abstraccion Abstracta
8 type Dispositivo struct {
9 conexion Conexion
10 }
11
12 func (d *Dispositivo) SetConexion(conexion Conexion) {
13 d.conexion = conexion
14 }
15
16 // Abstraccion Refinada
17 type Telefono struct {
18 numero string
19 *Dispositivo
20 }
21
22 func (t *Telefono) ConectarInternet() string {
23 return "Teléfono N° " + t.numero + " conectado a internet mediante " + t.conexion.Conec\
24 tar()
25 }
26
27 // Abstraccion Refinada
28 type Tablet struct {
29 *Dispositivo
30 }
31
Patrones Estructurales 96
Proxy
Propósito
Según el libro Patrones de Diseño [38] el patrón Proxy “proporciona un representante o sustituto
de otro objeto para controlar el acceso a este”.
Estructura
Participantes
• Proxy:
– mantiene una referencia que permite al proxy acceder a la variable original. El proxy
puede referirse a un Sujeto en caso de que las interfaces de SujetoReal y Sujeto sean la
misma.
– proporciona una interfaz idéntica a la de Sujeto, de manera que un proxy pueda ser
sustituido por el sujeto real.
– controla el acceso al sujeto real, y puede ser responsable de su creación y borrado.
– otras responsabilidades dependen del tipo de proxy:
* los proxies remotos son responsables de codificar una petición y sus argumentos
para enviar la petición codificada al sujeto real que se encuentra en un espacio de
direcciones diferente.
* los proxies virtuales pueden guardar información adicional sobre el sujeto real, por
lo que pueden retardar el acceso al mismo.
Patrones Estructurales 98
* los proxies de protección comprueban que el llamador tenga los permisos de acceso
necesarios para realizar una petición.
• Sujeto:
– define una interfaz común para el SujetoReal y el Proxy, de modo que pueda usarse un
Proxy en cualquier sitio en el que se espere un SujetoReal.
• SujetoReal:
– define la variable real representada.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos restringir los accesos a redes sociales en los navegadores de una
escuela. Para esto realizaremos un proxy de protección.
Implementación:
1 // Sujeto Interface
2 type NavegadorInterface interface {
3 Direccion(string) string
4 }
5
6 // Sujeto Real
7 type Navegador struct{}
8
9 func (n *Navegador) Direccion(url string) string {
10 return "Respuesta de la url " + url
11 }
12
13 // Proxy
14 type NavegadorProxy struct {
15 navegador NavegadorInterface
16 }
17
18 func (n *NavegadorProxy) Direccion(url string) string {
19 if url == "http://twitter.com" || url == "http://facebook.com" {
20 return "Acceso restringido a " + url
21 }
22
23 return n.navegador.Direccion(url)
24 }
1 navegadorProxy := &NavegadorProxy{&Navegador{}}
2
3 fmt.Printf("%s\n", navegadorProxy.Direccion("http://google.com"))
4 fmt.Printf("%s\n", navegadorProxy.Direccion("http://twitter.com"))
5 fmt.Printf("%s\n", navegadorProxy.Direccion("http://facebook.com"))
Decorator
Propósito
Según el libro Patrones de Diseño [38] el patrón Decorator “asigna responsabilidades adicionales
a un objeto dinámicamente, proporcionando una alternativa flexible a la herencia para extender
la funcionalidad”.
Estructura
Participantes
• Componente:
– define la interfaz para variables a las que se puede añadir responsabilidades dinámica-
mente.
• ComponenteConcreto:
– define una variable a la que se pueden añadir responsabilidades adicionales.
• Decorador:
– mantiene una referencia a una variable Componente y define una interfaz que se ajusta
a la interfaz del Componente.
• DecoradorConcreto:
– añade responsabilidades al componente.
Patrones Estructurales 101
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos agregarle dinámicamente ingredientes adicionales a un café que por
defecto viene simple.
Implementación:
1 // Componente Interface
2 type CafeInterface interface {
3 GetCosto() int
4 GetDetalle() string
5 }
6
7 // Componente Concreto
8 type Cafe struct{}
9
10 func (c *Cafe) GetCosto() int {
11 return 30
12 }
13
14 func (c *Cafe) GetDetalle() string {
15 return "Cafe"
16 }
17
18 // Decorador
19 type CafeDecorador struct {
20 CafeInterface
21 }
22
23 func (cd *CafeDecorador) GetCosto() int {
24 return cd.CafeInterface.GetCosto()
25 }
26
27 func (cd *CafeDecorador) GetDetalle() string {
28 return cd.CafeInterface.GetDetalle()
29 }
30
31 // Decorador Concreto
32 type CafeConCrema struct {
33 *CafeDecorador
34 }
35
36 func (ccc *CafeConCrema) GetCosto() int {
37 return ccc.CafeDecorador.GetCosto() + 15
38 }
Patrones Estructurales 102
39
40 func (ccc *CafeConCrema) GetDetalle() string {
41 return ccc.CafeDecorador.GetDetalle() + " con crema"
42 }
43
44 // Decorador Concreto
45 type CafeConCanela struct {
46 *CafeDecorador
47 }
48
49 func (ccc *CafeConCanela) GetCosto() int {
50 return ccc.CafeDecorador.GetCosto() + 10
51 }
52
53 func (ccc *CafeConCanela) GetDetalle() string {
54 return ccc.CafeDecorador.GetDetalle() + " con canela"
55 }
1 cafe := &Cafe{}
2 fmt.Printf("Detalle: %s - Importe $%d\n", cafe.GetDetalle(), cafe.GetCosto())
3
4 cafeConCrema := &CafeConCrema{&CafeDecorador{cafe}}
5 fmt.Printf("Detalle: %s - Importe $%d\n", cafeConCrema.GetDetalle(), cafeConCrema.GetCosto(\
6 ))
7
8 cafeConCremaConCanela := &CafeConCanela{&CafeDecorador{cafeConCrema}}
9 fmt.Printf("Detalle: %s - Importe $%d\n", cafeConCremaConCanela.GetDetalle(), cafeConCremaC\
10 onCanela.GetCosto())
Facade
Propósito
Según el libro Patrones de Diseño [38] el patrón Facade “proporciona una interfaz unificada para
un conjunto de interfaces de un subsistema. Define una interfaz de alto nivel que hace que el
subsistema sea más fácil de usar”.
Estructura
Participantes
• Fachada:
– sabe qué tipos de datos del subsistema son los responsables ante una petición.
– delega las peticiones de los clientes en las variables apropiadas del subsistema.
• Tipos del subsistema:
– implementa la funcionalidad del subsistema.
– realizan las labores encomendadas por la variable Fachada.
– no conocen a la fachada; es decir, no tienen referencias a ella.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos que un sistema de agencia de viajes pueda interactuar con otros
subsistemas: buscador de hoteles y buscador de pasajes aéreos.
Implementación:
Patrones Estructurales 104
1 // Subsistema
2 type BuscadorHotel struct{}
3
4 func (bh *BuscadorHotel) BuscarHabitacion(entrada string, salida string) []string {
5 return []string{
6 "Hotel A con Habitación Classic - Entrada " + entrada + ", Salida " + salida + " - \
7 $500.00",
8 "Hotel B con Habitación Deluxe - Entrada " + entrada + ", Salida " + salida + " - $\
9 750.00",
10 }
11 }
12
13 // Subsistema
14 type BuscadorAvion struct{}
15
16 func (ba *BuscadorAvion) BuscarPasaje(salida string, regreso string) []string {
17 return []string{
18 "Aerolinea A - Clase Turista - Salida " + salida + ", Regreso " + regreso + " - $24\
19 00.00",
20 "Aerolinea A - Clase Ejecutiva - Salida " + salida + ", Regreso " + regreso + " - $\
21 3200.00",
22 "Aerolinea B - Clase Ejecutiva - Salida " + salida + ", Regreso " + regreso + " - $\
23 3800.00",
24 }
25 }
26
27 // Fachada
28 type AgenciaViaje struct{}
29
30 func (av *AgenciaViaje) BuscarPaquete(desde string, hasta string) string {
31 buscadorHoteles := &BuscadorHotel{}
32 buscadorAvion := &BuscadorAvion{}
33
34 resultadosHabitaciones := buscadorHoteles.BuscarHabitacion(desde, hasta)
35 resultadosPasajes := buscadorAvion.BuscarPasaje(desde, hasta)
36
37 respuesta := "Hoteles disponibles:\n"
38
39 for _, habitacion := range resultadosHabitaciones {
40 respuesta = respuesta + " - " + habitacion + "\n"
41 }
42
43 respuesta = respuesta + "\nAerolineas disponibles:\n"
44
45 for _, pajase := range resultadosPasajes {
46 respuesta = respuesta + " - " + pajase + "\n"
47 }
48
49 return respuesta
50 }
Patrones Estructurales 105
1 agencia := &AgenciaViaje{}
2
3 fmt.Printf("%s\n", agencia.BuscarPaquete("2018-12-01", "2018-12-08"))
Flyweight
Propósito
Según el libro Patrones de Diseño [38] el patrón Flyweight “usa comportamiento para permitir
un gran número de objetos de grano fino de forma eficiente”.
Estructura
Participantes
• Flyweight:
– declara una interfaz a través de la cual los flyweight concretos pueden recibir un estado
extrínseco y actuar sobre él.
• FlyweightConcreto:
– implementa la interfaz Flyweight y permite almacenar el estado intrínseco, en caso de
que lo haya. Una variable FlyweightConcreto debe poder ser compartida, por lo que
cualquier estado que almacene debe ser intrínseco, esto es, debe ser independiente del
contexto de la variable FlyweightConcreto.
• FlyweightConcretoNoCompartido:
– no todas los subtipos de datos de Flyweight necesitan ser compartidas. La interfaz
Flyweight permite el comportamiento, no fuerza a él. Las variables FlyweightConcre-
toNoCompartido suelen tener variables FlyweightConcreto como hijos en algún nivel
de la jerarquía de variables.
Patrones Estructurales 107
• FabricaFlyweight:
– crea y controla variables flyweight.
– garantiza que los flyweight se compartan de manera adecuada. Cuando un cliente
solicita un flyweight, la variable FabricaFlyweight proporciona una variable concreta
o crea una nueva, en caso de que no exista ninguna.
• Cliente:
– mantiene una referencia a los flyweight.
– calcula o guarda el estado extrínseco de los flyweight.
Implementación
No se observan impedimentos y/o modificaciones de la estructura original del patrón para su
implementación en Go.
Código de ejemplo
En este ejemplo queremos que nuestro sistema sea capaz de dibujar controles en la pantalla
haciendo un uso eficiente de los recursos, ya que existen controles (los botones) que pueden ser
reutilizados.
Implementación:
1 // Flyweight Interface
2 type Control interface {
3 Dibujar(x string, y string) string
4 GetReferencia() string
5 }
6
7 // Flyweight Concreto
8 type Boton struct {
9 referencia string
10 }
11
12 func (b *Boton) Dibujar(x string, y string) string {
13 return "Dibujando Botón #" + b.referencia + " en ejes " + x + ", " + y
14 }
15
16 func (b *Boton) GetReferencia() string {
17 return b.referencia
18 }
19
20 // Flyweight Concreto No Compartido
21 type CampoPassword struct{}
22
23 func (cp *CampoPassword) Dibujar(x string, y string) string {
24 return "Dibujando Campo de Password en ejes " + x + ", " + y
25 }
26
Patrones Estructurales 108
1 pantalla := &PantallaFabrica{}
2
3 fmt.Printf("%s\n", pantalla.ObtenerControl("BOTON", "BTN1", "100", "300"))
4 fmt.Printf("%s\n", pantalla.ObtenerControl("BOTON", "BTN2", "200", "300"))
5 fmt.Printf("%s\n", pantalla.ObtenerControl("BOTON", "BTN3", "300", "300"))
6 fmt.Printf("%s\n", pantalla.ObtenerControl("PASSWORD", "PWD1", "500", "300"))
7 fmt.Printf("%s\n", pantalla.ObtenerControl("BOTON", "BTN1", "400", "300"))
No deberían programar en Go como lo hacen en Java, PHP, C#, etc. Deberían potenciar
las características propias del lenguaje en sus desarrollos; esto es comprender a fondo,
por ejemplo, como funcionan las interfaces, la composición y la concurrencia; y sobre esta
base reutilizar conceptos o usos de patrones de diseño cuando realmente se justifiquen.
Acerca De
Motivación
Esta publicación fue motivada como trabajo final de mi Posgrado de Especialización en Ingeniería
del Software que curse durante el año 2017 en la UCA - Pontificia Universidad Católica Argentina
[53].
El trabajo
El trabajo presentado se denomina:
“El objetivo principal del presente trabajo será mostrar cómo pueden aplicarse los
Patrones de Diseño GoF en un lenguaje de programación que no es completamente
orientado a objetos. Para esto se utilizará como referencia el lenguaje de programación
Go. Su propósito principal será servir de material de referencia para desarrolladores Go
que deseen aplicar los patrones de Diseño GoF. Se analizará la viabilidad, los ajustes,
y las adaptaciones necesarias para implementar los Patrones de Diseño en base a las
características del lenguaje de programación Go. Para esto, previamente se abordarán
y explicarán los atributos orientados a objetos que posee el lenguaje de programación
Go. Adicionalmente el trabajo se publicará como e-book online mediante la realización
de una página web, junto a ejemplos auto ejecutables y un repositorio público con todo
el código fuente, ejemplos y diagramas desarrollados.”
Porqué Go
Al momento de tomar la decisión sobre cuál de los dos lenguajes antes mencionados (Go, Rust)
iba a basar mi trabajo, decidí hacer una pequeño análisis sobre la popularidad de ambos lenguajes
en los últimos años. Para esto tome como referencia el índice de popularidad de los lenguajes de
programación [51] de la Empresa Tiobe (https://www.tiobe.com).
Tiobe es una empresa especializada en la evaluación y el seguimiento de la calidad del software
que publica mensualmente un índice [51] de popularidad de lenguajes de programación. Este
índice es conformado en base a la cantidad de resultados que arrojan varios motores de búsqueda.
Los resultados deben cumplir ciertos requerimientos para calificar para el índice, por ejemplo
el lenguaje de programación debe tener su propia entrada en Wikipedia, ser completo (poder
simular una máquina de Turing) y tener al menor 5.000 visitas en búsquedas aplicadas desde
Google. La empresa también utiliza filtros para evitar falsos positivos y otras reglas para valorar
la calificación del resultado.
Basándome en el índice antes mencionado realicé una comparación entre ambos lenguajes y Go,
tanto históricamente como actualmente, tiene mayor popularidad respecto de Rust.
Como se puede apreciar en la siguiente gráfica (Mayo/2018) Go obtuvo su mejor ubicación dentro
del ranking en Julio de 2017 al ubicarse entre los primeros 10 lenguajes de programación. Desde
mediados de 2016 a mediados de 2017 tuvo su mayor pico de popularidad, con un marcado
descenso actualmente.
Acerca De 113
Por el contrario Rust se ubica actualmente (Mayo/2018) en la 91ª posición en una clara caída
dentro del ranking. Si bien por su posición actual sus estadísticas ya no se publican dentro del
índice Tiobe, al momento de su evaluación estaba dentro del ranking de los 20ª a 50ª.
Las estadísticas registradas de Tiobe corresponden a Mayo del 2018. Consulte el Índice
Tiobe [51] para tener datos más actualizados.
El camino recorrido
Antes de formalizar la idea final de esta publicación me definí dos objetivos para evaluar la
factibilidad de su realización:
• hacer un muestreo de cuatro o cinco patrones GoF aleatoriamente con el fin de analizar si
se podían implementar “semánticamente” en Go.
• analizar si esas implementaciones realmente podían aportar valor al software.
11 }
12 };
13
14 var EmpresaA = function() {
15 this.calcularTasa = function() {
16 return 10;
17 }
18 };
19
20 var EmpresaB = function() {
21 this.calcularTasa = function() {
22 return 15;
23 }
24 };
25
26 var transportista = new Transportista;
27
28 transportista.setStrategy(new EmpresaA())
29 console.log("Tasa Empresa A: " + transportista.calcularTasa());
30
31 transportista.setStrategy(new EmpresaB())
32 console.log("Tasa Empresa B: " + transportista.calcularTasa());
• no tiene forma de validar que lo que se esté pasando al Transportista sea una Estrategia
válida.
• no tiene forma de implementar una interface Estrategia o heredar de una clase Estrategia.
• no permite generar código reutilizable en paquetes o namespaces.
• el Contexto no es autodocumentable a nivel código fuente ya que su función setStrategy
espera cualquier tipo de variable y no un objeto de tipo Estrategia.
Como se puede ver la programación orientada a objetos en Javascript ES5 es muy limitada, y si
bien semánticamente puede implementarse los patrones de diseño GoF, aportan valor al software
sólo en cuanto a su funcionamiento final pero no así respecto de la reutilización de código.
Aclaro ES5 de Javascript porque ES6 tiene un soporte más avanzado para la programa-
ción orientada a objetos.
• GitBook: plataforma para la primera publicación de este trabajo como e-book. - https://
legacy.gitbook.com/
• Leanpub: plataforma para la publicación actual de este trabajo como e-book. - https:
//leanpub.com/
• GitHub: plataforma para la publicación del código fuente de esta publicación. - https://
github.com/
• Git: software para el control de versiones del código fuente de esta publicación. - https:
//git-scm.com/
• Markdown: lenguaje de marcado para la redacción de la primera publicación. - https://
daringfireball.net/projects/markdown/
• Markua: lenguaje de marcado para la redacción de la publicación actual. - http://markua.
com/
• Go Playground: plataforma para la publicación y ejecución de códigos de ejemplo de Go.
- https://play.golang.org/
• Violet UML Editor: software para la generación de diagramas UML. - http://alexdp.free.fr/
violetumleditor
Agradecimientos
Quisiera concluir agradeciendo a:
• mis compañeros de cursada por los buenos momentos vividos y las experiencias comparti-
das.
• a la UCA por la excelente infraestructura y organización de la Carrera.
• al cuerpo docente por su alto nivel académico y la predisposición para transmitir sus
conocimientos.
• a mi tutor de trabajo final por su compromiso, sus consejos y acompañamiento durante la
realización de este trabajo.
• a mis seres queridos por apoyarme en este viaje a pesar del tiempo que no les pude dedicar.
Recursos de Interés
A continuación se exponen los recursos de interés que fueron utilizados como referencia para el
desarrollo de esta publicación.
Golang
[1] - Web oficial
Fuente: https://golang.org
[2] - Documentación oficial
Fuente: https://golang.org/doc
[3] - Preguntas frecuentes oficiales
Fuente: https://golang.org/doc/faq
[4] - Consola interactiva
Fuente: https://play.golang.org
[5] - Blog oficial
Fuente: https://blog.golang.org
Artículos Web
[6] - Let’s Go: Object-Oriented Programming in Golang
Fuente: https://code.tutsplus.com/tutorials/lets-go-object-oriented-programming-in-golang--cms-
26540
[7] - SOLID Go Design
Fuente: https://dave.cheney.net/2016/08/20/solid-go-design
[8] - Is Go An Object Oriented Language?
Fuente: http://spf13.com/post/is-go-object-oriented
[9] - Object Orientation In Go
Fuente: https://katcipis.github.io/blog/object-orientation-go
[10] - Design Patterns for Humans!
Fuente: https://github.com/kamranahmedse/design-patterns-for-humans
[11] - Java Design Patterns - Example Tutorial
Fuente: https://www.journaldev.com/1827/java-design-patterns-example-tutorial
[12] - Design patterns implemented in Java
Fuente: http://java-design-patterns.com
[13] - Design Patterns in Java Tutorial
Fuente: https://www.tutorialspoint.com/design_pattern
Recursos de Interés 119
Papers
[18] - Publicaciones académicas
Fuente: https://github.com/golang/go/wiki/ResearchPapers
[19] - GoHotDraw: Evaluating the Go Programming Language with Design Patterns - Frank
Schmager, Nicholas Cameron, James Noble
Fuente: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.188.5524&rep=rep1&type=pdf
Libros
[20] - Karl Seguin, “The Litte Go Book”, 2014
Fuente: https://github.com/karlseguin/the-little-go-book
[21] - Hemant Jain, “Data Structures & Algorithms In Go” - WOW, 2017
Fuente: https://www.amazon.com/Data-Structures-Algorithms-Hemant-Jain-ebook/dp/B075TBM9KS
[22] - Matt Aimoneaatti, “Go Bootcamp” - 2014
Fuente: http://www.golangbootcamp.com
[23] - Aaron Torres, “Go Cookbook” - Packt, 2017
Fuente: https://www.packtpub.com/application-development/go-cookbook
[24] - Mario Castro Contreras, “Go Design Patterns” - Packt, 2017
Fuente: https://www.packtpub.com/application-development/go-design-patterns
[25] - Vladimir Vivien, Mario Castro Contreras, Mat Ryer, “Go: Design Patterns for Real-World
Projects” - Packt, 2017
Fuente: https://www.packtpub.com/application-development/go-design-patterns-real-world-projects
[26] - Matt Butcher, Matt Farina, “Go In Practice” - Manning, 2016
Fuente: https://www.manning.com/books/go-in-practice
[27] - Mat Ryer, “Go Programming Blueprints Second Edition” - Packt, 2016
Fuente: https://www.packtpub.com/application-development/go-programming-blueprints-second-
edition
[28] - Shiju Varghese, “Go Recipes” - Apress, 2016
Fuente: https://www.apress.com/br/book/9781484211892
[29] - Mihalis Tsoukalos, “Go Systems Programming” - Packt, 2017
Fuente: https://www.packtpub.com/networking-and-servers/go-systems-programming
Recursos de Interés 120
Presentaciones
[42] - Go for Javaneros
Fuente: https://talks.golang.org/2014/go4java.slide#1
[43] - Rob Pike - Simplicity is Complicated
Fuente: https://www.youtube.com/watch?v=rFejpH_tAHM
[44] - Rob Pike - Go Proverbs
Fuente: https://www.youtube.com/watch?v=PAAkCSZUG1c
[45] - Francesc Campoy - Google Understanding Go Interfaces
Fuente: https://www.youtube.com/watch?v=F4wUrj6pmSI
[46] - Dave Cheney - SOLID Go Design
Fuente: https://www.youtube.com/watch?v=zzAdEt3xZ1M
[47] - William Kennedy - Golang OOP - Composition in Go
Fuente: https://www.youtube.com/watch?v=194blNHDdd0
Recursos de Interés 121
Otros Recursos
[48] - Librerías, paquetes y framewoks de Go
Fuente: https://github.com/avelino/awesome-go
[49] - Gophers oficiales
Fuente: https://golang.org/doc/gopher
[50] - Gophers libres
Fuente: https://github.com/golang-samples/gopher-vector
[51] - Índice Tiobe
Fuente: https://www.tiobe.com/tiobe-index
[52] - Logos oficiales de Go
Fuente: https://golang.org/s/logos
[53] - UCA - Pontificia Universidad Católica Argentina
Fuente: http://uca.edu.ar
[54] - Python - Glosario
Fuente: https://docs.python.org/3/glossary.html?highlight=duck#term-duck-typing
Glosario
Clase
Las clases propias de la programación orientada a objetos se definirán como tipos de datos o
tipos.
Objeto
Los objetos propios de la programación orientada a objetos se definirán como variables.
Método
Los métodos de clases propios de la programación orientada a objetos se definirán como
comportamientos de un tipo o simplemente como método (de tipo).
Propiedad
Las propiedades de clases propias de la programación orientada a objetos se definirán como
atributos de una estructura.