132
S.E.P. S.E.I.T. D.G.I.T. Centro Nacional de Investigación y Desarrollo Tecnológico cenidet Refactorización de Marcos Orientados a Objetos para Reducir el Acoplamiento Aplicando el Patrón de Diseño Mediator TESIS Que para obtener el grado de: MAESTRO EN CIENCIAS EN CIENCIAS DE LA COMPUTACIÓN Presenta: Leonor Adriana Cárdenas Robledo Director de tesis: Dr. René Santaolaya Salgado Codirector de tesis: M.C. Olivia Graciela Fragoso Díaz Cuernavaca, Morelos Agosto del 2004

Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

S.E.P. S.E.I.T. D.G.I.T.

Centro Nacional de Investigación y Desarrollo Tecnológico

cenidet

Refactorización de Marcos Orientados a Objetos para Reducir el Acoplamiento

Aplicando el Patrón de Diseño Mediator

TESIS

Que para obtener el grado de: MAESTRO EN CIENCIAS EN

CIENCIAS DE LA COMPUTACIÓN

Presenta:

Leonor Adriana Cárdenas Robledo

Director de tesis:

Dr. René Santaolaya Salgado

Codirector de tesis: M.C. Olivia Graciela Fragoso Díaz

Cuernavaca, Morelos Agosto del 2004

Page 2: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

*. Esta tesis es parte del proyecto No. 32042-A “Sistema de Administración de Componentes de Software Basado en Frameworks” financiado por CONACYT, y el proyecto No. 450.01-P “SR2: Sistema de Reingeniería para Reuso” financiado por COSNET.

S.E.P. S.E.I.T. D.G.I.T.

Centro Nacional de Investigación y Desarrollo Tecnológico

cenidet

Refactorización de Marcos Orientados a Objetos para Reducir el Acoplamiento

Aplicando el Patrón de Diseño Mediator

TESIS

Que para obtener el grado de: MAESTRO EN CIENCIAS EN

CIENCIAS DE LA COMPUTACIÓN

Presenta:

Leonor Adriana Cárdenas Robledo

Director de tesis:

Dr. René Santaolaya Salgado

Codirector de tesis: M.C. Olivia Graciela Fragoso Díaz

Cuernavaca, Morelos Agosto del 2004

Page 3: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

DEDICATORIAS

A mis padres: Magda y Manuel Por todo su esfuerzo y dedicación por apoyarme durante toda mi vida

A mis hermanos: Thania y Manuel Por brindarme todo su apoyo, su cariño y tantos momentos divertidos

Page 4: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

AGRADECIMIENTOS Al Centro Nacional de Investigación y Desarrollo Tecnológico CENIDET, y a todo el personal que labora en esta institución, por permitirme por un tiempo formar parte de este centro de investigación. Al COSNET y a la SEP, por brindarme su apoyo económico como becario, ya que sin su ayuda no hubiera sido posible la terminación de este proyecto. A mi director de tesis, Dr. René Santaolaya Salgado y mi codirectora de tesis, M.C. Olivia Graciela Fragoso Díaz, por compartir conmigo sus experiencias, consejos y conocimientos. Al comité revisor Dr. José Luis Liñán García, M.C. Reynaldo Alanís Cantú y al Dr. Máximo López Sánchez, por su valiosa disposición en la revisión de este trabajo de tesis, y por sus comentarios y sugerencias que contribuyeron a mejorarlo. A mis compañeros de generación y amigos: Vianey, Selene, Lupita, César, Alonso, Emilio, Armando, Juan José, Yanet, Marisela, Nubia, Edgardo, Rosario, Mario, Roberto, Jesús, Manuel, Isaac, Luis, Armando Alfonzo, Mariana por brindarme su amistad y apoyo durante mi estancia en CENIDET. A mis comadres Vianey, Selene, Nubia, Lupita, por brindarme su amistad y confianza, por compartir muy buenos momentos.

Gracias a todos

Page 5: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

RESUMEN Numerosas empresas cuentan con software legado que contiene años de conocimiento, reglas de negocio y experiencias obtenidas al trabajar en aplicaciones de dominios específicos. Estos representan recursos valiosos que podrían utilizarse a futuro para construir nuevas aplicaciones. Lamentablemente, este software, al desarrollarse en sus inicios, no fue pensado para ser reusable ni extensible. Los marcos de aplicaciones orientados a objetos se consideran un enfoque competente para lograr mayores beneficios de productividad y reuso. Desafortunadamente, muchos marcos exhiben un alto grado de acoplamiento debido a muchas interfaces o canales de comunicación entre clases. Para resolver este problema se presenta un método de refactorización para reducir el acoplamiento entre clases de marcos de aplicaciones orientados a objetos, incorporando a su arquitectura una estructura dirigida por el patrón de diseño ‘Mediator’. La idea es que en lugar de que las clases estén acopladas porque se comunican entre sí, se comuniquen a través de un módulo intermediario, cuya finalidad sea la de realizar dicha comunicación de manera indirecta. Este algoritmo fue implementado en una herramienta que realiza refactorización de manera automática, la cual incluye la implementación de la métrica que permite calcular los niveles de acoplamiento (Métrica del Factor de Acoplamiento COF) entre las clases antes y después de haber aplicado el proceso de refactorización. Se presenta la evaluación experimental utilizando distintos casos de prueba de marcos de aplicaciones orientados a objetos que se caracterizan por tener el problema de acoplamiento de clases debido a canales de comunicación. Con estas pruebas se demuestra que con el método de refactorización de reducción de acoplamiento, basado en el patrón de diseño ‘Mediator’ es posible disminuir el número de dependencias debido a llamadas a métodos.

Page 6: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

ABSTRACT Numerous companies have legacy software which contains years of knowdledge, bussiness rules and experience gained working on domain-based applications. Legacy software represents valuable resources that could be used in the future in order to build new applications. Regrettably, this software was developed at its beginnings, without having in mind terms of reusability or extensibility. Object-oriented frameworks are considered as a suitable approach for achieving greater benefits in terms of productivity and reuse. Unfortunately, several frameworks exhibit a high level of coupling due to many interfaces or communication channels among classes. In order to solve this problem, a refactoring method is presented for reducing coupling among framework classes, adding to the framework architecture a structure based on the ‘Mediator´ design pattern. The idea is that, instead of the classes being coupled, since they comunicate each other, they will establish the comunication through a mediator module, whose purpose is to fulfill such communication in an indirect manner. This algorithm was implemented within a tool that performs automated refactoring, which also includes the implementation of a metric that allows calculating the coupling level (COF Coupling Factor Metric) among classes before and after having accomplished the refactoring process. An experimental evaluation is presented using different case studies of object-oriented frameworks that present the problem of coupling between classes due to communication channels. This evaluation has proven that, when we use the refactoring method of coupling reduction based on the "Mediator" design pattern, it is possible to decrease dependencies due to functions calls.

Page 7: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

i

TABLA DE CONTENIDO Tabla de Contenido i Listado de Figuras iii Listado de Tablas iii Glosario de Términos iv INTRODUCCIÓN 1 Cap. 1. ANTECEDENTES 4 1.1. Antecedentes 5 1.2. Objetivos 6 1.3. Planteamiento del Problema 7 1.4. Método de Solución 9 1.5. Estado del Arte 10 1.6. Justificación 13 1.7. Alcances y Limitaciones 13 Cap. 2. MARCO TEÓRICO 15 2.1. Tecnología Orientada a Objetos 16 2.2. Reingeniería de Software 17 2.3. Marcos de Componentes Reusables 18 2.4. Reuso 19 2.5. Reestructuración 20 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24 Cap. 3. DESCRIPCIÓN DEL SISTEMA DESAROLLADO 27 3.1. Analizador Sintáctico para la Gramática del Lenguaje C++ 28 3.2. Método de Refactorización 33 3.3. Algoritmo de Reducción de Acoplamiento 40 3.4. Cálculo de la Métrica Factor de Acoplamiento (COF) 44 3.5. Diseño Conceptual del Sistema 46 3.6. Análisis del Sistema 46 3.7. Diseño del Sistema 49 3.8. Herramienta SR2 Refactoring 52 Cap. 4. EVALUACIÓN EXPERIMENTAL 58 4.1. Caso de Prueba 1: Sistema de Control de Procesos 59 4.2. Caso de Prueba 2: Marco de Listas Doblemente Ligadas 62 4.3. Caso de Prueba 3: Marco de Estadística 64

Page 8: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

ii

Cap. 5.

CONCLUSIONES Y TRABAJO FUTURO 69

Anexo A 72 Anexo B 84Anexo C 103Referencias 117

Page 9: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

iii

LISTADO DE FIGURAS Fig.1.3.1 Comunicación Bidireccional Ínter-Módulos 8Fig.1.3.2 Ejemplo de Comunicación entre Clases 8Fig.1.3.3 Ejemplo de Comunicación entre Clases con una Clase Mediadora 9Fig.2.9.1 Estructura del Patrón de Diseño ‘Mediator’ 26Fig.2.2.1 Diagrama de Clases del Programa de Ejemplo 33Fig.2.2.2 Diagrama de Clases del Programa de Ejemplo Refactorizado 36Fig.3.5.1 Diagrama del Diseño Conceptual del Sistema 46Fig.3.6.1 Diagrama de Casos de Uso Principal 47Fig.3.6.2 Diagrama del Caso de Uso Manejar Archivo 47Fig.3.6.3 Diagrama del Caso de Uso Análisis Sintáctico 48Fig.3.6.4 Diagrama del Caso de Uso Métrica 48Fig.3.6.5 Diagrama del Caso de Uso Método 49Fig.3.7.1 Estructura de Clases de las Pantallas de la Aplicación 50Fig.3.7.2 Estructura de Clases de los Comando de la Aplicación 51Fig.3.7.3 Estructura de Clases del Manejo de Usuarios 51Fig.3.8.1 Pantalla Principal de SR2 Refactoring 52Fig.3.8.2 Pantalla de Autenticación de Usuarios 53Fig.3.8.3 Diálogo para Abrir Múltiples Archivos 53Fig.3.8.4 Pantalla de la Métrica COF 54Fig.3.8.5 Pantalla del Método de Refactorización 55Fig.3.8.6 Pantalla de Comparación de Archivos 56Fig.3.8.7 Pantalla de Registro de Usuarios 56Fig.3.8.8 Pantalla de Tipos de Accesos 57Fig.4.1.1 Diagrama de Clases del Caso de Prueba 1. Marco Original 60Fig.4.1.2 Diagrama de Clases del Caso de Prueba 1. Marco Refactorizado 61Fig.4.2.1 Diagrama de Clases del Caso de Prueba 2. Marco Original 63Fig.4.2.2 Diagrama de Clases del Caso de Prueba 2. Marco Refactorizado 64Fig.4.3.1 Diagrama de Clases del Caso de Prueba 3. Marco Original 65Fig.4.3.2 Diagrama de Clases del Caso de Prueba 3. Marco Refactorizado 66 LISTADO DE TABLAS Tabla 1.5.1 Comparación de Herramientas 13Tabla 4.1 Comparación de Resultados 67

Page 10: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

iv

GLOSARIO DE TÉRMINOS

ACOPLAMIENTO Es una medida del grado de interdependencia entre módulos, es decir, el modo en que un módulo está siendo afectado por la estructura interna de otro módulo.

COMMAND Comando, patrón de diseño ‘Command’ definido en el

catálogo de patrones de diseño de Gamma [Gamm95]. Su intención es encapsular un mensaje como un objeto, con lo que permite parametrizar a los clientes, gestionar colas de mensajes y deshacer operaciones.

COMPONENTE Aunque en [Abra01] se establece que no existe un consenso generalizado entre la comunidad de Ingenieros del Software del mundo para definir lo que se entiende por componente, aquí se trata de esclarecer este concepto. [Szip99] define a un componente como: “una unidad de composición de software, que puede ser desarrollado, adquirido y utilizado independientemente, y que define las interfaces por medio de las cuáles puede ser ensamblado con otros componentes para proveer y usar servicios”.

COF Coupling Factor, Factor de Acoplamiento. Métrica definida en [Brit95] que representa la proporción entre el número real de acoplamientos no imputables a herencia y el máximo número posible de acoplamientos en el sistema. Es decir, indica la comunicación entre clases.

ENTENDIBILIDAD Es la cantidad de esfuerzo requerido por parte del usuario o desarrollador de aplicaciones para entender el software.

EXTENSIBILIDAD Es una medida de la capacidad que tiene un componente o un sistema de software para aceptar nuevos comandos definidos por el usuario o desarrollador de aplicaciones.

FLEXIBILIDAD Es el número de opciones que un programador tiene para determinar el uso del componente, también llamado “generalidad”.

Page 11: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

v

FRAMEWORK1 Conjunto de clases en colaboración que abarca un diseño abstracto para dar soluciones a una familia de problemas relacionados.

FUNCIONALIDAD Es el grado de funciones que posee el software necesaria y suficientemente para satisfacer las necesidades de un usuario.

IPADIC++ Acrónimo de “Sistema de identificación de patrones de diseño en lenguaje C++”.

MANTENIBILIDAD Es el grado del esfuerzo requerido para modificar, mejorar o corregir errores en el software con la intención de incrementar la eficiencia o funcionamiento del software.

MEDIATOR Mediador, patrón de diseño ‘Mediator’ definido en el catálogo de patrones de diseño de Gamma [Gamm95]. Su intención es definir a un objeto que encapsula el cómo interactúan un conjunto de objetos. El mediador promueve el acoplamiento débil, manteniendo la referencia entre cada uno de ellos explícitamente y les permite variar su interacción independientemente.

MÉTRICA DE SOFTWARE Es una forma estándar de medir algunos atributos de calidad del software. Ejemplos de estos atributos son: cohesión, acoplamiento, líneas de código, etc.

PATRÓN DE DISEÑO Una unidad de información que captura la estructura

esencial y la comprensión de una familia de soluciones exitosas probadas para un problema recurrente que ocurre dentro de un cierto contexto y un sistema de fuerzas.

PORTABILIDAD Es una medida de la facilidad con que un programa

determinado podrá funcionar en un ambiente de computación diferente, como una marca de computadora o un sistema operativo distinto.

REFACTORIZAR Martin Fowler en [Fowl99] da dos definiciones del término dependiendo del contexto: Como nombre o sustantivo: refactorización es “un

1 En esta tesis, para hacer referencia al término en ingles “framework”, se pueden emplear indistintamente los términos en español, “Marco”, “Marco de aplicaciones”, “Marco de componentes reusables” y “Marco de aplicaciones orientado a objetos".

Page 12: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

vi

cambio hecho a la estructura interna de software para hacerlo más fácil de entender y más barato de modificar sin cambiar su comportamiento observable”. Como verbo: refactorizar es la “reestructura de software aplicando una serie de refactorizaciones sin cambiar su comportamiento observable”. En la misma referencia, Fowler reune ambas definiciones en una sola quedando el termino refactorización como: “el proceso de cambiar un sistema de software en tal forma que no se altere el comportamiento externo del código aunque mejore su estructura interna”.

REUSABILIDAD Es la habilidad que los productos de software tienen para su reuso, de manera total o en parte, en nuevas aplicaciones.

SINGLETON Patrón de diseño ‘Singleton’ definido en el catálogo de patrones de diseño de Gamma [Gamm95]. Su intención es asegurar que sólo exista una instancia de una determinada clase y proporciona la forma de acceder a ella.

SR2 Acrónimo de “Sistema de Reingeniería de Software Legado para Reuso”, sistema del que este tema de tesis forma parte.

TEMPLATE METHOD Método plantilla, patrón de diseño ‘Template Method’ definido en el catálogo de patrones de diseño de Gamma [Gamm95]. Su intención es definir el esqueleto de un algoritmo en una operación, difiriendo algunos pasos a cada subclase cliente. Deja que las subclases implanten ciertos pasos de un algoritmo sin cambiar la estructura del algoritmo.

USABILIDAD Es la medida que establece la facilidad de uso de los componentes por el usuario o desarrollador de aplicaciones.

Page 13: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

1

INTRODUCCIÓN Actualmente las empresas invierten gran cantidad de recursos financieros y humanos en el desarrollo de sistemas informáticos, debido a que continuamente requieren modificar y agregar nueva funcionalidad a dichas aplicaciones. Por otro lado, resulta más económico desarrollar aplicaciones a partir de componentes reusables orientados a objetos que tener que rediseñar el software partiendo desde los requisitos. Los marcos de componentes reusables, en la actualidad, se consideran un enfoque competente para lograr mayores beneficios de productividad y reuso, ya que incorporan un diseño e integran un conjunto de clases genéricas, que colaboran y que pueden ser adaptadas a varios problemas específicos para desarrollar aplicaciones a la medida. La interdependencia de los módulos dentro de un diseño provoca que un software sea rígido, ya que es difícil de cambiar porque cada cambio puede provocar efectos en otras partes del sistema, frágil puesto que al realizar un cambio, partes inesperadas del sistema dejan de funcionar, e inmóvil debido a que es difícil de reusar en otras aplicaciones porque no puede separarse de la aplicación actual. Todas estas características en un marco de aplicaciones orientado a objetos son el producto de excesos en las dependencias entre módulos debido a un alto nivel de acoplamiento e impiden que los módulos no puedan ser reusados en contextos diferentes. El uso de patrones de diseño en las arquitecturas de marcos de componentes reusables, ofrecen grandes ventajas que permiten desarrollar aplicaciones más complejas y en menor tiempo. Por ejemplo, reducen la dependencia de implantación, promueven el diseño para cambios, la independencia de plataformas y de algoritmos, permiten la alteración de clases de forma conveniente, etc. Además ofrecen una mayor calidad al producto y promueven el reuso del software. Entonces, ¿Por qué no estructurar el marco de componentes con patrones de diseño, si se tienen las ventajas ya enunciadas? Una estrategia que se plantea en [Gamm95] para minimizar las dependencias por el grado de acoplamiento, que exhiben malos diseños de software orientado a objetos, es aplicando el patrón de diseño ‘Mediator’. El patrón de diseño ‘Mediator’ es responsable de controlar y coordinar las interacciones de un grupo de objetos, es decir, sirve como un intermediario. Los objetos únicamente conocen al mediador, por lo que se reduce el número de interconexiones. Sin embargo, hasta la fecha, de acuerdo a lo publicado, ninguno de los trabajos relacionados ha adoptado una solución al problema de dependencias empleando este patrón de diseño. El sistema que se presentará en esta tesis, automatiza la transformación de la estructura de marcos de componentes con un diseño pobre debido a las dependencias y la transforma en otra estructura con un diseño de mayor calidad a través de la implantación del patrón de comportamiento ‘Mediator’, según la clasificación de Gamma [Gamm95]. Se debe

Page 14: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

2

considerar que el programa a transformar posee cierto comportamiento, y que al realizar la transformación se preserva dicho comportamiento. El desarrollo de este sistema ayuda a reducir la interdependencia entre objetos y clases de un marco de componentes reusables para aplicaciones orientadas a objetos, así como a disminuir la complejidad del mantenimiento y por ende, disminuir el costo del mismo e incorporar al software legado una estructura que mejore el reuso y simplifique el protocolo entre objetos. Organización de la Tesis El presente documento de tesis está organizado de la siguiente forma: En el capítulo 1, en la sección 1.1, se presenta primeramente una descripción de los antecedentes de esta tesis, para ubicarse en el contexto de la presente investigación; en la sección 1.2 se muestran los objetivos de esta investigación; en la sección 1.3 se tiene el planteamiento del problema que se resolverá con esta tesis; en la sección 1.4 se expone de manera general el método de solución propuesto; en la sección 1.5 se presentan los trabajos que buscan resolver problemas similares al descrito en esta tesis, presentando las diferencias con la presente investigación; de acuerdo a lo tratado anteriormente, en la sección 1.6 se da una justificación de por qué realizar esta investigación; y finalmente, en la sección 1.7, se explican los alcances y limitaciones de esta investigación. En el capítulo 2 se presenta el marco teórico que respalda a la tesis. En la sección 2.1 se proporciona una breve descripción de la tecnología orientada a objetos; en la sección 2.2 se presenta la definición de reingeniería de software; en la sección 2.3 se muestra el concepto de marcos de aplicaciones orientados a objetos, el cual es uno de los conceptos más importantes de esta tesis; de ahí, en la sección 2.4, se describe una de las ventajas que ofrecen los marcos, la cualidad de reuso; en las secciones 2.5 y 2.6 se definen los procesos para mejorar a los marcos, la reestructuración y la refactorización, siendo el último el utilizado en esta tesis; en la sección 2.7 se define el concepto de acoplamiento; en la sección 2.8 se presenta un panorama general de las métricas de software, y se presenta además la métrica COF, la cual es empleada para detectar el problema de acoplamiento de clases; por último se muestra en la sección 2.9 una descripción general de patrones de diseño, sus características principales, y se expone en específico al patrón de diseño ‘Mediator’, base del método de solución. En el capítulo 3 se muestra todo el trabajo realizado para resolver el problema de acoplamiento entre clases, primeramente en la sección 3.1 se presenta una descripción del metalenguaje JavaCC utilizado para realizar el analizador sintáctico, así como el proceso propio de análisis; en la sección 3.2 se describe a detalle el método de refactorización para solucionar el problema, utilizando para ello un ejemplo; en la sección 3.3 se presenta el algoritmo de reducción de acoplamiento implementado en la herramienta de refactorización, así como las precondiciones que se tienen que cumplir para poder aplicar el método; en la sección 3.4 se muestra a base de ejemplos como se calcula la métrica COF para detectar el problema; en la sección 3.5 se muestra el diseño conceptual del proceso de refactorización; en la sección 3.6 se tiene el análisis del sistema, mostrado a base de

Page 15: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

3

diagramas de casos de uso; en la sección 3.7 se presenta el diseño general de la herramienta SR2 Refactoring, utilizando diagramas de clases; por último, en la sección 3.8 se muestra la herramienta, con la interfaz común a varios métodos de refactorización paralelos al método desarrollado en esta tesis. En el capítulo 4 se presentan las pruebas que se realizaron al método de refactorización utilizando distintos casos de prueba de marcos que se caracterizan por tener el problema de acoplamiento de clases. Finalmente, en el capítulo 5, se exponen las conclusiones a las que se llegó con la elaboración de esta tesis y los trabajos futuros para extender el proyecto SR2.

Page 16: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

4

CAPÍTULO 1 ANTECEDENTES

En este capítulo se presenta una perspectiva general del contenido de esta tesis, se

describe la línea de investigación de la que forma parte, se definen los objetivos a alcanzar, se realiza el planteamiento del problema a resolver y el método de solución en forma general. Posteriormente se sintetizan los trabajos relacionados con el tema de tesis y finalmente se señalan los alcances y limitaciones del trabajo desarrollado.

Page 17: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

5

1.1 ANTECEDENTES Numerosas empresas en la actualidad cuentan con sistemas de software legado que contiene años de conocimiento, reglas del negocio y experiencias obtenidas al trabajar en aplicaciones de dominios específicos. Estos representan recursos valiosos que podrían ser utilizados en el futuro para construir nuevas aplicaciones. Desafortunadamente, este software al ser desarrollado en sus inicios, no fue pensado para ser reusable ni extensible. Los conceptos que ofrecen los lenguajes de programación orientados a objetos parecen ser suficientes para producir componentes y marcos de aplicaciones orientados a objetos para reuso, sin embargo, el diseño apropiado de un componente es una precondición para la construcción de marcos de aplicaciones orientados a objetos. Por lo que se considera que los enfoques con patrones de diseño son los más avanzados y los más importantes si se desea enfatizar en el aspecto de la arquitectura del marco. Es por ello que los patrones de diseño deben ser vistos como un complemento a los lenguajes de programación orientados a objetos, además de que son muy útiles para dar soporte y mejorar las cualidades de extensión y reuso a los marcos de aplicaciones orientados a objetos. El propósito de los marcos de aplicaciones orientados a objetos basados en patrones de diseño es describir el diseño de un marco y sus clases individuales sin revelar sus detalles de implementación. Como resultado, los patrones de diseño pueden ayudar a adaptar un marco de aplicaciones a necesidades específicas y a construir nuevos marcos incorporándoles diseños maduros y probados [Pree96]. En la especialidad de ingeniería de software del Centro Nacional de Investigación y Desarrollo Tecnológico (Cenidet) se han desarrollado varios trabajos afines a la línea de investigación de esta tesis. El más importante de ellos es el proyecto SR2 “Sistema de Reingeniería de Software Legado para Reuso”. En este proyecto se implanta un ciclo evolutivo de reingeniería del software legado que permite, mediante el análisis de código fuente, patrones útiles, métricas, y métodos de refactorización; la construcción, refinamiento y maduración de marcos reusables orientados a objetos de dominios de aplicaciones [Sant02]. El modelo de reingeniería de SR2 está conformado por tres procesos principales:

El análisis de código fuente escrito en lenguaje ‘C’, a fin de extraer información útil en cuanto a las entidades, atributos y operaciones del dominio en exploración y las relaciones que existen entre éstos, para aplicarle reingeniería.

Los métodos de reestructura de este código para la configuración inicial de un marco de clases orientado a objetos para el dominio de aplicaciones en cuestión.

El proceso de refactorización del SR2 consiste en encontrar similitudes estructurales entre el marco de aplicaciones orientado a objetos y patrones de diseño, y en aplicar un conjunto de métodos de refactorización, para la mejora continua y el control de la evolución del marco inicial de clases obtenido del proceso anterior.

Page 18: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

6

En el SR2 se proporciona un sistema de apoyo al proceso de refactorización, llamado IPADIC++, que tiene por objetivo encontrar similitudes estructurales de patrones de diseño (específicamente ‘Abstract Factory’, ‘Composite’ e ‘Iterator’) en el código fuente de marcos de aplicaciones orientadas a objetos escritos en C++ [Cast99]. Otra aportación para el proceso de refactorización fue el desarrollo de un sistema que retoma la forma canónica del IPADIC++ y agrega la detección de los patrones ‘Factory Method’, ‘Strategy’ y ‘Template Method’, además de los patrones ya reconocidos por el IPADIC++ [Zava02]. En relación con el presente trabajo de tesis. Una de las bondades del SR2 es que incorpora patrones de diseño en el proceso de refactorización del marco de componentes reusables, no obstante, una desventaja observada es que no contempla el problema de acoplamiento debido a los canales de comunicación entre las clases del marco. La presente tesis sirve de apoyo al proceso de refactorización del SR2, aplicando el patrón de diseño ‘Mediator’ en la estructura del marco de componentes para resolver el problema de alto grado de dependencias debido al acoplamiento entre clases. Respecto al IPADIC++ y su consiguiente extensión que sirven de soporte al SR2, únicamente realizan la detección de algunos patrones de diseño y sugieren de qué forma debería reestructurarse la arquitectura del marco. Obviamente no realizan el reconocimiento del patrón ‘Mediator’, aspecto que es considerado en esta tesis. Otra diferencia encontrada es que estos programas no llevan a cabo ninguna transformación al código del marco. Por el contrario, en este proyecto de tesis se efectúa la transformación de la estructura de la arquitectura del marco de componentes incorporándole el patrón de diseño ‘Mediator’. 1.2 OBJETIVOS Objetivo General El objetivo principal de esta tesis, es presentar una solución para reducir el acoplamiento de marcos de aplicaciones orientados a objetos debido al alto grado de dependencias entre las diferentes clases del marco; incorporando a su arquitectura una estructura dirigida por el patrón de diseño ‘Mediator’. Objetivos Particulares

Realizar el análisis léxico y sintáctico para descubrir la interdependencia entre módulos de un marco orientado a objetos.

Medir el acoplamiento entre las clases que colaboran en el marco, tomando en cuenta únicamente los canales de comunicación.

Construir un algoritmo que refactorice el marco de aplicaciones orientado a objetos, con el patrón de diseño ‘Mediator’.

Integrar el sistema resultante a la tercera etapa del SR2, que trata sobre la refactorización de marcos orientados a objetos.

Page 19: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

7

1.3 PLANTEAMIENTO DEL PROBLEMA Los módulos que integran un sistema tienen beneficios reales en términos de sus cualidades de extensión y reuso, únicamente cuando los módulos son autónomos, coherentes y organizados en arquitecturas robustas [Meye97]. Debido a la existencia de demasiadas relaciones entre módulos, el efecto de un cambio o de un defecto en un módulo se puede propagar hacia un gran número de módulos y por ende afectar su reuso. Si se quiere que un módulo sea reusable por sí mismo en aplicaciones con nuevos contextos, entonces éste no debe depender de otros módulos. Por causa de estas dependencias entre módulos en los marcos de componentes, se presentan problemas de fragilidad, rigidez e inmovilidad en sus componentes. Bertrand Meyer [Meye97] menciona que existen cinco principios que se deben seguir para asegurar la modularidad apropiada en el software: Correspondencia (mapeo) directa. Pocas interfaces. Pequeñas interfaces (acoplamiento débil). Interfaces explícitas. Ocultamiento de la información.

