El diseño Orientado a Objeto es
difícil y el diseño de software orientado a objetos reutilizable lo
es aún más. Los diseñadores expertos no resuelven los problemas
desde sus principios; reutilizan soluciones que han funcionado en el
pasado. –
Se encuentran patrones de clases y
objetos de comunicación recurrentes en muchos sistemas orientados a
objetos. – Estos patrones resuelven problemas de diseño específicos
y hacen el diseño flexible y reusable.
Los patrones
de diseño son soluciones habituales a problemas que ocurren
con frecuencia en el diseño de software. Son como planos
prefabricados que se pueden personalizar para resolver un problema
de diseño recurrente en tu código.
No se puede elegir un patrón y copiarlo en el
programa como si se tratara de funciones o bibliotecas ya
preparadas. El patrón no es una porción específica de código, sino
un concepto general para resolver un problema particular. Puedes
seguir los detalles del patrón e implementar una solución que encaje
con las realidades de tu propio programa.
A menudo los patrones se confunden con algoritmos
porque ambos conceptos describen soluciones típicas a problemas
conocidos. Mientras que un
algoritmo siempre
define un grupo claro de acciones para lograr un objetivo, en cambio
un
patrón
es una descripción de más alto nivel de una
solución. El código del mismo patrón aplicado a dos programas
distintos puede ser diferente.
Una analogía de un algoritmo sería una receta de
cocina: ambos cuentan con pasos claros para alcanzar una meta. Por
su parte, un patrón es más similar a un plano, ya que puedes
observar cómo son su resultado y sus funciones, pero el orden exacto
de la implementación depende de ti.
¿Qué son los
patrones de diseño de software (design patterns) ?
Si eres programador o estás
iniciandote en el desarrollo informático y la programación, tarde o
temprano te cruzaras con el término
patrones de diseño de software.
Los patrones de diseño o design
patterns, son una solución general, reutilizable y aplicable a
diferentes problemas de diseño
de software. Se trata de plantillas
que identifican problemas en el sistema y proporcionan soluciones
apropiadas a problemas generales a los que se han
enfrentado los desarrolladores durante un largo periodo de tiempo, a
través de prueba y error.
La mayoría de los patrones se describe con mucha
formalidad para que la gente pueda reproducirlos en muchos
contextos. Aquí tienes las secciones que suelen estar presentes en
la descripción de un patrón:
El propósito del
patrón explica brevemente el problema y la solución.
La motivación explica
en más detalle el problema y la solución que brinda el patrón.
La estructura de
las clases muestra cada una de las partes del patrón y el modo
en que se relacionan.
El ejemplo
de código en uno de los lenguajes de programación
populares facilita la asimilación de la idea que se esconde tras
el patrón.
Algunos catálogos de patrones enumeran otros detalles
útiles, como la aplicabilidad del patrón, los pasos de
implementación y las relaciones con otros patrones.
Con este trabajo se inició el concepto de patrón de
diseño en el desarrollo de software y recoge 23
patrones de diseño comunes. Cada uno de ellos define la
solución para resolver un determinado problema, facilitando además
la reutilización del código fuente.
Existen muchísimos patrones de diseño de software e
irán apareciendo cada vez más. En este post hablaremos de los más
conocidos o los llamados patrones
clásicos
¿Quién inventó los patrones de diseño? Esa es una
buena, aunque imprecisa pregunta. Los patrones de diseño no son
conceptos opacos y sofisticados, al contrario. Los patrones son
soluciones habituales a problemas comunes en el diseño orientado a
objetos. Cuando una solución se repite una y otra vez en varios
proyectos, al final alguien le pone un nombre y explica la solución
en detalle. Básicamente, así es como se descubre un patrón.
Desde entonces se han descubierto decenas de nuevos
patrones orientados a objetos. La “metodología del patrón” se hizo
muy popular en otros campos de la programación, por lo que hoy en
día existen muchos otros patrones no relacionados con el diseño
orientado a objetos.
¿Por qué usar patrones
de diseño y aprenderlos ?
El gran crecimiento del sector de las
tecnologías de la información ha hecho que las prácticas
de desarrollo de software evolucionen. Antes se requería
completar todo el software antes de realizar pruebas, lo que suponía
encontrarse con problemas.
Para ahorrar tiempo y evitar volver a
la etapa de desarrollo una vez que este ha finalizado, se introdujo
una práctica de prueba durante la fase
de desarrollo.
Esta práctica se usa para identificar
condiciones de error y problemas en el código que pueden no ser
evidentes en ese momento. En definitiva, los patrones de diseño te ayudan
a estar seguro de la validez de tu código, ya que son soluciones que
funcionan y han sido probados por muchísimos desarrolladores siendo
menos propensos a errores.
La realidad es que podrías trabajar durante años como
programador sin conocer un solo patrón. Mucha gente lo hace. Incluso
en ese caso, podrías estar implementando patrones sin saberlo. Así
que, ¿por qué dedicar tiempo a aprenderlos?
Los patrones de
diseño son un juego de herramientas de soluciones
comprobadas a problemas habituales en el diseño de
software. Incluso aunque nunca te encuentres con estos
problemas, conocer los patrones sigue siendo de utilidad, porque
te enseña a resolver todo tipo de problemas utilizando
principios del diseño orientado a objetos.
Los patrones de diseño definen un lenguaje común que puedes
utilizar con tus compañeros de equipo para comunicaros de forma
más eficiente. Podrías decir: “Oh, utiliza un singleton para
eso”, y todos entenderían la idea de tu sugerencia. No habría
necesidad de explicar qué es un singleton si conocen el patrón y
su nombre.
Crítica de los patrones
Da la sensación de que todos los holgazanes han
criticado ya los patrones de diseño. Veamos los argumentos más
habituales contra el uso de los patrones.
Chapuzas para un lenguaje de
programación débil
Normalmente, la necesidad por los patrones surge
cuando la gente elige un lenguaje de programación o una tecnología
que carece del nivel necesario de abstracción. En este caso, los
patrones se convierten en una chapuza que otorga al lenguaje unas
súper habilidades muy necesitadas.
Por ejemplo, el patrón Strategy puede
implementarse con una simple función anónima (lambda) en la mayoría
de lenguajes de programación modernos.
Soluciones ineficientes
Los patrones intentan sistematizar soluciones cuyo
uso ya es generalizado. Esta unificación es vista por muchos como un
dogma, e implementan los patrones “al pie de la letra”, sin
adaptarlos al contexto del proyecto particular.
Uso injustificado
Si lo único que
tienes es un martillo, todo te parecerá un clavo.
Este es el problema que persigue a muchos
principiantes que acaban de familiarizarse con los patrones. Una vez
que aprenden sobre patrones, intentan aplicarlos en todas partes,
incluso en situaciones en las que un código más simple funcionaría
perfectamente bien.
Tipos de patrones de
diseño de software
Los patrones de diseño más utilizados se clasifican
en tres categorías principales, cada patrón de diseño individual
conforma un total de 23 patrones de diseño. Las
tres categorías principales son:
Patrones
creacionales
Patrones
estructurales
Patrones de
comportamiento
Patrones creacionales
Los patrones de creación proporcionan
diversos mecanismos de creación de objetos, que aumentan la flexibilidad
y la reutilización del código existente de una manera adecuada a la
situación. Esto le da al programa más flexibilidad para
decidir qué objetos deben crearse para un caso de uso dado.
Estos son los patrones
creacionales:
Abstract Factory:
En este patrón, una
interfaz crea conjuntos o familias de objetos relacionados sin
especificar el nombre de la clase.
Builder Patterns:
Permite producir
diferentes tipos y representaciones de un objeto utilizando el mismo
código de construcción. Se utiliza para la creación etapa por etapa
de un objeto complejo combinando objetos simples. La creación final
de objetos depende de las etapas del proceso creativo, pero es
independiente de otros objetos.
Factory Method:
Proporciona una
interfaz para crear objetos en una superclase, pero permite que las
subclases alteren el tipo de objetos que se crearán. Proporciona
instanciación de objetos implícita a través de interfaces comunes
Prototype:
Permite copiar objetos existentes sin hacer
que su código dependa de sus clases. Se utiliza para restringir las
operaciones de memoria / base de datos manteniendo la modificación
al mínimo utilizando copias de objetos.
Singleton:
Este patrón de diseño
restringe la creación de instancias de una clase a un único objeto.
Patrones estructurales
Facilitan soluciones y estándares
eficientes con respecto a las composiciones de clase y las
estructuras de objetos. El concepto de herencia se utiliza para
componer interfaces y definir formas de componer objetos para
obtener nuevas funcionalidades.
Adapter:
Se utiliza para vincular dos
interfaces que no son compatibles y utilizan sus funcionalidades. El
adaptador permite que las clases trabajen juntas de otra manera que
no podrían al ser interfaces incompatibles.
Bridge:
En este patrón hay una alteración
estructural en las clases principales y de implementador de interfaz
sin tener ningún efecto entre ellas. Estas dos clases pueden
desarrollarse de manera independiente y solo se conectan utilizando
una interfaz como puente.
Composite:
Se usa para agrupar objetos como un
solo objeto. Permite componer objetos en estructuras de árbol y
luego trabajar con estas estructuras como si fueran objetos
individuales.
Decorator:
Este patrón restringe la alteración de la estructura
del objeto mientras se le agrega una nueva funcionalidad. La clase
inicial permanece inalterada mientras que una clase decorator proporciona
capacidades adicionales.
Facade:
Proporciona una interfaz simplificada
para una biblioteca, un marco o cualquier otro conjunto complejo de
clases.
Flyweight:
El patrón Flyweight se usa para
reducir el uso de memoria y mejorar el rendimiento al reducir la
creación de objetos. El patrón busca objetos similares que ya
existen para reutilizarlo en lugar de crear otros nuevos que sean
similares.
Proxy:
Se utiliza para crear objetos que
pueden representar funciones de otras clases u objetos y la interfaz
se utiliza para acceder a estas funcionalidades
Patrones de comportamiento
El patrón de comportamiento se ocupa
de la comunicación
entre objetos de clase. Se utilizan para detectar la
presencia de patrones de comunicación ya presentes y pueden
manipular estos patrones.
Estos patrones de diseño están
específicamente relacionados con la comunicación entre objetos.
Chain of responsibility:
El patrón de diseño Chain of
Responsibility es un patrón de comportamiento que evita acoplar el
emisor de una petición a su receptor dando a más de un objeto la
posibilidad de responder a una petición.
Command:
Convierte una solicitud en un objeto
independiente que contiene toda la información sobre la solicitud.
Esta transformación permite parametrizar métodos con diferentes
solicitudes, retrasar o poner en cola la ejecución de una solicitud
y respaldar operaciones que no se pueden deshacer.
Interpreter:
Se utiliza para evaluar el lenguaje o
la expresión al crear una interfaz que indique el contexto para la
interpretación.
Iterator:
Su utilidad es proporcionar acceso
secuencial a un número de elementos presentes dentro de un objeto de
colección sin realizar ningún intercambio de información relevante.
Mediator:
Este patrón proporciona una
comunicación fácil a través de su clase que permite la comunicación
para varias clases.
Memento:
El patrón Memento permite
recorrer elementos de una colección sin exponer su representación
subyacente.
Observer:
Permite definir un mecanismo de
suscripción para notificar a varios objetos sobre cualquier evento
que le suceda al objeto que está siendo observado.
State:
En el patrón state,
el comportamiento de una clase varía con su estado y, por lo tanto,
está representado por el objeto de contexto.
Strategy:
Permite definir una familia de
algoritmos, poner cada uno de ellos en una clase separada y hacer
que sus objetos sean intercambiables.
Template method:
Se usa con componentes que tienen
similitud donde se puede implementar una plantilla del código para
probar ambos componentes. El código se puede cambiar con pequeñas
modificaciones.
Visitor:
El propósito de un patrón Visitor es
definir una nueva operación sin introducir las modificaciones a una
estructura de objeto existente.
Conclusión
En este post hemos hecho una breve introducción
a los patrones de diseño más populares que fueron definidos
en el libro de la Gang
of Four, Design Patterns.
Existen muchos tipos de patrones de diseño
de software que nos permiten crear nuestro código de manera más
fácil y con estructuras de código que ya han sido probadas y con
garantías de que funcionan. Siempre que trabajas con un código que
ha sido creado por otra persona, utilizar
patrones de diseño nos ayudará a descubrir problemas y a mejorar el
código.
Estos patrones explican cómo ensamblar
objetos y clases en estructuras más grandes, mientras se
mantiene la flexibilidad y eficiencia de la estructura.