19 de octubre de 2026
Impactos del uso de patrones de diseño
Impactos do Uso de Padrões de Projeto
Thalia Vilela Ferreira; Vinicius Santos Andrade
DOI: 10.22167/2675-6528-202602378
Artículo derivado del Trabajo de Conclusión de Curso (TCC), con contenido basado en el trabajo original del alumno y adaptado al formato editorial de la Revista E&S con el apoyo de la herramienta ResumeAI, solución de inteligencia artificial desarrollada por el Instituto Pecege para síntesis y organización textual.
Resumen
Los patrones de diseño son soluciones exitosas en diversos contextos que utilizan los conceptos de la orientación a objetos para crear código flexible y reutilizable. En el desarrollo de software, la aplicación de estas soluciones requiere la comprensión de sus impactos positivos y negativos. Así, el estudio tuvo como objetivo evaluar estos impactos mediante la implementación de los patrones de diseño Composite, Factory Method y Strategy, midiendo con las métricas CK los efectos en la complejidad, el acoplamiento y la reutilización. La metodología aplicada fue cuali-cuantitativa, con datos obtenidos por la aplicación de los patrones en un software, midiendo su estado antes y después, y observando las ventajas y desventajas resultantes de la alteración. Como resultado, se analizó que la complejidad disminuyó, haciendo el código más simple de trabajar y posibilitando una mayor reutilización. Las clases se volvieron más flexibles y pudieron adaptarse mejor a la extensión de los requisitos, concluyendo que el uso de patrones se recomienda cuando se obtienen ganancias en la complejidad de los requisitos.
Palabras clave: Abstracción; Complejidad; Flexibilidad; Objetos; Relación.
1. Introducción
La evolución de la programación de software marcó una transición significativa de enfoques monolíticos a estructuras más organizadas y modulares. Inicialmente, la codificación se realizaba en bloques únicos, con desviaciones condicionales puntuales. Posteriormente, la programación estructurada introdujo bloques de código como condicionales, bucles y funciones, fragmentando la lógica en partes más pequeñas. A finales de la década de 1960, surgió el paradigma de la orientación a objetos, redefiniendo la estructuración de los sistemas (Eduardo Guerra, 2014).
Un sistema orientado a objetos está compuesto por objetos que interactúan para mantener un estado interno y soportar operaciones específicas, siendo el estado inaccesible externamente. Este paradigma implica la creación de clases y el establecimiento de relaciones entre ellas, definiendo la interacción de los objetos en tiempo de ejecución. Los objetos encapsulan datos y acciones, permitiendo que sean extendidos o modificados de forma independiente, sin alterar otros componentes (Ian Sommerville, 2010). La abstracción de conceptos es fundamental para desarrollar componentes desacoplados, promoviendo mayor reutilización y flexibilidad del software (Eduardo Guerra, 2014). Los pilares de la orientación a objetos incluyen herencia, encapsulamiento, polimorfismo y abstracción. La herencia permite que una clase hija adquiera atributos y métodos de una clase madre, especializando su comportamiento. El encapsulamiento aísla la lógica y los datos, exponiendo solo la interfaz necesaria al cliente. El polimorfismo posibilita que un objeto asuma la forma de sus abstracciones, como una superclase o interfaz (Eduardo Guerra, 2014).
La aplicación de estos conceptos de orientación a objetos condujo al desarrollo de los patrones de diseño. Inspirados en el trabajo de Christopher Alexander sobre patrones arquitectónicos, se comprendió que la misma lógica podría aplicarse al desarrollo de software. En 1994, Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides catalogaron estas soluciones en el libro “Patrones de diseño: soluciones reutilizables de software orientado a objetos” (Ian Sommerville, 2010). Estos patrones representan soluciones probadas para problemas recurrentes, facilitando la creación de código flexible y reutilizable en diversos contextos.
Sin embargo, la mera existencia de una solución no garantiza su aplicación eficaz. Al utilizar patrones de diseño en el desarrollo de software, es esencial comprender los impactos positivos y negativos que su implementación puede generar. La elección de un patrón debe ser criteriosa, alineada a los requisitos y al contexto específico del software, considerando las ventajas y desventajas para una toma de decisión informada. Existe una brecha práctica en la comprensión profunda de cómo estos patrones se manifiestan en términos de métricas de calidad de software, especialmente en entornos de desarrollo contemporáneos.
Ante este escenario, la justificación de este estudio reside en la necesidad de proporcionar una evaluación empírica de los impactos de la aplicación de patrones de diseño. Comprender cómo la utilización de patrones como Composite, Factory Method y Strategy afecta el acoplamiento, la complejidad, la reutilización y la flexibilidad de un software es crucial para los desarrolladores. Este trabajo tiene como objetivo evaluar el impacto de la utilización de los patrones de diseño en un software, con las ventajas y desventajas de su utilización en acoplamiento, complejidad, reutilización y principalmente flexibilidad, con la motivación de presentarlos en el contexto común al desarrollo de software para web con la construcción de APIs REST, frameworks y consultas a la base de datos.
2. Material y Métodos
La investigación realizada se caracterizó como exploratoria, con el propósito de explicitar el impacto del uso de patrones de diseño en el desarrollo de software. Se adoptó un enfoque cuali-cuantitativo, combinando el análisis de información bibliográfica con la medición de métricas en un estudio de caso práctico, según la metodología descrita a continuación.
Inicialmente, se realizó una investigación bibliográfica exhaustiva para recopilar información sobre los patrones de diseño, incluyendo su intención, motivación, estructura, beneficios y desventajas. Adicionalmente, se buscó conocimiento sobre métodos para medir la complejidad y el acoplamiento en aplicaciones orientadas a objetos. Para esta etapa, se consultaron libros y artículos consolidados en el área, sin restricción de fecha de publicación, dada la estabilidad de los conceptos de patrones de diseño a lo largo del tiempo (Gamma et al., 2008; Sommerville, 2010).
El objeto empírico del estudio fue un software desarrollado específicamente para una plataforma de e-learning. La construcción inicial del software se realizó sin la aplicación de patrones de diseño, centrándose únicamente en la separación mínima de clases. Este estado inicial permitió el establecimiento de parámetros de referencia para la complejidad y el acoplamiento, antes de la intervención metodológica.
Los requisitos del proyecto se definieron basándose en la experiencia de la autora en plataformas de e-learning. Incluyeron la gestión de cursos, donde un curso se compone de módulos con diferentes tipos de contenido, como vídeo, texto, cuestionario y audio, y la organización de cursos en itinerarios. También se consideró un sistema de progresión no lineal, que libera módulos basándose en el rendimiento del alumno en los cuestionarios.
El desarrollo del software se realizó utilizando el lenguaje de programación Java, en la versión 17. Se empleó el framework Spring, versión 6.2.5, junto con Spring Boot, versión 3.4.4, para facilitar el desarrollo y la gestión de dependencias. Para la interacción con la base de datos, se utilizó Spring Data MongoDB, versión 3.4.4, y la biblioteca Lombok, versión 1.18.36, para la generación de código repetitivo.
La arquitectura del software se organizó en capas, dividiendo las clases en paquetes específicos: `Api` para la exposición de endpoints REST, `client` para llamadas a servicios externos (no implementados), `entity` para entidades de base de datos, `enumeration` para valores fijos, `repository` para acceso a la base de datos y `service` para la lógica de negocio. La base de datos utilizada fue MongoDB, versión 7.0, ejecutada en un contenedor Docker, versión 4.28.0, con WSL 2.6.3.0 y Ubuntu 22.04.
Basándose en el análisis del código del proyecto y los requisitos, se seleccionaron e implementaron los patrones de diseño Factory Method, Composite y Strategy. La aplicación de estos patrones se realizó sin otras modificaciones en el código, con el objetivo de aislar el impacto directo de su introducción. El patrón Factory Method se aplicó para la creación parametrizada de objetos de contenido, como video, quiz, audio y texto, que se guardan en la colección de contenidos y forman parte de la clase Contenido.
El patrón Composite se utilizó para tratar objetos simples y compuestos de forma uniforme, específicamente en la consulta de actividades de un alumno, donde se modelaron trilhas y cursos para ser tratados de manera similar. El patrón Strategy se empleó en la funcionalidad de progreso del alumno, para aplicar diferentes algoritmos en función de las notas obtenidas en quizzes, permitiendo la selección dinámica del comportamiento.
Para medir los cambios en el software, se utilizaron las métricas de Chidamber y Kemerer (CK), propuestas en 1994, con enfoque en la orientación a objetos. Las métricas empleadas fueron: Métodos Ponderados por Clase (WMC), para evaluar la complejidad de cada clase; Profundidad del Árbol de Herencia (DIT), para medir el número de niveles en el árbol de herencia; Número de Hijos (NOC), para cuantificar las subclases de una clase; Acoplamiento entre Clases de Objetos (CBO), para verificar el acoplamiento entre clases; y Respuesta para una Clase (RFC), para medir el número de métodos que pueden ser ejecutados en respuesta a un mensaje (Sommerville, 2010).
La recolección de datos se realizó en dos fases. Primero, se realizó una medición de las métricas CK en el software en su estado inicial, antes de la aplicación de los patrones de diseño, utilizando el análisis estático de la biblioteca CK Metrics añadida al proyecto. Luego, tras la implementación de los patrones Factory Method, Composite y Strategy, se realizó una nueva medición de las mismas métricas. El análisis de los datos consistió en la comparación de los valores de las métricas obtenidos antes y después de la aplicación de los patrones.
3. Resultados y Discusión
La aplicación de patrones de diseño en un software de e-learning fue evaluada con el objetivo de analizar sus impactos en métricas de calidad, como complejidad, acoplamiento, reutilización y flexibilidad. Los resultados obtenidos, mediante la aplicación de los patrones Composite, Factory Method y Strategy y la medición con las métricas CK (Chidamber y Kemerer), revelaron transformaciones significativas en la estructura y el comportamiento del código. El análisis comparativo entre el estado inicial del software y su versión tras la implementación de los patrones permitió identificar ventajas y desventajas prácticas, alineándose a la literatura y proporcionando una base empírica para la toma de decisiones en proyectos de desarrollo.
Levantamiento Bibliográfico
Los patrones de diseño, según la literatura, son soluciones consagradas que utilizan los principios de la orientación a objetos para desarrollar código flexible y reutilizable. Cada patrón se caracteriza por un nombre, un problema que busca resolver, una solución estructural y las consecuencias de su aplicación, que incluyen ventajas y desventajas (Gamma et al, 2008). Se clasifican en creacionales, estructurales y de comportamiento, cada uno abordando diferentes aspectos de la creación, organización o interacción de objetos. La esencia de estos patrones reside en la promoción de la flexibilidad, la reutilización y el desacoplamiento, logrados a través del uso de abstracciones, herencia y composición, que se manifiestan en el software a través del polimorfismo (Gamma et al, 2008).
El patrón Factory Method, de categoría creacional, se emplea para delegar la creación de objetos a las subclases, permitiendo que estas decidan qué objeto instanciar. Su flexibilidad reside en la capacidad de implementar cualquier abstracción de producto y adaptar la estructura del patrón a los requisitos específicos del software, siempre delegando la instanciación de clases concretas a sus subclases (Gamma et al, 2008). Sin embargo, una desventaja notable es la necesidad de crear una subclase de Creator para cada instancia de Product, lo que puede aumentar la complejidad y comprometer la mantenibilidad. La parametrización de la creación por identificador puede mitigar esta cuestión, pero puede introducir condicionales excesivas, disminuyendo el desacoplamiento entre las clases Factory y Product (Gamma et al, 2008).
El patrón Composite, de naturaleza estructural, se utiliza para tratar objetos simples y compuestos de manera uniforme, organizándolos en una estructura de árbol. Una interfaz común permite que tanto las hojas (objetos simples) como las ramas (composiciones) implementen el mismo método, utilizando el polimorfismo para un tratamiento consistente (Gamma et al, 2008). Entre sus ventajas, destaca la reducción de la complejidad de la aplicación, ya que los dos tipos de objetos se manipulan de forma uniforme, reforzando el encapsulamiento. La simplicidad de añadir nuevas subclases también es un beneficio. Sin embargo, una desventaja surge cuando los requisitos exigen restricciones de tipo, haciendo difícil la aplicación del patrón sin la necesidad de comprobaciones de tipo constantes (Gamma et al, 2008).
A su vez, el patrón Strategy, un patrón de comportamiento, se aplica cuando una clase principal necesita utilizar diversos algoritmos. Estos algoritmos se encapsulan en clases separadas que implementan una interfaz común, permitiendo que el comportamiento se altere en tiempo de ejecución (Gamma et al, 2008). La principal ventaja es la capacidad de alterar algoritmos de forma independiente, haciéndolos más comprensibles y flexibles, además de eliminar condicionales en la clase principal. En contrapartida, sus desventajas incluyen la creación de un número elevado de clases, lo que puede aumentar la complejidad de la lectura del código, la necesidad de tratar atributos nulos y el hecho de que el cliente necesita conocer las diferentes estrategias para seleccionar la correcta, lo que puede disminuir el acoplamiento entre ellas. Además, algunas clases concretas pueden no utilizar toda la información recibida, llevando al mantenimiento de datos innecesarios (Gamma et al, 2008).
Las métricas de Chidamber y Kemerer (CK) se emplearon para cuantificar los impactos de la aplicación de los estándares. El WMC (Weighted Methods per Class) mide la complejidad de una clase por la suma de las complejidades de sus métodos; valores altos indican menor legibilidad y reutilización (Ian Sommerville, 2010). El DIT (Depth of Inheritance Tree) indica el número de niveles en el árbol de herencia; mayor profundidad implica mayor complejidad de diseño (Ian Sommerville, 2010). El NOC (Number of Children) evalúa el número de subclases, con valores altos sugiriendo mayor reutilización, pero también mayor complejidad de entendimiento (Ian Sommerville, 2010). El CBO (Coupling Between Objects) verifica el acoplamiento entre clases; valores mayores indican mayor dependencia (Ian Sommerville, 2010). Por último, el RFC (Response For a Class) mide el número de métodos que pueden ser ejecutados en respuesta a un mensaje; cuanto mayor, más compleja la clase (Ian Sommerville, 2010).
Aplicación de los patrones de diseño
En la funcionalidad de consulta de las actividades de un alumno, específicamente en el método `buscarCursosETrilhasPorAluno`, se identificó la necesidad de tratar la distinción entre trilhas y cursos. Una trilha se compone de cursos, y su carga horaria es la suma de las cargas horarias de los cursos que la componen, mientras que un curso posee su propia carga horaria. Inicialmente, el mapeo a la clase `Aprendizado` exigía que, si el objeto era del tipo Curso, el atributo `módulos` fuera completado, y si era del tipo Trilha, el atributo `cursos` fuera completado. Este enfoque inicial resultaba en un código más complejo y menos flexible debido a la necesidad de diferenciación explícita y conversión de tipos.
La aplicación del patrón Composite permitió tratar los objetos Curso y Trilha de forma unificada, eliminando la necesidad de la clase intermedia `Aprendizado` y de los métodos de conversión de tipos. Con este enfoque, el código se volvió menos complejo y más flexible, ya que la manipulación de los objetos pudo realizarse a través de una interfaz común. El uso del Composite fue específico para dos abstracciones y un único tipo de composición, lo que evitó una generalización excesiva. Además, los requisitos del proyecto no impusieron restricciones de tipo que pudieran manifestar las desventajas del patrón, como la dificultad de restringir clases cuando solo se permiten algunos tipos, según lo descrito en la literatura.
Para la funcionalidad de progresión del estudiante, que implicaba la liberación de módulos basada en el rendimiento en cuestionarios, se aplicó el patrón Strategy. La lógica de procesamiento del rendimiento, que generaba diferentes mensajes para cada rango de calificación (por ejemplo, desbloquear el siguiente módulo para calificaciones superiores al 80%), se dividió entre clases de estrategia. Esta división redujo las validaciones condicionales en la clase principal, haciéndola menos compleja y más fácil de entender. Los algoritmos pudieron modificarse por separado, sin afectar la clase principal, lo que aumentó la flexibilidad del sistema y permitió la creación sencilla de nuevos algoritmos.
Sin embargo, la aplicación del patrón Strategy también evidenció algunas de las desventajas señaladas por la literatura. Se observó que algunas clases de estrategia no utilizaban toda la información pasada, como el objeto `módulo`, que se transmitía a todas las estrategias pero solo era utilizado por una de ellas. Además, la implementación del patrón exigió la creación de más código para la estructura del patrón que para la propia regla de negocio. La clase cliente, responsable de seleccionar la estrategia correcta, necesitó mantener una lista de referencias a todas las clases de estrategia concretas, lo que implica un conocimiento previo de las estrategias disponibles y una dependencia explícita, disminuyendo el desacoplamiento entre estas clases.
La creación de objetos de contenido, como video, cuestionario, audio y texto, se optimizó con la aplicación del patrón Factory Method parametrizado. Inicialmente, el método de creación de contenido era complejo, con condicionales para cada tipo de medio. Con el Factory Method, se creó la clase Factory para recibir el tipo de contenido y los datos necesarios, delegando la creación del objeto específico a un constructor apropiado. Este enfoque simplificó significativamente el método de creación, haciéndolo más legible y menos propenso a errores, ya que la lógica de instanciación se centralizó y parametrizó por tipo.
A pesar de la simplificación inicial, la aplicación del Factory Method reveló una desventaja potencial: la clase Factory, aunque más simple, puede volverse más compleja a medida que se agregan nuevos tipos de contenido al proyecto. Cada nuevo tipo de medio requeriría una nueva condicional en la clase Factory, aumentando su dificultad de mantenimiento y su complejidad interna. Esto demuestra que, si bien el patrón resuelve el problema de la creación de objetos, puede transferir la complejidad a la propia fábrica si no se diseña cuidadosamente para manejar la extensibilidad de manera más dinámica, como a través de un registro de fábricas.
Comparación de Métricas
El análisis de las métricas CK antes y después de la aplicación de los patrones reveló impactos distintos. En relación con el WMC (Weighted Methods per Class), se observó una disminución en todos los casos: de 7 a 3 en el Factory Method, de 10 a 9 en el Composite y de 4 a 2 en el Strategy. Esta reducción indica que la complejidad de las clases disminuyó, haciendo el código mejor distribuido y, consecuentemente, más simple de trabajar y con mayor potencial de reutilización. La disminución del WMC es un indicador positivo de mejora en la legibilidad y mantenibilidad del software.
Los indicadores DIT (Depth of Inheritance Tree) y NOC (Number of Children) no presentaron alteraciones significativas en ninguna de las aplicaciones de los patrones. Para el Factory Method, el DIT permaneció en 1 y el NOC en 0. Para el Composite, el DIT se mantuvo en 1 y el NOC en 0. De igual forma, para el Strategy, el DIT y el NOC permanecieron inalterados en 1 y 0, respectivamente. Esto ocurrió porque las clases evaluadas no tuvieron modificaciones relacionadas con la herencia o la alteración de sus métodos de forma a impactar estos indicadores, enfocando la simplificación en la lógica interna y en la distribución de responsabilidades.
La métrica RFC (Response For a Class) presentó variaciones. En el patrón Factory Method, hubo una gran disminución, pasando de 32 a 14. Esto se debe a que la clase pasó a ejecutar menos métodos directamente, ya que la creación de objetos fue delegada a la Factory. En Composite, el RFC tuvo un leve aumento, de 48 a 49, lo cual es esperado, pues se agregaron métodos para generalizar el tratamiento de objetos. En el patrón Strategy, el RFC permaneció estable en 24, indicando que el número de métodos que pueden ser ejecutados en respuesta a un mensaje no fue alterado significativamente.
En cuanto al CBO (Coupling Between Objects), también se observaron variaciones. En el Factory Method, hubo una ganancia en relación al acoplamiento, con una disminución de 14 a 12. Aunque se añadió la dependencia con la clase Factory, la clase pasó a llamarla solo para la creación de objetos, evitando el ensamblaje de objetos con métodos setters, lo que redujo el acoplamiento general. En el Strategy, el CBO aumentó de 9 a 10, ya que la clase pasó a llamar a dos métodos más de la interfaz del patrón, lo que representa una dependencia externa. Para el patrón Composite, el CBO tuvo un leve aumento de 13 a 14, pero el motivo exacto de esta variación no fue identificado en el estudio original.
En resumen, la aplicación de los patrones de diseño demostró impactos positivos en la flexibilidad y la capacidad de expansión del software, facilitando la adición de nuevas clases y el mantenimiento. La investigación evidenció que los patrones permiten la creación de estructuras adaptables para resolver problemas específicos, no siendo soluciones fijas. El uso del Factory Method, por ejemplo, puede simplificar la creación de objetos, pero exige atención a la complejidad de la clase Factory en sí. El patrón Composite demostró ser eficaz en la creación de estructuras que pueden ser cargadas con datos del banco y manipuladas recursivamente con polimorfismo, con la ventaja de poder crecer con la adición de más métodos en la interfaz.
Los patrones, al basarse en los principios de herencia, polimorfismo y abstracción de la orientación a objetos, hacen que el código sea más comprensible tras un análisis de su estructura, exigiendo, sin embargo, un conocimiento previo de la solución propuesta. Las desventajas observadas incluyen el aumento del número de clases y la necesidad de evaluar si los requisitos del proyecto justifican la complejidad adicional introducida por los patrones, o si refactorizaciones más simples podrían alcanzar ganancias similares. La aplicación del patrón Strategy, por ejemplo, puede ser particularmente beneficiosa cuando se alinea con las buenas prácticas de SOLID, promoviendo la separación de responsabilidades y la flexibilidad en la alteración de algoritmos.
4. Conclusión
El presente estudio evaluó el impacto de la utilización de los patrones de diseño Composite, Factory Method y Strategy en un software, buscando comprender sus ventajas y desventajas en términos de acoplamiento, complejidad, reutilización y flexibilidad, con foco en el contexto de desarrollo de software para web. Se verificó que la aplicación de estos patrones promovió una reducción significativa en la complejidad de las clases, conforme indicado por la disminución del WMC (Weighted Methods per Class) en todos los casos analizados. El patrón Composite, al unificar el tratamiento de objetos simples y compuestos, hizo el código más flexible y menos complejo, eliminando la necesidad de clases intermediarias. El Factory Method simplificó la creación de objetos, centralizando la lógica de instanciación y reduciendo el RFC (Response For a Class) y el CBO (Coupling Between Objects) en la clase cliente. Por su parte, el patrón Strategy contribuyó a la reducción de validaciones condicionales en la clase principal, aumentando la flexibilidad en la alteración de algoritmos y haciéndolos más comprensibles. Los indicadores DIT (Depth of Inheritance Tree) y NOC (Number of Children) permanecieron estables, sugiriendo que las modificaciones se concentraron en la lógica interna y en la distribución de responsabilidades, sin alterar la jerarquía de herencia.
La principal contribución de este trabajo reside en ofrecer una evaluación empírica de los efectos de los patrones de diseño en métricas de calidad de software, proporcionando subsidios prácticos para que los desarrolladores tomen decisiones sobre su aplicación. Se observó que, si bien los patrones aportan ganancias en flexibilidad y capacidad de expansión, pueden introducir desventajas, como el aumento del número de clases o la transferencia de la complejidad a la propia fábrica, en el caso de Factory Method, o la necesidad de que el cliente conozca las estrategias específicas, en el caso de Strategy. Tales limitaciones refuerzan la importancia de un análisis criterioso de los requisitos del proyecto para justificar la complejidad adicional. Se sugiere que estudios futuros exploren la aplicación de estos patrones en conjunto con técnicas de refactorización y las buenas prácticas del SOLID, con el fin de optimizar aún más la separación de responsabilidades y la mantenibilidad del código, evaluando si refactorizaciones más simples podrían alcanzar ganancias similares en contextos específicos.
Referencias Bibliográficas
GAMMA, E.; HELM, R.; JOHNSON, R.; VLISSIDES, J. Padrões de projeto: soluções reutilizáveis de software orientado a objetos. Porto Alegre: Bookman, 2008.
GUERRA, E. Design patterns com Java: projeto orientado a objetos guiado por padrões. São Paulo: Novatec, 2010.
SOMMERVILLE, I.; SIQUEIRA, F. Engenharia de software. São Paulo: Pearson, 2010.
Artículo originario del Trabajo de Conclusión de Curso de la Especialización en Ingeniería de Software del MBA USP/Esalq
Para saber más sobre el curso, haz clic aquí y accede a la plataforma MBX Academy