Desafortunadamente muchos marcos de componentes de aplicaciones orientados a objetos exhiben un alto grado de acoplamiento debido a muchas interfaces o canales de comunicación entre módulos. Problema que se aborda en el desarrollo de esta tesis. Al limitar los canales de comunicación se disminuye la dependencia entre los módulos o clases que integran a los marcos de componentes para aplicaciones orientadas a objetos. El problema mencionado anteriormente está relacionado con el principio de pocas interfaces, el cual restringe el número total de canales de comunicación entre módulos en una arquitectura de software. La comunicación entre módulos puede ocurrir en formas variadas. Módulos que hacen uso de otros módulos, envío de mensajes, módulos que comparten estructuras de datos, etc. El principio de pocas interfaces limita el número de tales conexiones. Si un sistema está compuesto de n módulos, entonces el número de conexiones bidireccionales existentes ínter módulos debe permanecer mucho más cercano al mínimo, n - 1 como se muestra en la figura 1.3.1a, que al máximo n* (n - 1)/2 como se ve en la figura 1.3.1b [Meye97].

Cada módulo debe comunicarse con tan pocos módulos como sea posible.

Page 20: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

8

Fig. 1.3.1. Comunicación Bidireccional Ínter-Módulos Ejemplo En el diagrama de la figura 1.3.2 se observa un conjunto de clases que están relacionadas entre sí, a través de mensajes (llamadas a métodos) que se envían; las líneas punteadas son los canales de comunicación existentes.

Fig. 1.3.2. Ejemplo de Comunicación entre Clases

A continuación se presenta el mismo conjunto de clases de la figura 1.3.2, en donde se coloca una clase intermediaria (mediador) para realizar la comunicación indirecta entre ellas. Esto se muestra en la figura 1.3.3, en donde se puede observar que se reducen los canales de comunicación.

c S tr11

c S r16

c S r12

c S r14

c S r15

c S r13

V A LO RE S

V A RIA B LE S

G RUP O S

M S G

objvar

objvar

objvarpidevar()

pidevar()

pidevar()

pidegrupo()

pidegrupo()

objegru

objegru

pideval()pideval() pideva l( )

objvalobjval

objval

objvarpidevar()

objm s g

o bjm sg

objm s g

objm s g

ob jm sg

objm s g

m ens aje()

m ens aje()

m ens aje()

m ens aje()

m ens aje()

m ens aje()

a) n - 1 b) n * (n - 1)/2

Page 21: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

9

Fig. 1.3.3. Ejemplo de Comunicación entre Clases con una Clase Mediadora

1.4 MÉTODO DE SOLUCIÓN Para solucionar el problema mencionado anteriormente, en esta tesis se plantea y se desarrolla un sistema que permita realizar automáticamente la refactorización de software legado orientado a objetos para su reuso, aplicando el patrón de diseño ‘Mediator’ según el catálogo de Gamma [Gamm95] con el fin de reducir el acoplamiento de clases. La idea es que en lugar de que las clases estén acopladas porque se comunican entre sí, se comuniquen a través de un módulo intermediario cuya finalidad sea la de realizar dicha comunicación entre clases de manera indirecta. Este módulo intermediario puede ser la clase mediadora del patrón de diseño ‘Mediator’. Esto es porque la intención del patrón es definir un objeto que encapsule el comportamiento de interacción de un conjunto de objetos. El patrón ‘Mediator’ promueve el acoplamiento débil, manteniendo explícitamente una referencia entre cada uno de ellos y les permite variar su interacción independientemente. En la sección 3.3 se presenta el algoritmo desarrollado denominado “Reducción de Acoplamiento”, que convierte el código original del marco de aplicaciones orientado a objetos que exhibe propiedades de alto acoplamiento y/o dependencias para refactorizarlo o transformarlo, incorporándole una arquitectura basada en el patrón ‘Mediator’, generando su código asociado con un menor grado de acoplamiento y/o dependencias. También se implementa una métrica que permite obtener los niveles de acoplamiento entre las clases del marco de componentes, antes y después de haber realizado el proceso de refactorización de la arquitectura del mismo. Dicha métrica se muestra en la sección “Métrica para el Factor de Acoplamiento” del capítulo 2.

cSt r11

cStr12

cStr14

MSG

GRUPOS

cSt r13

cStr15VALORES

VARIABLES

cStr16

MEDIADOR

med

med

med

med

med

med

gru

msg

var

valp ideval( )

pideval()

pideval()

pideval()

pidegrupo()

pidegrupo()

pidegrupo()mensaje()

pidevar()

pid evar()

pidevar()mensaje()

mensaje()

mensaje()

mensaje()

pid evar()

mensaje()

pidevar()

Page 22: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

10

1.5 ESTADO DEL ARTE La refactorización es el proceso de cambiar un sistema de software para mejorar su estructura interna de tal manera que no se altere el comportamiento externo del código [Fowl99]. Esta no es una actividad muy practicada, debido a la existencia de muy pocas herramientas de soporte y al poco entendimiento por parte de los desarrolladores de software. Sin embargo, es una actividad muy importante ya que continuarán existiendo sistemas legados que necesiten ser refactorizados para que sean más flexibles y adaptables a los cambios de los requerimientos. Trabajos Relacionados al Tema de esta Tesis Program Restructuring to Introduce Design Patterns [OCin99] Describe un esquema que permite la introducción semi-automática de patrones de diseño creacionales (‘Abstract Factory’, ‘Factory Method’, ‘Builder’, ‘Singleton’ y ‘Prototype’) a código legado escrito en Java. El proceso de refactorización lo realiza de manera automática, ya que la herramienta tiene implementada la validación de las precondiciones que se deben cumplir antes de aplicar un método de refactorización. Finalmente es decisión del diseñador realizar o no la refactorización del código. La desventaja de esta herramienta es que el diseñador del sistema tiene que seleccionar el patrón que desee identificar y la herramienta busca si existen elementos necesarios para poder aplicar el patrón. Además en este trabajo no se contempla el problema de acoplamiento de clases ni el uso del patrón ‘Mediator’ para resolver problemas de diseño de marcos. Pattern-Based Reverse-Engineering of Design Components [Kell99] Es una herramienta de ingeniería inversa que ayuda a entender la organización del software basado en patrones, que permite visualizar la representación del diseño y refinar los modelos. Esta herramienta presenta de forma visual la arquitectura del sistema y los patrones encontrados en el código escrito en Java y permite modificar esta estructura en un ambiente gráfico, pero no realiza la refactorización del código. La herramienta tiene el reconocimiento de todos los patrones de diseño del catálogo de Gamma. Los reconocimientos son de forma automática o de forma manual, en donde el usuario debe seleccionar las clases que considera él que forman un patrón, y el sistema verifica esto contra la estructura de cada patrón. Framework Comprehension and Design Patterns: A Reverse Engineering Approach [Camp97] Esta herramienta tiene un enfoque de ingeniería inversa para la comprensión de marcos de componentes reusables, basada en el reconocimiento y visualización de los posibles patrones de diseño existentes en el marco de componentes; Reconoce todos los patrones de diseño del catálogo de Gamma.

Page 23: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

11

Presenta de forma gráfica los posibles patrones existentes en el código y da una breve descripción del patrón al que se asemeja, la desventaja es que no realiza una refactorización en el código para aplicar los patrones. ModelMaker [Mode04] Es una herramienta CASE (Ingeniería de Software Asistida por Computadora) al estilo de UML (Lenguaje Unificado de Modelado), diseñada para generar código nativo en el lenguaje de programación Delphi, con capacidades completas de ingeniería inversa. Tiene soporte para algunos patrones de diseño. Una vez insertado el patrón de diseño, éste permanece activo y puede reflejar cambios hechos en el modelo al código relacionado con el patrón. Esta herramienta permite modelar el patrón y generar su código o viceversa. Una característica importante es que refleja los cambios tanto en el código como en el modelo. A diferencia del sistema que se desarrolla en esta tesis, no realiza refactorización del código existente. Design Evolution with Refactorings [Toku99] Este proyecto está enfocado hacia la refactorización de código en C++. Se utilizan tres tipos de refactorización, y la decisión sobre el hecho de ejecutar o no la transformación es tomada por el usuario. La primera forma de refactorización es una refactorización de estructura primitiva, que consiste en pequeños cambios al diseño de un marco, como pueden ser: cambios de nombres de variables, de clases o de métodos, agregación de clases, de métodos, etc. La segunda forma de refactorización es sobre estructuras propias de C++, como la transformación de un tipo de dato estructura a una clase. La tercera forma de refactorización trata sobre llevar ciertas arquitecturas defectuosas a una mejor estructura utilizando patrones de diseño. Los patrones que utiliza son de los tres tipos descritos en el catálogo de Gamma: Dentro de los creacionales utiliza ‘Factory Method’, ‘Singleton’ y ‘Abstract Factory’; dentro de los estructurales utiliza ‘Composite’ y ‘Decorator’; y dentro de los de comportamiento utiliza ‘Iterator’, ‘Command’ y ‘Visitor’. En esa investigación se hace la mención de que es factible implementar la refactorización con otros patrones de diseño. La diferencia que existe entre esta investigación y lo propuesto en esta tesis es que aquí no se plantea la solución del problema de acoplamiento de clases. Otra diferencia es que para hacer una refactorización esta herramienta requiere mucha interacción con el usuario, por lo que no se podría considerar que el proceso sea totalmente automatizado. Esta herramienta tiene automatizadas las refactorizaciones primitivas, pero unicamente tienen los algoritmos para hacer la refactorizacion con patrones de diseño, por tanto es responsabilidad del usuario verificar este algoritmo e ir aplicando paso a paso cada una de las refactorizaciones primitivas. Obviamente esto es una desventaja porque se pueden producir errores si el usuario realiza mal el orden de las refactorizaciones u omite refactorizaciones; ya que no se tiene una verificacion de precondiciones, lo cual no

Page 24: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

12

garantiza que el software refactorizado tendra la misma funcionalidad que el software original. Pattern-Based Software Reengineering: a Case Study [ChuW00] Este trabajo habla sobre la reestructura y refactorización de una aplicación específica de código legado en C hacia lenguaje Java. La reestructura de código legado hacia código orientado a objetos, así como la refactorización, es realizada de forma manual. La refactorización que llevan a cabo emplea algunos patrones de diseño del catálogo de Gamma: Dentro de los creacionales utiliza ‘Factory Method’ y ‘Builder’; dentro de los estructurales utiliza ‘Adapter’, ‘Bridge’, ‘Composite’ y ‘Proxy’; y dentro de los de comportamiento utiliza ‘Chain of Responsability’, ‘Command’, ‘Iterator’, ‘Mediator’, ‘Observer’, ‘State’ y ‘Strategy’. El patrón de diseño ‘Mediator’ es utilizado, al igual que en esta tesis, para reducir el número de canales de comunicación entre clases, para simplificar la comunicación entre diferentes partes de una aplicación. La diferencia que existe entre este trabajo y lo propuesto en esta tesis es que aquí la refactorización se hace de manera manual, y es aplicada de manera intuitiva a un caso de prueba. Sin embargo este trabajo confirma la importancia de resolver el problema de acoplamiento de clases y la factibilidad de usar el patrón de diseño ‘Mediator’ para solucionarlo. Refactoring to Patterns [Keri03] Este libro de Industrial Logic Inc. explora la relación que existe entre la refactorización y los patrones y, detalla varias refactorizaciones que muestran cómo llegar a la estructura de los patrones de diseño siguiendo un algoritmo. Utiliza los patrones de diseño del catálogo de Gamma: ‘Singleton’, ‘Factory Method’, ‘Strategy’, ‘Composite’, ‘Builder’, ‘Decorator’, ‘Proxy’, ‘Observer’, ‘Adapter’, ‘State’, ‘Template Method’, ‘Visitor’ y ‘Flyweight’. La diferencia que existe entre este libro y la presente tesis es que sólo proponen algoritmos y la forma manual de resolución para distintos problemas de diseño de marcos, pero no tiene la intención de construir una herramienta que haga la refactorización automática. Conclusión La mayoría de las herramientas mencionadas detectan algunos patrones del catálogo Gamma, tales como los de tipo creacional y estructural y muy pocos de comportamiento. Algunos trabajos están enfocados más hacia los algoritmos de métodos de refactorización que hacia la implementación de dichos métodos y, las herramientas que realizan refactorización de código no incorporan el patrón de diseño ‘Mediator’. En la tabla 1.5.1 se muestra una comparativa de los trabajos relacionados, mostrando características importantes que incorpora la herramienta que se realizará en esta tesis.

Page 25: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

13

Tabla 1.5.1. Comparación de Herramientas Herramienta Automática Lenguaje Refactorización Mediator Reducción

Acoplamiento [OCin99] Sí Java Sí No No [Kell99] Sí Java No Sí No [Camp97] Sí Smalltalk No Sí No [Mode04] Sí Delphi No Sí No [Toku99] Parcial C++ Sí No No [ChuW00] No Java Sí Sí Sí [Keri03] No Java Sí No No Esta tesis Sí C++ Sí Sí Sí

1.6 JUSTIFICACIÓN De los trabajos de investigación que se han publicado sobre la reestructura de software legado muy pocos van dirigidos hacia la construcción de frameworks (marcos de componentes reusables orientados a objetos), de éstos últimos unos cuantos aplican patrones de diseño del catálogo de Gamma. Y ninguno de ellos incorpora un método que resuelva el problema planteado, desde el punto de vista de aplicar el patrón de diseño ‘Mediator’. El acoplamiento es una medida del grado de interdependencia entre módulos, es decir, el modo en que un módulo está siendo afectado por la estructura interna de otro módulo. El objetivo es reducir el acoplamiento entre módulos, de modo que un módulo sea afectado lo menos posible por la estructura de otro módulo. Tal como define Booch, un sistema modular débilmente acoplado facilita [Joya96]: La sustitución de un módulo por otro, de modo que sólo unos pocos módulos serán

afectados por el cambio. El seguimiento de un error y el aislamiento del módulo defectuoso que produce ese

error. 1.7 ALCANCES Y LIMITACIONES El desarrollo de la tesis abarca los siguientes puntos: Se realiza el reconocimiento de código escrito únicamente bajo el estándar ANSI/ISO

de C++. Se reconocen las reglas de sintaxis que correspondan al acoplamiento entre las clases y

que estén relacionadas con los canales de comunicación. Reconocimiento de los canales de comunicación entre las clases del marco de

componentes.

Page 26: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 1

14

Se desarrolla un algoritmo que convierte el código original del marco orientado a

objetos, que exhibe propiedades de acoplamiento y/o dependencias, y lo refactoriza o transforma en otro código orientado a objetos incorporándole una arquitectura basada en el patrón ‘Mediator’, generando su código asociado con menor grado de dependencias por canales directos de comunicación entre clases.

Se realiza la integración del producto resultante de la tesis al sistema SR2 Refactoring

para dar soporte al proceso de refactorización. Implantación de la métrica que permite calcular los niveles de acoplamiento

relacionados únicamente a los canales de comunicación (Métrica del Factor de Acoplamiento COF [Brit95]) entre las clases antes y después de haber aplicado el proceso de refactorización.

Pruebas experimentales.

Documentación.

Los siguientes aspectos quedaron fuera del alcance de ésta tesis: En el reconocimiento de código no se abarcaron instrucciones al pre-procesador ni

cualquier otro código embebido dentro del lenguaje C++ que no sea parte del estándar ANSI/ISO.

No se realiza una precompilación al código, por lo tanto el código debe estar libre de

errores léxicos y sintácticos, es decir debe compilar. También en el reconocimiento de código no se reconoce el uso de clases parametrizadas

con tipos de datos definidos por el usuario, así como conversión de tipos definidos por el usuario.

La implantación de un mediador que sirva de intermediario entre otros mediadores.

La composición de mediadores.

Page 27: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

15

CAPÍTULO 2 MARCO TÉORICO

Se describen algunos de los fundamentos teóricos más importantes utilizados para el

desarrollo de este proyecto de tesis, como son: La tecnología orientada objetos, métricas de software, patrones de diseño, refactorización y marcos de aplicaciones orientados a objetos.

Page 28: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

16

2.1 TECNOLOGÍA ORIENTADA A OBJETOS La tecnología orientada a objetos nos ayuda a modelar el mundo real de un modo más fácil a la perspectiva del usuario que el modelo procedural tradicional. Proporciona mejores técnicas y paradigmas para construir componentes de software reusables, mejorando así la extensibilidad de los programas. Las características esenciales que son soportadas por la metodología orientada a objetos son: herencia, polimorfismo, abstracción y encapsulamiento. Herencia: Esta característica abre la posibilidad de compartir, extender y adaptar las descripciones de objetos y las implantaciones sin cambiar su código fuente. La herencia incrementa la posibilidad de reusar componentes simples y también permite la construcción de marcos de aplicaciones reusables. Se pueden distinguir dos tipos de herencia: la herencia simple y la herencia múltiple. Con la herencia simple una clase puede heredar solamente de una de las otras clases y la herencia múltiple permite que una clase pueda heredar de cualquier número de clases [Pree96]. Abstracción: La abstracción es uno de los medios más importantes, mediante el cual nos enfrentamos con la complejidad inherente al software. Se basa en el principio de ocultar los detalles innecesarios y revelar únicamente aspectos esenciales. Polimorfismo: Esta característica permite la posibilidad de que una entidad tome muchas formas o comportamientos. Los mecanismos que habilitan el polimorfismo se implantan a través de la herencia y abstracción, y se efectúa de manera dinámica en tiempo de ejecución. Encapsulación: Permite asegurar que el contenido de la información de un objeto esté oculta al mundo exterior: El objeto A no sabe de la representación e implantación del objeto B y viceversa. La encapsulación es el proceso de ocultar todos los secretos de un objeto que no contribuyen a sus características esenciales. Y permite la división de un programa en módulos [Joya96]. Clase: Una clase especifica los datos internos, la representación de un objeto y también define las operaciones que el objeto puede efectuar. A partir de la clase se pueden instanciar los objetos. Clase Abstracta: Una clase abstracta es aquella en la cual su propósito principal es definir una interfaz común para sus subclases. Una clase abstracta difiere algunas o todas sus implantaciones de sus operaciones a las subclases; es por eso que una clase abstracta no puede ser instanciada. Las operaciones que

Page 29: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

17

son declaradas en una clase abstracta pero no son implantadas son llamadas operaciones abstractas o interfaces. Clase Concreta: Es una clase que no es abstracta, es decir, implementa las operaciones abstractas que hereda. Asociación Dinámica: Cuando una petición es enviada a un objeto, la operación que es efectuada depende tanto de la petición como del objeto que la recibe. Objetos diferentes que soportan peticiones idénticas pueden tener diferentes implantaciones de las operaciones que realizan estas peticiones. La asociación en tiempo de ejecución de una petición a un objeto y a una de sus operaciones es conocida como asociación dinámica [Gamm95]. Invalidación y Reemplazo: Es la reescritura de una operación virtual heredada de una clase padre en una o más de sus subclases. Sobrecarga de Funciones: Es la definición de funciones con el mismo nombre, siempre y cuando tengan diferentes tipos de parámetros o cantidad de parámetros. La sobrecarga de funciones se utiliza normalmente para crear varias funciones con el mismo nombre que realicen tareas similares, pero sobre distintos tipos de datos o con distinto comportamiento [Deit03]. Plantillas: Las plantillas (en inglés, templates) proporcionan una forma sencilla de representar una amplia gama de conceptos generales y formas sencillas de combinarlos. Las clases y funciones resultantes pueden equipararse a código más especializado escrito a mano en cuanto a tiempo de ejecución y eficiencia de espacio. Proporcionan soporte directo para programación genérica, es decir, para programar usando tipos como parámetros. El mecanismo de plantillas en C++ permite que un tipo sea un parámetro en la definición de una clase o función [Stro98]. Las plantillas de clases fomentan el reuso de código al permitir la creación de instancias de versiones de las clases genéricas para tipos específicos [Deit03]. 2.2 REINGENIERÍA DE SOFTWARE La reingeniería de software examina los sistemas y aplicaciones con la intención de reestructurarlos o reconstruirlos de tal modo que muestren una mayor calidad. Abarca una serie de actividades entre las que se incluye el análisis de inventarios, la reestructuración de documentos, la reestructuración de programas y datos, y la ingeniería directa. El objetivo de estas actividades consiste en crear versiones de los programas existentes que muestren una mayor calidad, y faciliten su mantenimiento [Pres02].

Page 30: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

18

2.3 MARCOS DE COMPONENTES REUSABLES (FRAMEWORKS) Los marcos de componentes reusables de aplicaciones orientados a objetos, son la piedra angular de la ingeniería de software moderna. El desarrollo de marcos de componentes reusables está ganando aceptación debido a la capacidad de los marcos para promover el reuso del diseño y del código fuente [Mark01]. "Un framework o marco de componentes reusables de aplicaciones orientadas a objetos es un conjunto de clases en colaboración que abarca un diseño abstracto para dar soluciones a una familia de problemas relacionados" [Dami98]. Como se puede observar, el principal objetivo de un marco es permitir el reuso de su diseño y código, y esto se logra utilizando la herencia y la instanciación. Otro objetivo de un marco es facilitar la extensión de su funcionalidad, con el fin de cumplir con ciertos requerimientos necesarios para un problema particular del dominio; esto también es logrado utilizando la herencia, agregando clases concretas que se conectan a las clases genéricas, las cuales ofrecen las interfaces del marco. Sin embargo, no siempre es posible lograr el reuso de software en los marcos, debido a que algunos marcos no maduros presentan problemas de diseño, y ello impide que sus objetos sean reusados de manera independiente, porque no fueron bien diseñados o por haber sido obtenidos fríamente por procesos de reingeniería automatizados. Uno de estos problemas es el de acoplamiento de clases por una gran cantidad de canales de comunicación, al cual se enfoca esta tesis. Clasificación de los Marcos de Componentes Según su tipo, los marcos de componentes se pueden clasificar de la siguiente forma [Klei00]: Marcos de componentes de aplicación.- Son aplicables a una variedad de programas

(Interfaces de usuario gráficas). Marcos de componentes de dominio.- Se refiere a la experiencia en un problema

particular del dominio (Control de manufactura, procesamiento de documentos). Marcos de componentes de soporte.- Se refieren a los servicios a nivel de sistemas

(Sistemas de archivos, interacción con dispositivos). Otra clasificación más importante es desde la perspectiva del programador; considerando las técnicas usadas para extender el marco, puede ser utilizado como una caja blanca o caja negra. Marcos de componentes de caja blanca. Se basan principalmente en las características orientadas a objetos tales como la herencia y el enlace dinámico. El marco de componentes es extendido, ya sea heredando de las clases bases del marco o reemplazando los métodos predefinidos por él mismo.

Page 31: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

19

Un marco de caja blanca define interfaces para componentes que pueden ser enlazados vía composición de objetos, sin embargo, la dificultad de usar este tipo de marcos reside en el hecho de que requieren un profundo entendimiento de las clases que se van a extender. Marcos de componentes de caja negra. Son estructurados usando composición de objetos y delegación en lugar de la herencia. Enfatizan en las relaciones dinámicas de objetos. Se puede agregar nueva funcionalidad haciendo composición de objetos existentes en nuevas formas que reflejen el comportamiento de la aplicación. El usuario en este caso no tiene que conocer a fondo los detalles, sino solamente tiene que saber como usar los objetos existentes y combinarlos. Estas dos categorías presentadas son casos extremos, ya que en la práctica un marco de componentes no es puramente de caja blanca o de caja negra. Generalmente en un marco, la herencia es combinada con la composición de objetos [Dami99]. 2.4 REUSO El reuso puede definirse como “cualquier procedimiento que produce o ayuda a producir un sistema mediante el nuevo uso de algún elemento procedente de un esfuerzo de desarrollo anterior” [Free87]. El propósito del reuso es mejorar la eficiencia, la productividad y la calidad del desarrollo de aplicaciones de software [Garc97]. El reuso de software se ha estado efectuando por muchos años principalmente con las bibliotecas de software, viendo únicamente al código fuente como objeto del reuso. Sin embargo, en la actualidad este concepto ha estado evolucionando y se ha expandido mucho más lejos, hacia el reuso a gran escala. Esto es con la finalidad de tratar el tamaño y la complejidad del software actual. Por ello el reuso del software no debe estar aislado; debe aplicarse dentro de todo el marco de trabajo de la ingeniería de software, incluyendo las estructuras organizacionales, los procesos del ciclo de vida, políticas, métodos y personal capacitado [Fent97]. Uno de los objetivos principales de la Ingeniería de Software, así como de la tecnología orientada a objetos, es el reuso, esperando que no sólo se llegue al reuso de componentes completos de código, sino que se llegue al nivel de poder reusar el diseño de sistemas, de tal manera que se puedan generar marcos de componentes reusables de diferentes ámbitos de aplicaciones y se facilite la tarea de construir nuevos sistemas para resolver nuevos problemas [Abra01]. La clase proporciona los mecanismos para encapsular, abstraer y ocultar la información, además de ser un componente elemental en el reuso. La herencia es el concepto sobre el que se asientan el reuso y la extensión del software. La herencia es la propiedad que permite que nuevas clases puedan compartir comportamiento y representación a partir de las clases ancestro. A través de la herencia los diseñadores pueden construir nuevos elementos de software sobre una jerarquía de elementos existentes, permitiendo abordar el proceso de diseño y construcción del software, sin tener que partir de cero [Garc97].

Page 32: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

20

2.5 REESTRUCTURACIÓN La reestructuración del software modifica el código fuente y/o los datos en un intento de adecuarlo a futuros cambios. Se lleva a cabo para conseguir un diseño que produzca la misma función pero con mayor calidad que el programa original. Algunos de los beneficios que se pueden lograr cuando se reestructura el software son los siguientes [Pres02]: Programas de mayor calidad. Reduce la frustración entre los ingenieros que trabajan con el programa, mejorando su

productividad y simplificando su aprendizaje. Reduce el esfuerzo requerido para realizar actividades de mantenimiento. Hace que el software sea más sencillo de comprobar y de depurar.

2.6 REFACTORIZACIÓN Es el proceso de cambiar un sistema de software de tal manera que no altere el comportamiento externo del código y que mejore su estructura interna. Esta es una forma disciplinada de ordenar el código para minimizar las oportunidades de introducir errores. Para asegurarse que esto no ocurra siempre, una refactorización cuenta con precondiciones y poscondiciones que se deben de cumplir antes y después de aplicar una transformación. Por tanto, la refactorización no ayuda a un sistema actual sino a sistemas futuros que se extiendan del sistema actual [Opdy92]. Una herramienta que ofrece refactorización automatizada debe garantizar que sus operaciones preservan el comportamiento del programa. Una de las razones porque los programas no son refactorizados es debido a que al hacer un cambio se corre el riesgo de introducir errores al programa. Por eso es importante respetar las precondiciones y poscondiciones de una refactorización, para saber si se va a afectar el comportamiento del programa [Opdy92]. Dependiendo de la complejidad, las refactorizaciones se pueden hacer de manera automática o semiautomática, pero lo que deben de hacer automáticamente es la validación de las precondiciones y poscondiciones. Una herramienta de refactorización debe ayudar al diseñador y al administrador del marco de aplicaciones orientado a objetos, ofreciéndoles las refactorizaciones adecuadas a un problema y asegurando que cada refactorización será bien realizada, pero no puede tomar la decisión final. Por tanto, en ese sentido, la refactorización no puede ser completamente automatizada [Opdy92]. Esto es debido a que es responsabilidad del administrador del marco o experto del dominio tomar la decisión de realizar o no la refactorización. Una refactorización que puede aplicarse sin peligro a introducir errores no necesariamente mejora el diseño de un marco. Si se aplican refactorizaciones de manera arbitraria, es más probable que se empeore el diseño, aún cuando se mantenga el comportamiento. La aplicación y el diseñador son los que deciden que refactorizaciones son significativas. Esto implica que la tarea de refactorización, especialmente las más complejas, requieren algo de

Page 33: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

21

interacción con el diseñador [Opdy92], como ocurre en nuestro caso, en donde el administrador del marco tiene que tomar decisiones en cuanto a ciertos nombres de funciones y clases que se agregan a la arquitectura original. La refactorización es una herramienta que puede y debe ser usada para muchos propósitos [Fowl99]: Mejorar el diseño del software. Hacer el software más fácil de entender. Ayudar a encontrar errores. Ayudar a desarrollar código más rápidamente. Ayudar a que el software sea más flexible, robusto y reusable.

Algunas refactorizaciones son muy simples como cambiar el nombre de una variable o método; otras son más complejas y dependen de un lenguaje en particular; y las refactorizaciones más avanzadas están compuestas por refactorizaciones simples, e involucran el uso de los patrones de diseño orientados a objetos. De este último tipo es la refactorización que se presenta en esta tesis, utilizando patrones de diseño y está enfocada a marcos escritos en el lenguaje de programación C++. 2.7 ACOPLAMIENTO DE MÓDULOS El acoplamiento es una medida del grado de interdependencia entre módulos, es decir, el modo en que un módulo está siendo afectado por la estructura interna de otro módulo. El grado de acoplamiento se puede utilizar para evaluar la calidad del diseño de un sistema. El objetivo es minimizar el acoplamiento entre módulos, de modo que un módulo sea afectado lo menos posible por la estructura de otro módulo. Tal como define Booch, un sistema modular débilmente acoplado facilita [Joya96]: La sustitución de un módulo por otro, de modo que sólo unos pocos módulos serán

