En ingeniería de software , un patrón de diseño describe un aspecto relativamente pequeño y bien definido (es decir, la funcionalidad) de un programa de computadora en términos de cómo escribir el código .
El uso de un patrón tiene como objetivo aprovechar un concepto existente en lugar de reinventarlo . Esto puede reducir el tiempo de desarrollo del software y aumentar la calidad del programa resultante.
Cabe destacar que un patrón no consiste en un artefacto de software . La mayoría de los recursos de desarrollo que utiliza un programador implican la configuración de la base de código para utilizar un artefacto; por ejemplo, una biblioteca . Por el contrario, para utilizar un patrón, un programador escribe código tal como lo describe el patrón. El resultado es único cada vez, aunque pueda reconocerse como basado en el patrón.
Algunos consideran que el uso de patrones es la mejor práctica para el diseño de software . Otros consideran que el uso de patrones de diseño es un enfoque estructurado para la programación informática .
Conceptualmente, el patrón de diseño puede describirse como más específico que el paradigma de programación y menos específico que el algoritmo .
Los patrones se originaron como un concepto arquitectónico por Christopher Alexander en 1977 en A Pattern Language (véase su artículo, "The Pattern of Streets", JOURNAL OF THE AIP, septiembre de 1966, vol. 32, n.º 5, págs. 273-278). En 1987, Kent Beck y Ward Cunningham comenzaron a experimentar con la idea de aplicar patrones a la programación (específicamente, lenguajes de patrones ) y presentaron sus resultados en la conferencia OOPSLA de ese año. [1] [2] En los años siguientes, Beck, Cunningham y otros continuaron con este trabajo.
Los patrones de diseño ganaron popularidad en la informática después de que en 1994 se publicara el libro Design Patterns: Elements of Reutilizable Object-Oriented Software, obra de la denominada "Banda de los Cuatro" (Gamma et al.), que suele abreviarse como "GoF". Ese mismo año se celebró la primera Conferencia de Lenguajes de Patrones de Programación y al año siguiente se creó el Repositorio de Patrones de Portland para documentar los patrones de diseño. El alcance del término sigue siendo motivo de controversia. Entre los libros más destacados del género de los patrones de diseño se incluyen:
Aunque los patrones de diseño se han aplicado prácticamente durante mucho tiempo, la formalización del concepto de patrones de diseño languideció durante varios años. [3]
Los patrones de diseño pueden acelerar el proceso de desarrollo al proporcionar paradigmas de desarrollo probados. [4] Un diseño de software eficaz requiere tener en cuenta cuestiones que pueden no hacerse evidentes hasta más adelante en la implementación. El código recién escrito a menudo puede tener problemas ocultos y sutiles que tardan en detectarse; problemas que a veces pueden causar problemas importantes en el futuro. La reutilización de patrones de diseño puede ayudar a prevenir dichos problemas [5] y mejorar la legibilidad del código para quienes están familiarizados con los patrones.
Las técnicas de diseño de software son difíciles de aplicar a una gama más amplia de problemas. [ cita requerida ] Los patrones de diseño proporcionan soluciones generales, documentadas en un formato que no requiere detalles vinculados a un problema particular.
En 1996, Christopher Alexander fue invitado a dar un discurso de apertura en la Convención OOPSLA de 1996. Allí reflexionó sobre cómo había evolucionado su trabajo sobre patrones en la arquitectura y sus esperanzas sobre cómo la comunidad de diseño de software podría ayudar a la arquitectura a extender los patrones para crear estructuras vivas que utilicen esquemas generativos que se parezcan más al código informático.
Un patrón describe un motivo de diseño , también conocido como microarquitectura prototípica , como un conjunto de componentes del programa (por ejemplo, clases, métodos...) y sus relaciones. Un desarrollador adapta el motivo a su base de código para resolver el problema descrito por el patrón. El código resultante tiene una estructura y una organización similares al motivo elegido.
También se han hecho esfuerzos para codificar patrones de diseño en dominios particulares, incluyendo el uso de patrones de diseño existentes así como patrones de diseño específicos de dominio. Los ejemplos incluyen patrones de diseño de interfaz de usuario , [6] visualización de información , [7] diseño seguro, [8] "usabilidad segura", [9] diseño web [10] y diseño de modelos de negocios. [11]
Las actas anuales de la Conferencia sobre lenguajes de patrones de programación [12] incluyen muchos ejemplos de patrones específicos del dominio.
Los patrones de diseño orientados a objetos suelen mostrar relaciones e interacciones entre clases u objetos , sin especificar las clases u objetos de la aplicación final que están involucrados. Los patrones que implican un estado mutable pueden no ser adecuados para lenguajes de programación funcional . Algunos patrones pueden volverse innecesarios en lenguajes que tienen soporte integrado para resolver el problema que intentan resolver, y los patrones orientados a objetos no son necesariamente adecuados para lenguajes no orientados a objetos.
Los patrones de diseño se pueden organizar en grupos según el tipo de problema que resuelven. Los patrones de creación crean objetos. Los patrones estructurales organizan clases y objetos para formar estructuras más grandes que brindan nuevas funciones. Los patrones de comportamiento brindan comunicación entre objetos y la realización de estos patrones.
Nombre | Descripción | En patrones de diseño | En código completo [13] | Otro |
---|---|---|---|---|
Fábrica abstracta | Proporcionar una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas. | Sí | Sí | — |
Constructor | Separar la construcción de un objeto complejo de su representación, permitiendo que el mismo proceso de construcción cree diversas representaciones. | Sí | Sí | — |
Inyección de dependencia | Una clase acepta los objetos que requiere de un inyector en lugar de crear los objetos directamente. | — | Sí | — |
Método de fábrica | Define una interfaz para crear un único objeto, pero permite que las subclases decidan qué clase instanciar. El método Factory permite que una clase posponga la instanciación a las subclases. | Sí | Sí | — |
Inicialización perezosa | Táctica que consiste en retrasar la creación de un objeto, el cálculo de un valor o algún otro proceso costoso hasta la primera vez que se lo necesita. Este patrón aparece en el catálogo de GoF como "proxy virtual", una estrategia de implementación para el patrón Proxy . | Sí | Sí | Ley de Asociaciones de Abogados de la India [14] |
Multiton | Asegúrese de que una clase solo tenga instancias con nombre y proporcione un punto de acceso global a ellas. | Sí | Sí | Sí |
Grupo de objetos | Evite la adquisición y liberación costosas de recursos reciclando objetos que ya no se utilizan. Puede considerarse una generalización de los patrones de pool de conexiones y pool de subprocesos . | Sí | Sí | Sí |
Prototipo | Especifique los tipos de objetos a crear utilizando una instancia prototípica y cree nuevos objetos a partir del "esqueleto" de un objeto existente, mejorando así el rendimiento y manteniendo el uso de memoria al mínimo. | Sí | Sí | Sí |
La adquisición de recursos es inicialización (RAII) | Asegúrese de que los recursos se liberen adecuadamente vinculándolos a la vida útil de los objetos adecuados. | Sí | Sí | Sí |
Semifallo | Asegúrese de que una clase tenga solo una instancia y proporciónele un punto de acceso global. | Sí | Sí | Sí |
Nombre | Descripción | En patrones de diseño | En código completo [13] | Otro |
---|---|---|---|---|
Adaptador , contenedor o traductor | Convierte la interfaz de una clase en otra interfaz que esperan los clientes. Un adaptador permite que clases que de otra manera no podrían trabajar juntas debido a interfaces incompatibles trabajen juntas. El equivalente del patrón de integración empresarial es el traductor. | Sí | Sí | Sí |
Puente | Desacoplar una abstracción de su implementación permitiendo que ambas varíen independientemente. | Sí | Sí | Sí |
Compuesto | Componga objetos en estructuras de árbol para representar jerarquías de partes y todo. Composite permite que los clientes traten objetos individuales y composiciones de objetos de manera uniforme. | Sí | Sí | Sí |
Decorador | Asignar responsabilidades adicionales a un objeto de forma dinámica manteniendo la misma interfaz. Los decoradores proporcionan una alternativa flexible a la subclasificación para ampliar la funcionalidad. | Sí | Sí | Sí |
Delegación | Ampliar una clase mediante composición en lugar de subclasificación. El objeto gestiona una solicitud delegando en un segundo objeto (el delegado). | Sí | Sí | Sí |
Objeto de extensión | Agregar funcionalidad a una jerarquía sin cambiar la jerarquía. | Sí | Sí | Sí |
Fachada | Proporciona una interfaz unificada para un conjunto de interfaces en un subsistema. Facade define una interfaz de nivel superior que facilita el uso del subsistema. | Sí | Sí | Sí |
Peso mosca | Utilice el uso compartido para admitir un gran número de objetos similares de manera eficiente. | Sí | Sí | Sí |
Controlador frontal | El patrón se relaciona con el diseño de aplicaciones web y proporciona un punto de entrada centralizado para gestionar solicitudes. | Sí | Sí | Patrones J2EE [15] PoEAA [16] |
Marcador | Interfaz vacía para asociar metadatos con una clase. | Sí | Sí | Java eficaz [17] |
Módulo | Agrupar varios elementos relacionados, como clases, singletons, métodos, utilizados globalmente, en una única entidad conceptual. | Sí | Sí | Sí |
Apoderado | Proporcionar un sustituto o marcador de posición para otro objeto para controlar el acceso a él. | Sí | Sí | Sí |
Gemelo [18] | Twin permite modelar la herencia múltiple en lenguajes de programación que no admiten esta característica. | Sí | Sí | Sí |
Nombre | Descripción | En patrones de diseño | En código completo [13] | Otro |
---|---|---|---|---|
Pizarra | Patrón de inteligencia artificial para combinar fuentes dispares de datos (ver sistema de pizarra ) | Sí | Sí | Sí |
Cadena de responsabilidad | Evite acoplar al emisor de una solicitud con su receptor dándole a más de un objeto la oportunidad de manejar la solicitud. Encadene los objetos receptores y pase la solicitud a lo largo de la cadena hasta que un objeto la maneje. | Sí | Sí | Sí |
Dominio | Encapsular una solicitud como un objeto, lo que permite la parametrización de clientes con diferentes solicitudes y la puesta en cola o registro de solicitudes. También permite la compatibilidad con operaciones que no se pueden deshacer. | Sí | Sí | Sí |
Interfaz fluida | Diseñe una API que esté encadenada a métodos de modo que se lea como un DSL. Cada llamada a un método devuelve un contexto a través del cual se ponen a disposición las siguientes llamadas a métodos lógicos. | Sí | Sí | Sí |
Intérprete | Dado un idioma, defina una representación para su gramática junto con un intérprete que utiliza la representación para interpretar oraciones en el idioma. | Sí | Sí | Sí |
Iterador | Proporcionar una forma de acceder a los elementos de un objeto agregado de forma secuencial sin exponer su representación subyacente. | Sí | Sí | Sí |
Mediador | Define un objeto que encapsula cómo interactúa un conjunto de objetos. El mediador promueve el acoplamiento flexible al evitar que los objetos se refieran entre sí de manera explícita y permite que su interacción varíe de forma independiente. | Sí | Sí | Sí |
Recuerdo | Sin violar la encapsulación, capturar y externalizar el estado interno de un objeto permitiendo que el objeto sea restaurado a este estado más tarde. | Sí | Sí | Sí |
Objeto nulo | Evite referencias nulas proporcionando un objeto predeterminado. | Sí | Sí | Sí |
Observar o Publicar/suscribirse | Defina una dependencia de uno a muchos entre objetos donde un cambio de estado en un objeto da como resultado que todos sus dependientes sean notificados y actualizados automáticamente. | Sí | Sí | Sí |
Servidor | Define una funcionalidad común para un grupo de clases. El patrón de sirviente también se denomina frecuentemente clase auxiliar o implementación de clase de utilidad para un conjunto determinado de clases. Las clases auxiliares generalmente no tienen objetos, por lo que tienen todos métodos estáticos que actúan sobre diferentes tipos de objetos de clase. | Sí | Sí | Sí |
Especificación | Lógica empresarial recombinable en modo booleano . | Sí | Sí | Sí |
Estado | Permite que un objeto modifique su comportamiento cuando cambia su estado interno. El objeto parecerá cambiar de clase. | Sí | Sí | Sí |
Estrategia | Definir una familia de algoritmos, encapsular cada uno de ellos y hacerlos intercambiables. La estrategia permite que el algoritmo varíe independientemente de los clientes que lo utilicen. | Sí | Sí | Sí |
Método de plantilla | Define el esqueleto de un algoritmo en una operación, delegando algunos pasos en las subclases. El método de plantilla permite que las subclases redefinan ciertos pasos de un algoritmo sin cambiar la estructura del mismo. | Sí | Sí | Sí |
Visitante | Representa una operación que se realizará sobre instancias de un conjunto de clases. Visitor permite definir una nueva operación sin cambiar las clases de los elementos sobre los que opera. | Sí | Sí | Sí |
Nombre | Descripción | En POSA2 [19] | Otro |
---|---|---|---|
Objeto activo | Desacopla la ejecución de métodos de la invocación de métodos que residen en su propio hilo de control. El objetivo es introducir concurrencia mediante la invocación de métodos asincrónicos y un programador para gestionar solicitudes. | Sí | — |
Obstaculizando | Ejecutar una acción sobre un objeto únicamente cuando éste se encuentre en un estado particular. | No | — |
Propiedades de encuadernación | Combinar múltiples observadores para forzar que las propiedades de diferentes objetos se sincronicen o coordinen de alguna manera. [20] | No | — |
Núcleo de cómputo | El mismo cálculo muchas veces en paralelo, diferenciándose por parámetros enteros utilizados con matemáticas de puntero sin ramificación en matrices compartidas, como la multiplicación de matrices optimizada por GPU o la red neuronal convolucional . | No | — |
Bloqueo doblemente comprobado | Reduzca la sobrecarga de adquirir un bloqueo probando primero el criterio de bloqueo (la "pista de bloqueo") de manera insegura; solo si eso tiene éxito, se procede a la lógica de bloqueo real. Puede resultar inseguro si se implementa en algunas combinaciones de lenguaje y hardware. Por lo tanto, a veces se lo puede considerar un antipatrón . | Sí | — |
Asincrónico basado en eventos | Aborda los problemas con el patrón asincrónico que se producen en programas multiproceso. [21] | No | — |
Suspensión vigilada | Administra operaciones que requieren que se adquiera un bloqueo y que se cumpla una condición previa antes de que se pueda ejecutar la operación. | No | — |
Unirse | El patrón de unión proporciona una forma de escribir programas simultáneos, paralelos y distribuidos mediante el paso de mensajes. En comparación con el uso de subprocesos y bloqueos, este es un modelo de programación de alto nivel. | No | — |
Cerrar | Un hilo coloca un "bloqueo" en un recurso, impidiendo que otros hilos accedan a él o lo modifiquen. [22] | No | Ley de Asociaciones de Abogados de la India [14] |
Patrón de diseño de mensajería (MDP) | Permite el intercambio de información (es decir, mensajes) entre componentes y aplicaciones. | No | — |
Objeto de monitor | Un objeto cuyos métodos están sujetos a exclusión mutua , lo que evita que varios objetos intenten usarlo por error al mismo tiempo. | Sí | — |
Reactor | Un objeto reactor proporciona una interfaz asincrónica a los recursos que deben manejarse de forma sincrónica. | Sí | — |
Bloqueo de lectura y escritura | Permite el acceso de lectura concurrente a un objeto, pero requiere acceso exclusivo para operaciones de escritura. Se puede utilizar un semáforo subyacente para escribir y se puede utilizar o no un mecanismo de copia en escritura . | No | — |
Programador | Controlar explícitamente cuándo los subprocesos pueden ejecutar código de un solo subproceso. | No | — |
Patrón de controlador de servicio | Para cada solicitud, un servidor genera un controlador de cliente dedicado para manejar una solicitud. [23] También conocido como hilo por sesión . [24] | No | — |
Grupo de subprocesos | Se crean varios subprocesos para realizar varias tareas, que suelen organizarse en una cola. Normalmente, hay muchas más tareas que subprocesos. Puede considerarse un caso especial del patrón de grupo de objetos . | No | — |
Almacenamiento específico de subprocesos | Memoria estática o "global" local de un hilo. | Sí | — |
Concurrencia segura con propiedad exclusiva | Evitar la necesidad de mecanismos concurrentes en tiempo de ejecución, ya que se puede demostrar la propiedad exclusiva. Esta es una capacidad notable del lenguaje Rust, pero la comprobación en tiempo de compilación no es el único medio; un programador a menudo diseñará manualmente dichos patrones en el código, omitiendo el uso del mecanismo de bloqueo porque el programador evalúa que una variable dada nunca será accedida simultáneamente. | No | — |
Operación atómica de la CPU | Las arquitecturas de CPU x86 y otras admiten una variedad de instrucciones atómicas que garantizan la seguridad de la memoria para modificar y acceder a valores primitivos (números enteros). Por ejemplo, dos subprocesos pueden incrementar un contador de forma segura. Estas capacidades también se pueden utilizar para implementar los mecanismos para otros patrones de concurrencia como los mencionados anteriormente. El lenguaje C# utiliza la clase Interlocked para estas capacidades. | No | — |
La documentación de un patrón de diseño describe el contexto en el que se utiliza el patrón, las fuerzas dentro del contexto que el patrón busca resolver y la solución sugerida. [25] No existe un formato único y estándar para documentar patrones de diseño. Más bien, diferentes autores de patrones han utilizado una variedad de formatos diferentes. Sin embargo, según Martin Fowler , ciertas formas de patrones se han vuelto más conocidas que otras y, en consecuencia, se han convertido en puntos de partida comunes para nuevos esfuerzos de escritura de patrones. [26] Un ejemplo de un formato de documentación comúnmente utilizado es el utilizado por Erich Gamma , Richard Helm , Ralph Johnson y John Vlissides en su libro Design Patterns . Contiene las siguientes secciones:
Algunos sugieren que los patrones de diseño pueden ser una señal de que faltan características en un lenguaje de programación determinado ( Java o C++, por ejemplo). Peter Norvig demuestra que 16 de los 23 patrones del libro Design Patterns (que se centra principalmente en C++) se simplifican o eliminan (a través del soporte directo del lenguaje) en Lisp o Dylan . [27] Hannemann y Kiczales realizaron observaciones relacionadas, implementaron varios de los 23 patrones de diseño utilizando un lenguaje de programación orientado a aspectos (AspectJ) y demostraron que las dependencias a nivel de código se eliminaron de las implementaciones de 17 de los 23 patrones de diseño y que la programación orientada a aspectos podría simplificar las implementaciones de patrones de diseño. [28] Véase también el ensayo de Paul Graham "Revenge of the Nerds". [29]
El uso inadecuado de patrones puede aumentar innecesariamente la complejidad. [30]
Por definición, un patrón debe programarse de nuevo en cada aplicación que lo utilice. Dado que algunos autores consideran que esto supone un paso atrás con respecto a la reutilización de software que ofrecen los componentes , los investigadores han trabajado para convertir los patrones en componentes. Meyer y Arnout pudieron proporcionar la componentización total o parcial de dos tercios de los patrones que intentaron. [31]
Para lograr flexibilidad, los patrones de diseño pueden introducir niveles adicionales de indirección , lo que puede complicar el diseño resultante y disminuir el rendimiento en tiempo de ejecución .
Ward advirtió contra la necesidad de exigir demasiada programación en lo que él llamó "el alto nivel de los magos". Señaló que un "lenguaje de patrones" escrito puede mejorar significativamente la selección y aplicación de abstracciones. Propuso un "cambio radical en la carga del diseño y la implementación" basando la nueva metodología en una adaptación del trabajo de Christopher Alexander en lenguajes de patrones y que los lenguajes de patrones orientados a la programación desarrollados en
Tektronix
han ayudado significativamente a sus esfuerzos de desarrollo de software.
Si desea acelerar el desarrollo de sus aplicaciones .NET, está listo para los patrones de diseño de C#: formas elegantes, aceptadas y probadas de abordar problemas de programación comunes.
Patrones de diseño populares