afectados por el cambio. El seguimiento de un error y el aislamiento del módulo defectuoso que produce ese

error. Todavía no hay medidas estándar del acoplamiento, desde el punto de vista de la teoría de la medición. En particular hay algunas relaciones empíricas bien establecidas que involucran acoplamiento y sugieren una escala ordinal de métricas. Dado los módulos x y y podemos crear una clasificación ordinal para el acoplamiento definiendo cinco relaciones en un conjunto de pares de módulos [Fent97].

Page 34: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

22

Relación de no acoplamiento: x y y no tienen comunicación; esto es, ellos son totalmente independientes uno del otro.

Relación de acoplamiento de datos: x y y se comunican por parámetros, donde cada

parámetro es ya sea un elemento o un conjunto homogéneo de datos. Este tipo de acoplamiento es necesario para alguna comunicación ente módulos.

Relación de acoplamiento de control: x pasa un parámetro a y con la intención de

controlar su comportamiento; el parámetro es una bandera. Relación de acoplamiento común: x y y se refieren a los mismos datos globales. Este

tipo de acoplamiento es indeseable; si el formato de los datos globales deben cambiar, entonces todos los módulos acoplados deben también ser cambiados.

Relación de acoplamiento de contenido: x se refiere dentro de y; es decir, éste se

ramifica y cambia los datos o altera una sentencia en y. 2.8 MÉTRICAS DE SOFTWARE Una métrica de software es una forma estándar de medir algunos atributos del proceso de desarrollo de software. Ejemplos de estos atributos son: Tamaño, costos, defectos, comunicaciones, dificultad y ambiente. Aplicar las métricas nos lleva a un mejor entendimiento e incrementa lo predecible del proceso [Zuse98]. El producto a medir debe ser interpretado en un sentido amplio, por ejemplo las métricas pueden ser aplicadas a cualquier artefacto construido durante el desarrollo, incluyendo no sólo código sino también modelos de análisis y diseño, así como sus componentes. La meta de las métricas de software es la identificación y medida de los parámetros esenciales que afectan el desarrollo del software [Cham97]. Las métricas son un buen medio para entender, monitorizar, controlar, predecir y probar el desarrollo de software y los proyectos de mantenimiento [Bria96]. En general, la medición persigue tres objetivos fundamentales: ayudarnos a entender qué ocurre durante el desarrollo y el mantenimiento, permitirnos controlar qué es lo que ocurre en los proyectos y poder mejorar los procesos y productos [Fent94]. El software orientado a objetos es fundamentalmente diferente del software desarrollado con el uso de métodos convencionales. Por esta razón, las métricas para sistemas orientados a objetos deben ser afinadas a las características que distinguen al software OO del software convencional [Pres02]. El sistema implementa el cálculo de la métrica del factor de acoplamiento, el cual puede ser aplicado al código original y al código reestructurado con el fin de comparar y comprobar que se ha reducido el acoplamiento en el código resultante. En este trabajo de tesis se realizó un estudio de algunas métricas orientadas a objetos específicamente de aquellas que consideran la comunicación entre clases por paso de

Page 35: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

23

mensajes. Se seleccionó la métrica de Factor de Acoplamiento COF [Brit95] debido a que su nivel de granulación abarca a todo el sistema y no incluye el acoplamiento resultante de la herencia, esto es porque la herencia se considera como algo positivo, ya que habilita el reuso del software. Métrica para el Factor de Acoplamiento (Coupling Factor COF) [Brit95] Definición El factor de acoplamiento es la proporción entre el número real de acoplamientos no imputables a herencia y el máximo número posible de acoplamientos en el sistema. Es decir, indica la comunicación entre clases [Vazq01]. Fórmula

[ ( ) ]TCTC

CCclienteesCOF

TC

j jiTC

i

−=

∑∑ ==2

11,_

Donde: TC2 - TC es el máximo número de acoplamientos en un sistema con TC clases. La relación cliente-servidor (Cc => Cs) significa que Cc (la clase cliente) contiene al menos una referencia no basada en la herencia a una característica (método o atributo) de la clase Cs (clase servidora). El numerador representa el número real de acoplamientos no imputables a la herencia. El denominador representa el máximo número posible de acoplamientos en un sistema con TC clases. Las relaciones cliente-servidor pueden tener distintas formas: Paso de mensajes regular. Paso de mensajes “forzado”. Iniciación y destrucción de objetos. Asociaciones semánticas entre clases con una cierta relación.

Valoración COF puede ser una medida indirecta de los atributos con los cuales está relacionado: complejidad, falta de encapsulamiento, carencia de reuso, facilidad de comprensión y poca facilidad de mantenimiento. Valores muy altos del factor de acoplamiento deben ser evitados y es deseable que este factor se encuentre en los límites más bajos. Como resultado de experimentación en [Brit95] y [Proy04] se sugiere que el factor de acoplamiento (COF) en un sistema no exceda un 12% o un 17.7% respectivamente. Cabe aclarar que el valor de acoplamiento (COF) que mide el sistema desarrollado en esta tesis se refiere específicamente al tipo de acoplamiento por paso de mensajes (llamadas a

es_cliente(Cc , Cs) = 1 si y solo si Cc => Cs ^ Cc ≠ Cs 0 en caso contrario

Page 36: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

24

métodos), ya que únicamente se miden los canales de comunicación entre clases. Es decir, no se toman en cuenta otras relaciones por ejemplo declaración de objetos. 2.9 PATRONES DE DISEÑO El uso del término patrón, con el significado que actualmente se le da en la Ingeniería de Software, y más concretamente, en el área de la tecnología de objetos, se deriva de los trabajos del arquitecto Christopher Alexander. Sin embargo, aún siendo sus publicaciones propias de arquitectura, sus ideas son aplicables a muchas otras disciplinas, entre las que cabe destacar su aplicación en la ingeniería de software. Definición de Patrón Para Brad Appleton un patrón es “una unidad de información instructiva con nombre que captura la estructura esencial y la comprensión de una familia de soluciones exitosas probadas para un problema recurrente que ocurre dentro de un cierto contexto y de un sistema de fuerzas” [Garc98]. Componentes Esenciales de un Patrón de Software Un patrón es una regla que establece una relación entre un contexto, un sistema de fuerzas que aparecen en el contexto y una configuración que permite que las fuerzas se resuelvan dentro del contexto. Un patrón debe contar con cuatro elemento esenciales: El nombre del patrón: Un descriptor manejable del problema. Debe ser corto (una palabra o dos). Éste descriptor amplía el vocabulario de diseño. El problema: Describe cuándo aplicar el patrón. Explica el problema y su contexto. La solución: Describe los elementos que forman el diseño, sus relaciones, responsabilidades y colaboraciones. No describe un diseño o una implantación concreta, sino que ofrece una descripción abstracta a un problema. Las consecuencias: Son los resultados de aplicar un patrón. Son necesarias para evaluar alternativas de diseño, así como para evaluar los costos y beneficios de su aplicación. En el catálogo de Gamma [Gamm95] se distinguen tres tipos de patrones: patrones de creación, patrones estructurales y patrones de comportamiento. Patrones de creación: Abstraen el proceso de instanciación de objetos. Tienen la

misión de permitir construir sistemas independientes de la forma en que se crean, se componen o se representa los objetos.

Patrones estructurales: Se cuidan de cómo las clases y los objetos se componen para

formar estructuras mayores.

Page 37: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

25

Patrones de comportamiento: Este tipo de patrones está relacionado con algoritmos y la asignación de responsabilidades entre objetos. Describen, además de los patrones de objetos y clases, los patrones de comunicación entre ellos.

Patrón de Diseño ‘Mediator’ (Mediador) [Gamm95] A continuación se describe el patrón de diseño ‘Mediator’, el cual se encuentra clasificado como un patrón de comportamiento en el catálogo de Gamma. Al aplicar este patrón se pretende reducir el problema de dependencias entre clases del marco. Intención Define a un objeto que encapsula el cómo interactúan un conjunto de objetos. El mediador promueve el acoplamiento débil, manteniendo la referencia entre cada uno de ellos explícitamente y les permite variar su interacción independientemente. Un mediador es responsable de concentrar para coordinar las interacciones de un grupo de objetos. Sirve como un intermediario que mantiene las referencias entre los objetos en el grupo explícitamente. Los objetos únicamente conocen al mediador, por lo que se reduce el número de interconexiones. Motivación El diseño Orientado a objetos apoya la distribución del comportamiento entre objetos. Tal distribución puede resultar en una estructura con muchas conexiones entre éstos, en el peor de los casos, cada objeto termina conociendo mucho acerca de los otros objetos. Aunque el particionar a un sistema en muchos objetos generalmente aumenta el reuso, la proliferación de interconexiones tiende a reducirla. Aplicabilidad El patrón mediador se usa cuando: Un conjunto de objetos se comunican en formas bien definidas pero complejas. Las

interdependencias resultantes son no estructuradas y difíciles de entender. El reuso de un objeto es difícil porque éste se refiere y comunica con muchos otros

objetos dependientes. Un comportamiento que está distribuido entre muchas clases debe ser personalizable sin

demasiadas subclases. Consecuencias El patrón mediator tiene los siguientes beneficios e inconvenientes: Limita el subclaseo Desacopla a los colegas (clases que interactúan). Simplifica el protocolo entre objetos interactuantes.

Page 38: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 2

26

Realiza una abstracción de como colaboran los objetos. Centraliza el control. [Gamm95]

Estructura

Fig. 2.9.1. Estructura del Patrón de Diseño ‘Mediator’

ConcreteColleague1ConcreteMediator ConcreteColleague2

mediator ColleagueMediator

Page 39: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

27

CAPÍTULO 3 DESCRIPCIÓN DEL SISTEMA DESARROLLADO

Una vez que se ha realizado el planteamiento del problema en el capítulo 1, se presenta la solución adoptada que consiste en la implementación del patrón de diseño ‘Mediator’ en la arquitectura del marco, para que sirva de intermediario entre las clases que se comunican entre sí. Posteriormente se hace una descripción del método de refactorización que permite la implementación del patrón mencionado y de los módulos que integran el sistema.

3.1 ANALIZADOR SINTÁCTICO PARA LA GRAMÁTICA DEL LENGUAJE C++ Para llevar a cabo el desarrollo de la presente tesis fue necesario utilizar la herramienta JavaCC [Java03] para generar el analizador sintáctico (parser), con el fin de reconocer el código escrito en C++ y obtener la información necesaria para realizar el cálculo de la métrica de Factor de Acoplamiento (COF) e implementar el método de refactorización que incorpora el patrón de diseño ‘Mediator’. Java Compiler Compiler, JavaCC, es una herramienta generadora de analizadores léxicos y sintácticos (parsers) escrita en Java, que produce código en Java. Las características principales de este metalenguaje son:

Page 40: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

28

Top-down.- Genera analizadores descendentes recursivos, esto permite el uso de

gramáticas más generales. Especificaciones léxicas y gramáticas en un archivo.- Las especificaciones léxicas tales

como expresiones regulares, cadenas, etc. y las especificaciones de la gramática (BNF) ambas son escritas juntas en el mismo archivo.

Especificaciones sintácticas y semánticas hacia adelante “Lookahead”.- Por defecto,

JavaCC genera un analizador LL(1), esto es, sólo se analiza un token para realizar las acciones semánticas. Sin embargo, pueden haber porciones de la gramática que no sean LL(1). El analizador es LL(k) en determinados puntos, pero permanece LL(1) en cualquier otro lugar para un mejor desempeño. Al permitir un “Lookahead” mayor, se puede verificar toda una regla compuesta de varios tokens para llevar a cabo el reconocimiento de toda una instrucción o una acción semántica.

Además JavaCC proporciona otras herramientas estándares relacionadas a la generación del parser, tales como la construcción de árboles (JJTree), y la conversión de archivos de gramáticas JavaCC en documentos (JJDoc). Se realizó un estudio del analizador sintáctico de la gramática del lenguaje C++ desarrollado en JavaCC por Sreenivasa Viswanadha, dicho programa fue obtenido de un sitio de dominio público [Visw96]. La herramienta tiene asociados los siguientes archivos que son de ayuda para el análisis del código fuente. ClassScope.java Scope.java SymtabManager.java

Cuando se compila el archivo que contiene la gramática, en este caso “CPlusPlus.jj”, JavaCC para generar el parser genera los siguientes archivos: CPPParser.java CPPParserConstants.java CPPParserTokenManager.java SimpleCharStream.java ParseException.java Token.java TokenMgrError.java.

Para detectar ciertos elementos de un programa escrito en C++ que son necesarios para el proceso de refactorización, se requirió hacer algunas modificaciones a la gramática original y agregar algunas reglas de producción. A continuación se presentan algunos de los elementos que no se reconocían y que fueron agregados. No reconocía la declaración de objetos o punteros a objetos. Ejemplo:

Page 41: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

29

class x { ..... public: int x; float y; claseB objb; claseZ * objz; ..... };

No reconocía como parámetros a objetos o punteros a objetos. Ejemplo: int funcLee (int x, float y, BDBASE obj , BDBin objb ) { }

Al utilizar new únicamente reconocía datos primitivos (int, float, char) no permitía usarlo con objetos de tipo clase. Ejemplo: void cStr16::AlgoritmoDeInterfaz() { ..... obgru = new GRUPOS(); ..... }

No se permitía que las funciones tuvieran como valor de retorno a objetos o punteros a objetos. Ejemplo: class x { ..... claseY Funcion1(.....); claseZ *Funcion2(.....); ..... };

Finalmente, no se reconocían las llamadas a métodos de objetos definidos por el usuario. Ejemplo: void cStr16::AlgoritmoDeInterfaz() { ..... obgru = new GRUPOS(); obgru -> pidegrupo( ); ..... }

Page 42: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

30

También se detectaron los puntos dentro de la gramática en donde se deben introducir las acciones semánticas con el fin de obtener la información necesaria para llenar la base de datos que se emplea para aplicar el método de refactorización y el cálculo de la métrica. Con JavaCC se generó el analizador, que fue integrado a la arquitectura existente del sistema como un paquete, por tanto, el sistema completo cuenta con tres paquetes ya que se tienen integrados tres métodos de refactorización. El analizador generado con JavaCC sirve para llenar la base de datos del método y los registros que se obtienen son los siguientes: Reconocimiento de las clases existentes. Reconocimiento de las relaciones de herencia, indicando la clase padre y la clase hija. Reconocimiento de las llamadas de métodos por objetos, ya sea que la llamada sea con

el operador “->”, para punteros a objetos, o “.”, para objetos. Reconocimiento de los métodos declarados o implementados en cualquiera de los

archivos fuente, ya sea en la declaración de una clase o fuera de ella. Reconocimiento de los objetos declarados, ya sea en una clase como variables de

instancia o en métodos como variables locales. También se toman si están como parámetros de función.

Aparte se hace un análisis utilizando código en Java para encontrar la declaración de directivas #include. Cabe mencionar que la gramática de C++ con la que se cuenta hasta el momento está aún incompleta. Se ha acondicionado lo suficiente para reconocer el problema de acoplamiento de clases por gran cantidad de canales de comunicación, sin embargo existen instrucciones que no son reconocidas por el analizador y generan errores en el análisis. Las limitaciones del analizador creado son: No se reconocen clases parametrizadas, clases “templates”, en donde estos parámetros

sean tipos de referencia. No se reconocen operaciones “cast” con objetos o tipos de datos. No son reconocidas las macros. Se ignoran las directivas del pre-procesador. Existen limitaciones con la inicialización y uso de constructores de objetos. Debe haber explícitamente la declaración de tipo para las funciones. Los parámetros de las funciones deben tener un nombre y tipo explícito. No se reconocen los constructores y destructores, y el código de éllos.

Base de Datos Para aplicar el método de refactorización se requiere conocer el conjunto de clases colegas que colaboran entre sí, los nombres de los métodos desde donde se realizan las llamadas a otros métodos, los objetos que las realizan, así como los nombres de las clases a los que pertenecen y la herencia entre clases. La mayor parte de esta información es obtenida cuando se ejecuta el parser y se analizan los archivos de entrada (archivos cpp, h, hpp) y se almacena en tablas para su uso posterior por el módulo de refactorización y el módulo que realiza el cálculo de la métrica del factor de acoplamiento.

Page 43: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

31

La base de datos, llamada BDMediador, que es utilizada para recopilar la información, fue implementada con el manejador de bases de datos MySQL. Las tablas utilizadas son las siguientes: clases

Nom_clase Char

Tipo Char

Lininicio Int

Linfin Int

Archivo Char

Abstracta Char

Almacena el nombre de la clase (Nom_clase), si es clase base o derivada (Tipo), la línea donde empieza la declaración de la clase (Lininicio), la línea donde termina (Linfin), el nombre del archivo (Archivo) y si la clase es abstracta por tener interfaces (Abstracta). herencia

Clasehija Char

Clasepadre Char

Almacena el nombre de la clase derivada (Clasehija) y el nombre de la clase base (Clasepadre). llamadas

Lindec int

Obj_llama Char

Obj_llamadoChar

Parametros Char

Operador Char

Archivo Char

Almacena el número de línea donde está la llamada (Lindec), el nombre del objeto que inicia la llamada (Obj_llama), el nombre del método que es llamado (Obj_llamado), la cadena de la llamada completa (Parametros), si el operador fue “->” o “.” (Operador) y en que archivo se encuentra la llamada (Archivo). llamadas_filtro

Lindec int

Obj_llama Char

Obj_llamadoChar

ParametrosChar

OperadorChar

Archivo Char

Med Char

Almacena los mismos datos de la tabla “llamadas”, pero sólo de las llamadas que serán sustituidas por el mediador, este control se lleva en Med.

Page 44: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

32

metodos Nombre

Char Claseprop

Char Acceso Char

Tipo Char

Virtual Char

Lindec

Int Pura Char

Parametros Char

Archivo Char

Med Char

Almacena el nombre del método (Nombre), la clase a la que pertenece el método (Claseprop), la forma de acceder al método, ya sea en forma privada, pública o protegida (Acceso), el valor de retorno de la función (Tipo), si el método es virtual o no (Virtual), en que número de línea se encuentra la declaración del método (Lindec), si el método es una interfaz (Pura), que parámetros recibe (Parametros), y en que archivo fuente está declarado el método (Archivo). Si el método es implementado en el mediador se registra en Med. objetoscreados

Nom_obj Char

Claseprop Char

Acceso Char

Lindec Int

Nombre Char

Archivo Char

Almacena el nombre del objeto con todo y apuntadores (Nom_obj), la clase a la que pertenece ese objeto (Claseprop), la forma de acceder al objeto (Acceso), el número de línea donde está la declaración (Lindec), el puro nombre del objeto (Nombre), y el archivo donde está la declaración (Archivo). medconcretos

Almacena donde se están agregando los objetos del mediador. Se registra el nombre del mediador concreto (Medconcreto), en que archivo será agregado el mediador (Archivo) y cómo se llama el objeto mediador (Objconcreto). mediador

cMed_abstracta Char

cMed_concretaChar

cCol_abstracta Char

obj_mediador Char

obj_colega Char

Medconcreto Char

Archivo Char

Objconcreto Char

Page 45: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

33

Almacena los parámetros solicitados al usuario, el nombre de la clase mediadora abstracta (cMed_abstracta), el nombre de la clase mediadora concreta (cMed_concreta), el nombre de la clase colega (cCol_abstracta), el nombre del objeto mediador (obj_mediador) y el nombre del objeto colega (obj_colega). includes

Archivo Char

Include Char

Almacena en que archivo se encuentra la directiva #include (Archivo), y que archivo está siendo incluido (Include). 3.2 MÉTODO DE REFACTORIZACIÓN Como ya se ha mencionado, el objetivo de esta tesis es crear un método de refactorización que reduzca el número de dependencias debido a llamadas de funciones en un marco. Para explicar el método propuesto se hará uso de un ejemplo muy simple de un programa orientado a objetos, el cual realiza una suma o una resta. La estructura del programa se muestra en la figura 3.2.1, con todas las clases que intervienen, excepto la clase cliente que contiene el método “main”, el cual invoca al método Ejecutar( ) de la clase CInterfaz.

CSuma

<<virtual>> ~CSuma()CSuma()Sumar()

CResta

<<virtual>> ~CResta()CResta()Restar()

CDatovalor : int

<<virtual>> ~CDato()CDato()EstablecerValor()ObtenerValor()

CResultadoresultado : int

<<virtual>> ~CResultado()CResultado()EstablecerResultado()ObtenerResultado()

COperacion

<<virtual>> ~COperacion()COperacion()EstableceOperacion()

CInterfaz

<<virtual>> ~CInterfaz()CInterfaz()Ejecutar()

-valor1-valor2

-total

-operacion

v oid CSuma::Sumar(CDato sumando1, CDato sumando2, CResultado *suma){

suma->EstablecerResultado(sumando1.ObtenerValor() + sumando2.ObtenerValor());}

Fig. 3.2.1. Diagrama de Clases del Programa de Ejemplo

Page 46: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

34

En esta arquitectura se puede notar que existen llamadas entre casi todas las clases, y por tanto alta dependencia entre ellas, sin que exista una clase que tome el control de las llamadas. Por eso se busca disminuir y redirigir los canales de comunicación a través de clases mediadoras. El método consiste primeramente en detectar las clases que funcionan como colegas, es decir, clases que invoquen métodos de otras clases. Las funciones que contienen llamadas a objetos de otras clases son las siguientes: // Del archivo Interfaz.cpp void CInterfaz::Ejecutar() { int valor; int opcion; printf ("Ejemplo de Operaciones Basicas\n\n"); printf ("Introduzca valor # 1: "); scanf ("%d",&valor); valor1.EstablecerValor(valor); printf ("Introduzca valor # 2: "); scanf ("%d",&valor); valor2.EstablecerValor(valor); total.EstablecerResultado(0); printf ("\nPresionar 1 para sumar, 2 para restar\n"); scanf ("%d",&opcion); operacion.EstableceOperacion(opcion,valor1,valor2,&total); printf ("El resultado es: %d",total.ObtenerResultado()); printf ("\nFIN DE PROGRAMA"); getch(); }

// Del archivo Operacion.cpp void COperacion::EstableceOperacion(int tipo, CDato valor1, CDato valor2, CResultado *resultado) { switch (tipo){ case 1: CSuma *operacion1; operacion1=new CSuma(); operacion1->Sumar(valor1,valor2,resultado); break; case 2: CResta *operacion2; operacion2=new CResta(); operacion2->Restar(valor1,valor2,resultado); } }

// Del archivo Suma.cpp void CSuma::Sumar(CDato sumando1, CDato sumando2, CResultado *suma) { suma->EstablecerResultado(sumando1.ObtenerValor() + sumando2.ObtenerValor()); }

// Del archivo Resta.cpp void CResta::Restar(CDato minuendo, CDato sustraendo, CResultado *resta) { resta->EstablecerResultado(minuendo.ObtenerValor() – sustraendo.ObtenerValor()); }

Por tanto se determina que la clase CInterfaz tiene dependencias con las clases CDato, COperacion y CResultado. De la clase CDato utiliza el método EstablecerValor( ), de la

Page 47: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

35

clase COperacion utiliza el método EstableceOperacion( ) y de la clase CResultado utiliza los métodos EstablecerResultado( ) y ObtenerResultado( ). La clase COperacion tiene dependencia a su vez con las clases CSuma y CResta. De la clase CSuma utiliza el método Sumar( ) y de la clase CResta el método Restar( ). Las clases CSuma y CResta tienen dependencia también con las clases CDato y CResultado. De la clase CDato se utiliza el método ObtenerValor( ) y de la clase CResultado el método EstablecerResultado( ). En total existen nueve relaciones de dependencia, las cuales están ilustradas en la figura 3.2.1. Las clases que realizan peticiones de métodos son CInterfaz, COperacion, CSuma y CResta; las clases que reciben peticiones de métodos son COperacion, CSuma, CResta, CDato y CResultado. Una vez determinadas las clases colegas y los métodos que deben ser llamados a través de un mediador, se procede a crear dicho mediador, el cual contendrá la declaración original de los métodos antes mencionados con la diferencia que se agrega un parámetro adicional a cada método, el cual representa al objeto que realizó originalmente la llamada. Esto último se hace con la finalidad de preservar los valores originales que tuviera el objeto antes de la llamada y que pueden ser necesarios para realizar con éxito el método solicitado. En el ejemplo el mediador abstracto aMediador tiene el siguiente código: // Código del archivo aMediador.hpp #ifndef _aMediador #define _aMediador class CDato; class CResultado; class COperacion; class CSuma; class CResta; class aColega; class aMediador { protected: aColega *oCol1; public: aMediador() { } //Constructor virtual void EstableceOperacion ( COperacion *objCOperacion, int tipo , CDato valor1 , CDato valor2 , CResultado * resultado ) = 0; virtual void EstablecerResultado ( CResultado *objCResultado, int valor ) = 0; virtual int ObtenerResultado ( CResultado *objCResultado) = 0; virtual void EstablecerValor ( CDato *objCDato, int x ) = 0; virtual void Sumar ( CSuma *objCSuma, CDato sumando1 , CDato sumando2 , CResultado * suma ) = 0; virtual void Restar ( CResta *objCResta, CDato minuendo , CDato sustraendo , CResultado * resta ) = 0; virtual int ObtenerValor ( CDato *objCDato) = 0; }; // termina la clase aMediador #endif

Una vez declarada la clase mediadora abstracta se procede a realizar la clase mediadora concreta, la cual implementa las llamadas desde el mediador hacia las clases colegas. Para hacer esto posible, las clases que tienen los métodos que serán invocados desde el mediador deben tener una forma común de comunicación.

Page 48: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

36

Para lograrlo se crea una clase aColega que será padre para todas las clases colegas que sean base, es decir, que no tengan clases padres. Esta clase aColega tiene la declaración de las funciones que maneja el mediador. Si las clases colegas son derivadas entonces no se añade por herencia aColega a esta clase derivada sino a su clase base. Este proceso no se realiza cuando la clase que debería heredar de aColega es abstracta, es decir, tiene funciones virtuales puras. En este caso de clases abstractas, no se realiza nada con la clase aColega. Esta clase junto con sus clases derivadas se muestra en la figura 3.2.2.

cMediador

Sumar()EstablecerResultado()ObtenerResultado()Restar()EstableceOperacion()EstablecerValor()ObtenerValor()cMediador()

CSuma

<<virtual>> ~CSuma()CSuma()Sumar()

CResta

<<virtual>> ~CResta()CResta()Restar()

CDato

<<virtual>> ~CDato()CDato()EstablecerValor()ObtenerValor()

CResultado

<<virtual>> ~CResultado()CResultado()EstablecerResultado()ObtenerResultado()

COperacion

<<virtual>> ~COperacion()COperacion()EstableceOperacion()

aColega

<<virtual>> Sumar()<<virtual>> EstablecerResultado()<<virtual>> ObtenerResultado()<<virtual>> Restar()<<virtual>> EstableceOperacion()<<virtual>> EstablecerValor()<<virtual>> ObtenerValor()aColega()

aMediador

<<abstract>> Sumar()<<abstract>> EstablecerResultado()<<abstract>> ObtenerResultado()<<abstract>> Restar()<<abstract>> EstableceOperacion()<<abstract>> EstablecerValor()<<abstract>> ObtenerValor()aMediador()

#oMed

#oCol1

CInterfaz

<<virtual>> ~CInterfaz()CInterfaz()Ejecutar()

-valor1-valor2

-total

-operacion

#oMed

v oid CSuma::Sumar(CDato sumando1, CDato sumando2, CResultado *suma){

oMed = new cMediador();oMed->EstablecerResultado(suma,oMed->ObtenerValor(&(sumando1)) + oMed->ObtenerValor(&(sumando2)));

}

Fig. 3.2.2. Diagrama de Clases del Programa de Ejemplo Refactorizado

Para el caso del ejemplo refactorizado, la clase aColega tiene la siguiente implementación: // Código del archivo aColega.hpp #ifndef _aColega #define _aColega #include <stddef.h> class aMediador; class CDato; class CResultado; class aColega { protected: aMediador *oMed; public: aColega(){} //Constructor virtual void EstableceOperacion ( int tipo , CDato valor1 , CDato valor2 , CResultado * resultado ) ;

Page 49: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

37

virtual void EstablecerResultado ( int valor ) ; virtual int ObtenerResultado ( ) ; virtual void EstablecerValor ( int x ) ; virtual void Sumar ( CDato sumando1 , CDato sumando2 , CResultado * suma ) ; virtual void Restar ( CDato minuendo , CDato sustraendo , CResultado * resta ) ; virtual int ObtenerValor ( ) ; }; // termina la clase aColega #endif

// Código del archivo aColega.cpp #include "aColega.HPP" #include "Dato.h" #include "Resultado.h" void aColega:: EstableceOperacion ( int tipo , CDato valor1 , CDato valor2 , CResultado * resultado ) { } //fin del método EstableceOperacion void aColega:: EstablecerResultado ( int valor ) { } //fin del método EstablecerResultado int aColega:: ObtenerResultado ( ) { return 0; } //fin del método ObtenerResultado void aColega:: EstablecerValor ( int x ) { } //fin del método EstablecerValor void aColega:: Sumar ( CDato sumando1 , CDato sumando2 , CResultado * suma ) { } //fin del método Sumar void aColega:: Restar ( CDato minuendo , CDato sustraendo , CResultado * resta ) { } //fin del método Restar int aColega:: ObtenerValor ( ) { return 0; } //fin del método ObtenerValor

La clase mediadora concreta cMediador tiene el siguiente código: // Código del archivo cMediador.hpp #ifndef _cMediador #define _cMediador #include "aMediador.HPP" #include "Dato.h" #include "Resultado.h" #include "Operacion.h" #include "Suma.h" #include "Resta.h" class cMediador : public aMediador { public: cMediador() { } //Constructor void EstableceOperacion ( COperacion *objCOperacion, int tipo , CDato valor1 , CDato valor2 , CResultado * resultado ); void EstablecerResultado ( CResultado *objCResultado, int valor ); int ObtenerResultado ( CResultado *objCResultado); void EstablecerValor ( CDato *objCDato, int x); void Sumar ( CSuma *objCSuma, CDato sumando1 , CDato sumando2 , CResultado * suma ); void Restar ( CResta *objCResta, CDato minuendo , CDato sustraendo , CResultado * resta );

Page 50: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

38

int ObtenerValor ( CDato *objCDato); protected: }; // termina la clase cMediador #endif

// Código del archivo cMediador.cpp #include "cMediador.HPP" void cMediador:: EstableceOperacion ( COperacion *objCOperacion, int tipo , CDato valor1 , CDato valor2 , CResultado * resultado) { oCol1 = new COperacion(); oCol1 = objCOperacion; oCol1->EstableceOperacion(tipo,valor1,valor2,resultado); } //fin del método EstableceOperacion void cMediador:: EstablecerResultado ( CResultado *objCResultado, int valor) { oCol1 = new CResultado(); oCol1 = objCResultado; oCol1->EstablecerResultado(valor); } //fin del método EstablecerResultado int cMediador:: ObtenerResultado ( CResultado *objCResultado) { oCol1 = new CResultado(); oCol1 = objCResultado; return(oCol1->ObtenerResultado( )); } //fin del método ObtenerResultado void cMediador:: EstablecerValor ( CDato *objCDato, int x) { oCol1 = new CDato(); oCol1 = objCDato; oCol1->EstablecerValor(x); } //fin del método EstablecerValor void cMediador:: Sumar ( CSuma *objCSuma, CDato sumando1 , CDato sumando2 , CResultado * suma) { oCol1 = new CSuma(); oCol1 = objCSuma; oCol1->Sumar(sumando1,sumando2,suma); } //fin del método Sumar void cMediador:: Restar ( CResta *objCResta, CDato minuendo , CDato sustraendo , CResultado * resta) { oCol1 = new CResta(); oCol1 = objCResta; oCol1->Restar(minuendo,sustraendo,resta); } //fin del método Restar int cMediador:: ObtenerValor ( CDato *objCDato) { oCol1 = new CDato(); oCol1 = objCDato; return(oCol1->ObtenerValor( )); } //fin del método ObtenerValor

Como se puede observar a través de los objetos oCol1 de clases colegas, el mediador transmite los mensajes. En caso que se tuviera que comunicar a través de una clase abstracta, no se sigue la estrategia de utilizar objetos colegas, sino se transmite directamente la llamada a la función a través del objeto que originalmente hizo la llamada. El diagrama de clases del programa de ejemplo refactorizado se muestra en la figura 3.2.2. En este diagrama se notan los nuevos canales de comunicación, que claramente han disminuido y se han centrado en las clases mediadoras. También se nota como la clase aColega ahora es la clase base de COperacion, CSuma, CResta, CDato y CResultado.

Page 51: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

39

Las llamadas que existían de las clases CInterfaz, COperacion, CSuma y CResta hacia otras clases, ahora van directamente a aMediador, la cual a través de cMediador redirige las llamadas hacia los destinos adecuados. Las funciones que utilizaban a métodos de otras clases ahora utilizan a un objeto mediador oMed, de tipo aMediador, que toma la forma del mediador concreto cMediador en donde se requiera. El objeto mediador es agregado a las clases bases de las clases colegas, ya sea en aColega o en la superclase si la clase colega era derivada, o en la propia clase colega si es una clase abstracta. El nuevo código de las funciones que llamaban métodos a través de objetos de otras clases es el siguiente: // Del archivo Interfaz.cpp void CInterfaz::Ejecutar() { oMed = new cMediador(); int valor; int opcion; printf ("Ejemplo de Operaciones Basicas\n\n"); printf ("Introduzca valor # 1: "); scanf ("%d",&valor); oMed->EstablecerValor( &(valor1) , valor); printf ("Introduzca valor # 2: "); scanf ("%d",&valor); oMed->EstablecerValor( &(valor2) , valor); oMed->EstablecerResultado( &(total) , 0); printf ("\nPresionar 1 para sumar, 2 para restar\n"); scanf ("%d",&opcion); oMed->EstableceOperacion( &(operacion) , opcion,valor1,valor2,&total); printf ("El resultado es: %d",oMed->ObtenerResultado( &(total) )); printf ("\nFIN DE PROGRAMA"); getch(); }

// Del archivo Operacion.cpp void COperacion::EstableceOperacion(int tipo, CDato valor1, CDato valor2, CResultado *resultado) { oMed = new cMediador(); switch (tipo){ case 1: CSuma *operacion1; operacion1=new CSuma(); oMed->Sumar( operacion1 , valor1,valor2,resultado); break; case 2: CResta *operacion2; operacion2=new CResta(); oMed->Restar( operacion2 , valor1,valor2,resultado); } }

// Del archivo Suma.cpp void CSuma::Sumar(CDato sumando1, CDato sumando2, CResultado *suma) { oMed = new cMediador(); oMed->EstablecerResultado( suma , oMed->ObtenerValor( &(sumando1) ) + oMed-> ObtenerValor( &(sumando2) )); }

// Del archivo Resta.cpp void CResta::Restar(CDato minuendo, CDato sustraendo, CResultado *resta) { oMed = new cMediador(); oMed->EstablecerResultado( resta , oMed->ObtenerValor( &(minuendo) ) – oMed-> ObtenerValor ( &(sustraendo) )); }

Page 52: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

40

3.3 ALGORITMO DE REDUCCIÓN DE ACOPLAMIENTO 1. Por cada conjunto de clases colegas que se comuniquen entre sí: 2. Generar la clase mediadora abstracta.

2.1. Crear un archivo de definición, con extensión “.HPP” para la declaración de la clase mediadora abstracta. El nombre para la clase y el archivo se obtiene del campo cMed_abstracta de la tabla “mediador”.

2.2. Escribir las directivas al pre-procesador “#ifndef _nomAMediador”, y “#define _nomAMediador”, donde _nomAMediador es el nombre de la clase abstracta obtenido en el paso 2.1.

2.3. Añadir la palabra “class” con el nombre del archivo que contiene la clase aColega base creada (si se requiere), repetir por cada clase colega base existente: “class Colegabase.hpp”.

2.4. Agregar al archivo la palabra reservada “class” seguida del nombre de la clase y una llave que abre “{”.

2.5. Agregar al archivo la declaración protegida de un objeto por cada una de las clases colega base, con las siguientes líneas: “protected:” “Colega *objcol;” donde: Colega es el nombre de la clase colega base y objcol es el nombre del objeto.

2.6. Agregar al archivo la declaración pública del constructor de la clase con la cadena siguiente: “nomAMediador () { }”.

2.7. Obtener de la tabla “metodos” los nombres de los métodos en donde se realizarán las llamadas al mediador.

2.8. Agregar estos métodos en las declaraciones públicas, como métodos virtualmente puros de la siguiente manera: “virtual tipo nomMetodo(parámetros) = 0;” en donde tipo es el tipo de dato que regresa el método, nomMetodo es el nombre del método y parámetros es la lista de parámetros que recibe el método. Se agrega un parámetro adicional el cual representa al objeto que realizó originalmente la llamada.

2.9. Añadir la llave que cierra la clase “}” seguido de “;”. 2.10. Escribir en este archivo “#endif” que declara la directiva de terminación de

definición al pre-procesador. 3. Generar la definición de la clase mediadora concreta.

3.1. Crear un archivo de definición con extensión “.HPP” para la declaración de la clase mediadora concreta. El nombre para la clase y el archivo se obtiene del campo cMed_concreta de la tabla “mediador”.

3.2. Escribir las directivas al pre-procesador “#ifndef _nomCMediador” y “#define _nomCMediador” donde _nomCMediador es el nombre de la clase mediadora concreta obtenido en el paso 3.1.

3.3. Escribir el texto que declara la directiva al pre-procesador siguiente: “#include “nomAMediador.hpp” en donde nomAMediador es el nombre del archivo que contiene la declaración de la clase mediadora abstracta, que se definió en el paso 2. También agregar las directivas “#include” correspondientes a las clases colegas que interactúan.

3.4. Obtener de la tabla “mediador” el nombre del mediador concreto y escribir la declaración de la clase mediadora concreta heredando de su clase mediadora abstracta (del paso 2) de la forma siguiente: “class nomCMediador : public

Page 53: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

41

nomAMediador {”. En donde nomCMediador y nomAMediador son los nombres de las clases mediadoras concreta y abstracta respectivamente.

3.5. Añadir al archivo la declaración pública del constructor con la siguientes cadenas: “public :” “nomCMediador( ){}”.

3.6. Obtener de la tabla “llamadas_filtro” los nombres de los métodos en donde se realizarán las llamadas a través del mediador, luego obtener de la tabla “metodos” la información correspondiente a dichos métodos y agregarlos en el archivo en la parte de declaraciones públicas de la siguiente forma: “tipo método (parámetros);” donde tipo es el tipo de dato que regresa el método, método es el nombre del método y parámetros es la lista de parámetros que recibe el método. Se agrega un parámetro adicional como en el punto 2.8

3.7. Terminar la declaración de la clase concreta nomCMediador con una llave que cierra “}” seguido de “;”.

3.8. Escribir la directiva de terminación de definición al pre-procesador con el texto “#endif”.

4. Generar la implementación de la clase mediadora concreta.

4.1. Crear un archivo con extensión “.CPP” para la implementación de la clase nomCMediador. El nombre para la clase y el archivo se obtiene del campo cMed_concreta de la tabla “mediador”.

4.2. Escribir en este archivo la declaración de la directiva al pre-procesador siguiente. #include “nomCMediador.hpp” en donde nomCMediador es el nombre del archivo que contiene la declaración de la clase concreta nomCMediador, el cual se obtiene como en el paso 4.1.

4.3. Agregar su implementación de la forma siguiente: “Tipo nomCMediador :: método (parámetros) {” donde Tipo es el tipo de datos que regresa el método, nomCMediador es el nombre del mediador concreto, método es el nombre del método y parámetros es la lista de parámetros que recibe el método. También se agrega un parámetro adicional como en el punto 2.8.

4.4. Obtener de la tabla “metodos” el nombre de la clase propietaria del método original; donde nom_objOrig es el nombre original del objeto con el que se realiza la llamada, y objColx es el nombre del objeto colega creado.

Cuando el método proviene de una clase abstracta y: El tipo del método es “void” escribir: “nom_objOrig ->métodos(parámetros);” El tipo del método es objeto o puntero a objeto escribir: “return (nom_objOrig ->métodos(parámetros));” Cuando el método proviene de una clase base o derivada y: El tipo del método es “void” escribir:

objColx = new Clase( ); objColx = objClase; objColx -> métodos(parámetros); El tipo del método es diferente de“void” y no es de tipo objeto escribir: objColx = new Clase( ); objColx = objClase; return(objColx -> métodos(parámetros));

4.5. Terminar la implementación del método con una llave que cierra “}”.

Page 54: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

42

4.6. Repetir a partir del paso 4.3 por cada método al que se va a implementar las llamadas a través del mediador.

5. Generar la clase colega abstracta.

5.1. Crear un archivo de definición, con extensión “.HPP” para la declaración de la clase colega. El nombre para la clase y el archivo se obtiene del campo cCol_abstracta de la tabla “mediador”.

5.2. Escribir las directivas al pre-procesador “#ifndef _nomAColega”, y “#define _nomAColega”.

5.3. Agregar las directivas “#include<stddef.h>” para utilizar la palabra NULL. 5.4. Incluir el archivo donde se encuentra la clase mediadora abstracta, con la siguiente

cadena: “class nomAMediador;”, en donde nomAMediador es el nombre de la clase mediadora abstracta. El cual se obtiene del campo cMed_abstracta de la tabla “mediador”.

5.5. Agregar los “class nom_clase” necesarios para que se reconozcan objetos declarados en parámetros y valores de retorno.

5.6. Agregar al archivo la palabra reservada “class” seguida del nombre de la clase y una llave que abre “{“.

5.7. Agregar al archivo la declaración protegida de un objeto tipo mediador con la siguiente línea: “aMediador *objmed”, objmed se obtiene del campo obj_mediador de la tabla “mediador”.

5.8. En las declaraciones públicas agregar el constructor de la clase: “nomAColega(){}” 5.9. En la parte pública, por cada método al que el objeto mediador realice las llamadas,

agregar la línea siguiente: “virtual tipo método (parámetros);”. 5.10. Añadir la llave que cierra la clase “}” seguido por “;”. 5.11. Escribir en este archivo “#endif” que declara la directiva de terminación de

definición al pre-procesador. 6. Generar la implementación de la clase colega concreta.

6.1. Crear un archivo con extensión “.CPP” para la implementación de la clase nomCColega. El nombre para la clase y el archivo se obtiene del campo cCol_abstracta de la tabla “mediador”.

6.2. Escribir en este archivo la declaración de la directiva al pre-procesador siguiente. #include “nomAColega.hpp” en donde nomAColega es el nombre del archivo que contiene la declaración de la clase concreta nomCConcreta, el cual se obtiene como en el paso 6.1.

6.3. Agregar su implementación de la forma siguiente: “Tipo nomCColega :: método (parámetros) {” donde Tipo es el tipo de datos que regresa el método, nomCColega es el nombre del mediador concreto, método es el nombre del método y parámetros es la lista de parámetros que recibe el método.

6.4. Agregar los métodos que pertenecen a las clases que ahora van a ser derivadas de aColega.

Cuando el método proviene de una clase abstracta y: El tipo del método es “void” escribir: Se implementa vacía. El tipo del método es objeto, declarar un objeto de su tipo y escribir: “ Clase objClase;” “ return objClase;” El tipo del método es puntero a objeto escribir:

Page 55: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

43

“return NULL;” El tipo del método es diferente de“void” escribir y no es de tipo objeto: “return 0;”

6.5. Terminar la implementación del método con una llave que cierra “}”. 6.6. Repetir a partir del paso 4.3 por cada método al que se va a implementar las

llamadas a través del mediador.

7. Modificar las clases colegas que interactúan entre si. Si las clases colegas son independientes, es decir que no derivan de ninguna clase base o si las clases son abstracta, entonces hacer que la clase derive de la clase colega abstracta aColega, y realizar los siguientes pasos:

7.1. Obtener del campo cCol_abstracta, en la tabla “mediador”, el nombre de la clase colega abstracta de la cual van a heredar las clases colegas.

7.2. Abrir el archivo en donde se encuentra la definición de la clase colega. 7.3. Escribir el texto que declara la directiva al pre-procesador siguiente: #include

“aColega.hpp” en donde aColega es el nombre del archivo que contiene la declaración de la clase abstracta aColega, definida en el paso 5.

7.4. Sustituir la línea en donde se encuentra la definición de la clase colega por lo siguiente: “Class Nombre_clase : public aColega {” donde Nombre_clase es el nombre de la clase colega y aColega es el nombre de la clase colega abstracta.

Si las clases colegas derivan de una clase base, abrir el archivo que contiene la definición de su clase base y realizar el punto 5.5 y 5.7. 8. Agregar a las clases colegas, en cada función en donde se realizan las llamadas.

8.1. Hacer que el objeto de tipo mediador abstracto tome la forma de la clase mediadora concreta, agregando la siguiente línea: “oMed = new cMediador();”

8.2. En la línea en donde se encuentra la llamada al método, sustituir el objeto que realiza la llamada por el objeto mediador como se ve en la siguiente línea: “oMed->método (Parámetros);” donde oMed es el objeto mediador que sustituye al objeto existente, método es el nombre del método al que se realiza la llamada, y parámetros son los parámetros que recibe el método. En la parte de los parámetros se agrega un parámetro extra que es el objeto que realizaba la llamada pasándolo por referencia.

Precondiciones del Algoritmo Como todo método de refactorización, para ser ejecutado, debe validar ciertas precondiciones para que sea posible y factible la transformación del código fuente y llevar a cabo un rediseño exitoso. Todas las precondiciones son verificadas de manera automática por la herramienta antes de tratar de llevar a cabo la refactorización. Las precondiciones del método de reducción de acoplamiento son: Los nombres de las clases mediadoras y colegas que se agregan no deben estar siendo

usados por otra clase; la misma condición aplica para los nombres de los objetos de tipo mediador y colega.

Se debe verificar en la arquitectura del marco que no existan clases que estén haciendo la función de un mediador, ya que si existen no se mejorará la arquitectura actual, sino sólo se extenderá el paso de mensajes. Para verificar esta condición se analiza el

Page 56: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

44

porcentaje total de canales de comunicación que tienen las clases del marco, y si una sola clase excede el límite entonces no se realiza la refactorización.

Esta última precondición se verifica con cada clase del marco, tomando en cuenta tanto las llamadas que hace la clase como las llamadas que recibe, es decir, todas las líneas de dependencia con otras clases sin importar la dirección. De acuerdo a experimentación, se ha determinado que una clase se puede considerar mediadora si controla el 60% o más de los canales de comunicación. En el capítulo de “Evaluación Experimental” se detallarán los datos obtenidos experimentalmente, en donde se observa las tendencias de los marcos antes y después de la refactorización, con el porcentaje máximo de canales de comunicación que controla una sola clase. 3.4 CÁLCULO DE LA MÉTRICA FACTOR DE ACOPLAMIENTO (COF) La métrica COF sirve para calcular el factor de acoplamiento de un sistema debido a múltiples relaciones de dependencia entre clases incluyendo las llamadas a funciones, la creación de objetos y destrucción de objetos. En esta tesis sólo se consideran las llamadas a métodos o funciones que ocurren en primera instancia, es decir, llamadas a funciones de otras clases de manera directa o a través de clases abstractas, excepto mensajes entre clases hermanas o entre clases base con sus clases derivadas. Los datos a considerar para el cálculo de la métrica es el número total de clases y las relaciones de dependencia entre clases debido al paso de mensajes. Se considera que una clase A tiene una relación de dependencia con otra clase B, si una función de la clase A o de una instancia de A, invoca a una función de la clase B o instancia de B. En caso de que exista una instancia de B, esta no tiene que estar necesariamente declarada en la clase A. En la métrica no se toma en cuenta cuántos métodos de una clase son invocados por otra clase, sino que todos cuentan como una sola dependencia, lo único que importa es cuántas clases tienen dependencia con una clase en particular. En la métrica se considera la sumatoria de estas dependencias como se mostró en la sección 2.8 “Métricas de Software”. De manera simplificada se manejará la fórmula de COF como:

TCTCD

COF−

= ∑2

Donde: Σ D es la sumatoria de dependencias. TC es el total de clases. Para el cálculo de la métrica se utilizan los datos almacenados en la base de datos, en especial de las tablas: “clases”, “metodos”, “llamadas_filtro” y “objetoscreados”. La tabla

Page 57: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

45

“clases” es usada para obtener el total de clases, y las otras tablas para encontrar las llamadas que surgen de una clase hacia otra. Para entender mejor el manejo de la métrica COF, considerando únicamente dependencia por paso de mensajes, se utilizará el marco que se ha manejado como ejemplo a través de esta tesis. En el marco de la figura 3.2.1 se muestran las relaciones de dependencia que existen entre las clases. Se puede observar que el total de clases es TC = 6, y el total de la sumatoria es Σ D = 9, por tanto, COF = 9 / (62 - 6) = 0.3000. En este caso se observa que el valor es muy alto de acuerdo a lo establecido por la métrica COF, como se explicó en el capítulo 2. Considerando lo anterior, es necesario refactorizar el marco para mejorar la comunicación entre sus clases. Al aplicar el método de refactorización propuesto en esta tesis al marco de la figura 3.2.1, se obtuvo el marco de la figura 3.2.2, en donde se muestran también las nuevas relaciones de dependencia. Al igual que en el caso anterior, se calcula la métrica y se obtiene que TC = 9, Σ D = 5 y COF = 5 / (92 - 9) = 0.0694. El nuevo valor de la métrica indica que se ha disminuido el problema de acoplamiento de clases, ya que la mayor parte de la comunicación en el marco fluye a través de la clase mediadora aMediador. 3.5 DISEÑO CONCEPTUAL DEL SISTEMA El sistema se encuentra conformado por dos módulos: Módulo que calcula el nivel de acoplamiento utilizando la métrica COF y el módulo que realiza el método de reducción de acoplamiento. La implementación del sistema fué desarrollada en el lenguaje de programación Java y en el metalenguaje JavaCC para la generación del analizador, las tablas de información son gestionadas por el sistema manejador de base de datos MySQL. En la figura 3.5.1 se presenta un diagrama donde se muestran los módulos que integran el sistema y como se encuentran relacionados.

Page 58: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

46

Fig. 3.5.1. Diagrama del Diseño Conceptual del Sistema

3.6 ANÁLISIS DEL SISTEMA A continuación se presenta el análisis del sistema modelado con diagramas de casos de uso de UML. La Figura 3.6.1 muestra el diagrama general de la herramienta, mostrando las opciones que tiene el usuario. Hay cuatro casos de uso principales: Manejar Archivo, Análisis Sintáctico, Métrica, y Método. Los actores son: Usuario, la persona que usa la herramienta; Archivo Original, archivos del marco que escoge el usuario y serán refactorizados; Archivo Fuente, posible copia de seguridad de los archivos originales; Archivo Final, los archivos originales modificados usando los métodos de refactorización; y Base de Datos, para contener el análisis sintáctico y parte de la refactorización. La Figura 3.6.2 muestra el diagrama del caso de uso Manejar Archivo, que debe ser invocado antes de hacer cualquier otra operación.

Page 59: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

47

DiagramaPrincipal

Archivo FuenteManejar Archivo

Usuario

Análisis Sintáctico

Métrica

<<include>>

Archivo FinalMétodo

<<include>>

Archivo Original

BaseDatos

Fig. 3.6.1. Diagrama de Casos de Uso Principal

Caso de UsoManejar Archivo

Archivo Fuente

Usuario

Crear Copia de ArchivoArchivo Original

Seleccionar Archivo

Fig. 3.6.2. Diagrama del Caso de Uso Manejar Archivo

Primero se seleccionan todos los archivos del marco que se desean analizar y refactorizar, y opcionalmente se puede crear una copia de seguridad de estos archivos. La Figura 3.6.3 muestra el diagrama del caso de uso Análisis Sintáctico, que puede ser invocado ya sea desde la pantalla de la métrica o la del método de refactorización. Primero se encuentran las clases con su jerarquía, también todas las funciones, los objetos creados, y por último las llamadas entre clases. Adicionalmente se encuentran las clases ligadas por directivas #include.

Page 60: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

48

Caso de UsoAnálisis Sintáctico

Encontrar llamadas

BaseDatos

Encontrar Jerarquía de Clases

Archivo Original

Métrica

Encontrar Clases

<<include>>

<<include>>Método

<<include>>

Encontrar Métodos y Objetos

Encontrar #include

<<include>>

Fig. 3.6.3. Diagrama del Caso de Uso Análisis Sintáctico

La Figura 3.6.4 muestra el diagrama del caso de uso Métrica, que es invocado después del análisis sintáctico cuando se elige la opción de Calcular Métrica COF.

Caso de UsoMétrica

Usuario

Interpretar Resultado

Análisis SintácticoBaseDatos

Calcular COF

<<include>>

Fig. 3.6.4. Diagrama del Caso de Uso Métrica

Primero se debió de hacer el análisis sintáctico, y se calcula la métrica basada en la información de la base de datos. De acuerdo al valor de la métrica, se emite una interpretación del resultado, con la acción recomendada a seguir. La Figura 3.6.5 muestra el diagrama del caso de uso Método, que es invocado cuando se hace la refactorización. Antes de aplicar el método se validan las precondiciones y, posteriormente se pasa a la refactorización. Este caso consiste en crear las nuevas clases para aplicar el método de refactorización, y modificar las llamadas utilizando a estas clases.

Page 61: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

49

Caso de UsoMétodo

Usuario

Archivo FinalValidar precondiciones

Aplicar método de refactorización

<<include>>

BaseDatos

Análisis Sintáctico

<<include>>

Archivo Original

Fig. 3.6.5. Diagrama del Caso de Uso Método

Primero se crea la clase mediadora abstracta, posteriormente se crea la concreta. De ahí se debe crear la implementación de la clase mediadora concreta, incluyendo todos los métodos que serán redireccionados. Se crea la clase colega abstracta, y se cambian a las clases colegas que están interactuando para que utilicen a la colega abstracta, por último se hace el cambio de llamadas entre colegas para que utilicen el mediador concreto. 3.7 DISEÑO DEL SISTEMA La aplicación desarrollada en esta teis se encuentra integrada al sistema SR2 Refactoring; para diseñar este sistema se utilizaron varios patrones de diseño, con el fin de darle facilidades de extensión a la herramienta. Esta arquitectura permitió la integración de otros dos métodos de refactorización al actual [Sant04c] y [Vald04], y se podrían agregar más en el futuro. Se utiliza el patrón de diseño ‘Singleton’ para manejar las pantallas internas que tiene el sistema, de tal manera que sólo exista una instancia por pantalla, y todas ellas están contenidas en la pantalla principal. Cada pantalla tiene acceso a la base de datos de manera directa. La estructura de pantallas se muestra en la figura 3.7.1, además se muestran otras clases que dan soporte a la aplicación. Las pantallas que pertenecen al sistema hecho en esta tesis se representan por las clases FrameMetricaCOF, que se encarga de mostrar la pantalla correspondiente al cálculo de la métrica de factor de acoplamiento, y FrameMetodoMediador la cual muestra los botones y controles para realizar el análisis del código y la refactorización del marco.

Page 62: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

50

UtileriasContador

JFrame(f rom swing)

JInternalFrame(from swing)

ActionListener(from event)

<<Interface>>

Command

Principal

-comando

BaseDatos

+baseDA

FrameInterno

+comando

+frameMetricaCOF, +frameMetodoMediador, +frameComparacion

+base

FiltroArchivos

UtileriasArchivo

-filtro FrameComparacion

-$instancia

FrameMetricaCOF

-$instancia

FrameMetodoMediador

-$instancia

Fig. 3.7.1. Estructura de Clases de las Pantallas de la Aplicación

Se utiliza el patrón de diseño ‘Command’ para manejar los eventos generados en las pantallas por los botones, menús y listas desplegables. Se maneja una clase de tipo ‘Command’ por acción, teniendo todos los comandos de una pantalla un ‘Command’ genérico que implementa el patrón ‘Template Method’. Aparte cada clase Command genérica cuenta con una instancia de la pantalla a la que corresponde, para acceder de manera directa a sus elementos y poderlos modificar. Y a través del objeto de pantalla se puede acceder a la base de datos. La estructura de comandos se muestra en la figura 3.7.2, con las agregaciones que tienen cada uno de los comandos genéricos de pantalla. Todo este marco de pantallas y comandos fue diseñado por Manuel Valdés Marrero en [Vald04], donde se encuentra explicado a detalle la intención y funcionalidad de cada clase, así como el modo de comunicación y funcionamiento entre los comandos y las pantallas. Las clases de tipo comando que pertenecen al método de reducción de acoplamiento son las siguientes: CommandMetodoMediador, CommandMetodoMediadorAnalizar, Command MetodoMediadorEjecutar, CommandMetodoMediadorActualizar, CommandMetrodo MediadorModificar, CommandMetrodoMediadorCancelar, CommandMetricaCOF, CommandMetricaCOFAnalizar, CommandMetricaCOFEjecutar. Se muestran además una de las clases generadas por JavaCC para hacer el análisis sintáctico, CPPParser, invocado desde distintos comandos. Cada uno de los métodos de refactorización integrados en esta interfaz de usuario tiene su propio analizador, incluido en un paquete con el nombre del método. Se agregó además la funcionalidad de manejar usuarios del sistema, debido a que es necesario controlar los cambios que se le hagan a un

Page 63: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

51

marco, los cuales sólo deben ser hechos por el administrador del marco y notificados a todos los usuarios del marco.

CommandPrincipalComparacionCommandPrincipalOriginales

Command

CommandComparacionCompararCommandComparacionFuentesCommandComparacionOriginales

FrameComparacion

CommandComparacion

#frame

Principal CommandPrincipal+frame

CommandPrincipalMetodoMediadorCommandPrincipalMetricaCOF

CommandMetricaCOFFrameMetricaCOF #frame

CommandMetricaCOFEjecutar CommandMetricaCOFAnalizar

CommandMetodoMediadorAnalizar

CPPParser(f rom mediador)

$parser

$parser

CommandMetodoMediadorActualizar

CommandMetodoMediadorModificar

CommandMetodoMediadorCancelar

CommandMetodoMediadorEjecutar

CommandMetodoMediador

FrameMetodoMediador

#frame

Fig. 3.7.2. Estructura de Clases de los Comandos de la Aplicación

CommandAccesos

FrameAccesos

#frame

CommandAccesosCancelar

CommandAccesosEliminar

CommandAccesosGuardar

CommandAccesosModificar

CommandAccesosMostrar

CommandAccesosNuevo

CommandPassword

FramePassword

#frame

CommandPasswordAceptar

CommandPrincipalAccesos CommandPrincipalPasswordCommandPrincipalUsuarios

CommandUsuarios

FrameUsuarios

#frame

CommandUsuariosCancelar

CommandUsuariosEliminar

CommandUsuariosGuardar

CommandUsuariosModificar

CommandUsuariosMostrar

CommandUsuariosNuevo

CommandPrincipal

Command

Principal

+frame

-comando

FrameInterno

+comando

+frameAccesos, +frameUsuario, +framePassword

Fig. 3.7.3. Estructura de Clases del Manejo de Usuarios

En la Figura 3.7.3 se muestra la vista de la jerarquía de clases que se encargan de hacer este control. Esta funcionalidad fue agregada en [Vald04] y ahí se explica como funciona. También se explica como puede ser extendido el sistema para agregar nuevos métodos de refactorización y nuevas métricas.

Page 64: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

52

3.8 HERRAMIENTA SR2 REFACTORING La herramienta creada para resolver el problema de acoplamiento de clases por una gran cantidad de canales de comunicación está integrada en la herramienta denominada “SR2 Refactoring” [Vald04] y forma parte del proyecto “SR2: Reingeniería de Software Legado para Reuso” [Sant02]. La pantalla principal de la aplicación se observa en la figura 3.8.1. El proyecto SR2 consta de otros dos métodos de refactorización aparte del descrito aquí, y por ello fue necesario crear una interfaz que englobara a estos otros métodos de refactorización, los cuales son: Método de Adaptación de Interfaces [Sant04c] y Método de Separación de Interfaces [Vald04], ésta última implementa también la medición de la métrica V-DINO (Valdés – Dependencia por Interfaces que No se Ocupan) [Sant04a]. Aparte, el trabajo descrito aquí agrega el Método de Reducción de Acoplamiento y la Métrica COF. Como estos métodos de refactorización no serán los únicos en el proyecto, se diseñó la interfaz de tal manera que puedan soportar otras pantallas y métricas, y para ello se utilizaron los patrones de diseño ‘Singleton’ y ‘Command’ del catálogo de Gamma [Gamm95].

Fig. 3.8.1. Pantalla Principal de SR2 Refactoring

La pantalla cuenta con seis menús: Archivo para seleccionar archivos de origen, cambiar de sesión de usuario y para salir del sistema, Métricas para seleccionar la métrica V-DINO o la métrica COF, Métodos de Refactorización para seleccionar uno de los tres métodos disponibles, Comparación para comparar los archivos originales con los refactorizados,

Page 65: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

53

Usuarios para manejar los tipos de acceso y usuarios, y Ayuda para la información del sistema. Para autenticar usuarios cuando se entra por primera vez al sistema, o cuando se cambia de sesión de usuario se utiliza la pantalla mostrada en la figura 3.8.2. En esta pantalla se selecciona uno de los usuarios registrados en el sistema en la lista Usuario, escribiendo su nombre de usuario, Login, y su clave de acceso, Password. De acuerdo al tipo de acceso que tenga asignado el usuario se habilitan los menús a los que tiene derecho a usar.

Fig. 3.8.2. Pantalla de Autenticación de Usuarios

Fig. 3.8.3. Diálogo para Abrir Múltiples Archivos

Para seleccionar los archivos originales se cuenta con el cuadro de diálogo “Seleccionar Archivos Originales”, mostrado en la figura 3.8.3, que permite abrir los múltiples archivos fuente de C++, con las extensiones c, cpp, h y hpp, a los que se desea reducir su acoplamiento mediante el proceso de refactorización. Después de seleccionar los archivos o agregar más a la selección actual, el sistema pregunta si se desea realizar copia de seguridad de estos archivos seleccionados, para conservar la versión original del marco ya que los archivos seleccionados pueden ser modificados por alguno de los métodos de refactorización. Cuando se abren nuevos archivos se borran todas las bases de datos y los datos de las pantallas. A continuación se presentan las pantallas correspondientes al método de reducción de acoplamiento y al cálculo de la métrica del factor de acoplamiento. La Figura 3.8.4 muestra

Page 66: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

54

la pantalla para el cálculo de la métrica COF, que sirve como referencia al usuario para decidir si realiza o no la refactorización de su código fuente. Esta pantalla tiene el botón que realiza la ejecución del análisis sintáctico del código fuente.

Fig. 3.8.4. Pantalla de la Métrica COF

La pantalla cuenta con el botón Realizar análisis para ejecutar el análisis sintáctico del código y llenar la base de datos, después de este proceso se activa el botón Cálculo COF para calcular el factor de acoplamiento. Se muestran los valores del total de clases y el total de canales de comunicación, así como el valor de la métrica Factor de Acoplamiento COF; aparte se muestra una Recomendación para interpretar el valor de la métrica. La Figura 3.8.5 muestra la pantalla del método que sirve para modificar el código fuente del usuario según el método de refactorización. Esta pantalla también cuenta con el botón que realiza la ejecución del análisis sintáctico, permitiendo poder refactorizar sin pasar por la pantalla de la Figura 3.8.4, pero si el proceso ya fue hecho en dicha pantalla, no se vuelve a realizar. Es en esta parte donde se realiza el proceso de refactorización del código, incorporándole la arquitectura del patrón de diseño ‘Mediator’. Cuenta con el botón Analizar código para ejecutar el análisis sintáctico del código y llenar la base de datos. Se cuenta con el botón Aplicar Mediador que será el encargado de realizar la refactorización automática, después de verificar que se cumplan las precondiciones del método y tomar los datos del usuario

Page 67: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

55

con respecto a las nuevas clases y objetos. La pantalla le permite al usuario cambiar los nombres de las clases y de los objetos que van a generarse en el proceso de refactorización.

Fig. 3.8.5. Pantalla del Método de Refactorización

Esta interfaz fue enriquecida con una pantalla para comparar archivos, para verificar de manera visual los cambios hechos a los archivos originales, pero esto sólo está disponible si se eligió crear la copia de seguridad de los archivos fuente en la pantalla de la Figura 3.8.3. Dicha pantalla se muestra en la Figura 3.8.6. La pantalla cuenta con dos secciones para mostrar un Archivo Fuente y un Archivo Refactorizado. En la primera muestra las copias de seguridad de los archivos, si es que se hicieron, y en la segunda se muestran los archivos seleccionados en el cuadro de diálogo de la Figura 3.8.3, ya sea modificados o sin modificar. Para realizar el registro de usuarios que tienen permiso de usar el sistema, se utiliza la pantalla mostrada en la Figura 3.8.7. Estos usuarios tienen derecho a usar sólo ciertas partes del sistema, las que son especificadas en el tipo de Acceso de Usuario.

Page 68: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

56

Fig. 3.8.6. Pantalla de Comparación de Archivos

Fig. 3.8.7. Pantalla de Registro de Usuarios

Page 69: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 3

57

Para especificar los tipos de accesos se utiliza la pantalla mostrada en la Figura 3.8.8, que permite crear accesos genéricos que después se les asignarán a los usuarios. Aquí se especifica que menús son permitidos y que menús estarán desactivados. El menú Archivo y Ayuda están disponibles para todos los usuarios.

Fig. 3.8.8. Pantalla de Tipos de Accesos

Page 70: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

58

CAPÍTULO 4 EVALUACIÓN EXPERIMENTAL Se realizan las pruebas a la herramienta creada utilizando tres casos de prueba, en donde se analiza tanto el método de refactorización como el cálculo de la métrica para detectar el problema de acoplamiento de clases. En cada caso se muestran los diagramas de clases del código legado y del código refactorizado, las clases y funciones que intervienen en el problema y los cálculos de la métrica antes y después de la refactorización.

Page 71: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

59

4.1 CASO DE PRUEBA 1: SISTEMA DE CONTROL DE PROCESOS Aquí se analiza un programa hecho para el sistema de control de procesos distribuidos para los módulos del sistema 'SAC', del departamento de instrumentación y control del Instituto de Investigaciones Eléctricas. La función del sistema es manejar dos tablas de datos, una de señales analógicas y la otra de señales digitales para un sistema de control de procesos distribuidos. La arquitectura de clases de este programa fue obtenida de [Sant02] y se muestra en la figura 4.1.1. Dentro de la arquitectura se muestra la clase Contex1, que es la aplicación cliente e implementa la interfaz del sistema, por tanto no será tomada en cuenta en el estudio, ya que únicamente nos interesa el marco. En el diagrama se observan las relaciones de dependencia que existen entre las clases del marco. Las clases cStr11, cStr12, cStr13, cStr14, cStr15 y cStr16 son las clases que tienen llamadas hacia métodos de otras clases. Las clases que reciben las llamadas son MSG, VARIABLES, VALORES, GRUPOS y por último BDBASE, que redirige las llamadas a sus clases derivadas, pero estas llamadas no se toman en cuenta ya que se considera que las relaciones de herencia son buenas para permitir el reuso. La validación de las precondiciones arroja que las clases que tiene el mayor porcentaje de canales de comunicación son las clases MSG y BDBASE con un 28%. Esto quiere decir que es posible aplicar el método de refactorización. El cálculo de la métrica COF arroja el siguiente resultado: TC = 17, Σ D = 21 y por tanto, COF = 21 / (172 – 17) = 0.0772. Entonces se considera un 7.7% de acoplamiento entre clases, considerando únicamente las llamadas a funciones. Este número no es tan malo de acuerdo a la literatura, pero se puede disminuir utilizando el método de refactorización de reducción de acoplamiento. En el anexo A se muestra el código de las clases que realizan llamadas hacia métodos de otras clases. Las funciones que resultan problemáticas y que serán manejadas por el mediador, son: mensaje( ) de la clase MSG, llamada desde las clases cStr11, cStr12, cStr13, cStr14,

cStr15 y cStr16. pidevar( ) de la clase VARIABLES, llamada desde las clases cStr11, cStr12, cStr14,

cStr15. pideval( ) de la clase VALORES, llamada desde las clases cStr14, cStr15 y cStr16. pidegrupo( ) de la clase GRUPOS, llamada desde las clases cStr13 y cStr16. bdleea( ) de la clase BDBASE, llamada desde la clase cStr12. bdesca( ) de la clase BDBASE, llamada desde la clase cStr15.

Page 72: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

60

bdleeb( ) de la clase BDBASE, llamada desde la clase cStr11. bdleebw( ) de la clase BDBASE, llamada desde la clase cStr13. bdescb( ) de la clase BDBASE, llamada desde la clase cStr14. bdescbw( ) de la clase BDBASE, llamada desde la clase cStr16.

CCreadorBDana

CCreadorBDBin

BDanaBDBin

BDBASE

aStrat1

SupCreadorBDBASE

Contex1

-Strategy

#C

VARIABLES

cStr11

cStr12

cStr13

cStr14

cStr15

GRUPOSMSG

VALORES

cStr16

v oid cStr13::AlgoritmoDeInterf az(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("LEE BINARIO POR GRUPO"); obgru = new GRUPOS(); VAR = obgru->pidegrupo(); printf ("v alor = %4x",BDB->bdleebw (VAR)); } // Termina cStr13::AlgoritmoDeInterf az()

Fig. 4.1.1. Diagrama de Clases del Caso de Prueba 1. Marco Original

Page 73: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

61

Al aplicar el método de refactorización realizando las llamadas hacia el mediador, el cual redirige la llamada, se obtiene la arquitectura mostrada en la figura 4.1.2. En el anexo A también se muestra el nuevo código generado por el método, y la forma en que ahora se envían los mensajes.

cMediador

CCreadorBDana

CCreadorBDBin

cStr11

cStr12

cStr13

cStr14

cStr15

cStr16

GRUPOSMSG

BDana BDBin

VALORES

VARIABLES

aColega

BDBASE

aMediador

#oMed

#oCol1

aStrat1

#oMed

SupCreadorBDBASE Contex1

-Strategy

#C

void cStr13::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "LEE BINARIO POR GRUPO"); obgru = new GRUPOS(); VAR = oMed->pidegrupo( obgru ); printf("valor = %4x",oMed->bdleebw ( BDB,VAR)); } // Termina cStr13::AlgoritmoDeInterfaz()

int cMediador:: bdleea ( BDBASE * objBDBASE, unsigned int VAR ) { oCol1 = new BDBASE(); oCol1 = objBDBASE; return(oCol1->bdleea(VAR)); } //fin del método bdleea

int cMediador:: bdleebw (BDBASE * objBDBASE, unsigned int GRUPO ) { oCol1 = new BDBASE(); oCol1 = objBDBASE; return(oCol1->bdleebw(GRUPO)); } //fin del método bdleebw

Fig. 4.1.2. Diagrama de Clases del Caso de Prueba 1. Marco Refactorizado

En esta nueva arquitectura se crearon las clases aMediador, cMediador y aColega, para tomar la estructura del patrón de diseño ‘Mediator’. La clase aStrat1 también funciona como clase colega y todas cuentan con un objeto mediador oMed para dirigir sus llamadas. El mediador tiene los objetos oCol1, oCol2 y oCol3 para comunicarse con las clases colegas y atender las peticiones.

Page 74: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

62

Al calcular la métrica a este nuevo marco, se obtiene lo siguiente: TC = 20, Σ D = 7 y la métrica COF = 7 / (202 – 20) = 0.0184. Claramente puede verse que se ha mejorado la arquitectura del marco, ya que se disminuyeron los canales de comunicación y únicamente se tiene un 2.1% de acoplamiento. Si se intenta realizar nuevamente la refactorización sobre este marco, el sistema no lo permitirá, ya que se tiene que la clase aMediador tiene el 85.7% de los canales de comunicación, lo cual nos indica, según la precondición del método de reducción de acoplamiento, que esta clase ya funciona como mediadora y no es necesaria la refactorización. 4.2 CASO DE PRUEBA 2: MARCO DE LISTAS DOBLEMENTE LIGADAS Aquí se analiza un marco hecho para manejar listas doblemente ligadas de tipos de datos básicos. Este marco se presentó en [Sant04]. El programa cuenta con la funcionalidad adicional de hacer ordenación y búsqueda de datos, utilizando los algoritmos de ordenación por burbuja y búsqueda secuencial, respectivamente. También se le colocó al marco una clase CContexto para funcionar como la interfaz del marco. La arquitectura del marco se muestra en la figura 4.2.1 con toda la jerarquía de clases, excepto el archivo que funciona como cliente e invoca a la interfaz. En el diagrama se observan las relaciones de dependencia que existen entre las clases del marco. Aquí se puede observar que todas las clases están relacionadas al menos con una, por tanto hay muchos canales de comunicación. Las cuatro clases CContexto, CLista, CBubble y CSecuenc están involucradas en las llamadas a otras funciones. CElemento es la única clase que no hace llamadas a funciones de otras clases, pero sí recibe peticiones. La validación de las precondiciones arroja que las clases que tiene el mayor porcentaje de canales de comunicación son las clases CLista y CElemento con un 50%. Aunque el porcentaje es alto, aún es posible aplicar el método de refactorización y mejorar la arquitectura. El cálculo de la métrica COF arroja el siguiente resultado: TC = 5, Σ D = 8 y por tanto, COF = 8 / (52 – 5) = 0.4000. Este caso resulta grave debido a que existe un 40% de acoplamiento entre clases, considerando únicamente las llamadas a funciones. Entonces se tratará de disminuir este porcentaje utilizando el método de refactorización de reducción de acoplamiento. En el anexo B se muestra el código de los métodos que realizan llamadas hacia métodos de otras clases.

Page 75: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

63

CBubble

<<v irtual>> ~CBubble()CBubble()<<v irtual>> Busqueda()<<v irtual>> Ordena()

CSecuenc

<<v irtual>> ~CSecuenc()CSecuenc()<<v irtual>> Busqueda()<<v irtual>> Ordena()

CContextoposicion : int

PantallaFinal()MenuBusqueda()MenuOrdenacion()MenuPrincipal()SetPos()GetPos()SetNodoBusq()GetNodoBusq()Interactua()<<v irtual>> ~CContexto()CContexto()

CElementoX : f loat

SetAntSig()SetSigAnt()SetX()SetAnt()SetSig()GetX()GetAnt()GetSig()<<v irtual>> ~CElemento()CElemento()CElemento()

-nodoBusq

-AptSig, -AptAnt

CListaN : int

<<abstract>> Busqueda()<<abstract>> Ordena()SetT()SetH()SetN()GetT()GetH()GetN()<<v irtual>> ~CLista()CLista()Agrega()Borra()IsEmpty ()Siguiente()Anterior()

+L

-AptT

-AptH

Fig. 4.2.1. Diagrama de Clases del Caso de Prueba 2. Marco Original

Las funciones que resultan problemáticas, y serán manejadas por el mediador, son: GetNodoBusq( ) y SetPos( ) de la clase CContexto, llamadas desde la clase CSecuenc. GetSig( ), GetAnt( ), SetSig( ), SetAnt( ), SetSigAnt( ) y SetAntSig( ) de la clase

CElemento, llamadas desde la clase CLista. GetX( ) de la clase CElemento, llamada desde las clases CBubble, CSecuenc, CLista y

CContexto. SetX( ) de la clase CElemento, llamada desde las clases CBubble y CContexto. Siguiente( ) y GetH( ) de la clase CLista, llamadas desde las clases CBubble, CSecuenc

y CContexto. IsEmpty( ), Borra( ) y Agrega( ) de la clase CLista, llamadas desde la clase

CContexto. GetN( ) de la clase CLista, llamada desde las clases CBubble y CSecuenc. Ordena( ) y Busqueda( ) de la clase CLista, llamadas desde la clase CContexto.

Al aplicar el método de refactorización se obtiene la arquitectura mostrada en la figura 4.2.2. En el anexo B también se muestra el nuevo código generado por el método y la forma en que ahora se envían los mensajes. En esta nueva arquitectura se crearon las clases aMediador, cMediador y aColega, para tomar la estructura del patrón de diseño ‘Mediator’. La clase CLista también funciona como clase colega pero no se agrega a la jerarquía de clases de aColega, debido a que CLista es

Page 76: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

64

abstracta. Todas las clases colegas cuentan con un objeto mediador oMed para dirigir sus llamadas. El mediador tiene al objeto oCol1 para comunicarse con las clases colegas y atender las peticiones. Al calcular la métrica a este nuevo marco, se obtiene lo siguiente: TC = 8, Σ D = 6 y la métrica COF = 6 / (82 – 8) = 0.1071. Aquí se ha mejorado bastante la arquitectura del marco, ya que se disminuyeron los canales de comunicación y únicamente se tiene un 10.7% de acoplamiento del original 40%.

aMediador

aColega

#oMed

#oCol1

cMediador

CElemento -AptAnt

-AptSig

CContexto -nodoBusq

CLista

-AptT

-AptH

+L

CBubble CSecuenc

Fig. 4.2.2. Diagrama de Clases del Caso de Prueba 2. Marco Refactorizado

Si se intenta realizar nuevamente la refactorización sobre este marco, el sistema no lo permitirá, ya que se tiene que la clase aMediador tiene el 66.7% de los canales de comunicación, lo cual nos indica, según la precondición del método de reducción de acoplamiento, que esta clase ya funciona como mediadora y no es necesaria la refactorización. 4.3 CASO DE PRUEBA 3: MARCO DE ESTADÍSTICA Aquí se analiza un marco del dominio de la estadística, el cual fue presentado en [Sant04b]. Este marco proporciona algunas funciones para cálculo estadístico, utilizando tres listas doblemente ligadas para almacenar la serie de números sobre los que operan las funciones, también se cuenta con dos matrices para manejar operaciones adicionales. La funcionalidad total que tiene el marco completo es el cálculo de medidas de tendencia central, dispersiones, distribuciones, regresiones y correlaciones, y como auxiliares se tienen ordenaciones de datos y solución de sistemas de ecuaciones lineales.

Page 77: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

65

El diagrama de clases completo se muestra en la figura 4.3.1. Para simplicidad del gráfico, no se muestran las relaciones de dependencia, sino que serán mencionadas enseguida.

cED1

CRango

cED2

CMediaArm

cED3

CInserc

CSelec

CSuma

cED4

CBubble

CGaussJor

CMediaCua

CMediaGeo

CRegLin2 CRegLin3 CRegPar2 CRegPar3

CModa

CShell

CMediana

aEDCElemento-AptAnt

-AptSig+ED

CLista -AptC

-AptH

CMatriz

CMediaAri

CDistTStuCDesvMed

CCorrLin2

CContexto

+L3

+L2

+L1

+M2

+M1

CCorrPar2

CCorrLin3

CCorrPar3

CSumaDifC CDesvEstM

CDistJiC

CDesvEstP

CDistNorm

CStrategy

<<abstract>> GetResultado()<<abstract>> Resuelve()<<abstract>> Ordena()<<abstract>> Calcula()<<virtual>> ~CStrategy()CStrategy()+str

CVarianza

Fig. 4.3.1. Diagrama de Clases del Caso de Prueba 3. Marco Original

Las clases que reciben todas las peticiones del marco son aED, CStrategy, CLista, CElemento, CMatriz y CContexto. Las clases CBubble, CInserc, CSelec y CShell utilizan sólo a las clases CLista y aED. CContexto utiliza a todas las otras clases excepto CElemento. CLista es la única que utiliza a CElemento, también utiliza a aED. Las clases CCorLinX, CCorParX, CRegLinX y CRegParX utilizan todas las clases. La clase CGaussJor utiliza a CContexto y CMatriz. El resto de las clases utilizan a CContexto, CStrategy, CLista y aED. Analizando las precondiciones se encuentra que la clase con mayor porcentaje de canales de comunicación es la clase CContexto con un 27%. Esto implica que es posible realizar la refactorización para reducir el número de dependencias. El cálculo de la métrica COF arroja el siguiente resultado: TC = 39, Σ D = 106 y por tanto, COF = 106 / (392 – 39) = 0.0715.

Page 78: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

66

Entonces se considera un 7.1% de acoplamiento entre clases, considerando únicamente las llamadas a funciones. Este número no es tan malo, pero se puede disminuir utilizando el método de refactorización. En el anexo C se muestra parte del código de los métodos que realizan llamadas hacia métodos de otras clases. Las funciones que resultan problemáticas, y serán manejadas por el mediador, son: GetED( ) y SetED( ) de la clase aED. GetSig( ), GetAnt( ), SetSig( ), SetAnt( ), SetSigAnt( ) y SetAntSig( ) de la clase

CElemento, llamadas desde la clase CLista. Calcula( ), Ordena( ), Resuelve( ) y GetResultado( ) de la clase CStrategy. SetRen( ), SetCol( ), GetRen( ), SetCelda( ) y GetCelda( ) de la clase CMatriz. GetResultado( ), SetResultado( ), GetParametro1( ), SetParametro1( ) y

GetParametro2( ) de la clase CContexto. Anterior( ), Siguiente( ), EstaVacia( ), GetTipo( ), SetTipo( ), GetN( ), GetH( ),

GetC( ), Agregar( ) y Eliminar( ) de la clase CLista.

cED1

CRango

cED2

CMediaArm

cED3

CInserc

CSelec

CSuma

cED4

CBubble

CGaussJor

CMediaCua

CMediaGeo

CRegLin2 CRegLin3 CRegPar2 CRegPar3

CModa

CShell

CMediana

aED

CElemento -AptAnt

-AptSig

+ED

CLista -AptC

-AptH

CMatriz

CMediaAri

CDistTStuCDesvMed

CCorrLin2

CContexto

+L3

+L2

+L1+M2

+M1

CCorrPar2

CCorrLin3

CCorrPar3

CSumaDifC CDesvEstM

CDistJiC

CDesvEstP

CDistNorm CVarianza

CMediadorCon

CStrategy

<<abstract>> GetResultado()<<abstract>> Resuelve()<<abstract>> Ordena()<<abstract>> Calcula()<<virtual>> ~CStrategy()CStrategy()

+strCMediadorAbs

#oMed

CColega

#oMed

#oCol1

Fig. 4.3.2. Diagrama de Clases del Caso de Prueba 3. Marco Refactorizado

Page 79: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

67

Al aplicar el método de refactorización se obtiene la arquitectura mostrada en la figura 4.3.2. En el anexo C también se muestra el nuevo código generado por el método, y la forma en que ahora se envían los mensajes. En esta nueva arquitectura se crearon las clases CMediadorAbs, CMediadorCon y CColega, para tomar la estructura del patrón de diseño ‘Mediator’. Las clases CStrategy y aED también funcionan como clases colegas, pero no se agregan a la jerarquía de clases de aColega debido a que son abstractas. Todas las clases colegas cuentan con un objeto mediador oMed para dirigir sus llamadas. El mediador tiene al objeto oCol1 para comunicarse con las clases colegas y atender las peticiones. Al calcular la métrica a este nuevo marco, se obtiene lo siguiente: TC = 42, Σ D = 35 y la métrica COF = 35 / (422 – 42) = 0.0203. Claramente se puede ver que se ha mejorado la arquitectura del marco, ya que se disminuyeron los canales de comunicación y únicamente se tiene un 2% de acoplamiento. Si se intenta realizar nuevamente la refactorización sobre este marco, el sistema no lo permitirá, ya que se tiene que la clase CMediadorAbs tiene el 88.6% de los canales de comunicación, lo cual nos indica, según la precondición del método de reducción de acoplamiento, que esta clase ya funciona como mediadora y no es necesaria la refactorización. Resumen de Resultados En la tabla 4.1 se muestran los resultados obtenidos en las pruebas y en el caso de ejemplo. Se muestra el total de clases del marco (TC), el número de canales de comunicación (Σ D), el valor de la métrica (COF), y el porcentaje máximo de canales en una sola clase, para la precondición.

Tabla 4.1. Comparación de Resultados Marco % Canales TC Σ D COF

Figura 3.2.1. 33% 6 9 30% Figura 3.2.2. 80% 9 5 7% Figura 4.1.1. 28% 17 21 8% Figura 4.1.2. 75% 20 8 2% Figura 4.2.1. 50% 5 8 40% Figura 4.2.2. 66% 8 6 10% Figura 4.3.1. 27% 39 106 7% Figura 4.3.2. 88% 42 35 2%

Para el marco de ejemplo de las figuras 3.2.1 y 3.2.2 se puede observar que se agregaron tres clases, los canales de comunicación disminuyeron en cuatro, el valor de la métrica COF disminuyó un 23%, y la concentración de canales de comunicación en una sola clase aumentó en un 47%.

Page 80: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 4

68

Para el marco del caso de prueba 1 de las figuras 4.1.1 y 4.1.2 también se agregaron tres clases, se eliminaron 13 canales de comunicación, el valor de la métrica COF disminuyó un 6%, y la concentración de canales de comunicación en una clase que actúe como mediadora aumentó en un 47%. Para el marco del caso de prueba 2 de las figuras 4.2.1 y 4.2.2 también se agregaron tres clases, sólo se eliminaron dos canales de comunicación pero el valor de la métrica COF disminuyó en un 30%, y la clase que actúa como mediadora aumentó sus canales de comunicación en un 16%. Para el marco del caso de prueba 3 de las figuras 4.3.1 y 4.3.2 se agregaron dos clases mediadoras y una clase colega, la cantidad de canales de comunicación disminuyó en 71, el valor de la métrica COF disminuyó un 5%, y la clase mediadora tiene un 61% más de los canales de comunicación. Se puede observar que en los cuatro marcos se mejora el diseño, ya que se reducen los canales de comunicación y, por ende, la métrica COF. La evaluación de la precondición sirve para impedir que un marco que ya cuenta con clases que funcionan como mediador sea refactorizado, ya que sólo implicaría un aumento de canales de comunicación por la comunicación que existirá entre mediadores.

Page 81: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

69

CAPÍTULO 5 CONCLUSIONES Y TRABAJO FUTURO Se mencionan las conclusiones a las que se ha llegado después de haber realizado el diseño e implementación del método de refactorización, mostrando los beneficios que recibe un marco al ser sometido a refactorizaciones sucesivas. También se menciona el trabajo próximo dentro del proyecto SR2.

Page 82: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 5

70

Conclusiones El objetivo de todo el proyecto SR2 es el mejor aprovechamiento del software legado existente, para producir nuevas aplicaciones de mejor calidad. Para lograr esto, se lleva software procedural hacia el paradigma orientado a objetos, y con ello se busca ganar las cualidades de reuso y extensión que tiene el software que respeta los principios de la tecnología orientada a objetos. El proyecto SR2 se encuentra actualmente en la última fase de desarrollo, que consiste en implementar métodos de refactorización que ayudan a mejorar la arquitectura de marcos, no con la finalidad de mejorar el funcionamiento actual de los marcos, sino para permitir el reuso de los componentes en otras aplicaciones o extender la funcionalidad del marco. En esta tesis se propuso e implementó un método de refactorización que tiene la intención de reducir el número de canales de comunicación entre clases debido a llamadas a métodos. Con esto se buscó incrementar las cualidades de reuso y extensión de sistemas orientados a objetos. Las conclusiones obtenidas después de realizar esta tesis son las siguientes:

• Mediante las pruebas experimentales se demostró que es correcta la propuesta de que el patrón de diseño ‘Mediator’ sirve para reducir el acoplamiento entre clases.

• Al aplicar el método de refactorización realizado en esta tesis a un marco, se logró

reducir la interdependencia entre los objetos y las clases del marco. Con esto se disminuyó el acoplamiento entre los métodos de las clases y se evitó la dependencia entre ellos sólo por paso de mensajes.

• Una vez que el marco se encuentra refactorizado, es más fácil entender su

estructura, ya que el patrón de diseño ‘Mediator’ promueve las relaciones uno a uno. También todas las dependencias se centran en las clases mediadoras, por lo que es más fácil de seguir la colaboración entre clases colegas.

• Con las pruebas se observaron las tendencias de los marcos antes y después de tener

implementado una clase que actúe como mediador. Se encontró que una clase mediadora acumula el 60% aproximadamente de todos los canales de comunicación. Este dato sirvió para crear una precondición del método, con el fin de evitar que marcos que ya tengan mediadores vuelvan a ser refactorizados por el sistema.

• Aparte de la precondición anterior, al algoritmo se le agregó la precondición básica

de no repetir nombres existentes en las nuevas clases que serán añadidas al sistema, con el fin de que el sistema no falle después de la refactorización.

• Aunque no existe documentación en cuanto a cómo medir y evaluar el factor de

acoplamiento tomando únicamente las llamadas a métodos, se implementó la

Page 83: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Capítulo 5

71

métrica COF (Coupling Factor) para poder tomar una decisión acertada en cuanto a realizar la refactorización. Desgraciadamente, esta métrica toma en cuenta otros factores no contemplados en la presente tesis, como declaración y destrucción de objetos, por tanto no pudieron cumplirse cabalmente los preceptos establecidos en la literatura en cuanto a qué rangos de COF son los óptimos en un sistema.

• Sin importar que tan alto o bajo sea el factor de acoplamiento, mediante las pruebas

se observó que la estructura de un marco sí es mejorada si el marco cumple con las precondiciones establecidas en el algoritmo de reducción de acoplamiento.

• Por lo que se observó en las pruebas, en todo marco que cumplió las precondiciones

y fue refactorizado, aumentó su número de clases, disminuyó su cantidad de canales de comunicación así como su valor de la métrica COF y obtuvo una clase que acumuló más del 60% de todos los canales de comunicación del marco.

• El método de refactorización de Reducción de Acoplamiento fue integrado

satisfactoriamente en la herramienta SR2 Refactoring, la cual incluye también a otros métodos de refactorización del proyecto SR2.

Trabajos Futuros Lo que falta por realizar en el proyecto SR2 es simplemente agregar más métodos de refactorización al sistema SR2 Refactoring. Existen demasiados métodos propuestos en la literatura consultada ([Keri03], [OCin99] y [Toku99]) pero la mayoría no han sido implementados en herramientas automáticas, por tanto existe todavía una amplia gama de posibilidades en este aspecto. Inclusive existen otros patrones de diseño de Gamma [Gamm95] que pueden ser implementados para resolver problemas de diseño, no necesariamente utilizando la intención original de los patrones. Asimismo existen otros catálogos de patrones que pueden ser empleados. En lo concerniente a la herramienta realizada en esta tesis, aún se puede disminuir más la cantidad de dependencias entre clases, si se tomaran en cuenta otros aspectos, no sólo el paso de mensajes. Si se logra desacoplar clases, por ejemplo en la declaración de objetos de otras clases, se tendrá entonces que ya se podrá reusar clases colegas de manera separada, y una clase que tenía una llamada específica a otra clase ahora podrá comunicarse con cualquier otra clase simplemente cambiando al mediador concreto. Otro trabajo que queda a futuro es completar la gramática de C++ de JavaCC para que reconozca la totalidad del lenguaje C++ estándar. Esto ayudará a crear mejores analizadores sintácticos, no sólo para este método, sino para futuros métodos, ya que se tendrán bases de datos más completas y se podrá ampliar la gama de programas que son reconocidos y refactorizados.

Page 84: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

72

ANEXO A CÓDIGO DEL CASO DE PRUEBA 1 Se muestra el código del sistema de control de procesos, que fue utilizado como primer caso de prueba. También se muestra el código del sistema después de la refactorización, añadiendo las clases mediadoras abstracta y concreta, así como la colega abstracta. De las clases propias del sistema sólo se muestran las que sufren cambios.

Page 85: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

73

Código Original // Código del Archivo BD1.hpp #ifndef _BDBASE #define _BDBASE class BDBASE { protected: unsigned int CK; public: BDBASE () { } virtual void bdinicia(); virtual int bdleeb(unsigned int); virtual int bdleea(unsigned int); virtual int bdescb(unsigned int, unsigned int); virtual int bdesca(unsigned int, unsigned int); virtual int bdescbw(unsigned int, unsigned int); virtual int bdleebw(unsigned int); }; #endif

// Código del Archivo Msg.hpp #ifndef _MSG #define _MSG #include<stdio.h> #include<iostream> #include<stdlib.h> #include<String.h> class MSG { public: MSG() { } void mensaje char *s); }; #endif

// Código del Archivo Grupos.hpp #ifndef _GRUPOS #define _GRUPOS #include<stdio.h> #include<stdlib.h> class GRUPOS { private: unsigned VAR; public: GRUPOS() { } unsigned int getnum() { char s[80]; gets (s); return (atoi(s)); } int pidegrupo (); }; #endif

// Código del Archivo Valores.hpp #ifndef L_VAL #define L_VAL #include<stdio.h> #include<stdlib.h> class VALORES { private: unsigned VALOR; public: VALORES() { }

Page 86: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

74

unsigned int getnum() { char s[80]; gets (s); return (atoi(s)); } int pideval (); }; #endif

// Código del Archivo Variables.hpp #ifndef La_VAR #define La_VAR #include<stdio.h> #include<stdlib.h> class VARIABLES { private: unsigned VAR; public: VARIABLES() { } unsigned int getnum() { char s[80]; gets (s); return (atoi(s)); } int pidevar (); }; #endif

// Código del Archivo aStrat1.hpp #ifndef _aStrat1 #define _aStrat1 #include <stdio.h> #include <stdlib.h> #include "BD1.HPP" class aStrat1 { protected: unsigned VAR; unsigned VALOR; public: virtual void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) = 0; }; #endif

// Código del Archivo cStr11.hpp #ifndef _cStr11 #define _cStr11 #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "MSG.HPP" class cStr11: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; MSG msg; }; #endif

// Código del Archivo cStr11.cpp #include "aStrat1.HPP" #include "cStr11.HPP" void cStr11::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("LEE BINARIO"); obvar = new VARIABLES(); VAR = obvar->pidevar();

Page 87: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

75

printf("valor = %d",BDB->bdleeb (VAR)); }

// Código del Archivo cStr12.hpp #ifndef _cStr12 #define _cStr12 #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "MSG.HPP" class cStr12: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; MSG msg; }; #endif

// Código del Archivo cStr12.cpp #include "aStrat1.HPP" #include "cStr12.HPP" void cStr12::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("LEE ANALOGICO"); obvar = new VARIABLES(); VAR = obvar->pidevar(); printf("valor = %5d",BDA->bdleea (VAR)); }

// Código del Archivo cStr13.hpp #ifndef _cStr13 #define _cStr13 #include "aStrat1.HPP" #include "GRUPOS.HPP" #include "MSG.HPP" class cStr13: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); GRUPOS *obgru; MSG msg; }; #endif

// Código del Archivo cStr13.cpp #include "aStrat1.HPP" #include "cStr13.HPP" void cStr13::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("LEE BINARIO POR GRUPO"); obgru = new GRUPOS(); VAR = obgru->pidegrupo(); printf("valor = %4x",BDB->bdleebw (VAR)); }

// Código del Archivo cStr14.hpp #ifndef _cStr14 #define _cStr14 #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "VALORES.HPP" #include "MSG.HPP" class cStr14: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; VALORES *obval;

Page 88: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

76

MSG msg; }; #endif

// Código del Archivo cStr14.cpp #include "aStrat1.HPP" #include "cStr14.HPP" void cStr14::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("ESCRIBE BINARIO"); obvar = new VARIABLES(); obval = new VALORES(); VAR = obvar->pidevar(); VALOR = obval->pideval(); BDB->bdescb (VAR,VALOR); }

// Código del Archivo cStr15.hpp #ifndef _cStr15 #define _cStr15 #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "VALORES.HPP" #include "MSG.HPP" class cStr15: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; VALORES *obval; MSG msg; }; #endif

// Código del Archivo cStr15.cpp #include "aStrat1.HPP" #include "cStr15.HPP" void cStr15::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("ESC ANALOGICO"); obvar = new VARIABLES(); obval = new VALORES(); VAR= obvar->pidevar(); VALOR = obval->pideval(); BDA->bdesca (VAR,VALOR); }

// Código del Archivo cStr16.hpp #ifndef _cStr16 #define _cStr16 #include "aStrat1.HPP" #include "VALORES.HPP" #include "GRUPOS.HPP" #include "MSG.HPP" class cStr16: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VALORES *obval; GRUPOS *obgru; MSG msg; }; #endif

// Código del Archivo cStr16.cpp #include "aStrat1.HPP" #include "cStr16.HPP"

Page 89: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

77

void cStr16::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { msg.mensaje("ESC BINARIO POR GRUPO"); obgru = new GRUPOS(); obval = new VALORES(); VAR= obgru->pidegrupo(); VALOR = obval->pideval(); BDB->bdescbw (VAR,VALOR); }

Código Refactorizado // Código del Archivo aMediador.hpp #ifndef _aMediador #define _aMediador class BDBASE; class MSG; class VARIABLES; class GRUPOS; class VALORES; class aColega; class aMediador { protected: aColega *oCol1; public: aMediador() { } virtual int bdleeb( BDBASE *objBDBASE, unsigned int VAR ) = 0; virtual void mensaje( MSG *objMSG, char * s ) = 0; virtual int pidevar( VARIABLES *objVARIABLES) = 0; virtual int bdleea( BDBASE *objBDBASE, unsigned int VAR ) = 0; virtual int bdleebw( BDBASE *objBDBASE, unsigned int GRUPO ) = 0; virtual int pidegrupo( GRUPOS *objGRUPOS) = 0; virtual int bdescb( BDBASE *objBDBASE, unsigned int VAR , unsigned int VALOR ) = 0; virtual int pideval( VALORES *objVALORES) = 0; virtual int bdesca( BDBASE *objBDBASE, unsigned int VAR , unsigned int VALOR ) = 0; virtual int bdescbw( BDBASE *objBDBASE, unsigned int GRUPO , unsigned int VALOR ) = 0; }; #endif

// Código del Archivo cMediador.hpp #ifndef _cMediador #define _cMediador #include "aMediador.HPP" #include "BD1.HPP" #include "MSG.HPP" #include "VARIABLES.HPP" #include "GRUPOS.HPP" #include "VALORES.HPP" class cMediador : public aMediador { public: cMediador() { } int bdleeb( BDBASE *objBDBASE, unsigned int VAR ); void mensaje( MSG *objMSG, char * s ); int pidevar( VARIABLES *objVARIABLES); int bdleea( BDBASE *objBDBASE, unsigned int VAR ); int bdleebw( BDBASE *objBDBASE, unsigned int GRUPO ); int pidegrupo( GRUPOS *objGRUPOS); int bdescb( BDBASE *objBDBASE, unsigned int VAR , unsigned int VALOR ); int pideval( VALORES *objVALORES); int bdesca( BDBASE *objBDBASE, unsigned int VAR , unsigned int VALOR ); int bdescbw( BDBASE *objBDBASE, unsigned int GRUPO , unsigned int VALOR ); }; #endif

Page 90: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

78

// Código del Archivo cMediador.cpp #include "cMediador.HPP" int cMediador:: pidegrupo ( GRUPOS *objGRUPOS) { oCol1 = new GRUPOS(); oCol1 = objGRUPOS; return(oCol1->pidegrupo()); } void cMediador:: mensaje ( MSG *objMSG, char * s ) { oCol1 = new MSG(); oCol1 = objMSG; oCol1->mensaje(s); } int cMediador:: bdleea ( BDBASE *objBDBASE, unsigned int VAR ) { oCol3 = new BDBASE(); oCol3 = objBDBASE; return(oCol3->bdleea(VAR)); } int cMediador:: bdesca ( BDBASE *objBDBASE, unsigned int VAR , unsigned int VALOR ) { oCol3 = new BDBASE(); oCol3 = objBDBASE; return(oCol3->bdesca(VAR,VALOR)); } int cMediador:: bdleeb ( BDBASE *objBDBASE, unsigned int VAR ) { oCol3 = new BDBASE(); oCol3 = objBDBASE; return(oCol3->bdleeb(VAR)); } int cMediador:: bdleebw ( BDBASE *objBDBASE, unsigned int GRUPO ) { oCol3 = new BDBASE(); oCol3 = objBDBASE; return(oCol3->bdleebw(GRUPO)); } int cMediador:: bdescb ( BDBASE *objBDBASE, unsigned int VAR , unsigned int valor ) { oCol3 = new BDBASE(); oCol3 = objBDBASE; return(oCol3->bdescb(VAR,valor)); } int cMediador:: bdescbw ( BDBASE *objBDBASE, unsigned int GRUPO , unsigned int VALOR ) { oCol3 = new BDBASE(); oCol3 = objBDBASE; return(oCol3->bdescbw(GRUPO,VALOR)); } int cMediador:: pideval ( VALORES *objVALORES) { oCol1 = new VALORES(); oCol1 = objVALORES; return(oCol1->pideval()); } int cMediador:: pidevar ( VARIABLES *objVARIABLES) { oCol1 = new VARIABLES(); oCol1 = objVARIABLES; return(oCol1->pidevar()); }

// Código del Archivo aColega.hpp #ifndef _aColega #define _aColega #include <stddef.h> class aMediador; class aColega { protected: aMediador *oMed; public: aColega() { } virtual int bdleeb ( unsigned int VAR ) ; virtual void mensaje ( char * s ) ; virtual int pidevar ( ) ;

Page 91: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

79

virtual int bdleea ( unsigned int VAR ) ; virtual int bdleebw ( unsigned int GRUPO ) ; virtual int pidegrupo ( ) ; virtual int bdescb ( unsigned int VAR , unsigned int VALOR ) ; virtual int pideval ( ) ; virtual int bdesca ( unsigned int VAR , unsigned int VALOR ) ; virtual int bdescbw ( unsigned int GRUPO , unsigned int VALOR ) ; }; #endif

// Código del Archivo aColega.cpp #include "aColega.HPP" int aColega:: bdleeb ( unsigned int VAR ) { return 0; } void aColega:: mensaje ( char * s ) { } int aColega:: pidevar ( ) { return 0; } int aColega:: bdleea ( unsigned int VAR ) { return 0; } int aColega:: bdleebw ( unsigned int GRUPO ) { return 0; } int aColega:: pidegrupo ( ) { return 0; } int aColega:: bdescb ( unsigned int VAR , unsigned int VALOR ) { return 0; } int aColega:: pideval ( ) { return 0; } int aColega:: bdesca ( unsigned int VAR , unsigned int VALOR ) { return 0; } int aColega:: bdescbw ( unsigned int GRUPO , unsigned int VALOR ) { return 0; }

// Código del Archivo BD1.hpp #ifndef _BDBASE #define _BDBASE #include "aColega.hpp" class BDBASE : public aColega { protected: unsigned int CK; public: BDBASE () { } virtual void bdinicia(); virtual int bdleeb(unsigned int); virtual int bdleea(unsigned int); virtual int bdescb(unsigned int, unsigned int); virtual int bdesca(unsigned int, unsigned int); virtual int bdescbw(unsigned int, unsigned int); virtual int bdleebw(unsigned int); }; #endif

// Código del Archivo Msg.hpp #ifndef _MSG #define _MSG #include<stdio.h>

Page 92: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

80

#include<iostream> #include<stdlib.h> #include<String.h> #include "aColega.hpp" class MSG : public aColega { public: MSG( ) { } void mensaje (char *s); }; #endif

// Código del Archivo Grupos.hpp #ifndef _GRUPOS #define _GRUPOS #include<stdio.h> #include<stdlib.h> #include "aColega.hpp" class GRUPOS : public aColega { private: unsigned VAR; public: GRUPOS( ) { } unsigned int getnum( ) { char s[80]; gets (s); return (atoi(s)); } int pidegrupo (); }; #endif

// Código del Archivo Valores.hpp #ifndef L_VAL #define L_VAL #include<stdio.h> #include<stdlib.h> #include "aColega.hpp" class VALORES : public aColega { private: unsigned VALOR; public: VALORES( ) { } unsigned int getnum() { char s[80]; gets (s); return (atoi(s)); } int pideval (); }; #endif

// Código del Archivo Variables.hpp #ifndef La_VAR #define La_VAR #include<stdio.h> #include<stdlib.h> #include "aColega.hpp" class VARIABLES : public aColega { private: unsigned VAR; public: VARIABLES( ) { } unsigned int getnum() { char s[80]; gets (s);

Page 93: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

81

return (atoi(s)); } int pidevar (); }; #endif

// Código del Archivo aStrat1.hpp #ifndef _aStrat1 #define _aStrat1 #include <stdio.h> #include <stdlib.h> #include "BD1.HPP" class aMediador; class aStrat1 { protected: aMediador *oMed; unsigned VAR; unsigned VALOR; public: virtual void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) = 0; }; #endif

// Código del Archivo cStr11.hpp #ifndef _cStr11 #define _cStr11 #include "cMediador.hpp" #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "MSG.HPP" class cStr11: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; MSG msg; }; #endif

// Código del Archivo cStr11.cpp #include "aStrat1.HPP" #include "cStr11.HPP" void cStr11::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "LEE BINARIO"); obvar = new VARIABLES(); VAR = oMed->pidevar( obvar ); printf("valor = %d",oMed->bdleeb ( BDB , VAR)); }

// Código del Archivo cStr12.hpp #ifndef _cStr12 #define _cStr12 #include "cMediador.hpp" #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "MSG.HPP" class cStr12: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; MSG msg; }; #endif

Page 94: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

82

// Código del Archivo cStr12.cpp #include "aStrat1.HPP" #include "cStr12.HPP" void cStr12::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "LEE ANALOGICO"); obvar = new VARIABLES(); VAR = oMed->pidevar( obvar ); printf("valor = %5d",oMed->bdleea ( BDA , VAR)); }

// Código del Archivo cStr13.hpp #ifndef _cStr13 #define _cStr13 #include "cMediador.hpp" #include "aStrat1.HPP" #include "GRUPOS.HPP" #include "MSG.HPP" class cStr13: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); GRUPOS *obgru; MSG msg; }; #endif

// Código del Archivo cStr13.cpp #include "aStrat1.HPP" #include "cStr13.HPP" void cStr13::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "LEE BINARIO POR GRUPO"); obgru = new GRUPOS(); VAR = oMed->pidegrupo( obgru ); printf("valor = %4x",oMed->bdleebw ( BDB , VAR)); }

// Código del Archivo cStr14.hpp #ifndef _cStr14 #define _cStr14 #include "cMediador.hpp" #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "VALORES.HPP" #include "MSG.HPP" class cStr14: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; VALORES *obval; MSG msg; }; #endif

// Código del Archivo cStr14.cpp #include "aStrat1.HPP" #include "cStr14.HPP" void cStr14::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "ESCRIBE BINARIO"); obvar = new VARIABLES(); obval = new VALORES(); VAR = oMed->pidevar( obvar );

Page 95: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo A

83

VALOR = oMed->pideval( obval ); oMed->bdescb ( BDB , VAR,VALOR); }

// Código del Archivo cStr15.hpp #ifndef _cStr15 #define _cStr15 #include "cMediador.hpp" #include "aStrat1.HPP" #include "VARIABLES.HPP" #include "VALORES.HPP" #include "MSG.HPP" class cStr15: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VARIABLES *obvar; VALORES *obval; MSG msg; }; #endif

// Código del Archivo cStr15.cpp #include "aStrat1.HPP" #include "cStr15.HPP" void cStr15::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "ESC ANALOGICO"); obvar = new VARIABLES(); obval = new VALORES(); VAR= oMed->pidevar( obvar ); VALOR = oMed->pideval( obval ); oMed->bdesca ( BDA , VAR,VALOR); }

// Código del Archivo cStr16.hpp #ifndef _cStr16 #define _cStr16 #include "cMediador.hpp" #include "aStrat1.HPP" #include "VALORES.HPP" #include "GRUPOS.HPP" #include "MSG.HPP" class cStr16: public aStrat1 { public: void AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB); VALORES *obval; GRUPOS *obgru; MSG msg; }; #endif

// Código del Archivo cStr16.cpp #include "aStrat1.HPP" #include "cStr16.HPP" void cStr16::AlgoritmoDeInterfaz(BDBASE *BDA, BDBASE *BDB) { oMed = new cMediador(); oMed->mensaje( &(msg) , "ESC BINARIO POR GRUPO"); obgru = new GRUPOS(); obval = new VALORES(); VAR= oMed->pidegrupo( obgru ); VALOR = oMed->pideval( obval ); oMed->bdescbw ( BDB , VAR,VALOR); }

Page 96: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

84

ANEXO B CÓDIGO DEL CASO DE PRUEBA 2 Se muestra el código del marco de listas doblemente ligadas, que fue utilizado como segundo caso de prueba. También se muestra el código del marco después de la refactorización, añadiendo las clases mediadoras abstracta y concreta, así como la colega abstracta. De las clases propias del sistema sólo se muestran las que sufren cambios.

Page 97: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

85

Código Original // Código del Archivo Contexto.h #if !defined(AFX_CONTEXTO) #define AFX_CONTEXTO #include <stdio.h> #include <conio.h> #include "Lista.h" #include "Elemento.h" class CLista; class CContexto { private: CElemento nodoBusq; int posicion; public: CLista *L; public: CContexto(); virtual ~CContexto(); void Interactua(); CElemento GetNodoBusq(); void SetNodoBusq(CElemento nodo); int GetPos(); void SetPos(int pos); private: char MenuPrincipal(); char MenuOrdenacion(); char MenuBusqueda(); void PantallaFinal(); }; #endif

// Código del Archivo Contexto.cpp #include "Contexto.h" #include "Bubble.h" #include "Secuenc.h" CContexto::CContexto() { L=new CBubble(); } CContexto::~CContexto() { } CElemento CContexto::GetNodoBusq() { return nodoBusq; } void CContexto::SetNodoBusq(CElemento nodo) { nodoBusq=nodo; } int CContexto::GetPos() { return posicion; } void CContexto::SetPos(int pos) { posicion=pos; } void CContexto::Interactua() { char opcion,opcion1; CElemento *AptNodo; float ed; CLista *List; do { opcion=MenuPrincipal(); switch (opcion){ case '1': //Insertar Elemento AptNodo=new CElemento(); printf ("\n\nIntroduzca Dato: "); scanf ("%f",&ed);

Page 98: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

86

AptNodo->SetX(ed); L->Agrega(AptNodo); break; case '2': //Eliminar Elemento if (L->IsEmpty()==0){ printf ("\n\nLa Lista no tiene elementos"); getch(); break; } AptNodo=new CElemento(); printf ("\n\nIntroduzca Dato: "); scanf ("%f",&ed); AptNodo->SetX(ed); L->Borra(AptNodo); break; case '3': //Mostrar Lista if (L->IsEmpty()==0){ printf ("\n\nLa Lista no tiene elementos"); getch(); break; } AptNodo=L->GetH(); printf ("\n\n"); while (AptNodo!=NULL){ ed=(float)AptNodo->GetX(); printf ("\n%f",ed); L->Siguiente(AptNodo); } getch(); break; case '4': //Ordenar Lista opcion1=MenuOrdenacion(); switch (opcion1){ case '1': //Metodo de la Burbuja List=new CBubble(); List->Ordena(this); break; } break; case '5': //Buscar Elemento de la Lista if (L->IsEmpty()==0){ printf ("\n\nLa Lista no tiene elementos"); getch(); break; } AptNodo=new CElemento(); printf ("\n\nIntroduzca Dato a Buscar: "); scanf ("%f",&ed); AptNodo->SetX(ed); SetNodoBusq(*AptNodo); opcion1=MenuBusqueda(); switch (opcion1){ case '1': //Metodo de Busqueda Secuencial List=new CSecuenc(); List->Busqueda(this); break; } if (GetPos()!=-1){ printf ("\n\nElemento Encontrado en la posicion %d",GetPos()); } else { printf ("\n\nElemento No Encontrado"); } getch(); break; }

Page 99: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

87

} while (opcion!='0'); PantallaFinal(); } char CContexto::MenuPrincipal() { char opcion; do { printf ("\nMENU PRINCIPAL\n"); printf ("\n1. Insertar Elemento."); printf ("\n2. Eliminar Elemento."); printf ("\n3. Mostrar Lista."); printf ("\n4. Ordenar Lista."); printf ("\n5. Buscar Elemento de la Lista."); printf ("\n0. Salir.\n"); printf ("\nElegir opcion: "); opcion=getche(); } while (opcion<'0' || opcion>'5'); return opcion; } char CContexto::MenuOrdenacion() { char opcion; do { printf ("\nMENU METODOS DE ORDENACION\n"); printf ("\n1. Burbuja."); printf ("\n0. Regresar.\n"); printf ("\nElegir opcion: "); opcion=getche(); } while (opcion<'0' || opcion>'1'); return opcion; } char CContexto::MenuBusqueda() { char opcion; do { printf ("\nMENU METODOS DE BUSQUEDA\n"); printf ("\n1. Secuencial."); printf ("\n0. Regresar.\n"); printf ("\nElegir opcion: "); opcion=getche(); } while (opcion<'0' || opcion>'1'); return opcion; } void CContexto::PantallaFinal() { printf ("\nFramework de Ordenaciones y Búsquedas\n"); printf ("\nDiseñado e Implementado por:"); printf ("\n\t\tManuel Alejandro Valdes Marrero"); printf ("\n\nValdesCo. 2003"); }

// Código del Archivo Elemento.h #if !defined(AFX_ELEMENTO) #define AFX_ELEMENTO #include <stdio.h> class CElemento { private: CElemento *AptSig; CElemento *AptAnt; float X; public: CElemento(CElemento *apt1, CElemento *apt2); CElemento(); virtual ~CElemento(); CElemento* GetSig(); CElemento* GetAnt(); float GetX(); void SetSig(CElemento *apt); void SetAnt(CElemento *apt); void SetX(float dato);

Page 100: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

88

void SetSigAnt(CElemento *apt); void SetAntSig(CElemento *apt); }; #endif

// Código del Archivo Elemento.cpp #include "Elemento.h" CElemento::CElemento() { AptSig=NULL; AptAnt=NULL; } CElemento::CElemento(CElemento *apt1, CElemento *apt2) { AptSig=apt1; AptAnt=apt2; } CElemento::~CElemento() { } CElemento* CElemento::GetAnt() { return AptAnt; } CElemento* CElemento::GetSig() { return AptSig; } float CElemento::GetX() { return X; } void CElemento::SetAnt(CElemento *apt) { AptAnt=apt; } void CElemento::SetSig(CElemento *apt) { AptSig=apt; } void CElemento::SetX(float dato) { X=dato; } void CElemento::SetAntSig(CElemento *apt) { CElemento *AuxNodo; AuxNodo=GetAnt(); AuxNodo->SetSig(apt); } void CElemento::SetSigAnt(CElemento *apt) { CElemento *AuxNodo; AuxNodo=GetSig(); AuxNodo->SetAnt(apt); }

// Código del Archivo Lista.h #if !defined(AFX_LISTA) #define AFX_LISTA #include <stdio.h> #include "Elemento.h" #include "Contexto.h" class CElemento; class CContexto; class CLista { private: CElemento *AptH; CElemento *AptT; int N; public: void Anterior(CElemento *(&nodo)); void Siguiente(CElemento *(&nodo)); int IsEmpty(); void Borra(CElemento *(&nodo)); void Agrega(CElemento *nodo);

Page 101: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

89

CLista(); virtual ~CLista(); int GetN(); CElemento* GetH(); CElemento* GetT(); void SetN(int dato); void SetH(CElemento *nodo); void SetT(CElemento *nodo); virtual void Ordena(CContexto *ctx)=0; virtual void Busqueda(CContexto *ctx)=0; }; #endif

// Código del Archivo Lista.cpp #include "Lista.h" CLista::CLista() { AptH=NULL; AptT=NULL; N=0; } CLista::~CLista() { CElemento *NodoAux,*NodoActual; NodoActual=GetH(); while (NodoActual!=NULL){ NodoAux=NodoActual; Siguiente(NodoActual); delete NodoAux; } } int CLista::GetN() { return N; } void CLista::SetN(int dato) { N=dato; } CElemento* CLista::GetH() { return AptH; } CElemento* CLista::GetT() { return AptT; } void CLista::SetH(CElemento *nodo) { AptH=nodo; } void CLista::SetT(CElemento *nodo) { AptT=nodo; } void CLista::Agrega(CElemento *nodo) { CElemento *NodoFinal; if (IsEmpty()!=0){ //La lista tiene elementos NodoFinal=GetT(); NodoFinal->SetSig(nodo); nodo->SetAnt(NodoFinal); nodo->SetSig(NULL); SetT(nodo); } else { //Lista Vacia nodo->SetSig(NULL); nodo->SetAnt(NULL); SetH(nodo); SetT(nodo); } int num=GetN(); num++; SetN(num); }

Page 102: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

90

void CLista::Borra(CElemento *(&nodo)) { int Encontrado=1; CElemento *NodoLista; NodoLista=GetH(); while (NodoLista!=NULL) { if (NodoLista->GetX()==nodo->GetX()) { Encontrado=0; break; } Siguiente(NodoLista); } if (Encontrado==0){ if ((NodoLista->GetAnt())==NULL) { //Eliminado primer elemento SetH(NodoLista->GetSig()); } else { //hay un elemento antes NodoLista->SetAntSig(NodoLista->GetSig()); } if ((NodoLista->GetSig())==NULL){ //Eliminado ultimo elemento SetT(NodoLista->GetAnt()); } else { //hay un elemento despues NodoLista->SetSigAnt(NodoLista->GetAnt()); } delete nodo; int num=GetN(); num--; SetN(num); } } int CLista::IsEmpty() { int n; n=GetN(); if (n==0) return 0; else return 1; } void CLista::Siguiente(CElemento *(&nodo)) { nodo=nodo->GetSig(); } void CLista::Anterior(CElemento *(&nodo)) { nodo=nodo->GetAnt(); }

// Código del Archivo Bubble.h #if !defined(AFX_BUBBLE) #define AFX_BUBBLE #include "Lista.h" class CBubble : public CLista { public: virtual void Ordena(CContexto *ctx); virtual void Busqueda(CContexto *ctx); CBubble(); virtual ~CBubble(); }; #endif

// Código del Archivo Bubble.cpp #include "Bubble.h" CBubble::CBubble() { } CBubble::~CBubble() { } void CBubble::Ordena(CContexto *ctx) {

Page 103: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

91

CElemento *AptNodo1,*AptNodo2; int i,j,n; float x; n=ctx->L->GetN(); int bandera; for (i=1;i<n;i++){ bandera=0; AptNodo1=ctx->L->GetH(); AptNodo2=ctx->L->GetH(); ctx->L->Siguiente(AptNodo2); for (j=1;j<n;j++){ if ((AptNodo1->GetX())>(AptNodo2->GetX())){ bandera=1; x=AptNodo1->GetX(); AptNodo1->SetX(AptNodo2->GetX()); AptNodo2->SetX(x); } ctx->L->Siguiente(AptNodo1); ctx->L->Siguiente(AptNodo2); } if (bandera==0){ //Lista Ordenada break; } } } void CBubble::Busqueda(CContexto *ctx) { }

// Código del Archivo Secuenc.h #if !defined(AFX_SECUENC) #define AFX_SECUENC #include "Lista.h" class CSecuenc : public CLista { public: virtual void Ordena(CContexto *ctx); virtual void Busqueda(CContexto *ctx); CSecuenc(); virtual ~CSecuenc(); }; #endif

// Código del Archivo Secuenc.cpp #include "Secuenc.h" CSecuenc::CSecuenc() { } CSecuenc::~CSecuenc() { } void CSecuenc::Ordena(CContexto *ctx) { } void CSecuenc::Busqueda(CContexto *ctx) { CElemento *AptNodo; CElemento nodo; int i,n; double x; double datoNodo; int bandera=0; n=ctx->L->GetN(); nodo=ctx->GetNodoBusq(); datoNodo=nodo.GetX(); AptNodo=ctx->L->GetH(); for (i=1;i<=n;i++){ x=AptNodo->GetX(); if (x==datoNodo) { // Dato Encontrado ctx->SetPos(i); bandera=1;

Page 104: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

92

break; } ctx->L->Siguiente(AptNodo); } if (bandera==0){ ctx->SetPos(-1); } }

Código Refactorizado // Código del Archivo aMediador.hpp #ifndef _aMediador #define _aMediador class CElemento; class CContexto; class CLista; class aColega; class aMediador { protected: aColega *oCol1; public: aMediador() { } virtual CElemento GetNodoBusq ( CContexto *objCContexto) = 0; virtual void SetPos ( CContexto *objCContexto , int pos) = 0; virtual CElemento* GetSig ( CElemento *objCElemento) = 0; virtual CElemento* GetAnt ( CElemento *objCElemento) = 0; virtual float GetX ( CElemento *objCElemento) = 0; virtual void SetSig ( CElemento *objCElemento , CElemento * apt) = 0; virtual void SetAnt ( CElemento *objCElemento , CElemento * apt) = 0; virtual void SetX ( CElemento *objCElemento , float dato) = 0; virtual void SetSigAnt ( CElemento *objCElemento , CElemento * apt) = 0; virtual void SetAntSig ( CElemento *objCElemento , CElemento * apt) = 0; virtual void Siguiente ( CLista *objCLista , CElemento * ( & nodo )) = 0; virtual int IsEmpty ( CLista *objCLista) = 0; virtual void Borra ( CLista *objCLista , CElemento * ( & nodo )) = 0; virtual void Agrega ( CLista *objCLista , CElemento * nodo) = 0; virtual int GetN ( CLista *objCLista) = 0; virtual CElemento* GetH ( CLista *objCLista) = 0; virtual void Ordena ( CLista *objCLista , CContexto * ctx) = 0; virtual void Busqueda ( CLista *objCLista , CContexto * ctx) = 0; }; #endif

// Código del Archivo cMediador.hpp #ifndef _cMediador #define _cMediador #include "aMediador.HPP" #include "Elemento.h" #include "Contexto.h" #include "Lista.h" class cMediador : public aMediador { public: cMediador() { } CElemento GetNodoBusq ( CContexto *objCContexto); void SetPos ( CContexto *objCContexto , int pos); CElemento* GetSig ( CElemento *objCElemento); CElemento* GetAnt ( CElemento *objCElemento); float GetX ( CElemento *objCElemento); void SetSig ( CElemento *objCElemento , CElemento * apt); void SetAnt ( CElemento *objCElemento , CElemento * apt); void SetX ( CElemento *objCElemento , float dato); void SetSigAnt ( CElemento *objCElemento , CElemento * apt); void SetAntSig ( CElemento *objCElemento , CElemento * apt); void Siguiente ( CLista *objCLista , CElemento * ( & nodo ));

Page 105: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

93

int IsEmpty ( CLista *objCLista); void Borra ( CLista *objCLista , CElemento * ( & nodo )); void Agrega ( CLista *objCLista , CElemento * nodo); int GetN ( CLista *objCLista); CElemento* GetH ( CLista *objCLista); void Ordena ( CLista *objCLista , CContexto * ctx); void Busqueda ( CLista *objCLista , CContexto * ctx); }; #endif

// Código del Archivo cMediador.cpp #include "cMediador.HPP" CElemento cMediador:: GetNodoBusq ( CContexto *objCContexto) { oCol1 = new CContexto(); oCol1 = objCContexto; return(oCol1->GetNodoBusq()); } void cMediador:: SetPos ( CContexto *objCContexto , int pos) { oCol1 = new CContexto(); oCol1 = objCContexto; oCol1->SetPos(pos); } CElemento* cMediador:: GetSig ( CElemento *objCElemento) { oCol1 = new CElemento(); oCol1 = objCElemento; return(oCol1->GetSig()); } CElemento* cMediador:: GetAnt ( CElemento *objCElemento) { oCol1 = new CElemento(); oCol1 = objCElemento; return(oCol1->GetAnt()); } float cMediador:: GetX ( CElemento *objCElemento) { oCol1 = new CElemento(); oCol1 = objCElemento; return(oCol1->GetX()); } void cMediador:: SetSig ( CElemento *objCElemento , CElemento * apt) { oCol1 = new CElemento(); oCol1 = objCElemento; oCol1->SetSig(apt); } void cMediador:: SetAnt ( CElemento *objCElemento , CElemento * apt) { oCol1 = new CElemento(); oCol1 = objCElemento; oCol1->SetAnt(apt); } void cMediador:: SetX ( CElemento *objCElemento , float dato) { oCol1 = new CElemento(); oCol1 = objCElemento; oCol1->SetX(dato); } void cMediador:: SetSigAnt ( CElemento *objCElemento , CElemento * apt) { oCol1 = new CElemento(); oCol1 = objCElemento; oCol1->SetSigAnt(apt); } void cMediador:: SetAntSig ( CElemento *objCElemento , CElemento * apt) { oCol1 = new CElemento(); oCol1 = objCElemento; oCol1->SetAntSig(apt); } void cMediador:: Siguiente ( CLista *objCLista , CElemento * ( & nodo )) { objCLista->Siguiente(nodo); } int cMediador:: IsEmpty ( CLista *objCLista) {

Page 106: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

94

return(objCLista->IsEmpty()); } void cMediador:: Borra ( CLista *objCLista , CElemento * ( & nodo )) { objCLista->Borra(nodo); } void cMediador:: Agrega ( CLista *objCLista , CElemento * nodo) { objCLista->Agrega(nodo); } int cMediador:: GetN ( CLista *objCLista) { return(objCLista->GetN( )); } CElemento* cMediador:: GetH ( CLista *objCLista) { return(objCLista->GetH( )); } void cMediador:: Ordena ( CLista *objCLista , CContexto *ctx) { objCLista->Ordena( ctx); } void cMediador:: Busqueda ( CLista *objCLista , CContexto *ctx) { objCLista->Busqueda( ctx); }

// Código del Archivo aColega.hpp #ifndef _aColega #define _aColega #include <stddef.h> class aMediador; class CElemento; class aColega { protected: aMediador *oMed; public: aColega() { } virtual float GetX ( ) ; virtual void SetX ( float dato ) ; virtual void SetAnt ( CElemento * apt ) ; virtual void SetSig ( CElemento * apt ) ; virtual CElemento* GetSig ( ) ; virtual CElemento* GetAnt ( ) ; virtual void SetAntSig ( CElemento * apt ) ; virtual void SetSigAnt ( CElemento * apt ) ; virtual CElemento GetNodoBusq ( ) ; virtual void SetPos ( int pos ) ; }; #endif

// Código del Archivo aColega.cpp #include "aColega.HPP" #include "Elemento.h" float aColega:: GetX ( ) { return 0; } void aColega:: SetX ( float dato ) { } void aColega:: SetAnt ( CElemento * apt ) { } void aColega:: SetSig ( CElemento * apt ) { } CElemento* aColega:: GetSig ( ) { return NULL; } CElemento* aColega:: GetAnt ( ) { return NULL; } void aColega:: SetAntSig ( CElemento * apt ) { }

Page 107: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

95

void aColega:: SetSigAnt ( CElemento * apt ) { } CElemento aColega:: GetNodoBusq ( ) { CElemento objCElemento; return objCElemento; } void aColega:: SetPos ( int pos ) { }

// Código del Archivo Contexto.h #if !defined(AFX_CONTEXTO) #define AFX_CONTEXTO #include <stdio.h> #include <conio.h> #include "cMediador.hpp" #include "Lista.h" #include "Elemento.h" class CLista; #include "aColega.hpp" class CContexto : public aColega { private: CElemento nodoBusq; int posicion; public: CLista *L; public: CContexto(); virtual ~CContexto(); void Interactua(); CElemento GetNodoBusq(); void SetNodoBusq(CElemento nodo); int GetPos(); void SetPos(int pos); private: char MenuPrincipal(); char MenuOrdenacion(); char MenuBusqueda(); void PantallaFinal(); }; #endif

// Código del Archivo Contexto.cpp #include "Contexto.h" #include "Bubble.h" #include "Secuenc.h" CContexto::CContexto() { L=new CBubble(); } CContexto::~CContexto() { } CElemento CContexto::GetNodoBusq() { return nodoBusq; } void CContexto::SetNodoBusq(CElemento nodo) { nodoBusq=nodo; } int CContexto::GetPos() { return posicion; } void CContexto::SetPos(int pos) { posicion=pos; } void CContexto::Interactua() { oMed = new cMediador(); char opcion,opcion1;

Page 108: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

96

CElemento *AptNodo; float ed; CLista *List; do { opcion=MenuPrincipal(); switch (opcion){ case '1': //Insertar Elemento AptNodo=new CElemento(); printf ("\n\nIntroduzca Dato: "); scanf ("%f",&ed); oMed->SetX(AptNodo,ed); oMed->Agrega(L,AptNodo); break; case '2': //Eliminar Elemento if (oMed->IsEmpty(L)==0){ printf ("\n\nLa Lista no tiene elementos"); getch(); break; } AptNodo=new CElemento(); printf ("\n\nIntroduzca Dato: "); scanf ("%f",&ed); oMed->SetX(AptNodo,ed); oMed->Borra(L,AptNodo); break; case '3': //Mostrar Lista if (oMed->IsEmpty(L)==0){ printf ("\n\nLa Lista no tiene elementos"); getch(); break; } AptNodo=oMed->GetH(L); printf ("\n\n"); while (AptNodo!=NULL){ ed=(float)oMed->GetX(AptNodo); printf ("\n%f",ed); oMed->Siguiente(L,AptNodo); } getch(); break; case '4': //Ordenar Lista opcion1=MenuOrdenacion(); switch (opcion1){ case '1': //Metodo de la Burbuja List=new CBubble(); oMed->Ordena(List,this); break; } break; case '5': //Buscar Elemento de la Lista if (oMed->IsEmpty(L)==0){ printf ("\n\nLa Lista no tiene elementos"); getch(); break; } AptNodo=new CElemento(); printf ("\n\nIntroduzca Dato a Buscar: "); scanf ("%f",&ed); oMed->SetX(AptNodo,ed); SetNodoBusq(*AptNodo); opcion1=MenuBusqueda(); switch (opcion1){ case '1': //Metodo de Busqueda Secuencial List=new CSecuenc(); oMed->Busqueda(List,this); break; }

Page 109: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

97

if (GetPos()!=-1){ printf ("\n\nElemento Encontrado en la posicion %d",GetPos()); } else { printf ("\n\nElemento No Encontrado"); } getch(); break; } } while (opcion!='0'); PantallaFinal(); } char CContexto::MenuPrincipal() { char opcion; do { printf ("\nMENU PRINCIPAL\n"); printf ("\n1. Insertar Elemento."); printf ("\n2. Eliminar Elemento."); printf ("\n3. Mostrar Lista."); printf ("\n4. Ordenar Lista."); printf ("\n5. Buscar Elemento de la Lista."); printf ("\n0. Salir.\n"); printf ("\nElegir opcion: "); opcion=getche(); } while (opcion<'0' || opcion>'5'); return opcion; } char CContexto::MenuOrdenacion() { char opcion; do { printf ("\nMENU METODOS DE ORDENACION\n"); printf ("\n1. Burbuja."); printf ("\n0. Regresar.\n"); printf ("\nElegir opcion: "); opcion=getche(); } while (opcion<'0' || opcion>'1'); return opcion; } char CContexto::MenuBusqueda() { char opcion; do { printf ("\nMENU METODOS DE BUSQUEDA\n"); printf ("\n1. Secuencial."); printf ("\n0. Regresar.\n"); printf ("\nElegir opcion: "); opcion=getche(); } while (opcion<'0' || opcion>'1'); return opcion; } void CContexto::PantallaFinal() { printf ("\nFramework de Ordenaciones y Búsquedas\n"); printf ("\nDiseñado e Implementado por:"); printf ("\n\t\tManuel Alejandro Valdes Marrero"); printf ("\n\nValdesCo. 2003"); }

// Código del Archivo Elemento.h #if !defined(AFX_ELEMENTO) #define AFX_ELEMENTO #include <stdio.h> #include "aColega.hpp" class CElemento : public aColega { private: CElemento *AptSig; CElemento *AptAnt;

Page 110: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

98

float X; public: CElemento(CElemento *apt1, CElemento *apt2); CElemento(); virtual ~CElemento(); CElemento* GetSig(); CElemento* GetAnt(); float GetX(); void SetSig(CElemento *apt); void SetAnt(CElemento *apt); void SetX(float dato); void SetSigAnt(CElemento *apt); void SetAntSig(CElemento *apt); }; #endif

// Código del Archivo Elemento.cpp #include "Elemento.h" CElemento::CElemento() { AptSig=NULL; AptAnt=NULL; } CElemento::CElemento(CElemento *apt1, CElemento *apt2) { AptSig=apt1; AptAnt=apt2; } CElemento::~CElemento() { } CElemento* CElemento::GetAnt() { return AptAnt; } CElemento* CElemento::GetSig() { return AptSig; } float CElemento::GetX() { return X; } void CElemento::SetAnt(CElemento *apt) { AptAnt=apt; } void CElemento::SetSig(CElemento *apt) { AptSig=apt; } void CElemento::SetX(float dato) { X=dato; } void CElemento::SetAntSig(CElemento *apt) { CElemento *AuxNodo; AuxNodo=GetAnt(); AuxNodo->SetSig(apt); } void CElemento::SetSigAnt(CElemento *apt) { CElemento *AuxNodo; AuxNodo=GetSig(); AuxNodo->SetAnt(apt); }

// Código del Archivo Lista.h #if !defined(AFX_LISTA) #define AFX_LISTA #include <stdio.h> #include "cMediador.hpp" #include "Elemento.h" #include "Contexto.h" class CElemento;

Page 111: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

99

class CContexto; class aMediador; class CLista { protected: aMediador *oMed; private: CElemento *AptH; CElemento *AptT; int N; public: void Anterior(CElemento *(&nodo)); void Siguiente(CElemento *(&nodo)); int IsEmpty(); void Borra(CElemento *(&nodo)); void Agrega(CElemento *nodo); CLista(); virtual ~CLista(); int GetN(); CElemento* GetH(); CElemento* GetT(); void SetN(int dato); void SetH(CElemento *nodo); void SetT(CElemento *nodo); virtual void Ordena(CContexto *ctx)=0; virtual void Busqueda(CContexto *ctx)=0; }; #endif

// Código del Archivo Lista.cpp #include "Lista.h" CLista::CLista() { AptH=NULL; AptT=NULL; N=0; } CLista::~CLista() { CElemento *NodoAux,*NodoActual; NodoActual=GetH(); while (NodoActual!=NULL){ NodoAux=NodoActual; Siguiente(NodoActual); delete NodoAux; } } int CLista::GetN() { return N; } void CLista::SetN(int dato) { N=dato; } CElemento* CLista::GetH() { return AptH; } CElemento* CLista::GetT() { return AptT; } void CLista::SetH(CElemento *nodo) { AptH=nodo; } void CLista::SetT(CElemento *nodo) { AptT=nodo; } void CLista::Agrega(CElemento *nodo) { oMed = new cMediador(); CElemento *NodoFinal; if (IsEmpty()!=0){ //La lista tiene elementos

Page 112: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

100

NodoFinal=GetT(); oMed->SetSig(NodoFinal,nodo); oMed->SetAnt(nodo,NodoFinal); oMed->SetSig(nodo,NULL); SetT(nodo); } else { //Lista Vacia oMed->SetSig(nodo,NULL); oMed->SetAnt(nodo,NULL); SetH(nodo); SetT(nodo); } int num=GetN(); num++; SetN(num); } void CLista::Borra(CElemento *(&nodo)) { oMed = new cMediador(); int Encontrado=1; CElemento *NodoLista; NodoLista=GetH(); while (NodoLista!=NULL) { if (oMed->GetX(NodoLista)==oMed->GetX(nodo)) { Encontrado=0; break; } Siguiente(NodoLista); } if (Encontrado==0){ if ((oMed->GetAnt(NodoLista))==NULL) { //Eliminado primer elemento SetH(oMed->GetSig(NodoLista)); } else { //hay un elemento antes oMed->SetAntSig(NodoLista,oMed->GetSig(NodoLista)); } if ((oMed->GetSig(NodoLista))==NULL){ //Eliminado ultimo elemento SetT(oMed->GetAnt(NodoLista)); } else { //hay un elemento despues oMed->SetSigAnt(NodoLista,oMed->GetAnt(NodoLista)); } delete nodo; int num=GetN(); num--; SetN(num); } } int CLista::IsEmpty() { int n; n=GetN(); if (n==0) return 0; else return 1; } void CLista::Siguiente(CElemento *(&nodo)) { oMed = new cMediador(); nodo=oMed->GetSig(nodo); } void CLista::Anterior(CElemento *(&nodo)) { oMed = new cMediador(); nodo=oMed->GetAnt(nodo); }

// Código del Archivo Bubble.h #if !defined(AFX_BUBBLE)

Page 113: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

101

#define AFX_BUBBLE #include "cMediador.hpp" #include "Lista.h" class CBubble : public CLista { public: virtual void Ordena(CContexto *ctx); virtual void Busqueda(CContexto *ctx); CBubble(); virtual ~CBubble(); }; #endif

// Código del Archivo Bubble.cpp #include "Bubble.h" CBubble::CBubble() { } CBubble::~CBubble() { } void CBubble::Ordena(CContexto *ctx) { oMed = new cMediador(); CElemento *AptNodo1,*AptNodo2; int i,j,n; float x; n=oMed->GetN(ctx->L); int bandera; for (i=1;i<n;i++){ bandera=0; AptNodo1=oMed->GetH(ctx->L); AptNodo2=oMed->GetH(ctx->L); oMed->Siguiente(ctx->L,AptNodo2); for (j=1;j<n;j++){ if ((oMed->GetX(AptNodo1))>(oMed->GetX(AptNodo2))){ bandera=1; x=oMed->GetX(AptNodo1); oMed->SetX(AptNodo1,oMed->GetX(AptNodo2)); oMed->SetX(AptNodo2,x); } oMed->Siguiente(ctx->L,AptNodo1); oMed->Siguiente(ctx->L,AptNodo2); } if (bandera==0){ //Lista Ordenada break; } } } void CBubble::Busqueda(CContexto *ctx) { }

// Código del Archivo Secuenc.h #if !defined(AFX_SECUENC) #define AFX_SECUENC #include "cMediador.hpp" #include "Lista.h" class CSecuenc : public CLista { public: virtual void Ordena(CContexto *ctx); virtual void Busqueda(CContexto *ctx); CSecuenc(); virtual ~CSecuenc(); }; #endif

// Código del Archivo Secuenc.cpp #include "Secuenc.h" CSecuenc::CSecuenc() {

Page 114: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo B

102

} CSecuenc::~CSecuenc() { } void CSecuenc::Ordena(CContexto *ctx) { } void CSecuenc::Busqueda(CContexto *ctx) { oMed = new cMediador(); CElemento *AptNodo; CElemento nodo; int i,n; double x; double datoNodo; int bandera=0; n=oMed->GetN(ctx->L); nodo=oMed->GetNodoBusq(ctx); datoNodo=oMed->GetX(&(nodo)); AptNodo=oMed->GetH(ctx->L); for (i=1;i<=n;i++){ x=oMed->GetX(AptNodo); if (x==datoNodo) { // Dato Encontrado oMed->SetPos(ctx,i); bandera=1; break; } oMed->Siguiente(ctx->L,AptNodo); } if (bandera==0){ oMed->SetPos(ctx,-1); } }

Page 115: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

103

ANEXO C CÓDIGO DEL CASO DE PRUEBA 3 Se muestra parte del código del marco de estadística, que fue utilizado como tercer caso de prueba. También se muestra parte del código del marco después de la refactorización, añadiendo las clases mediadoras abstracta y concreta, así como la colega abstracta. De las clases propias del sistema sólo se muestran las que sufren cambios.

Page 116: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

104

Código Original // Código del Archivo Contexto.h #if !defined(AFX_CONTEXTO) #define AFX_CONTEXTO #include <stdio.h> #include <conio.h> #include "Lista.h" #include "Strategy.h" #include "Elemento.h" #include "Matriz.h" class CStrategy; class CContexto { private: double Resultado; double Parametro1; double Parametro2; public: CLista *L1; CLista *L2; CLista *L3; CStrategy *str; CMatriz *M1; CMatriz *M2; public: CContexto(); virtual ~CContexto(); void Interactua(); double GetRes(); void SetRes(double dato); double GetParametro1(); void SetParametro1(double dato); double GetParametro2(); void SetParametro2(double dato);

... }; #endif

// Parte del Código del Archivo Contexto.cpp ... case 4: //double AptNodo=new CElemento(); AptNodo->ED=new cED4(); printf ("\n\nIntroduzca Dato: "); scanf ("%lf",&ed4); AptNodo->ED->SetED(ed4); break; } L1->Eliminar(AptNodo); break; case '4': //Mostrar Lista AptNodo=L1->GetH(); printf ("\n\n"); while (AptNodo!=NULL){ switch(L1->GetTipo()){ case 1: //float ed1=(float)AptNodo->ED->GetED(); printf ("\n%f",ed1); break; case 2: //int ed2=(int)AptNodo->ED->GetED(); printf ("\n%d",ed2); break; case 3: //char

Page 117: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

105

ed3=(char)AptNodo->ED->GetED(); printf ("\n%c",ed3); break; case 4: //double ed4=AptNodo->ED->GetED(); printf ("\n%lf",ed4); break; } L1->Siguiente(AptNodo); } getch(); break; case '5': //Ordenar Lista opcion111=MenuOrdenacion(); switch (opcion111){ case '1': //Metodo de la Burbuja str=new CBubble(); str->Ordena(this); break; case '2': //Metodo Shell str=new CShell(); str->Ordena(this); break; case '3': //Metodo de Seleccion str=new CSelec(); str->Ordena(this); break; case '4': //Metodo de Insercion str=new CInserc(); str->Ordena(this); break; } break; } } while (opcion11!='0'); } } while (opcion1!='0'); L1=&Lista1; L2=&Lista2; L3=&Lista3; break; case '2': //Calculo de Medidas de Tendencia Central do{ opcion1=MenuTendenciaCentral(); switch (opcion1){ case '1': //Media Aritmetica str=new CMediaAri(); str->Calcula(this); result=GetRes(); if (result==NULL) printf ("\nPrimero debe introducir elementos en la Lista"); else printf ("\nLa Media Aritmetica es: %lf",result); getch(); break;

... // Código del Archivo Strategy.h #if !defined(AFX_STRATEGY) #define AFX_STRATEGY #include "Contexto.h" class CContexto; class CStrategy { public: CStrategy(); virtual ~CStrategy();

Page 118: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

106

virtual void Calcula(CContexto *ctx)=0; virtual void Ordena(CContexto *ctx)=0; virtual void Resuelve(CContexto *ctx)=0; virtual double GetResultado()=0; }; #endif

// Código del Archivo MediaAri.h #if !defined(AFX_MEDIAARI) #define AFX_MEDIAARI #include "Strategy.h" class CMediaAri : public Cstrategy { public: void SetMedia(double dato); double GetMedia(); virtual void Calcula(CContexto *ctx); virtual void Ordena(CContexto *ctx); virtual void Resuelve(CContexto *ctx); virtual double GetResultado(); CMediaAri(); virtual ~CMediaAri(); private: CStrategy *obj; double media; }; #endif

// Parte del Código del Archivo MediaAri.cpp ... void CMediaAri::Calcula(CContexto *ctx) { double sumatoria=0; double aux=0; int N=0; obj=new CSuma(); obj->Calcula(ctx); sumatoria=obj->GetResultado(); N=ctx->L1->GetN(); if (N==0) //caso de error aux=NULL; else aux=sumatoria/N; SetMedia(aux); ctx->SetRes(aux); }

... // Código del Archivo Selec.h #if !defined(AFX_SELEC) #define AFX_SELEC #include "Strategy.h" class CSelec : public Cstrategy { public: virtual void Calcula(CContexto *ctx); virtual void Ordena(CContexto *ctx); virtual void Resuelve(CContexto *ctx); virtual double GetResultado(); CSelec(); virtual ~CSelec(); }; #endif

Page 119: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

107

// Parte del Código del Archivo Selec.cpp ... void CSelec::Ordena(CContexto *ctx) { CElemento *AptNodo1,*AptNodo2; int i,j,k,n; double x; n=ctx->L1->GetN(); AptNodo1=ctx->L1->GetH(); for (i=0;i<(n-1);i++){ AptNodo2=ctx->L1->GetH(); for (k=1;k<=(i+1);k++) ctx->L1->Siguiente(AptNodo2); for (j=i+1;j<n;j++){ if ((AptNodo1->ED->GetED())>(AptNodo2->ED->GetED())){ x=AptNodo1->ED->GetED(); AptNodo1->ED->SetED(AptNodo2->ED->GetED()); AptNodo2->ED->SetED(x); } ctx->L1->Siguiente(AptNodo2); } ctx->L1->Siguiente(AptNodo1); } }

... // Código del Archivo Lista.h #if !defined(AFX_LISTA) #define AFX_LISTA #include <stdio.h> #include "Elemento.h" class CElemento; class CLista { private: CElemento *AptH; CElemento *AptC; int tipo; int N; public: void Anterior(CElemento *(&AptNodo)); void Siguiente(CElemento *(&AptNodo)); void Insertar(CElemento *AptAux, CElemento *AptNodo); void Apilar(CElemento *AptNodo); CLista(int tipoDato); int EstaVacia(); void Eliminar(CElemento *(&AptNodo)); void Agregar(CElemento *AptNodo); CLista(); virtual ~CLista(); int GetTipo(); int GetN(); CElemento* GetH(); CElemento* GetC(); void SetTipo (int dato); void SetN(int dato); void SetH(CElemento *AptNodo); void SetC(CElemento *AptNodo); }; #endif

// Parte del Código del Archivo Lista.cpp ... void CLista::Agregar(CElemento *AptNodo) { CElemento *NodoFinal; if (EstaVacia()!=0){

Page 120: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

108

//La lista tiene elementos NodoFinal=GetC(); NodoFinal->SetSig(AptNodo); AptNodo->SetAnt(NodoFinal); AptNodo->SetSig(NULL); SetC(AptNodo); } else { //Lista Vacia AptNodo->SetSig(NULL); AptNodo->SetAnt(NULL); SetH(AptNodo); SetC(AptNodo); } int num=GetN(); num++; SetN(num); } void CLista::Eliminar(CElemento *(&AptNodo)) { int Encontrado=1; CElemento *NodoLista; NodoLista=GetH(); while (NodoLista!=NULL) { if (NodoLista->ED->GetED()==AptNodo->ED->GetED()) { Encontrado=0; break; } Siguiente(NodoLista); } if (Encontrado==0){ if ((NodoLista->GetAnt())==NULL) { //Eliminado primer elemento SetH(NodoLista->GetSig()); } else { //hay un elemento antes NodoLista->SetAntSig(NodoLista->GetSig()); } if ((NodoLista->GetSig())==NULL){ //Eliminado ultimo elemento SetC(NodoLista->GetAnt()); } else { //hay un elemento despues NodoLista->SetSigAnt(NodoLista->GetAnt()); } delete AptNodo; int num=GetN(); num--; SetN(num); } }

... Código Refactorizado // Código del Archivo CMediadorAbs.hpp #ifndef _CMediadorAbs #define _CMediadorAbs class CElemento; class CContexto; class CLista; class aED; class CStrategy; class CMatriz;

Page 121: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

109

class CColega; class CMediadorAbs { protected: CColega *oCol1; public: CMediadorAbs() { } virtual void Siguiente( CLista *objCLista, CElemento * ( & AptNodo ) ) = 0; virtual int GetN( CLista *objCLista) = 0; virtual CElemento* GetH( CLista *objCLista) = 0; virtual double GetED( aED *objaED) = 0; virtual void SetED( aED *objaED, double dato ) = 0; virtual int EstaVacia( CLista *objCLista) = 0; virtual void Eliminar( CLista *objCLista, CElemento * ( & AptNodo ) ) = 0; virtual void Agregar( CLista *objCLista, CElemento * AptNodo ) = 0; virtual int GetTipo( CLista *objCLista) = 0; virtual void SetTipo( CLista *objCLista, int dato ) = 0; virtual void Calcula( CStrategy *objCStrategy, CContexto * ctx ) = 0; virtual void Ordena( CStrategy *objCStrategy, CContexto * ctx ) = 0; virtual double GetCelda( CMatriz *objCMatriz, int renglon , int columna ) = 0; virtual double GetRes( CContexto *objCContexto) = 0; virtual void SetRes( CContexto *objCContexto, double dato ) = 0; virtual double GetResultado( CStrategy *objCStrategy) = 0; virtual double GetParametro1( CContexto *objCContexto) = 0; virtual double GetParametro2( CContexto *objCContexto) = 0; virtual int GetRen( CMatriz *objCMatriz) = 0; virtual void SetRen( CMatriz *objCMatriz, int dato ) = 0; virtual void SetCol( CMatriz *objCMatriz, int dato ) = 0; virtual void SetCelda( CMatriz *objCMatriz, int renglon , int columna , double dato ) = 0; virtual void Anterior( CLista *objCLista, CElemento * ( & AptNodo ) ) = 0; virtual CElemento* GetSig( CElemento *objCElemento) = 0; virtual CElemento* GetAnt( CElemento *objCElemento) = 0; virtual void SetSig( CElemento *objCElemento, CElemento * AptNodo ) = 0; virtual void SetAnt( CElemento *objCElemento, CElemento * AptNodo ) = 0; virtual void SetSigAnt( CElemento *objCElemento, CElemento * AptNodo ) = 0; virtual void SetAntSig( CElemento *objCElemento, CElemento * AptNodo ) = 0; virtual void SetParametro1( CContexto *objCContexto, double dato ) = 0; virtual CElemento* GetC( CLista *objCLista) = 0; virtual void Resuelve( CStrategy *objCStrategy, CContexto * ctx ) = 0; }; #endif

// Código del Archivo CMediadorCon.hpp #ifndef _CMediadorCon #define _CMediadorCon #include "CMediadorAbs.HPP" #include "Elemento.h" #include "Contexto.h" #include "Lista.h" #include "aED.h" #include "Strategy.h" #include "Matriz.h" class CMediadorCon : public CMediadorAbs { public: CMediadorCon() { } //Constructor void Siguiente( CLista *objCLista, CElemento * ( & AptNodo ) ); int GetN( CLista *objCLista); CElemento* GetH( CLista *objCLista); double GetED( aED *objaED); void SetED( aED *objaED, double dato ); int EstaVacia( CLista *objCLista); void Eliminar( CLista *objCLista, CElemento * ( & AptNodo ) ); void Agregar( CLista *objCLista, CElemento * AptNodo ); int GetTipo( CLista *objCLista); void SetTipo( CLista *objCLista, int dato ); void Calcula( CStrategy *objCStrategy, CContexto * ctx );

Page 122: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

110

void Ordena( CStrategy *objCStrategy, CContexto * ctx ); double GetCelda( CMatriz *objCMatriz, int renglon , int columna ); double GetRes( CContexto *objCContexto); void SetRes( CContexto *objCContexto, double dato ); double GetResultado( CStrategy *objCStrategy); double GetParametro1( CContexto *objCContexto); double GetParametro2( CContexto *objCContexto); int GetRen( CMatriz *objCMatriz); void SetRen( CMatriz *objCMatriz, int dato ); void SetCol( CMatriz *objCMatriz, int dato ); void SetCelda( CMatriz *objCMatriz, int renglon , int columna , double dato ); void Anterior( CLista *objCLista, CElemento * ( & AptNodo ) ); CElemento* GetSig( CElemento *objCElemento); CElemento* GetAnt( CElemento *objCElemento); void SetSig( CElemento *objCElemento, CElemento * AptNodo ); void SetAnt( CElemento *objCElemento, CElemento * AptNodo ); void SetSigAnt( CElemento *objCElemento, CElemento * AptNodo ); void SetAntSig( CElemento *objCElemento, CElemento * AptNodo ); void SetParametro1( CContexto *objCContexto, double dato ); CElemento* GetC( CLista *objCLista); void Resuelve( CStrategy *objCStrategy, CContexto * ctx ); protected: }; #endif

// Parte del Código del Archivo CMediadorCon.cpp #include "CMediadorCon.HPP" void CMediadorCon:: Siguiente( CLista *objCLista, CElemento * ( & AptNodo ) ) { oCol1 = new CLista( ); oCol1 = objCLista; oCol1->Siguiente(AptNodo); } //fin del método Siguiente int CMediadorCon:: GetN( CLista *objCLista) { oCol1 = new CLista( ); oCol1 = objCLista; return(oCol1->GetN()); } //fin del método GetN CElemento* CMediadorCon:: GetH( CLista *objCLista) { oCol1 = new CLista( ); oCol1 = objCLista; return(oCol1->GetH()); } //fin del método GetH double CMediadorCon:: GetED( aED *objaED) { return(objaED->GetED()); } //fin del método GetED void CMediadorCon:: SetED( aED *objaED, double dato ) { objaED->SetED(dato); } //fin del método SetED

... void CMediadorCon:: Eliminar( CLista *objCLista, CElemento * ( & AptNodo ) ) { oCol1 = new CLista( ); oCol1 = objCLista; oCol1->Eliminar(AptNodo); } //fin del método Eliminar void CMediadorCon:: Agregar( CLista *objCLista, CElemento * AptNodo ) { oCol1 = new CLista( ); oCol1 = objCLista; oCol1->Agregar(AptNodo); } //fin del método Agregar

... void CMediadorCon:: Calcula( CStrategy *objCStrategy, CContexto * ctx ) { objCStrategy->Calcula(ctx); } //fin del método Calcula void CMediadorCon:: Ordena( CStrategy *objCStrategy, CContexto * ctx ) { objCStrategy->Ordena(ctx);

Page 123: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

111

} //fin del método Ordena

... // Código del Archivo Colega.hpp #ifndef _CColega #define _CColega #include <stddef.h> class CMediadorAbs; class CElemento; class CColega { protected: CMediadorAbs *oMed; public: CColega(){} virtual void Siguiente ( CElemento * ( & AptNodo ) ) ; virtual int GetN ( ) ; virtual CElemento* GetH ( ) ; virtual int EstaVacia ( ) ; virtual void Eliminar ( CElemento * ( & AptNodo ) ) ; virtual void Agregar ( CElemento * AptNodo ) ; virtual int GetTipo ( ) ; virtual void SetTipo ( int dato ) ; virtual double GetCelda ( int renglon , int columna ) ; virtual double GetRes ( ) ; virtual void SetRes ( double dato ) ; virtual double GetParametro1 ( ) ; virtual double GetParametro2 ( ) ; virtual int GetRen ( ) ; virtual void SetRen ( int dato ) ; virtual void SetCol ( int dato ) ; virtual void SetCelda ( int renglon , int columna , double dato ) ; virtual void Anterior ( CElemento * ( & AptNodo ) ) ; virtual CElemento* GetSig ( ) ; virtual CElemento* GetAnt ( ) ; virtual void SetSig ( CElemento * AptNodo ) ; virtual void SetAnt ( CElemento * AptNodo ) ; virtual void SetSigAnt ( CElemento * AptNodo ) ; virtual void SetAntSig ( CElemento * AptNodo ) ; virtual void SetParametro1 ( double dato ) ; virtual CElemento* GetC ( ) ; }; #endif

// Parte del Código del Archivo Colega.cpp #include "CColega.HPP" #include "Elemento.h" void CColega:: Siguiente ( CElemento * ( & AptNodo ) ) { } //fin del método Siguiente int CColega:: GetN ( ) { return 0; } //fin del método GetN CElemento* CColega:: GetH ( ) { return NULL; } //fin del método GetH int CColega:: EstaVacia ( ) { return 0; } //fin del método EstaVacia void CColega:: Eliminar ( CElemento * ( & AptNodo ) ) { } //fin del método Eliminar void CColega:: Agregar ( CElemento * AptNodo ) { } //fin del método Agregar

... // Código del Archivo Contexto.h #if !defined(AFX_CONTEXTO)

Page 124: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

112

#define AFX_CONTEXTO #include <stdio.h> #include <conio.h> #include "CMediadorCon.hpp" #include "Lista.h" #include "Strategy.h" #include "Elemento.h" #include "Matriz.h" class CStrategy; #include "CColega.hpp" class CContexto : public CColega { private: double Resultado; double Parametro1; double Parametro2; public: CLista *L1; CLista *L2; CLista *L3; CStrategy *str; CMatriz *M1; CMatriz *M2; public: CContexto(); virtual ~CContexto(); void Interactua(); double GetRes(); void SetRes(double dato); double GetParametro1(); void SetParametro1(double dato); double GetParametro2(); void SetParametro2(double dato);

... // Parte del Código del Archivo Contexto.cpp ... case 4: //double AptNodo=new CElemento(); AptNodo->ED=new cED4(); printf ("\n\nIntroduzca Dato: "); scanf ("%lf",&ed4); oMed->SetED( AptNodo->ED , ed4); break; } oMed->Eliminar( L1 , AptNodo); break; case '4': //Mostrar Lista AptNodo=oMed->GetH( L1 ); printf ("\n\n"); while (AptNodo!=NULL){ switch(oMed->GetTipo( L1 )){ case 1: //float ed1=(float)oMed->GetED( AptNodo->ED ); printf ("\n%f",ed1); break; case 2: //int ed2=(int)oMed->GetED( AptNodo->ED ); printf ("\n%d",ed2); break; case 3: //char ed3=(char)oMed->GetED( AptNodo->ED ); printf ("\n%c",ed3); break; case 4: //double ed4=oMed->GetED( AptNodo->ED );

Page 125: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

113

printf ("\n%lf",ed4); break; } oMed->Siguiente( L1 , AptNodo); } getch(); break; case '5': //Ordenar Lista opcion111=MenuOrdenacion(); switch (opcion111){ case '1': //Metodo de la Burbuja str=new CBubble(); oMed->Ordena( str , this); break; case '2': //Metodo Shell str=new CShell(); oMed->Ordena( str , this); break; case '3': //Metodo de Seleccion str=new CSelec(); oMed->Ordena( str , this); break; case '4': //Metodo de Insercion str=new CInserc(); oMed->Ordena( str , this); break; } break; } } while (opcion11!='0'); } } while (opcion1!='0'); L1=&Lista1; L2=&Lista2; L3=&Lista3; break; case '2': //Calculo de Medidas de Tendencia Central do{ opcion1=MenuTendenciaCentral(); switch (opcion1){ case '1': //Media Aritmetica str=new CMediaAri(); oMed->Calcula( str , this); result=GetRes(); if (result==NULL) printf ("\nPrimero debe introducir elementos en la Lista"); else printf ("\nLa Media Aritmetica es: %lf",result); getch(); break;

... // Código del Archivo Strategy.h #if !defined(AFX_STRATEGY) #define AFX_STRATEGY #include "Contexto.h" class CContexto; class CMediadorAbs; class CStrategy { protected: CMediadorAbs *oMed; public: CStrategy(); virtual ~CStrategy(); virtual void Calcula(CContexto *ctx)=0; virtual void Ordena(CContexto *ctx)=0;

Page 126: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

114

virtual void Resuelve(CContexto *ctx)=0; virtual double GetResultado()=0; }; #endif

// Código del Archivo MediaAri.h #if !defined(AFX_MEDIAARI) #define AFX_MEDIAARI_H #include "CMediadorCon.hpp" #include "Strategy.h" class CMediaAri : public CStrategy { public: void SetMedia(double dato); double GetMedia(); virtual void Calcula(CContexto *ctx); virtual void Ordena(CContexto *ctx); virtual void Resuelve(CContexto *ctx); virtual double GetResultado(); CMediaAri(); virtual ~CMediaAri(); private: CStrategy *obj; double media; }; #endif

// Parte del Código del Archivo MediaAri.cpp ... void CMediaAri::Calcula(CContexto *ctx) { oMed = new CMediadorCon(); double sumatoria=0; double aux=0; int N=0; obj=new CSuma(); oMed->Calcula( obj , ctx); sumatoria=oMed->GetResultado( obj ); N=oMed->GetN( ctx->L1 ); if (N==0) //caso de error aux=NULL; else aux=sumatoria/N; SetMedia(aux); oMed->SetRes( ctx , aux); }

... // Código del Archivo Selec.h #if !defined(AFX_SELEC) #define AFX_SELEC_H #include "CMediadorCon.hpp" #include "Strategy.h" class CSelec : public CStrategy { public: virtual void Calcula(CContexto *ctx); virtual void Ordena(CContexto *ctx); virtual void Resuelve(CContexto *ctx); virtual double GetResultado(); CSelec(); virtual ~CSelec(); }; #endif

Page 127: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

115

// Parte del Código del Archivo Selec.cpp ... void CSelec::Ordena(CContexto *ctx) { oMed = new CMediadorCon(); CElemento *AptNodo1,*AptNodo2; int i,j,k,n; double x; n=oMed->GetN( ctx->L1 ); AptNodo1=oMed->GetH( ctx->L1 ); for (i=0;i<(n-1);i++){ AptNodo2=oMed->GetH( ctx->L1 ); for (k=1;k<=(i+1);k++) oMed->Siguiente( ctx->L1 , AptNodo2); for (j=i+1;j<n;j++){ if ((oMed->GetED( AptNodo1->ED ))>(oMed->GetED( AptNodo2->ED ))){ x=oMed->GetED( AptNodo1->ED ); oMed->SetED( AptNodo1->ED , oMed->GetED( AptNodo2->ED )); oMed->SetED( AptNodo2->ED , x); } oMed->Siguiente( ctx->L1 , AptNodo2); } oMed->Siguiente( ctx->L1 , AptNodo1); } }

... // Código del Archivo Lista.h #if !defined(AFX_LISTA) #define AFX_LISTA #include <stdio.h> #include "CMediadorCon.hpp" #include "Elemento.h" class CElemento; #include "CColega.hpp" class CLista : public CColega { private: CElemento *AptH; CElemento *AptC; int tipo; int N; public: void Anterior(CElemento *(&AptNodo)); void Siguiente(CElemento *(&AptNodo)); void Insertar(CElemento *AptAux, CElemento *AptNodo); void Apilar(CElemento *AptNodo); CLista(int tipoDato); int EstaVacia(); void Eliminar(CElemento *(&AptNodo)); void Agregar(CElemento *AptNodo); CLista(); virtual ~CLista(); int GetTipo(); int GetN(); CElemento* GetH(); CElemento* GetC(); void SetTipo (int dato); void SetN(int dato); void SetH(CElemento *AptNodo); void SetC(CElemento *AptNodo); }; #endif

// Parte del Código del Archivo Lista.cpp ...

Page 128: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Anexo C

116

void CLista::Agregar(CElemento *AptNodo) { oMed = new CMediadorCon(); CElemento *NodoFinal; if (EstaVacia()!=0){ //La lista tiene elementos NodoFinal=GetC(); oMed->SetSig( NodoFinal , AptNodo); oMed->SetAnt( AptNodo , NodoFinal); oMed->SetSig( AptNodo , NULL); SetC(AptNodo); } else { //Lista Vacia oMed->SetSig( AptNodo , NULL); oMed->SetAnt( AptNodo , NULL); SetH(AptNodo); SetC(AptNodo); } int num=GetN(); num++; SetN(num); } void CLista::Eliminar(CElemento *(&AptNodo)) { oMed = new CMediadorCon(); int Encontrado=1; CElemento *NodoLista; NodoLista=GetH(); while (NodoLista!=NULL) { if (oMed->GetED( NodoLista->ED )==oMed->GetED( AptNodo->ED )) { Encontrado=0; break; } Siguiente(NodoLista); } if (Encontrado==0){ if ((oMed->GetAnt( NodoLista ))==NULL) { //Eliminado primer elemento SetH(oMed->GetSig( NodoLista )); } else { //hay un elemento antes oMed->SetAntSig( NodoLista , oMed->GetSig( NodoLista )); } if ((oMed->GetSig( NodoLista ))==NULL){ //Eliminado ultimo elemento SetC(oMed->GetAnt( NodoLista )); } else { //hay un elemento despues oMed->SetSigAnt( NodoLista , oMed->GetAnt( NodoLista )); } delete AptNodo; int num=GetN(); num--; SetN(num); } }

...

Page 129: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Referencias

117

REFERENCIAS [Abra01] Alain Abran, James W. Moore, Pierre Bourque, Robert Dupuis y Leonard

L. Tripp; Guide to the Software Engineering Body of Knowledge; IEEE Trial Version 0.95; www.swebok.org; 2001

[Bria96] Lionel Briand, Sandro Morasca y Victor R. Basili; “Property-Based

Software Engineering Measurement”; IEEE Transactions on Software Engineering, No 1; 1996

[Brit95] Fernando Brito e Abreu, Miguel Goulao y Rita Esteves; “Toward the Design

Quality Evaluation of Object-Oriented Software Systems”; Proceedings of the 5th International Conference on Software Quality; Austin, Estados Unidos; 1995

[Camp97] Marcelo Campo, Claudia A. Marcos y Alvaro Ortigosa; “Framework

Comprehension and Design Patterns: A Reverse Engineering Approach”; Proceedings of the Ninth International Conference on Software Engineering and Knowledge Engineering; Madrid, España; 1997

[Cast99] Félix A. Castro; IPADIC++ Sistema de Identificación de Patrones de

Diseño en Código C++; Tesis de Maestría; Departamento de Ciencias Computacionales, Centro Nacional de Investigación y Desarrollo Tecnológico; 1999

[Cham97] Dennis de Champeaux; Object Oriented Development Process and Metrics;

Prentice Hall; 1997 [ChuW00] William C. Chu, Chih-Wei Lu, Chih-Peng Shiu y Xudong He; “Pattern-

Based Software Reengineering: a Case Study”; Journal of Software Maintenance: Research and Practice, No 12; 2000

[Dami98] Adrian Damian; Software Frameworks; Reporte Técnico, SENG 609.03

Object Theory; 1998 [Dami99] Adrian Damian; An Object-Oriented Framework for the Simulation of

Network Models; Tesis de Maestría; Department of Computer Science, University of Calgary; 1999

[Deit03] Harvey M. Deitel y Paul J. Deitel; C++ Cómo Programar; Prentice Hall;

2003 [Fent94] Norman E. Fenton; “Software Measurement: A Necessary Scientific Basis”;

IEEE Transactions on Software Engineering, No 3; 1994

Page 130: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Referencias

118

[Fent97] Norman E. Fenton y Shari L. Pfleeger; Software Metrics: A Rigorous and Practical Approach; PWS Publishing; 1997

[Fowl99] Martin Fowler, Kent Beck, John Brant, William F. Opdyke y Donald

Roberts; Refactoring, Improving the Design of Existing Code; Addison Wesley, 1999

[Free87] Peter A. Freeman; “A Perspective on Reusability”; IEEE Tutorial: Software

Reusability, IEEE Computer Society Press; 1987 [Gamm95] Erich Gamma, Richard Helm, Ralph Johnson, y John Vlissides; Design

Patterns: Elements of Reusable Software Architecture; Addison-Wesley; 1995

[Garc97] Francisco J. García, José M. Marqués y Jesús M. Maudes; Análisis y Diseño

Orientado al Objeto para Reutilización; Reporte Técnico, TR-GIRO-01-97V2.1.1; Universidad de Valladolid; 1997

[Garc98] Francisco J. García; “Patrones: De Alexander a la Tecnología de Objetos”;

Revista Profesional para Programadores (RPP), No 45; Editorial América-Ibérica; 1998

[Java03] Java – net; Java Compiler Compiler (JavaCC) - The Java Parser Generator;

https://javacc.dev.java.net/; 2003 [Joya96] Luis Joyanes; Programación Orientada a Objetos. Conceptos, Modelado,

Diseño y Codificación en C++; Mc Graw Hill; 1996 [Kell99] Rudolf K. Keller, Reinhard Schauer, Sébastien Robitaille y Patrick Pagé;

“Pattern-Based Reverse-Engineering of Design Components”; Proceedings of the 21st International Conference on Software Engineering, ICSE 99; Los Angeles, Estados Unidos; 1999

[Keri03] Joshua Kerievsky; DRAFT of Refactoring to Patterns, v 0.17; Industrial

Logic, Inc; to be Published by Addison Wesley in 2004; 2003 [Klei00] Jürgen Kleinöder y Franz J. Hauck; Object-Oriented Concepts in Distributed

Systems; Lecture OODS-1; University of Erlangen-Nürnberg; Alemania; 2000

[Mark01] Marcus E. Markiewics, Carlos J. P. de Lucena y Paulo N. Lama; “El

Desarrollo del Framework Orientado al Objeto”; ACM Crossroads Student Magazine; 2001

[Meye97] Bertrand Meyer; Object-Oriented Software Construction; Prentice Hall;

1997

Page 131: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Referencias

119

[Mode04] ModelMaker; the Borland Productivity CASE Tool; http://www. modelmaker.demon.nl/index.htm; 2004

[OCin99] Mel Ó Cinnéide y Paddy Nixon; “Program Restructuring to Introduce

Design Patterns”; Proceedings of the IEEE International Conference on Software Maintenance; Oxford, Inglaterra; 1999

[Opdy92] William F. Opdyke; Refactoring Object-Oriented Frameworks; Tesis de

Doctorado; Department of Computer Science, University of Illinois at Urbana Champaign; 1992

[Pree96] Wolfgang Pree; Design Patterns for Object-Oriented Software

Development; Addison-Wesley; 1996 [Pres02] Roger S. Pressman; Ingeniería del Software. Un Enfoque Práctico; Mc Graw

Hill; 2002 [Proy04] Proyect Analyser v7.0; MOOD Metrics; http://www.aivosto.com/

project/help/pm-oo-mood.html; 2004 [Sant02] René Santaolaya; Modelo de Representación de Patrones de Código para

la Construcción de Componentes Reusables; Tesis de Doctorado; Departamento de Ciencias Computacionales, Centro de Investigación en Computación, IPN; 2002

[Sant04] René Santaolaya, Olivia G. Fragoso, Manuel Valdés e Isaac M. Vásquez;

“Preparing Frameworks to Become Web Services”; Proceedings of the IADIS International Conference Applied Computing 2004; Lisboa, Portugal; 2004

[Sant04a] René Santaolaya, Olivia G. Fragoso, Manuel Valdés, Isaac M. Vásquez y

Sheila L. Delfín; “An Object-Oriented Metric to Measure the Degree of Dependency due to Unused Interfaces”; Proceedings of The 2004 International Conference on Computational Science and Its Applications – ICCSA 2004; Springer-Verlag LNCS 3046; Asís, Italia; 2004

[Sant04b] René Santaolaya, Olivia G. Fragoso, Manuel Valdés, Isaac M. Vásquez y

Luis E. Santos; “Achieving Software Reuse Using the Interface Separation Principle of Object-Oriented Design”; Proceedings of The 8th World Multi-Conference on Systemics, Cybernetics and Informatics, SCI 2004; Orlando, Estados Unidos; 2004

[Sant04c] Luis E. Santos; Adaptación de Interfaces de Marcos de Aplicaciones

Orientados a Objetos por Medio del Patrón de Diseño Adapter; Tesis de Maestría; Departamento de Ciencias Computacionales, Centro Nacional de Investigación y Desarrollo Tecnológico; 2004

Page 132: Centro Nacional de Investigación y Desarrollo ... - CENIDET · 2.6. Refactorización 20 2.7. Acoplamiento de Módulos 21 2.8. Métricas de Software 22 2.9. Patrones de Diseño 24

Referencias

120

[Stro98] Bjarne Stroustrup; El lenguaje de programación C++; Addison-Wesley; 1998

[Szip99] Clemens Sziperski; Component Software: Beyond Object-Oriented

Programming; Addison-Wesley; 1999 [Toku99] Lance Tokuda; Design Evolution with Refactorings; Tesis de Doctorado;

Department of Computer Science, University of Texas at Austin; 1999 [Vald04] Manuel Valdés; Método de Refactorización de Marcos de Aplicaciones

Orientados a Objetos por la Separación de Interfaces; Tesis de Maestría; Departamento de Ciencias de la Computación, Centro Nacional de Investigación y Desarrollo Tecnológico; 2004

[Vazq01] Pedro J. Vázquez, María N. Moreno y Francisco J. García; Métricas

Orientadas a Objetos; Informe Técnico DPTOIA-IT-2001-002; Departamento de Informática y Automática, Universidad de Salamanca; 2001

[Visw96] Sreenivasa Viswanadha; JavaCC Grammar Repository, C++ Grammar

v1.1; http://www.cobase.cs.ucla. edu/pub/javacc/CPLUSPLUS.jj; Sun Microsystems Inc.; 1996

[Zava02] Patricia Zavaleta; Reconocimiento de Patrones de Diseño de Gamma a

Partir de la Forma Canónica Definida en el IPADIC++; Tesis de Maestría; Departamento de Ciencias Computacionales, Centro Nacional de Investigación y Desarrollo Tecnológico; 2002

[Zuse98] Horst Zuse; A Framework of Software Measurement; Walter de Gruytier;

1998