Você está na página 1de 220

1 Introducción a la Ingeniería de

la Programación
Si un antropólogo del futuro analizase los hábitos de las sociedades occidentales
de principios del siglo XXI, observaría un entusiasmo desaforado de las hoy llamadas
tecnologías de la información. Muchas de éstas se basan en la producción de software.
Estos ciudadanos esperan nuevas prestaciones de sus teléfonos móviles, de sus
diagnósticos médicos, de sus coches, de sus electrodomésticos,... En fin, hasta los
medios de comunicación se hacen eco de la presentación de los nuevos sistemas
operativos, de aplicaciones 3D o de videojuegos.
Tras estos deseos, se encuentran millones de desarrolladores intentando
introducir más inteligencia a los artefactos del siglo XXI. Las abigarradas
comunicaciones entre personas o entre máquinas, los controles de cientos de millones
de procesadores sobre los sistemas productivos, las millares de aplicaciones de ocio, las
transacciones económicas y un sin fin de aplicaciones están basadas en la introducción
de conocimiento a través del software.
Pero la producción de software es una disciplina de la Ciencia muy reciente, de
unas pocas décadas. Todavía no ha habido una estructuración formal de este
conocimiento humano. A diferencia con otras ingenierías no hay una metodología que
tenga procedimientos matemáticos que indique el camino más correcto a seguir en la
elaboración del software.
Recientemente, los investigadores de las Ciencias de la Computación han
decantado una metodología que ayuda a la creación del software. Durante los últimos
treinta años ha habido múltiples experiencias cuantitativas (nuevos lenguajes de

Dpto. Electrónica, Automática e Informática Industrial 11


Carlos Platero Apuntes de Sistemas Informáticos Industriales

programación, método de representación y procedimientos de producción software) que


han dado paso a un salto cualitativo produciéndose un nuevo paradigma en esta
disciplina. Para mostrar este salto y ver su cercanía en el tiempo, sólo es necesario
indicar tres referencias bibliográficas: en 1995 la Pandilla de los Cuatro (Gang of Four,
GoF) publicaron su famoso libro de “Patrones de diseño”, editado en castellano en el
2003; UML 1.0 aparece en 1997 y el Proceso Unificado en 1998.
Este curso trata precisamente de dar la metodología necesaria para la producción
del software de principios del siglo XXI. Los siguientes capítulos mostrarán cómo hacer
software siguiendo el Proceso Unificado, abarcando los aspectos desde la recogida de
los requisitos hasta las etapas de análisis, diseño e implementación.
Se inicia este temario analizando qué es el software, cuales son sus
características y cómo se ha evolucionado hacia el paradigma orientado a objetos, para
encuadrar definitivamente el ámbito del curso: el Proceso Unificado, las herramientas
de UML y el diseño con patrones.

1.1 Qué es el software y la ingeniería del software


Según la definición de la IEEE, un sistema software es:
“la suma total de los programas, procedimientos, reglas, la documentación
asociada y los datos que pertenecen a un sistema de cómputo, esto es, un conjunto
integrado de programas que en su forma definitiva se pueden ejecutar, pero comprende
también las definiciones de estructura de datos (p.ej. tipos de ficheros, acceso bases de
datos, interacción con otros componentes) que utilizan estos programas y también la
documentación referente a todo ello”
El Software no es una obra de arte, sino un producto de consumo utilitario y
masivo. Es un producto industrial. Pero tiene características especiales. No es una
producción en serie, es un producto singular y extremadamente complejo. Muchos
autores dicen que la producción del SW se parece a la construcción de edificios. Cada
uno requiere su propio proyecto.
Otra característica del SW es que no se “estropea” por el uso ni por el paso del
tiempo. Aunque hay problemas relacionados con el mantenimiento y también está la
obsolescencia del producto SW por el avance de estas tecnologías.
Resumiendo, los productos de programación se hacen a medida, representan el
conocimiento introducido a la máquina, no se rompen aunque resultan difíciles de
mantener y son un producto industrial que no se fabrica pero que se desarrolla.
A cada tipo de producto industrial le corresponde un tipo de ingeniería,
entendida como el conjunto de procedimientos, técnicas y herramientas, que se emplean
para desarrollar el producto. Una técnica es la manera preestablecida en la que se lleva a
término un paso en la elaboración del producto. Un procedimiento es la manera de
aplicar varias técnicas sucesivamente. Por último, una herramienta es un instrumento de
cualquier tipo que se utiliza en la aplicación de una técnica.
En este contexto, la Ingeniería del Software es la rama de la Ingeniería que
aplica los principios de la Ciencia de la Computación y las Matemáticas para lograr
soluciones costo-efectivas a los problemas de desarrollo del software. El proceso de la

12 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

Ingeniería del Software se define como un conjunto de etapas parcialmente ordenadas


con la intención de lograr un objetivo, en este caso, la obtención de un software de
calidad. Este desarrollo se traduce en requerimientos del SW, estas especificaciones son
transformadas en diseño y el diseño implementado en código, el código es probado,
documentado y certificado para su uso operativo.
En la tabla adjunta se compara, a modo de ejemplo, dos tipos de Ingenierías
diferentes. Una la aplicada en proyectos de Control y la otra la que se empleará en la
construcción de sistemas orientado a objetos (OO), la cual será el objetivo de este curso.
Tabla 1.1 Comparación entre las Ingenierías de Control y las de Sistemas orientado a objetos

Control Ingeniería SW (AOO/D)

Especificaciones del Diseño Captura de los requisitos

Identificación y modelado AOO (investigación del dominio)

Diseño ( técnicas de compensación ) DOO (Definición de los diagramas de


clases de diseño y de los diagramas de
interacción)

Simulación e implementación Modelo de implementación


(Programación eXtrema)

Entre las categorías de tipos de software, en una primera aproximación, se


podrían clasificar en: a) Sistemas Operativos, b) Tiempo real, c) Gestión, d) Empotrados
y e) Ingeniería y científico. Sin embargo, en este temario lo que interesa es el desarrollo
y proceso de la construcción de los sistemas orientados a objetos, los cuales pueden
englobar a la mayoría de tipos de SW. Los sistemas operativos actuales son OO,
muchas aplicaciones en tiempo real están basadas en programación OO y así podría
citarse cada una de las categorías referenciadas. Este salto se debe a que actualmente el
paradigma de programación se basa en tecnologías orientadas a objetos. Las razones de
esta elección se presentan en el siguiente apartado.

1.1.1 Los grandes problemas de la ingeniería del SW


La calidad y la productividad del SW todavía no han alcanzado niveles
comparables con otras tecnologías. En cuanto a la calidad, la causa principal es la gran
complejidad. La falta de modelos formales para saber cómo introducir conocimiento en
las máquinas es un gran inconveniente. Respecto a la productividad, el nivel más alto en
la fabricación se da en la producción en serie y no en la generación de un producto
singular. Además, los proyectos SW suelen empezar de cero. Si se piensa en la
construcción de un edificio, ejemplo típico de producto singular, hay muchos elementos
que son comunes: materiales, instalaciones, planos, cálculos, ... Una de las razones de
haberse decantado por la tecnología OO es por haber empezado a utilizarse software
prefabricado. Las vías ofrecidas por la POO para la reutilización del SW son:
1. Componentes: los lenguajes OO ofrecen servicios de alto nivel mediante un
universo computacional repletos de objetos servidores (ActiveX, COM, ...).

Dpto. Electrónica, Automática e Informática Industrial 13


Carlos Platero Apuntes de Sistemas Informáticos Industriales

2. Diseño con patrones: recetas para solventar problemas que aparecen en


muchos proyectos.
3. Marcos de trabajos (Frameworks): Bibliotecas de servicios disponibles
contrastadas y de calidad para enchufar a otros SW (STL, Qt, .NET, ..).
Se deja al lector que resuelva las siguientes cuestiones:
1. ¿Por qué lleva tanto tiempo programar?
2. ¿Por qué es tan caro?
3. ¿Por qué no se puede hacer sin errores?
4. ¿Por qué no se puede planificar?
5. ¿Por qué no hace lo que se esperaba?
6. ¿Por qué es difícil modificar el SW?
7. ¿Por qué un aumento de los programadores no ayuda?

1.2 El paradigma orientado a objetos


El concepto de paradigma en la Ciencia fue dado por Kuhn en La estructura de
las revoluciones científicas (1962):
Un paradigma es aquello que los miembros de una comunidad científica, y sólo
ellos, comparten y a la inversa, es la posesión de un paradigma común lo que
constituye a un grupo de personas en una comunidad científica [...]. Una teoría
científica se declara inválida sólo cuando se dispone de un candidato
alternativo para que ocupe su lugar. La decisión de rechazar un paradigma es
siempre, simultáneamente, la decisión de aceptar otro.
La llegada a la programación orientada a objetos proviene de múltiples intentos
de mejorar la producción del SW. La Programación Orientada a Objetos (POO) como
paradigma es una forma de pensar, una filosofía, de la que surge una cultura nueva que
incorpora técnicas y metodologías diferentes. La POO percibe el universo
computacional como poblaciones de objetos, cada uno responsabilizándose de sí
mismo, y comunicándose con los demás por medio de mensajes.
El paradigma OO se basa en el concepto de objeto. Un objeto es aquello que
tiene estados (atributos y su evolución en el tiempo), comportamientos (acciones y
reacciones a los mensaje) e identidad (propiedad que lo distingue de los demás objetos).
La estructura y comportamiento de objetos similares están definidos en su clase común;
los términos instancia y objeto son intercambiables. Una clase es un conjunto de objetos
que comparten una estructura y comportamiento común. La diferencia entre un objeto y
una clase es que un objeto es una entidad concreta que existe en el tiempo y en el
espacio, mientras que las clases son representaciones de unas abstracciones, las esencias
de los objetos.
Estas ideas de clase y objetos provienen del espíritu cognitivo de los seres
humanos. Así, al nombrar la clase “perro”, la mente humana asocia a un conjunto de
objetos caracterizados por ser animales mamíferos, con cuatro patas, un rabo, … Uno de
los triunfos de las tecnologías OO es su correspondencia con la biología evolutiva.

14 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

Pero antes de entrar en la tecnología OO, se verán las razones de haber llegado a
este punto de la evolución en los lenguajes informáticos.

1.2.1 Programación estructurada y programación orientada a objetos


Una de las cuestiones más importantes que hay que tener en cuenta al construir
un programa es el control de su ejecución. Son raros los programas que constan de un
conjunto de instrucciones que se ejecutan sucesivamente una tras otra. En la mayor
parte de los casos, diversas partes del programa se ejecutan o no, dependiendo de que se
cumpla alguna condición. Además, hay instrucciones (los bucles) que deben efectuarse
varias veces, ya sea en número fijo o hasta que se cumpla una condición determinada.
Los lenguajes más antiguos (como Fortran) se apoyaban en una sola instrucción para
definir el control de los programas: la instrucción GOTO (del inglés go to, que significa
ir a). Ésta corresponde con la transferencia incondicional de los lenguajes simbólicos.
También, se le puede combinar con alguna expresión condicional, permitiendo bifurcar
el orden de ejecución de las instrucciones.
Pero las etiquetas numéricas y las transferencias arbitrarias hacen los programas
muy poco legibles y difíciles de comprender. Como primer intento de resolver el
problema, en lenguajes más modernos se recurrió a utilizar etiquetas no numéricas,
igual que se hace en los lenguaje simbólicos de segunda generación.
Sin embargo, a finales de los años sesenta surgió una nueva forma de programar
que reduce a la mínima expresión el uso de la instrucción GOTO y la sustituye por otras
más comprensibles.
Un famoso teorema, demostrado por Edsger Dijkstra
(http://www.cs.utexas.edu/users/UTCS/notices/dijkstra/ewdobit.html) en los años
sesenta, demuestra que todo programa puede escribirse utilizando únicamente las tres
instrucciones de control siguientes:
1. El bloque secuencial de instrucciones: instrucciones ejecutadas
sucesivamente.
2. La instrucción condicional alternativa, de la forma "IF condición THEN
instrucción-1 ELSE instrucción-2". Si la condición se cumple, se
ejecutará "instrucción-1". En caso contrario se ejecuta "instrucción-2".
Abreviadamente, esta instrucción se suele llamar IF-THEN-ELSE.
3. El bucle condicional "WHILE condición DO instrucción", que ejecuta la
instrucción repetidamente mientras la condición se cumpla. En su lugar,
se puede utilizar también la forma "UNTIL condición DO instrucción",
que ejecuta la instrucción hasta que la condición se cumpla. Los dos
bucles se diferencian entre sí porque en la forma WHILE la condición se
comprueba al principio, por lo que es posible que la instrucción no se
ejecute ni una sola vez. En cambio, en la forma UNTIL la condición se
comprueba al final del bucle, por lo que la instrucción se ejecuta siempre
al menos una vez.
Los programas que utilizan sólo estas tres instrucciones de control básicas o sus
variantes (como los bucles FOR o la instrucción condicional CASE), pero no la
instrucción GOTO, se llaman estructurados. La programación estructurada (llamada
también "programación sin GOTO") se convirtió durante los años setenta en la forma de

Dpto. Electrónica, Automática e Informática Industrial 15


Carlos Platero Apuntes de Sistemas Informáticos Industriales

programar más extendida. A pesar de todo, la mayoría de los lenguajes conservan la


instrucción GOTO y las etiquetas de las instrucciones, para utilizarla en casos muy
especiales, aunque normalmente se desaconseja su uso.
Entre los lenguajes de alto nivel, Pascal, C y Ada pueden considerarse
especializados en programación estructurada, y aunque todos ellos permiten utilizar la
instrucción GOTO, se desaconseja su uso (aunque en C es una práctica común utilizarlo
para manejo de errores).
Los métodos estructurados provienen de la programación estructurada. Se
caracterizan por:
 La especificación de los procesos y la de las estructuras de datos
generalmente quedan bastante diferenciadas.
 Las técnicas de análisis y diseño o bien pasa de lo general a lo particular
o a la inversa.
Las técnicas más usadas son los diagramas de entidad-relación y de flujos de
datos. Los primeros se refieren a los datos y los segundos a los procesos.
Diferente a la programación estructurada es la programación orientada a
objetos. Esta última se enfoca en reducir la cantidad de estructuras de control y
reemplazarlo con el concepto de polimorfismo. Aún así los programadores todavía
utilizan las estructuras de control (if, while, for, etc...) para implementar sus algoritmos,
porque en muchos casos es la forma más natural de hacerlo.

Resumen
Algoritmos + datos = programa (programación estructurada)

Servicios + atributos = objeto (programación orientada a objetos)

Pero estas diferencias en sus apariencias son mucho más profundas y de un gran
calado. Resulta fácil de citar los conceptos de abstracción, ocultación de la información,
reutilización del software, polimorfismo y otras palabras claves que todos los autores de
programación orientada a objetos comentan. Pero éstas quedarán en el olvido si sólo se
pasa de codificar de un lenguaje estructurado a otro orientado a objeto.
Para entender qué es la programación orientada a objetos hay que tratarla desde
el punto de vista del método y enmarcarse en su paradigma. Por tanto, hay que examinar
lo que los investigadores acaban de destilar después de más de treinta años y que sólo
desde hace unos pocos de años está algo más claro.

1.2.2 Programación orientada a objetos


El proverbio “tener un martillo no te hace ser un arquitecto” es especialmente
cierto con respecto a las tecnologías de objetos. Una cosa es conocer C++, Java o C# y
otra es “pensar en objetos”. De hecho, muchos saben codificar en un lenguaje OO, pero

16 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

no emplean POO. Justamente, el objetivo del curso es saber POO, para ello se requiere
de:
1. Un marco para el análisis y el diseño OO (A/DOO) aplicando el
Lenguaje Unificado de Modelado (UML).
2. La utilización de patrones de diseño y
3. El Proceso Unificado.
La producción del software requiere seguir un conjunto de etapas que van desde
la recogida de los requisitos, el análisis y diseño de la aplicación hasta la
implementación. Por tanto, en el paradigma orientado a objetos se requiere de
disciplinas y artefactos para realizar estas etapas, a las que se describirán mediante el
acrónimo de AOO/D (Análisis y diseño orientado a objetos).
En el análisis se pone énfasis en una investigación del problema y de los
requisitos, en vez de poner una solución. En el AOO se presta atención a encontrar los
objetos en el dominio del problema. Por tanto, el AOO es un método de análisis que
examina los requerimientos desde la perspectiva de las clases y objetos encontrados en
el vocabulario del dominio del problema.
El diseño pone énfasis en una solución conceptual que satisface los requisitos, en
vez de ponerlo en la implementación. En DOO se presta atención a la definición de los
objetos software y en cómo colaboran para satisfacer los requisitos.
UML es sólo una notación, capaz de hacer los planos del SW. Últimamente han
aparecido muchos cursos de UML, pero UML es una herramienta, no un fin en sí
mismo. A nadie se le ocurriría dar un curso exclusivo de PSPICE, ya que es sólo una
herramienta de simulación de circuitos electrónicos, habrá que darlo dentro del contexto
del análisis de los circuitos eléctricos-electrónicos. Lo mismo pasa con UML, sólo se
entiende si se está dentro de un contexto y éste es el de la producción del software.
Como se verá a lo largo del curso, la POO se basa en la asignación de
responsabilidades, pero ¿cómo se debería asignar las responsabilidades a los objetos?
¿cómo deberían interactuar los objetos?. Ciertas soluciones contrastadas a problemas de
diseño se pueden expresar mediante patrones o buenas prácticas. A éstas se las conocen
como patrones de diseño. Una habilidad clave y fundamental en el A/DOO es la
asignación cuidadosa de responsabilidades a los componentes software. En
consecuencia, este curso se centra en los pasos a seguir para asignar responsabilidades a
los objetos. Se emplearán los patrones GRASP y GoF.
La captura de los requisitos, el A/DOO y la implementación requieren moverse
dentro de un proceso. En este caso, se seleccionará mediante un proceso de desarrollo
iterativo llamado Proceso Unificado. La figura adjunta muestra un gráfico que sintetiza
los temas y habilidades en el que se va a centrar el curso.

Dpto. Electrónica, Automática e Informática Industrial 17


Carlos Platero Apuntes de Sistemas Informáticos Industriales

A/DOO Captura
requisitos

Diseño con Temas y habilidades UML


patrones

Proceso
Unificado

Figura 1. 1 Habilidades para la programación orientada a objetos

1.3 El ciclo de vida SW


El problema del software se reduce a la dificultad que afrontan los desarrolladores
para coordinar las múltiples cadenas de trabajo de un gran proyecto. La comunidad de
desarrolladores necesita una forma coordinada de trabajar. Necesita un proceso que integre
las múltiples facetas del desarrollo. Necesita un método común, un proceso que:
 Proporcione una guía para ordenar las actividades del equipo.
 Dirija las tareas de cada desarrollador por separado y del equipo como un
todo.
 Especifique los artefactos que deben desarrollarse.
 Ofrezca criterios para el control y la medición de los productos y actividades
del proyecto.
La presencia de un proceso bien definido y bien gestionado es una diferencia esencial
entre proyectos productivos y otros que fracasan. A continuación se muestran diferentes
tipos de procesos de producción del software.

1.3.1 Modelo lineal secuencial (Ciclo de vida clásico)


Enfoque sistemático y secuencial del desarrollo del software que comienza en un
nivel de sistemas y progresa con el análisis, diseño, codificación, pruebas y
mantenimiento.

Actividades:
Ingeniería y modelado de Sistemas/Información
Ubicación del software en el ámbito donde va a funcionar.

18 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

Análisis de requisitos:
Se deben conocer los aspectos relacionados con la información a tratar, la función
requerida, comportamiento, rendimiento, etc.
El cliente debe dar el visto bueno.

Diseño:
Estructura del programa y arquitectura del software.
Representaciones de la Interfaz.
Detalle Procedimental (algoritmo).

Generación de código o Implementación:


Puede automatizarse si el diseño está bien detallado.

Pruebas:
De Caja Blanca: Análisis de los distintos caminos de ejecución de los algoritmos.
De Caja Negra: Análisis de los procesos externos funcionales.

Mantenimiento:
Gestión de cambios en el software debidos a:
 Errores durante el desarrollo.
 Adaptación a nuevos entornos (e.g. sistemas operativos)
 Mejoras funcionales o de rendimiento.

1.3.2 Modelo de construcción de prototipos


Se da un conjunto de objetivos generales de
entrada, procesamiento y salida. Con ellos se desarrolla
un prototipo inicial que sirve para detallar los objetivos
(requisitos) más concretos del producto final. El
prototipo se suele desechar.

1.3.3 Desarrollo rápido de aplicaciones.


Es una adaptación a “alta velocidad” del
modelo lineal secuencial en el que se logra el desarrollo rápido utilizando un enfoque de
construcción basado en componentes. Puede permitir el desarrollo de un sistema
completamente funcional en periodos cortos de tiempo (de 60 a 90 días). Los
componentes que se desarrollen se pueden reutilizar en posteriores proyectos, llamados
repositorio de componentes.
El sistema se descompone en un conjunto de bloques que se pueden desarrollar
de manera independiente por distintos equipos de desarrollo.
Sólo puede aplicarse cuando se cumplen una serie de condiciones:

Dpto. Electrónica, Automática e Informática Industrial 19


Carlos Platero Apuntes de Sistemas Informáticos Industriales

 Se comprenden muy bien los requisitos del sistema a desarrollar; ya sea


porque los conoce el propio desarrollador o porque se tiene una
experiencia previa en un sistema similar.
 Se delimita muy bien el ámbito del problema.
 La interacción del software con el nuevo sistema no es complicada o se
utilizan nuevas tecnologías que son dominadas por el equipo de desarrollo.
Inconvenientes:
 Debe haber un compromiso por parte del equipo de desarrollo y del cliente
en el desarrollo rápido de actividades.
 Requiere recursos suficientes para crear el número de equipos necesarios.

1.3.4 Modelos Evolutivos


El software, al igual que el resto de los sistemas, evoluciona con el tiempo. Se
necesita de procedimientos que permitan una evolución permanente.

Modelo Incremental

 Combina elementos del modelo lineal secuencial con la filosofía


interactiva de construcción de prototipos.
 Entrega por incrementos.
 Fácil adaptación a requerimientos temporales de entrega.
Modelo en Espiral
Combina el modelo lineal secuencial y la
construcción de prototipos, proporcionando el potencial
necesario para el desarrollo rápido de versiones
incrementales del software.
Se debe establecer el número de interacciones.

20 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

1.4 El Proceso Unificado


El Proceso Unificado (Unified Process, UP) es una solución al problema de
producción del software. En primer lugar el Proceso Unificado es un proceso de desarrollo
del software. Un proceso de desarrollo del SW es el conjunto de actividades necesarias para
transformar los requisitos del usuario en un sistema SW. UP se ha convertido en el
procedimiento de gran éxito para la construcción de sistemas orientado a objetos.
UP está basado en componentes, lo cual quiere decir que la aplicación está
constituida por componentes software interconectados entre ellos a través de sus interfaces
bien definidas. UP utiliza UML para preparar todos los esquemas de un sistema SW. De
hecho, UML es una parte esencial del Proceso Unificado; sus desarrollos fueron en paralelo.
No obstante, los verdaderos aspectos definitorios del Proceso Unificado se resumen
en tres frases claves: a) dirigido por los casos de uso, b) centrado en la arquitectura y c)
iterativo e incremental.
Un caso de uso es un fragmento de funcionalidad del sistema que proporciona al
usuario un beneficio. Los casos de uso representan los requisitos funcionales de la
aplicación. Todos los casos de uso juntos constituyen el modelo de casos de uso, el cual
describe la funcionalidad total del sistema. Todos estos aspectos serán tratados en el
siguiente capítulo.
El concepto de arquitectura del SW incluye los aspectos estáticos y dinámicos más
significativos del sistema. No sólo refleja la solución a los distintos casos de uso, sino que
también muestra los bloques de construcción reutilizables, los marcos de trabajo para los
interfaces, los sistemas de gestión de bases de datos, consideraciones de implementación,
etc. La arquitectura debe diseñarse para permitir que el sistema evolucione, no sólo en su
desarrollo inicial, sino también a lo largo de las futuras generaciones. Estos conceptos serán
el núcleo del temario.
UP emplea el ciclo de vida iterativo y desarrollo dirigido por el riesgo. El desarrollo
iterativo se organiza en una serie de mini-proyectos, de duración fija (aproximadamente 4
semanas) llamadas iteraciones. El ciclo de vida iterativo se basa en la ampliación y
refinamiento sucesivos mediante iteraciones, con retroalimentación cíclica y adaptación.
Ejemplo de actividades en una iteración
- Clarificar tareas y requisitos de la iteración
- Ingeniería inversa (código de iteración anterior a UML)
- Discusión de incremento de diseño
- Implementar y probar

Dpto. Electrónica, Automática e Informática Industrial 21


Carlos Platero Apuntes de Sistemas Informáticos Industriales

Figura 1. 2 UP y las iteraciones

El desarrollo iterativo es Aceptar el Cambio. En lugar de luchar contra el inevitable


cambio, el desarrollo iterativo se basa en una aptitud de aceptación del cambio y la
adaptación como motores inevitables. Se buscará el equilibrio entre estabilizar un conjunto
de requisitos y por otro la realidad cambiante de los requisitos. Tener realimentación en una
etapa temprana vale su peso en oro.
“Sí, esto es lo que pedí, pero ahora que lo pruebo, lo que realmente quiero es algo un
poco distinto”.
En consecuencia, el trabajo se desarrolla a lo largo de una serie de ciclos
estructurados de construir-realimentar-adaptar.
Beneficios del desarrollo iterativo:
 Mitigar tan pronto como sea posible los altos riesgos.
 Progreso visible en las primeras etapas.
 Retroalimentación con los usuarios.
 Gestión de la compatibilidad. No se abruma por la parálisis del análisis muy
largo.
 El propio conocimiento en cada iteración se puede utilizar para mejorar el
proceso del desarrollo.

1.4.1 Las fases del UP


Un proyecto UP organiza el trabajo y las iteraciones en cuatro fases fundamentales:
1. Inicio: Visión aproximada, análisis del negocio, alcance, estimaciones
imprecisas.

22 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

2. Elaboración: visión refinada, implementación iterativa del núcleo, resolución de


los altos riesgos.
3. Construcción: implementación iterativa del resto de requisitos de menor riesgo.
4. Transición: pruebas beta, despliegue.
Esto no se corresponde con el antiguo ciclo de vida “en cascada” o secuencial. La
fase de inicio no es una fase de requisitos; sino una especie de fase de viabilidad. En la fase
de elaboración no sólo se hace requisitos y diseño, sino que es una fase de implementación
del núcleo central y se mitigan las cuestiones de alto riesgo.
Ciclo de desarrollo
iteración

inicio elaboración construcción transición

fase
En UP se describe las actividades de trabajo en disciplinas. Una disciplina es un
conjunto de actividades o artefactos relacionados dentro de un área determinada. En UP, un
artefacto es el término general para cualquier producto del trabajo: código, documentos,
gráficos, diagramas, etc.
En UP hay varias disciplinas (ver tabla 1.2), aunque en este temario se centrará en:
 Requisitos: Sus artefactos son Casos de Uso, Visión, Especificaciones
Complementarias y Glosario.
 Modelo del negocio: El artefacto más empleado en una aplicación única es el
Modelo del Dominio. A nivel más grande se hace ingeniería inversa de todos
los procesos del negocio de toda la empresa.
 Diseño: Modelo del Diseño, documentos de Arquitectura SW, Modelo de
Datos.
En este temario se hace especial hincapié en las fases de Inicio y Elaboración, cuyos
artefactos están unidos con las disciplinas de Requisitos, Modelado de Negocio y Diseño,
donde se aplica el análisis de los requisitos, el AOO/D, loa patrones y su notación mediante
UML.

Dpto. Electrónica, Automática e Informática Industrial 23


Carlos Platero Apuntes de Sistemas Informáticos Industriales

Tabla 1.2 Disciplinas del UP. c= comenzar, r=refinar

Disciplina Artefacto Inicio Elaboración Construcción Transición

Modelo de Casos de Uso c r


Requisitos Visión c r
Especificaciones Complementarias c r
Glosario c r
Modelo del Dominio c
Modelado del Negocio

Modelo de Diseño c r
Diseño Documento de Arquitectura SW c
Modelo de Datos c r
Modelo de implementación c r r
Implementación

Plan de Desarrollo SW c r r r
Gestión del Proyecto

Modelo de Pruebas c r
Pruebas

Marco de Desarrollo c r
Entorno

Es importante saber que en UP todas las actividades y artefactos son opcionales.


Dependiendo del tipo de proyecto se escogen los artefactos y las disciplinas necesarias.

1.5 Herramientas CASE


CASE es el acrónimo de Computer-Aided Software Engineering. Son herramientas
de apoyo al desarrollo, mantenimiento y documentación informatizada del SW. No son
herramientas CASE:
a) Las que no tienen esa finalidad
b) Las que se utilizan para codificar SW.
Tipos de herramientas:
 Herramientas diagramáticas (Rational Rose, BoUML)
 Herramientas de gestión de cambios (CVS)
 Herramientas para la documentación (Doxygen)

24 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

1.6 Problemas
1. Objetivos del curso AOO/D.
2. Características del producto SW.
3. ¿Qué es la Ingeniería del SW?.
4. El paradigma OO.
5. Diferencias entre los métodos estructurados y los métodos OO.
6. Habilidades necesarias para la POO.
7. Enfoques sobre el proceso de desarrollo del SW.
8. ¿Qué es el UP?
9. Fases, iteraciones, disciplinas y artefactos en UP.

Dpto. Electrónica, Automática e Informática Industrial 25


Carlos Platero Apuntes de Sistemas Informáticos Industriales

Ejercicio 1
Diseñar un juego de lanzar dos dados, si la suma de las caras es siete
se gana en caso contrario se pierde. Emplear métodos estructurados y
métodos orientado a objetos.
METODOLOGÍA ESTRUCTURADA
1. Definición del flujograma e implementación:

26 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int lanzarDado ( void );

void main (void)


{
int caraDado1, caraDado2;
int continuarJuego = 1;
char letra;

printf("\nJuego de dados,lanzar dos dados y sumar 7 ganar\n");

while(continuarJuego)
{
puts("Pulsar cualquier tecla para lanzar dado 1");
getch();
caraDado1 = lanzarDado();
puts("Pulsar cualquier tecla para lanzar dado 2");
getch();
caraDado2 = lanzarDado();
if( (caraDado1 + caraDado2) == 7 )
puts ("Ha ganado");
else
puts("Ha perdido");
puts("Si desea jugar otra vez, pulse C");
letra = getch();
if ((letra == 'c' )||(letra == 'C'))
continuarJuego = 1;
else
continuarJuego = 0;
}

puts("Se termino el juego de dados. Un saludo");


}
int lanzarDado ( void )
{
int valorCara;
valorCara=(int)((rand()%6)+1);
printf("\n%d\n",valorCara);
return (valorCara);
}

Dpto. Electrónica, Automática e Informática Industrial 27


Carlos Platero Apuntes de Sistemas Informáticos Industriales

MÉTODO PROCESO UNIFICADO


1. Definición de casos de uso:
Jugar una partida de dados: Un jugador recoge y lanza los dados. Si el valor de
las caras de los dados suman siete, gana; en caso contrario, pierde.

2. Definición del modelo del dominio


El modelo del dominio se ilustra mediante un diagrama que muestran el
vocabulario del problema mediante clases conceptuales.

3. Definición de los diagramas de interacción


La finalidad del DOO es definir los objetos SW y sus colaboraciones. Las
colaboraciones se expresan mediante diagramas de interacción.

28 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

4. Definición de los diagramas de clase de diseño.


A diferencia del modelo del dominio, este diagrama no muestra conceptos del
mundo real, sino clases de diseño que no de SW.

5. Implementación
Utilizando la programación extrema, XP, se empieza a escribir el código de prueba y
luego se construyen desde las clases menos acopladas a las más acopladas. En este caso se
codificará en C++.

Dpto. Electrónica, Automática e Informática Industrial 29


Carlos Platero Apuntes de Sistemas Informáticos Industriales

#include <iostream>
#include <conio.h>
#include "JuegoDados.h"

void main ()
{
bool ganarPartida, continuarJuego = true;
char tecla;
JuegoDados elJuego;

std::cout << "\nJuego de dados, lanzar dos dados y sumar 7 para ganar\n";

while (continuarJuego)
{
std::cout << "\nPulsar cualquier tecla para lanzar dados\n";
getch();

ganarPartida = elJuego.jugar();

if ( ganarPartida )
std:: cout << "Ha ganando.\n";
else
std:: cout << "Ha perdido.\n";

std::cout<<"\nSi desea jugar otra vez, pulse C\n";


std::cin>> tecla;
continuarJuego = (tecla == 'c')||(tecla == 'C')?true:false;
}

std::cout << "Se termino el juego de dados. Un saludo\n";


}

class Dado #include "Dado.h"


{ #include <stdlib.h>
public:
void lanzar(); void Dado::lanzar()
int getValorCara(); {
valorCara = ((rand() % 6) +1);
private:
int valorCara; }

}; /* Dado.h */ int Dado::getValorCara()


{
ç return valorCara;;

} /* Dado.cpp */

#include "Dado.h" #include "JuegoDados.h"

class JuegoDados
{
public: bool JuegoDados::jugar()
{
bool jugar(); dado1.lanzar();
dado2.lanzar();
private:
Dado dado1; return((dado1.getValorCara()+
Dado dado2; dado2.getValorCara())==7?true:false);

}; /* JuegoDados.h */ } /* JuegoDado.cpp */

30 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Sistemas Informáticos Industriales Capítulo 1: Introducción a la Ingeniería del SW

Derecho de Autor © 2014 Carlos Platero Dueñas.

Permiso para copiar, distribuir y/o modificar este documento bajo los términos
de la Licencia de Documentación Libre GNU, Versión 1.1 o cualquier otra
versión posterior publicada por la Free Software Foundation; sin secciones
invariantes, sin texto de la Cubierta Frontal, así como el texto de la Cubierta
Posterior. Una copia de la licencia es incluida en la sección titulada "Licencia de
Documentación Libre GNU".

La Licencia de documentación libre GNU (GNU Free Documentation License)


es una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
apuntes están cubiertos por esta licencia. La version 1.1 se encuentra en
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html

Dpto. Electrónica, Automática e Informática Industrial 31


2 Recogida y documento de los
requisitos
Al iniciar un proyecto software y al decidir que se emplea el Proceso Unificado,
la primera iteración corresponde con la fase de Inicio. En ella se pretende vislumbrar el
alcance del producto. El principal problema es si el personal involucrado está de
acuerdo en la visión del proyecto, tanto desarrolladores como los posibles usuarios del
producto final.

En esta fase se analiza la viabilidad del proyecto, aunque también podría incluir
los primeros talleres de requisitos y la planificación de la primera iteración. La tabla
adjunta muestra los artefactos comunes de la fase de inicio.

Dpto. Electrónica, Automática e Informática Industrial 37


Carlos Platero Apuntes de Informática Industrial

Tabla 2-1 Ejemplos de artefactos de la etapa de inicio

Artefactos Comentario

Visión y análisis del negocio Describe los objetivos y las restricciones de alto nivel, el
análisis del negocio y proporciona un informe para la toma de
decisiones.

Modelo de Casos de Uso Cuenta los requisitos funcionales y en menor medida los no
funcionales.

Especificación Complementaria Documenta los requisitos relacionados con la calidad del SW.

Glosario Terminología clave del dominio

Lista de Registros & Plan Detalla los riesgos del negocio, técnicos, recursos,
de Gestión del Riesgo planificación y las ideas para mitigarlos.
darles respuestas.

Prototipos y pruebas de conceptos Para clarificar la visión y validar las ideas técnicas.

Plan de Iteración Describe qué hacer en la primera iteración de la elaboración.

Fase Plan de & Plan Estimación de poca precisión de la duración y esfuerzo de la


de Desarrollo de Software fase de elaboración. Herramientas, personas, formación y
otros recursos.

Marco de Desarrollo Una descripción de los pasos del UP y los artefactos


adaptados para este proyecto. El UP siempre se debe adaptar
al proyecto.

Estos artefactos se completan sólo parcialmente en esta fase. Se refinarán de


manera iterativa en las siguientes iteraciones. El nombre en mayúsculas indica que es un
artefacto UP con ese nombre oficial.

En esta etapa se puede dar la mayoría de los casos de uso, aunque sólo un 10%
de ellos con detalles, sobre todo aquellos que son críticos. El resto sólo se enumeran.

También se puede lanzar algunas tareas de programación con la misión de crear


prototipos de “pruebas de conceptos”. Éstos tratan de clarificar unos pocos requisitos
mediante prototipos, aclarando la programación para cuestiones técnicas de carácter
crítico.

La documentación se almacena digitalmente y en línea. Con el objeto de hacerla


accesible a todo el personal involucrado, se puede emplear un servidor bien en una
intranet o usar páginas privadas en un servidor web.

38 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

Ejemplo 2.1

Se pretende realizar un proyecto de clasificación de espermatozoides humanos


mediante técnicas de análisis de imágenes digitales. Las imágenes son capturadas a
través de un microscopio y el objetivo es detectar los espermatozoides y clasificarlos
según su morfología.

La primera tarea fue capturar los


requisitos de la aplicación. Se
emplearon varias reuniones entre los
biomédicos y los ingenieros para
aclarar realmente qué es lo que se
quería. De estos encuentros se
rellenaron varios documentos
(Visión y Alcance, Glosario,
algunos casos de uso y
Especificaciones Complementarias).

Para realimentar el conocimiento de los biomédicos en la aplicación, se


desarrolló un prototipo empleando Matlab. Esta aplicación, exige poco tiempo y
esfuerzo, sirve para reforzar algunas ideas que quedaron en el aire y para descartar otras.
Muchas veces, la mentalidad de los desarrolladores va en una dirección, mientras los
usuarios piensan en otros tipos de servicios.

La presentación de un prototipo favorece la realimentación y acaba con


actividades que no son necesarias. Además de acotar las singularidades del proyecto.

Dpto. Electrónica, Automática e Informática Industrial 39


Carlos Platero Apuntes de Informática Industrial

Ejemplo 2.2

Diseñar una aplicación que entregue la respuesta en frecuencia de los filtros


analógicos lineales. Una vez capturado el circuito eléctrico, se pasará a determinar
cual es la función de transferencia en el
dominio de la frecuencia y se presentará la
respuesta en frecuencia en un diagrama de
Bode.

Este ejemplo sólo se empleará como hilo


conductor de la materia de la asignatura,
analizando las diferentes etapas que hay que
cumplir, según el Proceso Unificado.

No obstante, el sistema
pretende capturar un
circuito analógico y mostrar
su respuesta en frecuencias.
En la actualidad hay
aplicaciones que realizan
este cometido, como por
ejemplo PSPICE.

2.1 Comprensión de los requisitos

Los requisitos son capacidades y condiciones con las cuales debe estar conforme
el sistema. El primer reto del trabajo de los requisitos es encontrar, comunicar y
recordar lo que realmente se necesita, de manera que tenga un significado claro para el
cliente y para los desarrolladores.

En un estudio sobre los costes reales de los proyectos SW, el 37% estaban
relacionados con los requisitos.
Coste de los proyectos %
Entradas de usuarios erróneas 13
Requisitos incompletos 12
Cambios en los requisitos 12
Habilidades técnicas pobres 7
Mala dirección 6
Otros 50

Los requisitos se clasifican de acuerdo con el modelo FURPS+ (Functional,


Usability, Reliability, Performance, Supportability):

40 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

 Funcional (Functional): características funcionales de la aplicación, esto


es, las utilidades que le dan al usuario.

 Facilidad de uso (Usability): factores humanos relacionados con su


manejo, ayuda y documentación.

 Fiabilidad (Reliability): Capacidad de recuperación ante los fallos.

 Rendimiento (Perfomance): Tiempos de respuesta, precisión, eficacia.

 Soporte (Supportability): Adaptabilidad, facilidad de mantenimiento,


internacionalización, configurabilidad.

El + indica requisitos adicionales tales como:

 Implementación: lenguajes y herramientas, soporte físico.

 Interfaz: interacción con otros sistemas externos.

 Operaciones: gestiones del sistema en su puesta en marcha.

 Empaquetamiento: instaladores, distribución.

 Legales: licencias, claves de instalación,...

Lo normal es dividir los requisitos en funcionales y no funcionales. Los


requisitos funcionales se estudian y se recogen en los documentos de Casos de Uso. Los
no funcionales aparecen en los informes de Especificaciones Complementarias.

Evidentemente, los requisitos influyen en la arquitectura del sistema. Se entiende


como arquitectura los diferentes paquetes que constituyen el proyecto. Es el nivel más
elevado de abstracción del proyecto y define los componentes que van a participar en la
elaboración del sistema.

2.2 La secuencia de captura de los requisitos

Una secuencia recomendada en la captura de los requisitos puede ser:

1. Escribir un primer borrador breve de la visión del proyecto.

2. Identificar los objetivos de usuario y los casos de uso de apoyo.

3. Escribir algunos casos de uso y comenzar el documento de especificaciones


complementarias.

Dpto. Electrónica, Automática e Informática Industrial 41


Carlos Platero Apuntes de Informática Industrial

4. Refinar la visión del proyecto, resumiendo la información a partir de de los


documentos redactados.

2.3 Visión y Alcance del proyecto

El documento de Visión y Alcance del proyecto resume la visión del proyecto.


Sirve para comunicar de manera concisa las grandes ideas de por qué se pospuso el
proyecto, cuáles son los problemas a resolver, quienes son las personas involucradas,
qué se necesita y cuál podría ser la apariencia de la solución propuesta. Puede servir
como documento en la contratación entre la empresa receptora del servicio y los
desarrolladores.

En este informe la granularidad que se refleja es alta, i.e. narra los aspectos más
relevantes del proyecto, sin entrar en los detalles. El documento de Visión y Alcance
resulta complementario con los documentos de Casos de Uso y Especificaciones
Complementarias, los cuales se verán más adelante.

En este documento debe de aparecer cuáles son los objetivos esenciales y los
problemas que hay que resolver. Pero ¿qué técnicas se pueden emplear para
localizarlos?.

Habrá que realizar trabajo de grupo. Existen distintas técnicas para el


descubrimiento de los problemas. Con el objeto de descubrir los objetivos esenciales y
para ayudar a la generación de ideas y su priorización se pueden utilizar: mapas
mentales, diagramas causa-efecto, tormentas de ideas, votaciones,... Ante todo, son
importantes las descripciones breves de alto nivel.

Una técnica para identificar los aspectos esenciales del proyecto es utilizar un
esquema a dos niveles. Sucintamente se citará las características esenciales en una
jerarquía de objetivos principales y objetivos secundarios.

Una guía para detectar las características del sistema es el siguiente test
lingüístico:

El sistema debe de hacer la <característica X>

Si se supera la prueba, la característica se introducirá en el esquema. Con esta


herramienta y con otras más, se confeccionará el esquema a dos niveles. Una vez
realizado el trabajo de detectar las características del sistema, éstas deberán de reflejarse
en el documento de Visión y Alcance.

Ejemplo 2.3

Determinar las características para la aplicación de clasificación de los


espermatozoides enunciada en el ejemplo 2.1. Utilícese un esquema de dos niveles.

42 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

El producto residirá en los laboratorios biomédicos. Tendrá una interfaz sencilla.


Proporcionará el servicio de automatizar la clasificación de los espermatozoides:
1. El sistema debe de procesar las imágenes procedentes del microscopio
a. Adquirir las imágenes de ficheros de tipo JPG, BMP, TIF, ...
b. Segmentar cada espermatozoide
c. Diferenciar en cada espermatozoide el núcleo y el halo.
d. Eliminar manchas y elementos espurios que hubiese en la imagen
e. Sólo se tomarán espermatozoides que estén completo su halo y su
núcleo.
f. No se considerarán aquellos espermatozoides que estén juntos.
2. El sistema debe de clasificar los espermatozoides
a. Clasificarlos en un rango numérico de 0 a 1.
b. Correspondencia entre el rango numérico con las cinco categorías
morfológicas de los espermatozoides.
3. El sistema debe producir un informe de resultados
a. Generar histograma continuo de las frecuencias de los espermatozoides
del 0 al 1.
b. Tanto por ciento de espermatozoide del total en cada categoría. Se
asociarán intervalos del rango del 0 al 1 con las categorías morfológicas
de HG, HM, HP, SH y D.
c. Datos auxiliares: Fecha y hora, número de espermatozoides total del
análisis, datos del cliente (Nombre, dirección,...).
d. Informe imprimible.

Ejemplo 2.4

Determinar las características para la aplicación de Respuesta en Frecuencia


enunciada en el ejemplo 2.2. Utilícese un esquema de dos niveles.
1. El sistema debe capturar un circuito electrónico
a. Interacción con el usuario para determinar el circuito analógico
b. Determinar la FDT del circuito lineal.
2. El sistema debe realizar análisis en frecuencia
a. Parámetros de la respuesta en frecuencia (Rango de frecuencia, intervalo
en el cálculo, lineal o en décadas)
b. Presentación gráfica del diagrama de Bode.

Otra sugerencia, resulta que a veces, las características del sistema son
básicamente equivalentes a los nombres de los Casos de Uso. No hay que olvidar que
los casos de uso, como se verá más adelante, hacen referencia a requisitos. Por tanto, los
documentos de Visión y de Casos de Uso son complementarios. En este sentido, se debe
evitar la repetición de conceptos, para mantener fluidez en los documentos y facilitar la
actualización. Una manera eficiente es realizar referencia cruzadas a los otros
documentos. Por ejemplo, se puede mencionar una característica y ampliar sus aspectos
en un caso de uso o en el documento de Especificaciones Complementarias.

En la página Web de la asignatura está las plantillas de los documentos de


recogida de los requisitos. El documento de Visión y Alcance está formado por la
siguiente tabla de contenidos:

Dpto. Electrónica, Automática e Informática Industrial 43


Carlos Platero Apuntes de Informática Industrial

1REQUERIMIENTOS DEL NEGOCIO


1.1BACKGROUND ............................................................................................................................
1.2OPORTUNIDAD DEL NEGOCIO ...................................................................................................
1.3OBJETIVOS ESENCIALES Y CRITERIOS DE ÉXITO .....................................................................
1.4NECESIDADES DE LOS USUARIOS ..............................................................................................
1.5RIESGOS DEL NEGOCIO .............................................................................................................
2.VISIÓN DE LA SOLUCIÓN ..........................................................................................................
2.1VISIÓN GLOBAL..........................................................................................................................
2.2PRINCIPALES CARACTERÍSTICAS..............................................................................................
2.3HIPÓTESIS Y DEPENDENCIAS.....................................................................................................
3.ALCANCE Y RESTRICCIONES ..................................................................................................
3.1.CARACTERÍSTICAS PRINCIPALES EN LA PRIMERA VERSIÓN
3.2.MEJORAS EN LAS SIGUIENTES VERSIONES ..............................................................................
3.3.LIMITACIONES Y EXCLUSIONES ..............................................................................................
4.CONTEXTO DEL NEGOCIO .......................................................................................................
4.1PERFILES DE POSIBLE CLIENTES EN EL PROYECTO.................................................................
4.2PRIORIDADES DEL PROYECTO ..................................................................................................
4.3AMBIENTE DE OPERACIÓN ........................................................................................................

En cada apartado se orienta al desarrollador a que responda una serie de


preguntas con el objeto de identificar los aspectos más relevantes del proyecto. El
documento está formado en cuatro apartados: 1) hace referencia a la oportunidad de este
proyecto, 2) analiza las características de la nueva aplicación, 3) tiene en cuenta cuales
van a ser sus limitaciones y 4) analizar las condiciones en el que se va a desarrollar el
proyecto.

2.4 Glosario

El glosario almacena los términos y las definiciones del proyecto. Puede jugar el
rol de diccionario de los datos relevantes. Es muy sorprendente que, a veces, el personal
involucrado en el proyecto esté utilizando distinto nombres para la misma cosa.

El glosario podría almacenarse en una tabla de base de datos. Los campos que
se puede utilizar son: nombre del término, la definición del campo, algún tipo de alias o
cualquier otro campo que pueda ser considerado.

Ejemplo 2.5

Para la aplicación del análisis de los espermatozoides, el glosario de términos


dado por los biomédicos fue:

44 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

Término Definición e Información Alias Otros

Cromatina Material nuclear (ADN + proteínas) que se tiñe de manera


diferencial con ciertos colorantes ( en nuestro caso: TODO LO QUE
SE COLOREA, excepto la pieza intermedia y la cola)
Tinción Colorante que retiene la cromatina del espermatozoide. Una mayor
densidad de color se traduce en una mayor masa de cromatina.

Nucleoide Núcleo celular parcialmente desproteinizado. Se compone de un


“core” central y de un halo periférico.
Halo Superficie de la cromatina que se dispersa y que emana del core. Los
halos tienen forma de corona circular o elíptica.
Core: Cuerpo central del nucleoide, que corresponde a la silueta del núcleo Núcleo
del espermatozoide. Los cores tienen forma circular o elíptica.
Espermatozoide con Espermatozoide cuyo halo es igual o mayor que el diámetro menor HG
Halo grande del core.

Espermatozoide con El grosor del halo está comprendido entre: mayor que 1/3 del HM
Halo mediano diámetro menor del core y menor que el diámetro menor del core

Espermatozoide con El grosor del halo es igual o menor que 1/3 del diámetro menor del HP
Halo pequeño core

Espermatozoide Espermatozoide que carece de halo de dispersión de la cromatina SH


Sin Halo

Degradada(D): Aquellos que sin mostrar halo, presentan la cabeza fragmentada en D


gránulos o muestran una tinción muy débil.

2.5 Casos de uso

Los casos de uso son un mecanismo para ayudar a entender y describir los
requisitos de forma simple y entendible para todo el personal involucrado. Fue
introducido por Jacobson. En UP, el Modelo de Casos de Uso es un artefacto de la
disciplina de Requisitos.

Definiciones para entender los casos de uso:

 Actor es algo (persona o sistema informatizado) que interactúa con el


sistema.

 Un escenario es una secuencia específica de acciones e interacciones


entre los actores y el sistema. Un escenario recoge los pasos que

Dpto. Electrónica, Automática e Informática Industrial 45


Carlos Platero Apuntes de Informática Industrial

dinamizan al sistema, que pueden ser de tres tipos: a) Una interacción


con el actor, b) Una validación (normalmente a cargo del sistema) y c) un
cambio de estado realizado por el sistema.

 Un caso de uso es una colección de escenarios de éxitos y fallos


relacionados, que describe a los actores utilizando un sistema para
satisfacer un objetivo.

Lo que hay que desarrollar es cómo utilizando el sistema proporciona un valor


añadido al usuario o cómo cumple con sus objetivos. No hay que pensar en los
requisitos del sistema a modo de “lista de la compra” (que tenga capacidad de imprimir,
la aplicación tiene acceso a Internet,...). Los desarrolladores son muy dados a trabajar
sobre objetivos que nada interesa a los futuros usuarios del sistema.

¿Cómo debería cubrirse un caso de uso?. Las tareas pueden agruparse en


distintos niveles de granularidad. Para un primer nivel de análisis de los requisitos de
una aplicación, hay que centrarse en los casos de uso al nivel de procesos del negocio
elementales (EBP, Elementary Business Processes).

Hay que añadir valor observable y cuantificable al negocio y llegar a un acuerdo


para que el sistema y los datos se encuentren en un estado estable y consistente. Por
ejemplo, en una aplicación sobre la Declaración de la Renta, que el usuario se
identifique al sistema no es un EBP. En cambio, si es un EBP calcular si la declaración
es positiva o negativa. Hay tareas como “Identificarse al sistema y ser validado” que no
añade valor observable o cuantificable al negocio. Se pueden definir subobjetivos que
den soporte al objetivo del usuario. Sin embargo, no suele ser útil escribir casos de uso
para las subfunciones, sólo se hace cuando ésta se repite o es una precondición en
muchos casos. Centrándose en la guía EBP y en los requisitos funcionales, éstos
orientan a realizar las siguientes tareas:

1. Encontrar los objetivos del usuario.

2. Definir un caso de uso para cada uno de estos objetivos.

2.5.1 Descubrir los actores, los objetivos y los casos de usos

Los pasos a seguir son:

1. Elegir los límites del sistema.

2. Identificar los actores principales.

3. Para cada uno de ellos, identificar sus objetivos de usuario.

4. Definir los casos de uso que satisfagan los objetivos de usuario.

46 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

Los actores y los objetivos se identifican a la vez. Una batería de preguntas útiles
para encontrar los actores principales y sus objetivos pueden ser:

¿Quién arranca y para el ¿Quién se encarga de la


sistema? administración del sistema?

¿Quién gestiona a los usuarios y ¿Es un actor “el tiempo” de


la seguridad? forma que haya que dar una
respuesta en un tiempo
¿Existe un proceso de control determinado?
que reinicie el sistema si falla?
¿Quién evalúa la actividad o el
rendimiento del sistema?

Otra forma de localizarlos es haciendo una lista de actor-objetivos. Por ejemplo,


las siguientes tablas muestran las listas de actor-objetivos para las aplicaciones de
análisis de imágenes biomédicas y para el análisis en frecuencia de los filtros
analógicos.

Tabla 2-2 Lista de actor-objetivo para el análisis de imágenes de espermatozoides

Actor Objetivos
Biomédico Clasificar los espermatozoides en cinco tipos
distintos
Microscopio robotizado Entregar al sistema las imágenes de
espermatozoides adquiridas

Tabla2-3 Lista de actor-objetivo para la aplicación de respuesta en frecuencia

Actor Objetivos
Ingeniero Respuesta en frecuencia de circuitos analógicos
lineales

Otro enfoque para ayudar en la búsqueda de los actores, objetivos y casos de uso
es identificar los eventos externos que llegan al sistema, ¿Cuáles son?, ¿de dónde
proceden y por qué?. Una lista del evento externo, quién lo produce y cual es el objetivo
son presentados para las dos problemáticas abordadas.

Tabla 2-4 Lista evento-actor-objetivo para la aplicación de análisis de los espermatozoides


Evento Externo Parte del Actor Objetivo
introducir un directorio de Biomédico clasificar los espermatozoides que
imágenes de hay en cada imagen
espermatozoides
Adquirir las imágenes Microscopio Generar la entrada al sistema de
robotizado clasificación
Tabla 2-5 Lista evento-actor-objetivo para la aplicación de respuesta en frecuencia
Evento Externo Parte del Actor Objetivo
introducir el esquema de un Ingeniero electrónico Determinar la respuesta en
filtro analógico frecuencia

Dpto. Electrónica, Automática e Informática Industrial 47


Carlos Platero Apuntes de Informática Industrial

En general, se define un caso de uso, de nivel EBP, por cada objetivo que tiene
un actor. Obviamente se han identificado algunos casos de uso y éstos ni están
completos, ni son perfectos. Habrá que refinar en otra iteración.

Como norma, los casos de uso son nominados comenzando con un verbo.

En la elaboración de los casos de uso, no deben de existir intermediarios entre


los usuarios finales y los programadores. Los usuarios deben tener dedicación completa
al proyecto.

Los casos de uso se escriben no considerando la interfaz del usuario, hay que
centrarse en la intención.

2.5.2 La plantilla de documento de Casos de Uso

Los casos de uso de caja negra son la forma más recomendada y común; no
describen el funcionamiento interno del sistema, ni sus componentes o diseño, sino que
especifica cuáles son sus responsabilidades; muy en la línea del análisis orientado a
objetos.

A través de la definición de las responsabilidades del sistema con los casos de


uso de caja negra, es posible especificar qué debe hacer el sistema (los requisitos
funcionales) sin decidir cómo lo hará (el diseño).

Los casos de uso se escriben con diferentes formatos:

 Breve: resumen conciso, normalmente del escenario principal con éxito.

 Informal: Formato de párrafo en estilo informal.

 Completo: el más elaborado y el que se va a tratar a continuación.

2.5.2.1 Elementos fundamentales del informe completo

La plantilla dejada en la página web de la asignatura tiene el siguiente índice:


1. IDENTIFICACIÓN DEL CASO DE USO ...............................................................................
2. DEFINICIÓN DEL CASO DE USO .........................................................................................
2.1. ACTOR .............................................................................................................................
2.2. DESCRIPCIÓN ..................................................................................................................
2.3. PRECONDICIONES ...........................................................................................................
2.4. POSTCONDICIONES .........................................................................................................
2.5. CURSO DE ÉXITO .............................................................................................................
2.6. CURSO ALTERNATIVO.....................................................................................................
2.7. EXCEPCIONES..................................................................................................................
2.8. INCLUSIONES ...................................................................................................................
2.9. PRIORIDAD ......................................................................................................................
2.10. FRECUENCIA DE CASO DE USO .......................................................................................
2.11. REGLAS DEL NEGOCIO....................................................................................................

50 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

2.12. REQUERIMIENTOS ESPECIALES .....................................................................................


2.13. HIPÓTESIS DE PARTIDA ..................................................................................................
2.14. NOTAS Y DOCUMENTOS ABIERTOS ................................................................................

El primer apartado hace referencia a un identificador que se le da al caso de uso,


para su reconocimiento particular. Sin duda, la parte importante está en el segundo
apartado, en la definición del caso de uso.

Se empieza definiendo al actor. El actor principal es el que recurre a los


servicios del sistema para cumplir un objetivo concreto. El caso de uso captura el
comportamiento relacionado con la satisfacción de los intereses del personal indicado.
Un estilo habitual es poner con mayúsculas los nombres de los actores para facilitar sus
identificaciones.

Las precondiciones establecen lo que siempre debe cumplirse antes de comenzar


un escenario del caso de uso. El escenario de caso de uso recoge la dinámica de éste. Su
evolución temporal depende de los eventos generados. Las postcondiciones son las
acciones que se prevén tener finalizadas al acabar el caso de uso.

El curso de éxito establece que debe de cumplirse cuando el caso de uso se


completa con éxito. El curso debería satisfacer las necesidades de todo el personal
involucrado. En él se establece el flujo básico, el cual describe el camino de éxito típico
que satisface los intereses del personal involucrado. Normalmente no incluye ninguna
condición o bifurcación. Hay que intentar posponer todas las sentencias condicionales y
de bifurcación a las secciones externas. Se utilizará una enumeración del tipo 1.0, 2.0, ...
para cada una de las acciones del flujo básico.

Los cursos alternativos que pueden ocurrir dentro de este caso el uso, describen
cualquier diferencia en la secuencia de los pasos de éxito. Se enumera cada curso
alternativo en la forma "X.Y", donde "X" identifica el paso del caso de uso de éxito y la
“Y” es un número de serie para la alternativa y mayor que cero. Por ejemplo, "5.3"
indicarían el tercer curso alternativo para la etapa número 5 del caso de uso.

Las excepciones son interrupciones generadas de forma inesperada, cuya causa


es un mal funcionamiento en la ejecución del curso básico. Por ejemplo, hay una falta
de memoria, no existe el fichero indicado, hay errores de desbordamiento matemático,
etc. También se indicará qué se propone para resolverlo. Para cada excepción se
enumerará en la forma "X.Y.E.Z ", donde "X" identifica el paso del caso del uso, Y
indica (0) normal o el curso alternativo (>0) durante los cuales esta excepción podría
ocurrir, "E" indica una excepción, y "Z" es un número de serie para las excepciones. Por
ejemplo "5.0.E.2" indicaría la segunda excepción para el curso normal para el caso
número 5 del uso.

Entre el camino de éxito y las extensiones (alternativa y excepciones) debería


cubrirse “casi” todos los intereses del personal involucrado.

Los requisitos especiales o no funcionales suelen ir en el documento de


Especificaciones Complementarias.

Dpto. Electrónica, Automática e Informática Industrial 51


Carlos Platero Apuntes de Informática Industrial

Ejemplo 2.6

Rellenar el caso de uso de ClasificarEspermatozoides de la aplicación


de análisis de las imágenes.
Actores: Biomédico
Descripción: Analizar las imágenes con espermatozoides humanos y clasificarlos
Precondiciones: Las imágenes están disponibles en un único directorio
Postcondiciones: Informe de resultados de la clasificación
Curso normal: 1.0. El biomédico carga las imágenes de la muestra en un directorio.
2.0. Inicializa la aplicación y entrega al sistema, mediante el GUI, el
directorio donde se encuentran las imágenes a analizar.
3.0. El biomédico introduce el nombre del fichero donde desea que se
escriba los resultados de la clasificación.
4.0. El sistema procesa las imágenes y clasifica los espermatozoides.
5.0. El biomédico espera a que el sistema clasifique los espermatozoides
Curso alternativo: 4.1. Interacción entre el sistema y el biomédico. El biomédico desea
analizar y clasificar paso a paso cada una de las imágenes
Excepciones: 2.0.E.1 No hay imágenes en el directorio.
3.0.E.1 Es ilegal el nombre del fichero de resultados.
4.0.E.1 Hay errores o falla el módulo de análisis y de clasificación.
Inclusiones:
Prioridad: Máxima. Núcleo del sistema.
Frecuencia de uso: Podría ser casi continuo.
Reglas de negocio:
Requerimientos especiales: Los tiempos de análisis de cada imagen por debajo de los 5 segundos.
Internacionalización del lenguaje de texto que se muestra.
Suposiciones de partida: Se sigue el protocolo de adquisición definido
Notas y documentos: Documento de adquisición de las imágenes a definir

Ejemplo 2.7

Rellenar el caso de uso RespuestaFrecuencia de la aplicación de


análisis de los filtros electrónicos.
Actores: Ingeniero electrónico
Descripción: El ingeniero elige el tipo de filtro lineal e introduce los valores de los
componentes analógicos, luego elige los parámetros de la respuesta en
frecuencia y la aplicación le devolverá la respuesta en frecuencia en un
diagrama de Bode
Precondiciones: El ingeniero conoce y sabe todos los parámetros del filtro lineal y de la
respuesta
Postcondiciones: Se presentará en diagrama de Bode la respuesta en frecuencia del filtro
capturado
Curso normal: 1.0.El ingeniero introduce el circuito eléctrico (mirar caso de uso incluido
de capturar el circuito)
2.0. La aplicación pide el rango de frecuencias y el intervalo aplicado en
la determinación de la respuesta en frecuencia. Además se le solicitará si
desea una presentación en decibelios o lineal.
3.0. La aplicación calcula la FDT del circuito y determina la respuesta en
frecuencia.
4.0. Los resultados son presentados en un diagrama de Bode
(módulo/argumento).

52 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

Curso alternativo: 1.1 El circuito es capturado desde un fichero de descripción de


componentes electrónicos tipo * CIR
Excepciones: 3.0.E.1 Hay algún error de desbordamiento o de división por cero en el
cálculo de la respuesta en frecuencia. Se le notificará del error matemático
al usuario
Inclusiones: Captura del circuito
Prioridad: Máxima. Núcleo del sistema.
Frecuencia de uso: Podría ser casi continuo.
Reglas de negocio:
Requerimientos especiales:
Suposiciones de partida:
Notas y documentos: Documento de adquisición de los circuitos

2.5.3 Los casos de uso y la notación UML

Los Diagramas de Casos de Uso, dados por UML, son secundarios. Los Casos
de Uso son documentos. Dibujar un diagrama de casos de uso junto con la lista actor-
objetivos es complementario al documento.

En UML, los actores son representados, generalmente, por un “muñeco”, pero


puede haber variaciones dependiendo del tipo de actor. Dentro de los actores están los
principales, los actores de apoyo (aquellos que proporcionan un servicio al sistema) y
los actores pasivos (los que están interesados en el caso de uso, pero no son ni el
principal ni de apoyo). Por ejemplo, en un aplicación financiera, el actor principal
puede ser un empleado de banca, la impresora sería un actor de apoyo y la Agencia
Tributaria un actor pasivo.

Los “muñecos” suelen emplearse para actores humanos. Cuando los actores son
otros sistemas informáticos o equipos en general, se representa mediante un cuadrado,
con el estereotipo1 <<actor>>.

Los casos de uso se representan mediante una elipse con el nombre dado. Las
relaciones entre los actores y los casos de uso sen unen mediante líneas que pueden
llevar un estereotipo.

Ejemplo 2.8

Diagrama del caso de uso de la aplicación de análisis de los espermatozoides

1
Un estereotipo es una variante de un elemento de UML. Hay estereotipos estándares, definidos
dentro del UML y hay otros que se pueden definir específicamente en un proyecto. Los estereotipos se
identifican por una palabra clave entre los signos << y >>.

Dpto. Electrónica, Automática e Informática Industrial 53


Carlos Platero Apuntes de Informática Industrial

Ejemplo 2.9

Diagrama de caso de uso para la aplicación de respuesta en frecuencia

Los casos de uso no son orientados a objetos. Los casos de uso podrían ser
utilizados dentro de los métodos estructurados. Es sólo una herramienta para capturar
los requisitos. En UP serán la entrada para las actividades de AOO/D.

A los casos de uso se les puede acompañar con una lista de características de alto
nivel del sistema. Aunque ésta es parte del documento de Visión y Alcance.

2.5.4 Casos de uso en el UP

Los casos de uso en el UP fomentan el desarrollo dirigido por los casos de uso.
Éstos son una parte importante de la planificación iterativa. Los casos de uso dirigen el
diseño.

UP diferencia entre los casos de uso del sistema (los vistos hasta ahora) con los
casos de uso del negocio. Por ejemplo, en un restaurante, un caso de uso del negocio es

54 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

servir una comida. Esta actividad incluye no sólo la aplicación informática sino todo lo
concerniente a este proceso: pedidos, colocación de la mesa, camareros,... Rational Rose
al iniciar un proyecto, siguiendo UP, realiza el diagrama de UML que aparece en la
figura; dando a entender una relación más amplia entre los casos de uso de la aplicación
informática y su entorno ambiental.

Business Use-Case
Model

The Use-Case Model is


traceable to (and
deriv es f rom) the
Business Model. The
sy stem (as described
in the Use Case
Model) prov ides
behav ior that supports
the business.

Use-Case Model

Figura 2. 1 Casos de uso de la aplicación y del negocio

Los casos de uso empiezan en la primera iteración, en el inicio, y son refinados


en las siguientes iteraciones de la fase de elaboración. La tabla muestra un análisis de
los requisitos de forma escalonada, donde se dirige por el alto riesgo y con la
realimentación que incluye la evaluación del usuario, las pruebas y el conocimiento de
lo que no se conocía hasta ese momento.

Dpto. Electrónica, Automática e Informática Industrial 55


Carlos Platero Apuntes de Informática Industrial

Tabla 2-6 Muestra del esfuerzo de los requisitos a lo largo de las primeras iteraciones; no es
una receta

Comentarios y nivel de esfuerzo de los requisitos

Disciplina Artefacto Inicio Elab 1 Elab 2 Elab 3 Elab 4

1 semana 4 semanas 4 semanas 3 semanas 3 semanas

Requisitos. Modelo de 2 días de taller Al iniciar esta Al iniciar esta Repetir, se Repetir con la
Casos de Uso de requisitos. iteración, tiene iteración, tiene completa el intención de
Se identifican lugar un taller de lugar un taller de 70% de todos clarificar y
por el nombre requisitos de 2 requisitos de 2 los casos de escribir en
de la mayoría días. Se obtiene días. Se obtiene uso en detalle del 80-
de los casos un mejor una mejor detalle. 90% de los
de uso y éstos entendimiento y comprensión y casos de uso.
se resumen en retroalimentación retroalimentación
un párrafo a partir del a partir del
breve. trabajo de trabajo de Sólo una
implementación, implementación, pequeña parte
entonces se entonces se de éstos se
Sólo el 10% completa el 30% completa el 50% construyen
se escribe en de los casos de del los casos de durante la
detalle. uso en detalle. uso en detalle. elaboración; el
resto se aborda
durante la
construcción.

Diseño. Modelo de Nada. Diseño de un Repetir. Repetir. Repetir.


Diseño. pequeño Deberían ahora
conjunto de estabilizarse
requisitos de alto los aspecto de
riesgo alto riesgo
significativos significativos
desde el punto de para la
vista de la arquitectura.
arquitectura.

Implementación. Modelo de Nada. Implementar Repetir. Se Repetir. Se Repetir. Se


implementación esto. construye el 5% construye el construye el
(código, etc.) del sistema final 10% del 15% del
sistema final sistema final.

Gestión del Plan de Estimación La estimación Un poco mejor ... Un poco Ahora se
proyecto. Desarrollo de muy comienza a mejor ... pueden
SW. imprecisa del tomar forma. establecer
esfuerzo total racionalmente
la duración
global del
proyecto, los
hitos más
importantes,
estimación del
coste y
esfuerzo.

56 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

2.6 Especificaciones complementarias

No es suficiente con escribir los casos de uso y el documento de Visión y


Alcance. Existen otros requisitos que no son necesarios de identificar con los usuarios,
como los relacionados con la fiabilidad, el rendimiento, la documentación, el
empaquetado, las licencias, etc. Éstos se recogen en el informe de las Especificaciones
Complementarias, i.e. los que comprenden con los atributos o requisitos de calidad
“URPS+”. Estos incluyen:
∙ Requisitos URPS+
∙ Informes
∙ Restricciones de HW y SW
 Idiomas, unidades, estándares
 Empaquetado
 ...
 y reglas del dominio o negocio
La calidad del SW no se refiere a los requisitos de funcionalidad, habla de la
fiabilidad del sistema que influye en la arquitectura de la aplicación.

Las reglas del dominio dictan el modo en el que podrían operar un dominio o
negocio. Con frecuencia, resulta útil identificar y registrar aquellas reglas del dominio
que afectan a los requisitos, ya que pueden clarificar el contenido de un caso de uso
ambiguo o incompleto.

Hay que evitar restricciones de diseño temprano, especialmente en la fase de


inicio. Todavía se tiene poco conocimiento.

La plantilla empleada para este informe tiene la siguiente tabla:


1.INTRODUCCIÓN ...........................................................................................................................
1.1 PROPÓSITO...............................................................................................................................
1.2 CONVENCIONES DEL DOCUMENTO .........................................................................................
1.3 SUGERENCIAS PREVISTAS DE TIPO DE PERSONAL QUE VA A LEER ESTE
DOCUMENTO....................................................................................................................................
1.4 ALCANCE DEL PROYECTO .......................................................................................................
1.5 REFERENCIAS ..........................................................................................................................
2.DESCRIPCIÓN GENERAL ...........................................................................................................
2.1 PERSPECTIVA DEL PRODUCTO ................................................................................................
2.2 CARACTERÍSTICAS DEL PRODUCTO .......................................................................................
2.3 CLASES DE USUARIOS Y CARACTERÍSTICA ............................................................................
2.4 AMBIENTE DE OPERACIÓN ......................................................................................................
2.5 RESTRICCIONES DE DISEÑO O DE IMPLEMENTACIÓN ...........................................................
2.6 DOCUMENTACIÓN DEL USUARIO ............................................................................................
2.7 SUPOSICIONES Y DEPENDENCIAS ............................................................................................
3.CARACTERÍSTICAS DEL SISTEMA .........................................................................................
3.1 PRIMERA CARACTERÍSTICA DEL SISTEMA .............................................................................
3.2 SEGUNDA CARACTERÍSTICA DEL SISTEMA (Y SIGUIENTES) ..................................................
4.REQUISITOS DE LAS INTERFASES EXTERNAS ...................................................................
4.1 INTERFASES CON LOS USUARIOS ............................................................................................
4.2 INTERFASES DEL SOPORTE FÍSICO (HARDWARE) ..................................................................

Dpto. Electrónica, Automática e Informática Industrial 57


Carlos Platero Apuntes de Informática Industrial

4.3 INTERFASES DEL SOPORTE LÓGICO (SOFTWARE) .................................................................


4.4 INTERFASES DE COMUNICACIONES ........................................................................................
5.OTROS REQUISITOS NO FUNCIONALES ...............................................................................
5.1 REQUISITIOS DE RENDIMIENTO ..............................................................................................
5.2 REQUISITOS DE FIABILIDAD ....................................................................................................
5.3 REQUISITOS DE SEGURIDAD ....................................................................................................
5.4 ATRIBUTOS DE CALIDAD DEL SOFTWARE ..............................................................................
6. OTROS REQUISITOS ...................................................................................................................

Este documento debe de complementar a los de Visión y Alcance y a los Casos


de Uso. Se evitará la duplicación de información entre todos los documentos de los
requisitos, realizando conexiones y referencias a los otros documentos, cuando se
consideren que deberían ser tratados con mayor profundidad en otros informes.

En este documento se hablará especialmente de los requisitos no funcionales y


del tipo de arquitectura propuesta. Respecto a los requisitos no funcionales a tratar
podrían ser, por ejemplo:
 Plataformas
 Herramientas de desarrollo
 Control de errores
 Instalación
 Multilenguajes
 ...

Ejemplo 2.10

Rellenar las especificaciones complementarias para la aplicación de


respuesta en frecuencia
Este documento es complementario al de Visión y Alcance del producto FrecuenciaELAI.
Se describe los requisitos no funcionales. En éste se hace referencia a la arquitectura y a los
aspectos relacionados con:
 Procesamiento multihebra en las el procesamiento de la respuesta en frecuencia
 Multilenguaje, al menos español e inglés
 Lenguajes de programación y librerías de servicio: ANSI C++, STL y Qt
 Tipos de plataforma: Linux y Microsoft.
 Control de errores: excepciones con try-catch.
 Instalación:
 Documentación: del código mediante Doxygen, manuales de usuario en pdf.

La arquitectura propuesta es del tipo:

MFC (.NET)
ActiveX-Bode VistaFrecuenci a
ELAI

DominioFrecunc
iaEla STL-ANSI C++

58 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

2.7 Problemas

1. Actividades a desarrollar en la fase de inicio dentro de UP.

2. Tipos de requisitos.

3. ¿Cómo capturar la lista de características principales?, ¿Dónde deben de aparecer?.

4. Técnicas para la identificación de actores, objetivos y casos de uso.

5. Estructura del documento de Casos de Uso.

6. Casos de Uso: documento, diagrama UML de Casos de Uso y lista de actores


objetivos.

7. Evolución de las disciplinas con sus artefactos en la fase de inicio y de elaboración.

8.¿Qué se recoge en el documento de Especificaciones Complementarias?.

Problema 2.1

Los simuladores
simplificados de los procesos
monovariables (SISO) se basan en
tener modelos lineales e
invariantes en el tiempo (LTI) para
dichos sistemas. Éstos se
caracterizan por tener, cada uno
de ellos, una función de
transferencia, FDT, en el dominio
en
Z:
Y z  b0  b1 z 1  ...  bm z  m
M z   
X z  a0  a1 z 1  ...  an z n

Donde ai y bi son constantes y conocidas. De forma que ante una señal


de excitación, x(t), de tipo test (impulsional, escalón, rampa, parábola, senoidal,
...), se determina la salida haciendo la anti-transformada en Z, dando paso al
siguiente algoritmo:

yk 
1
b0 xk  b1 xk 1  ...  bm xk m   a1 yk 1  a2 yk 2  ...  an yk n 
a0

Dpto. Electrónica, Automática e Informática Industrial 59


Carlos Platero Apuntes de Informática Industrial

El índice k da el valor de la muestra en el instante t=kT, siendo T el


intervalo de tiempo empleado entre muestra y muestra. Para los sistemas
físicos reales, los valores de k negativos son iguales a cero. Se pide, dado un
proceso LTI-SISO y conocido los coeficientes ai y bi, realizar la recogida de
requisitos:

1. Visión y Alcance. Lista de características principales (jerarquía a dos


niveles)

2. Glosario

3. Lista de evento-actor-objetivos

4.Casos de uso

5. Especificaciones complementarias
1. El sistema debe de simular la dinámica del control del avión ante una maniobra.
1.a. El sistema debe tener la función de transferencia del modelo.
1.b. Se debe definir el tipo de maniobra a realizar
1.c. Opcionalmente se podrá introducir algunas perturbaciones
2. El sistema visualizará la evolución temporal del proceso.
2.a El sistema debe visualizar la orientación del avión en función del tiempo.
2.b El sistema debe visualizar la posición del timón en función del tiempo.

Glosario: Función de transferencia, maniobra, perturbación, variable de salida,


periodo de muestro, tiempo de simulación.
Evento Actor Objetivo
Definir función de transferencia Ingeniero Introducir modelo del proceso
Definir maniobra Ingeniero Definir la señal de entrada
Definir parámetro de la Ingeniero Tiempo de evolución del proceso
simulación
Visualización de resultado Maquina Mostrar en gráficas los resultados de la simulación

Actores: Ingeniero de Control


Descripción: El ingeniero introduce la función de transferencia, la maniobra y
opcionalmente las perturbaciones y el simulador debe de visualizar la
dinámica del proceso ante las entradas dadas.
Precondiciones: El ingeniero conoce la función de transferencia y las señales de mando y
perturbaciones.
Poscondiciones: El simulador visualiza la dinámica del proceso
Curso normal: 1.0. El ingeniero introduce la función de transferencia del proceso.
2.0. El ingeniero introduce el tipo de excitación y define opcionalmente
las perturbaciones.
3.0. El ingeniero introduce los tiempos de simulación.
4.0. El sistema calcula la dinámica de simulación.
5.0. Visualizar la evolución temporal de la señal de salida.
Curso alternativo: 1.1 El ingeniero introduce el modelo a través de un fichero.
5.1 La salida es guardada en fichero.
Excepciones: 4.0.E.1 Hay algún problema en el cálculo de la dinámica.

Inclusiones:
Prioridad: Máxima. Núcleo del sistema.
Frecuencia de uso: Podría ser casi continuo.

60 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

Reglas de negocio:
Requerimientos especiales:
Suposiciones de partida:
Notas y documentos:

Problema 2.2

Recoger los requisitos más importantes de una aplicación para el alquiler


automático de películas de cine en DVD. Realizar las siguientes tareas:
1. Lista de características principales (jerarquía a dos niveles).
2. Lista de evento-actor-objetivos.
3. Diagrama de Casos de Uso.
Problema 2.3

Rellenar los siguientes artefactos de la fase de Inicio


para la aplicación del juego de las tres en raya:

1. Lista de características principales (jerarquía a dos


niveles).

2. Glosario

3. Lista de evento-actor-objetivos

4. Casos de Uso.

Problema 2.4

Realizar la recogida de requisitos para el


juego del frontón.

En jerarquía a dos niveles se plantea las


siguientes características:

1. Un jugador juega al frontón con una raqueta y


una pelota con tres paredes

a. El sistema debe de permitir mover la raqueta


según el deseo del usuario dentro de un área
restringida

b. El sistema debe simular la interacción entre la pelota contra las paredes y la raqueta.

c. El sistema debe visualizar el escenario de paredes, pelota y raqueta.

d. El sistema debe de terminar la partida cuando la pelota cruce una determinada línea,
al que se le llamará línea roja.

Dpto. Electrónica, Automática e Informática Industrial 61


Carlos Platero Apuntes de Informática Industrial

Los términos para el glosario serían:

Frontón, Pelota, Pared, Raqueta, LineaRoja, ...

La lista de evento-actor-objetivo sería:


Evento Actor Objetivo
Mover raqueta Jugador Dar a la pelota
Iniciar saque Jugador Lanzar inicialmente la pelota
Interacción entre pelota- Maquina La pelota cambia la dirección de la velocidad
raqueta
Interacción entre pelota- Maquina La pelota cambia la dirección de la velocidad
paredes

A este nivel y utilizando el criterio EBP se definirá el caso de uso


JugarAlFrontón. Escribir el resumen de este caso de uso.
Actores: Jugador
Descripción: El jugador inicia una partida, con el saque de la pelota. El jugador
pretenderá dar la pelota, antes de que ésta cruce la línea roja. La pelota
rebota contra las paredes y contra la raqueta
Precondiciones: El jugador conoce las reglas y sabe cuales son las teclas para mover la
raqueta.
Poscondiciones: El jugador ha terminado de jugar
Curso normal: 1.0. El jugador inicializa el saque de la pelota.
2.0. La pelota rebota contra las paredes.
3.0. El jugador mueve la raqueta.
4.0. El jugador acierta a dar a la pelota y entonces se va a 2.0.

Curso alternativo: 4.1 El jugador no acierta a dar a la pelota y se termina la partida.


Excepciones: 2.0.E.1 Hay algún problema en el choque entre pelota-pared.
4.0.E.1. Hay algún problema en el choque entre pelota-raqueta.
Inclusiones:
Prioridad: Máxima. Núcleo del sistema.
Frecuencia de uso: Podría ser casi continuo.
Reglas de negocio:
Requerimientos especiales:
Suposiciones de partida:
Notas y documentos:

Problema 2.5

Rellenar los artefactos de la fase de Inicio para el juego del ‘Pang’. Éste
trata de un escenario cerrado donde un jugador pretende eliminar las esferas
existentes. El hombre dispara a las esferas, las cuales se dividen si son
grandes, en caso contrario desaparecen. Además el jugador deberá de evitar
que las esferas le toquen, ya que si le impacta perderá la partida. Se pide:
1. Lista de características principales (jerarquía a dos niveles).
2. Glosario
3. Lista de evento-actor-objetivos.
4. Casos de Uso.

62 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 2: Recogida y documentos de requisitos

Derecho de Autor © 2014 Carlos Platero Dueñas.


Permiso para copiar, distribuir y/o modificar este documento bajo los términos
de la Licencia de Documentación Libre GNU, Versión 1.1 o cualquier otra
versión posterior publicada por la Free Software Foundation; sin secciones
invariantes, sin texto de la Cubierta Frontal, así como el texto de la Cubierta
Posterior. Una copia de la licencia es incluida en la sección titulada "Licencia de
Documentación Libre GNU".

La Licencia de documentación libre GNU (GNU Free Documentation License)


es una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
apuntes están cubiertos por esta licencia. La version 1.1 se encuentra en
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html

Dpto. Electrónica, Automática e Informática Industrial 63


3 Análisis orientado a objetos
En la fase de Elaboración, siguiendo a UP, las iteraciones que se van a llevar a
cabo deberán de servir para:

 Descubrir la mayoría de los requisitos.

 Estabilizar la arquitectura, reduciendo o eliminando los riesgos más


importantes.

 Implementar el núcleo de la aplicación.

La Elaboración es una serie de iteraciones durante la cual el equipo lleva a cabo


un estudio serio e implementa el núcleo central de la arquitectura. Esta fase puede estar
constituida entre dos a cuatro iteraciones. En ellas no sólo se realiza una preparación de
los módulos para que se implementen en la fase de construcción, sino que en esta fase
es donde se implementan el núcleo del sistema. Durante esta etapa, los desarrolladores
no están creando prototipos desechables, al contrario, el diseño y el código son
porciones del sistema final con calidad de producción. Por tanto, en la Elaboración se
construirá el núcleo central de la arquitectura, se resolverá la mayoría de los requisitos y
se podrá estimarse la planificación y los recursos globales del proyecto.

Algunas buenas prácticas en la Elaboración serían:

 Llevar a cabo iteraciones de duración fija y dirigida por el alto riesgo.

Dpto. Electrónica, Automática e Informática Industrial 65


Carlos Platero Apuntes de Informática Industrial

 Comenzar a programar pronto.

 Diseñar, implementar y probar, de manera adaptable, las partes básicas y


arriesgadas de la arquitectura.

 Probar desde el principio, a menudo y de manera realista.

 Adaptarse en base a la realimentación procedente de las pruebas,


usuarios y desarrolladores.

 Escribir con detalle la mayoría de los casos de uso

UP pone los siguientes artefactos para conseguir los objetivos expuestos en la


fase de elaboración:

Tabla 3-1. Artefactos en la fase de elaboración

Artefacto Comentario

Modelo del Dominio Es una visualización de los conceptos del dominio; es similar al modelo
de información estático de las entidades del dominio.

Modelo de Diseño Es el conjunto de diagramas que describen el diseño lógico.


Comprenden los diagramas de clases de diseño, diagramas de
interacción, diagramas de paquete, etc.

Documento de la Una ayuda de aprendizaje que resume las cuestiones claves de la


Arquitectura Software arquitectura y de cómo se resuelven en el diseño. Es un resumen de las
ideas destacadas del diseño y su motivación en el sistema.

Modelo de Datos Incluye esquema de bases de datos y las estrategias de transformación


entre representaciones de objetos y no objetuales.

Modelo de Pruebas Una descripción de lo que se probará y de cómo se hará.

Modelo de Se corresponde con la implementación real (el código, los ejecutables,


Implementación los manuales, las bases de datos, etc.)

Guiones de Casos de Descripción de la interfaz de usuarios, caminos de navegabilidad,


Uso, prototipos GUI modelos de facilidad de uso, etc.

3.1 El Modelo del Dominio

El Modelo del Dominio es el artefacto más importante del Análisis Orientado a


Objetos, AOO. Un modelo del dominio muestra las clases conceptuales significativas en
un dominio del problema. Las clases conceptuales son categorías reales del universo del
problema, i.e. son las esencias del problema. Un modelo del dominio es fuente de
inspiración para el diseño de los objetos. En UP, el Modelo del Dominio pertenece a la
disciplina de Modelado del Negocio.

66 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

Las clases conceptuales del mundo real no son clases software. Hay tres tipos de
clases: conceptuales, de diseño y de implementación. Las primeras corresponden con las
esencias del universo del problema, la segunda categoría surge de la solución lógica
dada en la etapa de diseño y la tercera se da en la implementación.

Hay diferencia entre las clases conceptuales, las clases de diseño y las de
implementación, por tanto, en el modelo del dominio hay que evitar los métodos y los
artefactos del software. Por ejemplo, las relacionadas con el GUI (Graphical User
Interface), las bases de datos,...

El modelo del dominio es una representación visual de las clases conceptuales.


El modelo del dominio podría considerarse como un diccionario visual de las
abstracciones relevantes, del vocabulario del dominio y un resumen de la información
del dominio.

En UML, el Modelo del Dominio se representa con un conjunto de diagramas de


clases, mostrándose las clases conceptuales, sus asociaciones y sus atributos. En UML
no existe el término de “Modelo de Dominio”. UML es sólo unas normas para la
representación gráfica de los conceptos de Ingeniería de la Programación; es UP el que
crea el “Modelo del Dominio”, los “Diagramas de Secuencia del Sistema” (DSS) y los
“Contratos de Operación”.

Las clases conceptuales podrían considerarse en términos de: a) su símbolo, b)


su intensión y c) por su extensión:

 Símbolo: palabra o imágenes que representan una clase conceptual.

 Intensión: la definición de una clase conceptual.

 Extensión: el conjunto de ejemplos a los que se aplica la clase


conceptual.

La diferencia esencial entre el análisis orientado a objetos y el análisis


estructurado es:

“la división por clases conceptuales (objetos) en lugar de la división por funciones”

Los pasos para crear un modelo del dominio son:

1. Lista de las clases conceptuales candidatas.

2. Representación en un modelo del dominio.

3. Añadir las asociaciones necesarias para registrar las relaciones que hay que
mantener en mente.

4. Añadir los atributos necesarios para satisfacer los requisitos de información.

Dpto. Electrónica, Automática e Informática Industrial 67


Carlos Platero Apuntes de Informática Industrial

El modelo del dominio se construirá:

• Utilizando los nombres existentes en el dominio.

• Excluyendo las características irrelevantes.

• No añadiendo cosas que no están.

Si se considera que un concepto es más que un número o un texto, entonces será


una clase conceptual y no un atributo. En caso de duda, siempre será una clase
conceptual.

3.1.1 Identificación de las clases conceptuales

La tarea central del AOO es identificar las clases conceptuales relacionadas con
el escenario que se está diseñando. Se presentan dos técnicas:

1. Utilización de una lista de categorías de clases conceptuales.

2. Identificación de frases nominales.

Se comenzará la creación de un modelo del dominio haciendo una lista de clases


conceptuales candidatas. Como regla general es mejor definir por exceso el número de
clases que por defecto. La tabla 3.2 presenta una lista de categoría de clases
conceptuales. Para una mejor comprensión, se ha puesto las categorías de tres
problemas distintos: a) Clasificación de los espermatozoides, b) Aplicación para un
puesto de venta en un comercio y c) Gestión de los billetes de avión:

68 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

Categoría de clase conceptual Ejemplos


objetos tangibles o físicos Espermatozoide, Imagen,
Registro
Avión
especificaciones, diseños o descripciones de las CaracterísticaDelEspermatozoide
cosas EspecificaciónDelProducto
DescripcionDelVuelo
Lugares Laboratorio
Tienda
Aeropuerto
Transacciones Clasifica, Procesa
Venta, Pago
Reserva
roles de la gente Biomédico
Cajero, Cliente
Piloto, Pasajero
contenedores de otras cosas Directorios de imágenes, MatrizDeCaracteristicas
Tienda
Avión
cosas de un contenedor Ficheros
Artículo
Pasajero
otros sistemas informáticos o electromecánicos ServicioImpresion
externos al sistema SistemaAutorizaciónPagoCredito
ControlDeTraficoAereo
conceptos abstractos Ansia Acrofobia
Organizaciones LaboratorioDeAnálisis
DepartamentoDeVentas
CompañiaAerea
Hechos ClasificarEspermatozoides
Venta, Pago, Reunión
Vuelo, Colisión, Aterrizaje
procesos (normalmente no se representan como ProcesadorImagenes, ClasificadorEspermatozoide
conceptos, pero podría ocurrir) VentaDeUnProducto
ReservaUnAsiento
reglas y políticas Reglas de clasificación espermatozoides
PoliticaDeReintegro
PoliticaDeCancelacion
catálogos CatálogoDeEspermatozoides
CatalogoDeProductos
CatalogoDePiezas
registros de finanzas, trabajo, contratos cuestiones Recibo,LibroMayor, ContratoEmpleo
legales RegistroMantenimiento
instrumentos y servicios financieros LineaDeCredito
Stock
manuales, documentos, artículos de referencia, LineaDeCambiosDePreciosDiarios
libros ManualReparaciones
Tabla 3-2 Categorías de clases conceptuales

Otra técnica es el análisis lingüístico de los documentos de captura de los


requisitos. Se trata de identificar los nombres y las frases nominales en las descripciones
textuales y considerarlas como clases conceptuales o atributos candidatos. Sin embargo,
la imprecisión del lenguaje natural es un punto débil de este enfoque. Se recomienda
que se combine con las técnicas de lista de categorías de clases conceptuales.

Dpto. Electrónica, Automática e Informática Industrial 69


Carlos Platero Apuntes de Informática Industrial

Ejemplo 3.1

Determinar las clases conceptuales para la aplicación de


RespuestaFrecuencia.
Categoría de clases conceptuales Propuesta
Objetos tangibles o físicos Filtro lineal, circuito electrónico
Especificaciones o descripciones de cosas Respuesta en frecuencia, Función de
transferencia
Lugares Laboratorio
Transacciones
Líneas de la transacción
Roles de la gente Ingeniero electrónico
Contenedores de otras cosas Filtro lineal, Función de transferencia
Cosas en un contenedor Función de transferencia, polinomios
Otros sistemas informáticos o electromecánicos Capturador de circuitos electrónicos
externos al sistema
Conceptos abstractos
Organizaciones
Hechos
Procesos (normalmente no se representan como
conceptos, pero podría ocurrir)
Reglas y políticas
Catálogos
Registros de finanzas,
Instrumentos Diagrama de Bode
Manuales, documentos, artículos, libros Apuntes de Regulación Automática

Ejemplo 3.2

Realizar el análisis de la aplicación de juego “dados” mediante técnicas


estructuradas y mediante el artefacto modelo del dominio

70 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

3.1.2 Clases conceptuales de especificación

Las clases conceptuales de especificación están fuertemente relacionadas con las


cosas que describen. Se añadirán cuando:

a) Se necesita la descripción de un atributo o servicio, independientemente de


la existencia actual de algún ejemplo de esos atributos o servicios.

b) La eliminación de las instancias que describen da como resultado una


pérdida de información que necesita mantenerse, debido a la asociación
incorrecta de la información con la cosa eliminada.

c) Reduce información redundante o duplicada.

Las clases conceptuales de especificación de X describen características de la


clase conceptual X.

Ejemplo 3.3

Realizar la descripción de clase conceptual de un artículo de compra de


una tienda.

Un artículo en concreto estará constituido por una descripción, un precio y un


número de serie. Esta clase conceptual podría ser elaborada de esta manera. Sin
embargo, en el caso de que se acabase las existencias del artículo desaparecería toda la
información. Suceso éste que no se puede dar. En este caso se utilizará una clase
conceptual de especificación.

3.1.3 Reducción en el salto de la representación

El modelo del dominio proporciona un diccionario visual de los conceptos del


dominio. En la etapa del diseño, el modelo del dominio inspirará para nombrar algunas
cosas de la solución lógica y de la implementación. Este modo de actuar acelerará la

Dpto. Electrónica, Automática e Informática Industrial 71


Carlos Platero Apuntes de Informática Industrial

comprensión del código existente. Los nombres de algunas clases del diseño coincidirán
con las dadas en las clases conceptuales, luego sabiendo el modelo del dominio
sugerirá, de forma natural, la comprensión del código.

Así, por ejemplo, al hablar de las clases conceptuales de “Función de


Transferencia” y “Polinomios”, al conocer el dominio del problema, cuando éstas pasen
a ser clases de diseño y al encontrarlas en el código, sus relaciones con el mundo real
deberán de coincidir con la lectura de sus implementaciones.

3.1.4 Modelo del Dominio: Añadir asociaciones

Una asociación es una relación entre clases conceptuales que indica alguna
conexión significativa e interesante. Las asociaciones son abstracciones; no se trata de
conexiones entre entidades software. Se trata de identificar las asociaciones y añadirlas
al modelo del dominio.

Guía para las asociaciones:

∙ Centrarse en aquellas asociaciones para las que se necesita conservar


el conocimiento de la relación durante algún tiempo (asociaciones
“necesito-conocer”).

∙ Es más importante identificar las clases conceptuales que identificar


asociaciones.

∙ Demasiadas asociaciones tienden a confundir un modelo del dominio


en lugar de aclararlo. Su descubrimiento puede llevar tiempo, con
beneficio marginal.

∙ Evitar mostrar asociaciones redundantes.

Para la localización de las asociaciones comunes se emplea la técnica de rellenar


la siguiente lista propuesta:

Tabla 3.3. Lista de asociaciones comunes


Categoría Ejemplos
A es una parte física de B Halo-Espermatozoide
Cajón-Registro
Ala-Avión
A es una parte lógica de B Ficheros-DirectorioDeImagenes
LineaDeVenta-Venta
EtapaVuelo-RutaVuelo
A está contenida físicamente en B Espermatozoides-muestra
Registro-Tienda, Articulo-Estantería
Pasajero-Avión
A está contenido lógicamente en B Espermatozoides-imagen
DescripcionDelArticulo-Catalogo
Vuelo-PlanificacionVuelo
A es una descripción de B Características-Espermatozoide

72 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

DescripcionDelArticulo-Articulo
DescripcionDelVuelo-Vuelo
A es una línea de una transacción o informe de B Histograma-Espermatozoides
LineaDeVenta-Venta
TrabajoMantenimiento-RegistroMantenimiento
A se conoce/registra/recoge/informa/captura en B Venta-Registro
Reserva-ListaPasajeros
A es miembro de B Cajero-Tienda
Piloto-CompañiaAerea
A es una subunidad organizativa de B Departamento-Tienda
Mantenimiento-CompañíaAerea
A utiliza o gestiona B Cajero-Registro
Piloto-Avión
A se comunica con B Procesador-Clasificador
Cliente-Cajero
AgenteDeReserva-Pasajero
A está relacionado con una transacción de B Cliente-Pago
Pasajero-Billete
A es una transacción relacionada con otra Pago-Venta
transacción B Reserva-Cancelación
A está al lado de B LineaDeVenta-LineaDeVenta
Ciudad-Ciudad
A es prioridad de B Registro-Tienda
Avión-CompañíaAerea
A es un evento relacionado con B Venta-Cliente
Salida-Vuelo

Las asociaciones más prioritarias son:

• A es una parte lógica o física de B.

• A está contenida física o lógicamente en B.

• A se registra en B

En UML se representan como una línea entre clases con un nombre de


asociación. La asociación es inherentemente bidireccional. Es posible el recorrido
lógico de una a otra. Este recorrido es puramente abstracto. No se trata de una sentencia
entre conexiones. Una flecha, de carácter opcional, indica la dirección de lectura. No
indica la dirección de visibilidad o navegación.

Los roles son cada extremo de una asociación. Se suele indicar la multiplicidad
(*: cero o muchos, 1...*: uno o más, 1 ...40: de uno a 40, 5: exactamente 5, 3,7,8:
exactamente 3,7 y 8). La multiplicidad define cuántas instancias de una clase A puede
asociarse con una instancia de una clase B.

El nombre de las asociaciones comienza por una mayúscula, puesto que


representa un clasificador de enlaces entre instancias. Su formato es NombreTipo-
FraseVerbal-NombreTipo (los nombres tipos corresponden a las clases conceptuales).

Dpto. Electrónica, Automática e Informática Industrial 73


Carlos Platero Apuntes de Informática Industrial

Hay que centrarse en las asociaciones necesito-conocer, pero se puede completar


las asociaciones de sólo-comprensión para enriquecer el conocimiento básico del
dominio.

Estas asociaciones, posteriormente, se implementarán muchas de ellas como


caminos de navegación y visibilidad, pero su presencia en la vista conceptual de un
modelo del dominio no requiere de su implementación.

No todas las relaciones descubiertas en la lista de asociaciones comunes deben


ser colocadas. Puede haber un exceso y mostrar un ruido visual en el modelo del
domino. Hay que seleccionar las relaciones necesito-conocer durante algún tiempo y
eliminar asociaciones redundantes o derivadas.

Ejemplo 3.4

Dibujar el modelo del dominio de la aplicación RespuestaFrecuencia,


indicando las asociaciones.

3.1.5 Modelo del dominio: añadir los atributos

Un atributo es un valor de un objeto. Los atributos se incluirán cuando se sugiera


o implique una necesidad de registrar esta información.

Un error típico es modelar un concepto complejo del dominio como un atributo.


Los atributos deben ser datos simples o tipos de datos. Los tipos de datos de los
atributos incluyen: booleanos, fechas, números, horas, color, código postal, etc.

Una regla básica es que un atributo no es significativo de crear instancias


diferentes del él. Por ejemplo, el concepto Estudiante tiene entidad de ser clase
conceptual, pero no el número de matrícula. Existen muchos estudiantes con diferentes
atributos, pero el número de matrícula carece de sentido de que tenga más de una

74 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

instancia por estudiante. Por tanto, Estudiante si es una clase y el número de matrícula
es un atributo.

En caso de duda sobre un concepto, éste se definirá como una clase conceptual
en vez de un atributo.

Guía para presentar un concepto como una clase y no como un atributo:

1. Si el concepto está constituido por partes.

2. Hay operaciones asociadas con él.

3. Es una cantidad con unidades.

4. Tiene otros atributos.

5. Es una abstracción de uno o más tipos (superclase – subclase, relacionado


con conceptos de herencia).

Los tipos de datos pueden ser representados en el modelo del dominio, pero
puede producir ruido visual.

No se debería utilizar atributos para relacionar las clases conceptuales en el


modelo del dominio. Hay que relacionarlas con una asociación, no con un atributo. Se
trata de posponer y no deslizarse hacia el diseño.

Ejemplo 3.5

Describir el modelo del dominio para el caso de uso de


RespuestaFrecuencia

Dpto. Electrónica, Automática e Informática Industrial 75


Carlos Platero Apuntes de Informática Industrial

Ejemplo 3.6

Describir el modelo del dominio para el caso de uso de


ClasificaciónEspermatozoides

3.2 Diagrama de secuencias del sistema

El comportamiento de un sistema es una descripción de lo qué hace el sistema,


sin explicar cómo lo hace. Una parte de esta descripción es un diagrama de secuencias
del sistema, DSS. Otras partes corresponden con los casos de uso y con los contratos de
operación.

Un diagrama de secuencias del sistema o DSS es un dibujo que muestra, para un


escenario específico de un caso de uso, los eventos que generan los actores, indicando el
orden y la respuesta del sistema a modo de caja negra cerrada. Los DSS forman parte de
la disciplina de Modelo de Casos de Uso. La mayoría de los DSS se crean durante la
fase de Elaboración, cuando es útil identificar con detalle los eventos del sistema. No es
necesario crear DSS para todos los escenarios de los casos de uso, sólo para aquellos
seleccionados en la iteración con la que se trabaja.

Los eventos del sistema y sus operaciones asociadas deberían expresarse al nivel
de intenciones, en lugar de en términos de interacción con los elementos del interfaz
gráfico. También se mejora la claridad expositiva, si se comienza el nombre de un
evento del sistema con un verbo.

Ejemplo 3.7

Realizar el DSS para el caso de uso de RespuestaFrecuencia.

76 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

A los DSS se les puede añadir una leyenda adicional sobre los eventos del
sistema.

Ejemplo 3.8

Realizar el DSS del caso de uso de ClasificarEspermatozoides.

Dpto. Electrónica, Automática e Informática Industrial 77


Carlos Platero Apuntes de Informática Industrial

3.3 Los contratos de operación

Los contratos de operación describen los resultados de las ejecuciones de las


operaciones del sistema en función de los cambios de estado de los objetos del dominio.
Los contratos son complementarios a los casos de uso.

Se pueden definir contratos para las operaciones del sistema. Éstas se descubren
identificando los eventos del sistema.

Las secciones del contrato son:

Operación: Nombre de la operación y parámetros.

Referencias cruzadas: (opcional) Casos de usos en los que pueden tener lugar
esta operación.

Precondiciones: Suposiciones relevantes sobre el estado del sistema o de los


objetos del modelo del dominio, antes de la ejecución de la operación. Se supondrá que
todo es verdad.

Poscondiciones: El estado de los objetos del modelo del dominio después de


que se complete la operación.

Las poscondiciones no son acciones que se ejecutarán durante la operación; más


bien son cómo los objetos del dominio han evolucionado cuando la operación ha
terminado. Las postcondiciones se dividen en tres categorías:

 Creación y eliminación de objetos.

 Modificación de atributos.

 Formación y rotura de asociaciones.

La eliminación de instancias es más rara, nadie se preocupa de forzarla


explícitamente. Ésta es una perspectiva conceptual, no de implementación.

Los contratos de operación se expresan dentro del Modelo del Dominio y


describen los cambios de estado que requiere una operación del sistema, sin tener que
describir cómo se van a llevar a cabo.

Es normal, durante la creación de los contratos, descubrir nuevas clases


conceptuales. Hágase una realimentación.

78 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

Los casos de uso son los principales artefactos de los requisitos del proyecto.
Los contratos de operación se emplearán donde la complejidad sea alta y añade valor la
precisión detallada.

Para hacer contratos:

1. Identifique las operaciones del sistema a partir de los Diagramas de


Secuencias del Sistema, DSS.

2. Construir un contrato para las operaciones complejas del sistema y quizás


sutiles en sus resultados.

3. Para describir las postcondiciones utilice las siguientes categorías:

a) Creación y eliminación de instancias

b) Modificación de atributos

c) Formación y rotura de asociaciones.

Las sentencias de las postcondiciones se emplearán en forma verbal pasiva y en


pasado, ya que son resultados del pasado.

Los Contratos de Operación no se justifican en la fase de Inicio, son demasiado


detallados, se hacen en la Elaboración y sólo para las operaciones más complejas y
sutiles.

Ejemplo 3.6

Realizar los contratos de operación de RespuestaFrecuencia.


Contrato CO1: introducirCircuito()
Operación: introducirCircuito ();
Referencias Cruzadas: Caso de uso: Respuesta en frecuencia (inclusión de
Capturar circuito lineal)
Precondiciones: Se le pasa el esquema del circuito lineal
Poscondiciones: Se creó una instancia de Filtro lineal pFiltro.
pFiltro se construyo con la FDT correspondiente .

Contrato CO2: introducirParamResFr


Operación: introducirParamResFr ();
Referencias Cruzadas: Caso de uso: Respuesta en frecuencia
Precondiciones: Existe pFiltro.
Postcondiciones: Se creo una instancia de Respuesta en Frecuencia.
Se cálculo el módulo y argumento para el rango de
frecuencias dadas.

Dpto. Electrónica, Automática e Informática Industrial 79


Carlos Platero Apuntes de Informática Industrial

3.4 Problemas

1. Objetivos, disciplinas y artefactos al servicio de la fase de elaboración en


UP.

2. Diferencia entre el análisis estructurado y el análisis orientado a objetos.

3. Diferencia entre clases conceptuales, clases de diseño y clases de


implementación.

4. Guía para la localización de las clases conceptuales.

5. Asociaciones más importantes a retener en el modelo del dominio.

6. Cómo diferenciar que un concepto es una clase conceptual o un atributo.

7. Que es un DSS.

8. Cuando emplear un contrato de operación y sus partes.

Problema 3.1

Para el simulador de dinámica temporal de un sistema LTI (ver problema


1 del capítulo 2), se solicita:

1. Modelo del dominio

2. Diagrama de Secuencias del Sistema (DSS)

3. Contrato de Operaciones para los eventos más importantes.

Problema 3.2

Determinar para el juego de las tres en raya:

1. Modelo del dominio

2. Diagrama de Secuencias del Sistema (DSS)

3. Contrato de Operaciones para los eventos más importantes.

80 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

Problema 3.3

Emplear los artefactos necesarios para el AOO del juego del frontón (ver
problema 2.4)

Empleando la información de la lista jerárquica a dos niveles, el glosario, la lista


de evento-actor-objetivo y el caso de uso, se rellena la tabla de clases de conceptos:
Categoría de clases conceptuales Propuesta
Objetos tangibles o físicos Raqueta, pelota, frontón, pared, línea roja
Especificaciones o descripciones de cosas
Lugares Frontón
Transacciones
Líneas de la transacción
Roles de la gente Jugador
Contenedores de otras cosas Frontón
Cosas en un contenedor Pared, línea roja
Otros sistemas informáticos o electromecánicos
externos al sistema
Conceptos abstractos
Organizaciones
Hechos
Procesos (normalmente no se representan como
conceptos, pero podría ocurrir)
Reglas y políticas
Catálogos
Registros de finanzas,
Instrumentos Raqueta
Manuales, documentos, artículos, libros

Seguidamente se buscarán asociaciones entre las clases conceptuales:


Categoría Ejemplos
A es una parte física de B Pared-frontón, línea roja-frontón
A es una parte lógica de B
A está contenida físicamente en B Pared-frontón, línea roja-frontón
A está contenido lógicamente en B
A es una descripción de B
A es una línea de una transacción o informe de B
A se conoce/registra/recoge/informa/captura en B Raqueta-pelota, pelota-pared, pelota-línea roja
A es miembro de B
A es una subunidad organizativa de B
A utiliza o gestiona B Jugador-raqueta
A se comunica con B
A está relacionado con una transacción de B
A es una transacción relacionada con otra
transacción B
A está al lado de B
A es prioridad de B
A es un evento relacionado con B

A continuación se refleja las asociaciones más importantes en el Modelo del


Dominio:

Dpto. Electrónica, Automática e Informática Industrial 81


Carlos Platero Apuntes de Informática Industrial

Otro artefacto a realizar es el Diagrama de Secuencias del Sistema.

Problema 3.4

Para el juego del ‘Pang’ (ver problema 2.5), se solicita:

1. Modelo del dominio

82 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 3: Análisis Orientado a objetos

2. Diagrama de Secuencias del Sistema (DSS)

3. Contrato de Operaciones para los eventos más importantes.

Derecho de Autor © 2014 Carlos Platero Dueñas.


Permiso para copiar, distribuir y/o modificar este documento bajo los términos
de la Licencia de Documentación Libre GNU, Versión 1.1 o cualquier otra
versión posterior publicada por la Free Software Foundation; sin secciones
invariantes, sin texto de la Cubierta Frontal, así como el texto de la Cubierta
Posterior. Una copia de la licencia es incluida en la sección titulada "Licencia de
Documentación Libre GNU".

La Licencia de documentación libre GNU (GNU Free Documentation License)


es una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
apuntes están cubiertos por esta licencia. La version 1.1 se encuentra en
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html

Dpto. Electrónica, Automática e Informática Industrial 83


4 UML estructural
Tanto para AOO como para DOO se utilizan los conceptos y las notaciones,
esencialmente gráficas, de UML (Unified Modeling Language). En una primera
clasificación de la notación UML se puede dividir en varias vistas. Una vista es un
subconjunto de construcciones de UML que representan un aspecto del sistema:

 UML estructural logico: describe la estructura lógica de los elementos


del sistema y sus relaciones. Sus conceptos principales son las clases, los
paquetes y los casos de uso. Esta vista incluye los diagramas de clases y
los diagramas de casos de uso.

 UML Dinámico: describe las interacciones entre los objetos con el


tiempo. Las vistas de comportamiento dinámico incluyen los diagramas
de interacción, las máquinas de estado y los diagramas de actividades

 Implementación: describe la estructura física del SW en cuanto a los


componentes de que consta y su ubicación. Está formada por los
diagramas de componentes y de despliegue.

Este capítulo se centrará en el UML estructural lógico. Se llama así ya que


muestra todas las relaciones posibles a lo largo del tiempo y no las que son válidas en
un cierto momento. UML estructural lógico está constituido por:

• Diagramas de clases

Dpto. Electrónica, Automática e Informática Industrial 83


Capítulo 4: UML estructural Apuntes de Informática Industrial

• Diagrama de casos de uso

4.1 OMG y UML

OMG (Object Managment Group), creada en 1989, es una organización no


lucrativa en la que participan más de 800 empresas de SW, HW, consultorías,... Su
objetivo es la elaboración de estándares para la Programación Orientada a Objetos. Sólo
se dedican a realizar documentos, no su implementación. Por ejemplo, CORBA (objetos
distribuidos en la Red) es un estándar (documentos) de la OMG. Posteriormente, existen
empresas que realizan su implementación. En el caso de CORBA, paquetes como
MICO son componentes que dan soporte a los servicios establecidos en la
documentación.

UML ha sido propuesto por OMG a ISO para que sea un estándar. UML es una
cierta unificación de métodos anteriores como:

 OMT de Rumbaugh

 OOSE de Jacobson

 El método de Booch.

En 1997 aparece UML V1.0 presentado por la OMG.

4.2 Clases en UML

Las clases se representan por un rectángulo dividido en tres compartimentos:


nombre de la clase, atributos y servicios. En el apartado del nombre, en la parte
superior, se puede indicar un estereotipo, tales como <<análisis>>, <<diseño>>, ... El
nombre de la clase será un sustantivo y empezará por <<analisis>>
mayúscula. Debajo del nombre se puede encontrar comentarios ImagenEspermatozoides

optativos entre llaves, { }.

Cada atribuyo tiene un nombre o identificador y un tipo. Un atributo se define de


la siguiente forma:

Visibilidad nombre_atributo ‘:’ tipo_atributo ‘=’ valor inicial ´{`otras propiedades ‘}’

84 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

La visibilidad hace referencia a si el atributo es público, protegido o privado.


UML emplea los símbolos +, # y – para indicar si es
público, protegido o privado respectivamente1. El nombre
del atributo es un sustantivo y empieza en minúsculas.
Seguidamente aparecerá el tipo de atributo (float, char, int,
...). Opcionalmente puede aparecer el valor inicial del
atributo y otras propiedades colocadas entre los signos de
paréntesis.

Las especificaciones de las operaciones en UML tienen la siguiente sintaxis:

Visibilidad nombre_servicio ‘(‘lista de parámetros’)’:’tipo de retorno’ {`otras propiedades´}`

El nombre del servicio empleará un verbo con un


sustantivo. La primera letra se escribirá en minúscula. Entre
paréntesis aparecerán los parámetros del servicio, siguiendo
para cada uno de ellos, la regla sobre los atributos. Después
se especificará el tipo de retorno y opcionalmente otras
propiedades entre llaves. El usuario puede crear otros
compartimentos para dar información adicional como
excepciones, requisitos, etc.

Ejemplo 4.1
#ifndef _INC_ESFERA_
#define _INC_ESFERA_
Realizar la implementación en
C++ de la siguiente descripción UML class Esfera
{
referente a la clase Esfera. private:
float radio_esfera;

public:
Esfera()
{this->radio_esfera = 2.0f;}
float getRadio()
{return (this->radio_esfera);}
void setRadio(float radio)
{this->radio_esfera=radio;}
};

#endif

4.2.1 Variantes en el concepto de clases

UML soporta diferentes tipos de clases que pueden ser implementadas o no por
el lenguaje de programación.

1
Rational Rose emplea los siguientes iconos para señalar la visibilidad del atributo o del
servicio: . El candado significa privado, la llave es protegido y la goma que es público.

Dpto. Electrónica, Automática e Informática Industrial 85


Capítulo 4: UML estructural Apuntes de Informática Industrial

4.2.1.1 Clases parametrizadas o contenedores

Las clases parametrizadas son unas clases que son empleadas para crear una
familia de otra clase. Estas clases son un tipo de contenedor, son conocidas también
como templete. No todos los lenguajes soportan los templetes. Por ejemplo, en ANSI
C++ existe el paquete STL (Standar Templete Library), mientras que JAVA no soporta
este tipo de clases. La biblioteca contenedora STL permite a los programadores
desarrollar aplicaciones con contenedores estándar, tales como pilas, listas, colas de
espera, así como manipular el contenido de dichos contenedores de diversas maneras.
De esta forma, los desarrolladores hacen uso de servicios de alta calidad sobre
componentes muy utilizados en casi todas las aplicaciones. Por ejemplo, la necesidad de
mantener una lista dinámica de objetos es algo muy habitual. Al emplear los templetes,
los desarrolladores no deben de implementar dichos servicios, sólo deben de saber
utilizarlos. Por tanto, una clase parametrizada permite reutilizar el código.

Las clases parametrizadas son sólo plantillas de contenedores (vector, lista,


árboles, ...). A las clases que definen un contenedor de un tipo específico, se las llama
clases instanciadas, esto es, las clases instanciadas son instancias de clases
parametrizadas. UML utiliza los signos de desigualdad, <>, para definir el tipo
específico acompañado con el nombre del contenedor.

Ejemplo 4.2

Se desea realizar una aplicación para un pocket sobre los pasajeros de


un vuelo. Plantéese bajo los frameworks de ANSI C++.

En jerarquía a dos niveles se plantea las siguientes características:

1. Mantener una lista de pasajeros asociados a un vuelo

a. El sistema debe de tener de cada pasajero, el nombre, el número


de pasaporte y el asiento.

b. El sistema debe dar el número total de pasajeros, de asientos


ocupados y asientos libres.

c. El sistema debe de listar los datos de todos los pasajeros.

d. El sistema debe de añadir datos sobre los pasajeros.

Los términos para el glosario serían: Pasajero, Vuelo, Asiento, Pasaporte,


Nombre,.... La lista de evento-actor-objetivo estaría constituida por:
Evento Actor Objetivo
Introducir datos pasajero Azafat@ Formar la base de datos del pasaje
Visualizar datos pasajero Azafat@ Verificar los datos de un pasajero
Ocupación del vuelo Azafat@ Obtener datos de ocupación del vuelo

86 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

El caso de uso sería la “ListaPasajeroVuelo”. Se podría considerar que los datos


pudieran venir de una base de datos y ser cargadas a través de algún tipo de conexión al
pocket.

La primera tarea del AOO sería la construcción del modelo del dominio, éste
podría ser:

Se deja al lector que haga el DSS y algún contrato de operación.

En un primer diseño se puede emplear ANSI C++. Se emplearán las std::string


para los atributos de tiras de caracteres y las STL std::vector para el contenedor
requerido. Para una mejor compresión de las clases parametrizadas sólo se muestra la
solución lógica de una parte de la lista de Pasajeros. Un primer esbozo queda reflejado
en el siguiente diagrama de clase de diseño, DCD:

Dpto. Electrónica, Automática e Informática Industrial 87


Capítulo 4: UML estructural Apuntes de Informática Industrial

Cuya implementación en C++ será:

#ifndef _INC_LISTA_PASAJEROS
#ifndef _PASAJERO_INC_
#define _INC_LISTA_PASAJEROS
#define _PASAJERO_INC_
#include <vector>
#include "Pasajero.h";
#include <string>

class Pasajero
class ListaPasajeros
{
{
public:
public:
void setNombre(const char *nom)
void setDatosPasajero (const Pasajero p1)
{nombre = nom;}
{laListaPasajeros.push_back(p1);}
std::string & getNombre( void )
int darNumeroPasajeros ( void ) const
{return nombre;}
{ return laListaPasajeros.size(); }
void setPasaporte(unsigned long
void iniciarLista ( void )
pasaporte)
{ iteradorPasaje = laListaPasajeros.begin();}
{ numPasaporte =DNI;}
Pasajero getDatoPasajero( unsigned numPasajero )
unsigned long getDNI( void ) const
{ return (*(iteradorPasaje + numPasajero)); }
{return (numPasaporte);}
private:
private:
std::vector<Pasajero> laListaPasajeros;
std::string nombre;
std::vector<Pasajero>::iterator iteradorPasaje;
unsigned long numPasaporte;
};
};
#endif
#endif

Nótese los tres tipos de clase mostrados: conceptuales, de diseño y de


implementación. En la página web de la asignatura encontrará las fuentes de este
ejemplo.

4.2.1.2 Interfaces

Una interfaz especifica ciertas operaciones de algunos elementos del paquete


que son visibles fuera del mismo. No necesita especificar todas las operaciones que
soporta el paquete, por lo que el paquete podría incluir varias interfaces diferentes.

Una interfaz se define en un diagrama de clases utilizando un rectángulo, como


el de icono de clase, pero con el estereotipo de <<interface>> en la división del nombre
de la clase. No tiene atributos, por tanto, el icono sólo tiene dos divisiones. En Rational
Rose también se representa por un círculo.

El sentido de las interfaces está relacionada con el concepto de cliente –


servidor. Si un paquete está especializado en algunas tareas o servicios, se le dota de un
interfaz para que los clientes pidan ese trabajo. Las modificaciones internas dentro del
paquete no serán transmitidas a los clientes de estos servicios. Estos aspectos se verán
con mayor detenimiento en el capítulo de diseño con patrones.

En C++ se emplea las clases abstractas para implementar los interfaces. En Java
y en C# existe la palabra clave “interface”.

Ejemplo 4.3

Definir un interfaz para la visualización de los diagramas de Bode en la


aplicación de respuesta en frecuencia de los filtros lineales.

88 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Un buen diseño debería de independizar la aplicación de la visualización del


diagrama de Bode. En el mercado existen distintos componentes para realizar un
ploteado de una gráfica X-Y. Se ha localizado un componente gratuito llamado
NTGRAPH2. Sin embargo, en el futuro se podría optar por otro tipo de componente.
Para evitar las fluctuaciones e inestabilidades de este servicio, se define un interfaz
estable a este servicio. El diagrama de paquetes quedaría:

El DCD resultante de aplicar diversos patrones GoF muestra la solución lógica


del problema:

2
www.codeproject.com

Dpto. Electrónica, Automática e Informática Industrial 89


Capítulo 4: UML estructural Apuntes de Informática Industrial

Ejemplo 4.4

Realizar un paquete que sea capaz de ocultar el uso de framework para


el manejo de tiras de caracteres. Empléese las MFC y ANSI C++.

90 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

#ifndef _INOMBRE_INC_ #ifndef _INC_CNOMBRE_


#define _INOMBRE_INC_ #define _INC_CNOMBRE_

enum Plataforma{ESTANDAR_STL, ESTILO_C, #include <string>


CADENA_MFC}; #include "INombre.h"

class INombre { class CNombre : public INombre


public: {
virtual void setNombre (const char *) = 0; public:
virtual const char * getNombre () = 0; virtual void setNombre(const char *cadena)
//Factoria de objetos { strcpy (elNombre, cadena); }
static INombre *factoriaObjetos virtual const char * getNombre (void)
(enum Plataforma); { return (elNombre);}
}; private:
#endif char elNombre[80];
};
#endif
#ifndef _INC_MFCNOMBRE_
#define _INC_MFCNOMBRE_ #};ifndef _INC_STDNOMBRE_
#define _INC_STDNOMBRE_
#include <afx.h> #endif
#include "INombre.h" #include <string>
#include "INombre.h"
class MFCNombre : public INombre
{ class STDNombre : public INombre
public: {
virtual void setNombre(const char *cadena) public:
{ elNombre=cadena; } virtual void setNombre(const char *cadena)
virtual const char * getNombre (void) { elNombre = cadena; }
{ return (elNombre);} virtual const char * getNombre (void)
private: { return (elNombre.c_str());}
CString elNombre; private:
}; std::string elNombre;
#endif };
#endif
};

#endif
#include <iostream>
#include "../includes/STDNombre.h"
#include "../includes/CNombre.h"
#include "../includes/MFCNombre.h"

//Método único para producir los objetos nombres


INombre* INombre::factoriaObjetos(enum Plataforma tipo)
{
if(tipo == ESTANDAR_STL) return new STDNombre;
else if(tipo == ESTILO_C) return new CNombre;
else if(tipo == CADENA_MFC) return new MFCNombre;
else return NULL;

}
using namespace std;
int main ( void )
{
INombre *pNombre1 = INombre::factoriaObjetos(ESTANDAR_STL);
INombre *pNombre2 = INombre::factoriaObjetos(ESTILO_C);
INombre *pNombre3 = INombre::factoriaObjetos(CADENA_MFC);

pNombre1->setNombre("Manolo Gonzalez");
pNombre2->setNombre("Pedro Lopez");
pNombre3->setNombre("Ana Rodriguez");

cout << pNombre1->getNombre() << endl;


cout << pNombre2->getNombre() << endl;
cout << pNombre3->getNombre() << endl;

delete pNombre1, pNombre2, pNombre3;


return 0;
}

Se recuerda que las clases abstractas en C++ carecen de instancias.

Dpto. Electrónica, Automática e Informática Industrial 91


Capítulo 4: UML estructural Apuntes de Informática Industrial

4.3 Representación de los objetos

Los objetos se representa parecido a una clase, indicando los valores


instanciados de los atributos. El nombre del objeto, el cual es opcional, va seguido de
“:” y el nombre de la clase, todo ello subrayado. En general, se suele omitir el tipo de
los atributos, así como el comportamiento de los servicios, porque ambos se conocen
gracias a la especificación de la clase.
Fernandez : Alumno

Los objetos suelen aparecer en los diagramas de


interacción. Estos artefactos describen la dinámica de la
aplicación. Se verán en el UML dinámico y se analizarán
con mayor detalle en el siguiente capítulo.

4.4 Tipos de relaciones

Hay varios tipos de relaciones en UML entre las clases, de las que se destacan:
asociación, generalización y varios tipos de dependencia.

4.4.1 Asociaciones

Las asociaciones son conexiones semánticas entre clases. Cuando una asociación
conecta a dos clases, cada clase puede mandar un mensaje a la otra. Una asociación
permite a una clase conocer los atributos y las operaciones públicas de la otra clase. La
asociación se representa por una línea continua. Esta opción indica que las clases unidas
por la asociación tienen dependencia cíclica. Esta presentación es válida en el AOO y en
su artefacto de Modelo del Dominio. Sin embargo, en el diseño se verá que esta forma
de actuar es impropia con una buena organización de las responsabilidades entre las
clases. Por este motivo, en las asociaciones de diseño suelen aparecer reflejadas unas
flechas que indican el sentido de la navegabilidad. Este concepto indica que la
asociación entre las clases es de carácter unidireccional. La fecha refleja que la clase a
la que apunta puede ser empleada por la clase que emana la asociación, pero no en
sentido contrario.

Si se pone un ejemplo de asociación entre la clase A y B de forma que sea


bidireccional o unidireccional, véase el resultado de su implementación en C++:

92 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

A +elA +elB B A +elB B

class B;
class B;
class A
{ class A
public: {
B elB; public:
B elB;
};
};

class B
class A; {
};
class B
{
public:
A elA;

};

Cada conexión de una asociación a una clase puede tener nombre (el rol que
desempeña en la asociación), visibilidad (si se pueden ver los atributos y servicios) y la
propiedad más importante que es la multiplicidad: cuantas instancias de una clase se
puede relacionar con una instancia de otra clase. Si la asociación, además del nombre,
tiene atributos se dice que es una clase de asociación, la cual será tratada más adelante.

La clase A está asociada con la clase B cuando:

 Un objeto de la clase A usa un servicio de un objeto de la clase B.

 Un objeto de la clase A crea un objeto de la clase B.

 Un objeto de la clase A tiene un atributo cuyos valores son objetos de


la clase B o colecciones de objetos de la clase B.

 Un objeto de la clase A recibe un mensaje con un objeto de la clase B


pasado como argumento.

En resumen, si un objeto de la clase A tiene que saber algo de un objeto de la


clase B aparece la asociación, i.e. se establece la relación “necesito-conocer”.

Dpto. Electrónica, Automática e Informática Industrial 93


Capítulo 4: UML estructural Apuntes de Informática Industrial

4.4.1.1 Agregación y composición

Una agregación es una forma de asociación. Es un tipo de asociación del todo


con las partes. Se represente con una línea continua, con un diamante en la clase que
representa el todo y una flecha en la parte.

Ruedas Coche

4
Puertas
3..5

Motor

Un caso particular de la agregación es la composición o agregación por valor. En


una composición, la vida del todo es la vida de las partes, i.e. que cuando se destruye el
objeto compuesto también se destruyen las partes. Esta particularidad no se cumple en
la agregación. Además, un objeto “parte” sólo puede ser de un objeto compuesto y no
puede pasar de un objeto compuesto a otro.

En una composición las partes son atributos del todo. Se representa en UML
mediante el diamante relleno.

JuegoDados Dado

Considere la agregación cuando:

• Existe un ensamblaje obvio del todo con las parte.

• Alguna propiedad del compuesto se propaga a las partes.

• Las operaciones que se aplican sobre el compuesto se propagan a las


partes, como la destrucción, movimiento o grabación.

• El tiempo de vida de la parte está unido al tiempo de vida del compuesto


(existe una dependencia de creación-eliminación de la parte con el todo).

Las prestaciones de la agregación se dan en el paso del análisis al diseño, por lo


que no es muy significativa su inclusión en el Modelo del Dominio. Los beneficios son:

• Ayuda en la identificación de un creador utilizando el patrón GRASP


creador.

94 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

• Las operaciones –como la copia y la eliminación– que se aplican al todo a


menudo se propagan a las partes.

• Como recomendación, en caso de duda hay que descartarla. Los noveles del
AOO/D utilizan la agregación y la composición demasiado a menudo.
Recuerde que ambos tipos son una asociación. En caso de duda utilice una
simple asociación.

4.4.2 Generalización

La generalización y la especialización son conceptos fundamentales en el


modelado del dominio que favorece una economía en las palabras; más aún, las
jerarquías de clases conceptuales a menudo constituyen la fuente de inspiración para las
jerarquías de clases SW que se aprovechan de la herencia y reducen la duplicación del
código.

En el ejemplo:

La clase Pago representa la generalización y es la superclase, mientras las otras


son de especialización y son subclases. En UML, la generalización se representa por
una línea continua con una flecha hueca que apunta a la superclase.

Es una forma de construir clasificaciones taxonómicas entre los conceptos que


son representados en una jerarquía de clases. Para la realización de estas
generalizaciones deben de cumplir dos reglas:

A) Regla del 100%: La definición de la superclase se debe poder aplicar a la


subclase. La subclase debe ajustarse al 100% de los atributos y asociaciones de la
superclase.

B) Regla Es-Un: En el lenguaje natural debe comprobarse que la subclase Es Un


tipo de la superclase (p.ej: PagoACrédito es un tipo de Pago).

Una subclase potencial debería de estar de acuerdo con la regla del 100% y de la
regla Es-un. Se creará una subclase de una superclase cuando:

Dpto. Electrónica, Automática e Informática Industrial 95


Capítulo 4: UML estructural Apuntes de Informática Industrial

 La subclase tiene atributos adicionales.

 La subclase tiene asociaciones adicionales.

 La subclase funciona de manera diferente e interesante a la superclase o a


otras subclases.

Se creará una superclase conceptual en una relación de generalización de


subclases cuando:

1. Cuando las subclases potenciales representen variaciones de un concepto


similar.

2. Las subclases se ajustarán a las reglas del 100% y Es-un.

3. Todas las subclases tienen el mismo atributo que se puede factorizar y


expresarlo en la superclase.

4. Todas las subclases tienen la misma asociación que se puede factorizar y


relacionar con la superclase.

4.4.2.1 Clases abstractas

Son aquellas que carecen de instancia y que son instanciadas desde una clase
derivada (subclase). Recuérdese el ejemplo utilizado en las interfases.

En UML las clases abstractas se ponen su nombre en cursiva o se le añade el


estereotipo de <<interface>> si éstas son empleadas para tal fin.

96 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

4.4.2.2 Herencia

Es una manera de implementar la generalización. La herencia no es la gran


solución. Tiene el problema de la dependencia de la subclase con la superclase. De
manera que si se modifica la superclase puede afectar a la subclase. Por este motivo sólo
se empleará la herencia de clases cuando proceda de una relación de generalización
conceptual. La composición es más robusta que la herencia.

Ejemplo 4.5

Realizar una agenda telefónica

Las características de la aplicación, en jerarquía a dos niveles, son:

1. La agenda telefónica debe contener y gestionar la lista de teléfonos de los


contactos:

1.a. Debe permitir añadir, eliminar, listar un contacto

El glosario estaría formado por: listín telefónico, contacto, nombre, teléfono,


agenda telefónica,… El caso de uso sería ObtenerInfoAgenda. La arquitectura básica
estaría formada por un paquete del dominio y otro de visualización.

El modelo del dominio tiene las siguientes clases conceptuales:

Dpto. Electrónica, Automática e Informática Industrial 97


Capítulo 4: UML estructural Apuntes de Informática Industrial

La solución lógica podría ser de forma jerárquica o de composición. Sol. 1:


Hacer Agenda sucbclase y que sea la ListaUsuarios de superclase. Esta solución no es
buena, ya que la jerarquía es no conceptual. Sol. 2: Agenda tiene una composición con
la clase instanciada de ListaUsuarios. Es mejor está solución; cualquier variación en la
ListaUsuarios queda acotada por la asociación de agregación por valor. En el caso de
que hubiese sido una subclase, las posibles variaciones en el futuro ListaUsuarios
afectarían en la clase Agenda.

Ejemplo 4.6

Realizar un programa para la gestión de las fichas de libros y revista en


una biblioteca.

La lista de características del sistema a dos niveles sería:

1. Gestionar las fichas de una biblioteca

1.a. Insertar, eliminar y listar las fichas.

1.b. Las fichas pueden ser de libros o de revistas. Los libros pueden estar
constituidos por uno o más volúmenes. Los libros pueden ser en lengua extranjera.

1.c. Las fichas de libros contendrán los campos de referencia, estante,


posición, título, autor, editorial y volumen; mientras para las revistas deberán estar
formados por el año y el número de la revista, junto con la referencia, estante. posición
y el título.

El glosario estaría constituido por las definiciones de: Ficha, Biblioteca, Libros,
Revista, Referencia, Título,...

El modelo del dominio podría ser del tipo:

98 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Este ejemplo se ha utilizado como prácticas de la asignatura. Sobre el código entregado


se ha realizado ingeniería inversa con el siguiente diagrama de clases:

En Java no existe la multiherencia.

4.4.3 Dependencia

Una dependencia es un tipo de relación entre dos o más elementos del modelo.
La dependencia relaciona los elementos del modelo sin la necesidad de tener un
conjunto de instancias para su significado. Indica una situación tal que un cambio en el
elemento servidor puede requerir un cambio en el elemento cliente.

Dpto. Electrónica, Automática e Informática Industrial 99


Capítulo 4: UML estructural Apuntes de Informática Industrial

Una relación de dependencia muestra que una clase hace referencia a otra clase.
Cuando hay dependencia entre dos clases, no se añaden atributos a la otra clase. Este
aspecto lo diferencia respecto a la asociación. Cuando no hay una relación de asociación
o de generalización se utiliza normalmente la dependencia para el resto de relaciones.

Las dependencias se suelen emplear con los paquetes.

En UML se representan mediante una línea a trazos acabada en flecha abierta.

4.4.4 Realización

La realización es un tipo de dependencia. La relación de realización conecta un


elemento del modelo, tal como una clase, con otro elemento, como un interfaz,
especificando su comportamiento pero no su estructura o implementación. Presenta un
tipo de relación típica entre cliente con el servidor. El cliente debe tener por herencia o
por declaración directa alguna de las operaciones públicas que tenga el proveedor.

La realización se indica con una flecha de línea discontinua con una punta de
flecha hueca cerrada. Es similar al símbolo de generalización pero con una línea
discontinua, para indicar que es similar a un tipo de herencia con relación de
dependencia.

4.4.5 Otras asociaciones

De vez en cuando es útil dar más detalles de los que se tiene sobre una
asociación. En estos casos se puede emplear un calificador. Un calificador es un valor
que selecciona un objeto único del conjunto de objetos relacionados a través de la
asociación. Los calificadores son importantes para modelar nombres y códigos de
identificación.

Véase el modelado del tablero del juego de tres en rayas.

constituido por
Tablero Cuadrado

1 9

100 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

constituido por
Tablero fila : float[3] Cuadrado
columna : float[3]
1 1

Se puede combinar la notación de asociación con calificador con otros adornos


de las asociaciones.

4.4.5.1 Asociaciones derivadas

Una asociación derivada es una asociación redundante que se puede obtener


como combinación de otras relaciones del modelo.

1 estudia las
Alumno Asignatura

1..n
3
1..n 1
/enseña
Impartida por

1
Profesor
1..n

Un elemento derivado puede ser determinado a partir de otros. Los atributos y


las asociaciones son los elementos comunes para ser derivados.

En UML un elemento derivado se representa anteponiendo una “/” al nombre del


elemento.

4.4.5.2 Clases asociativas

En principio, una asociación no es una clase; no necesita tener atributos ni


operaciones. No obstante, si una asociación debe tener atributos y operaciones propias o
bien uno de los dos, entonces es preciso que se defina como clase. En este caso se habla
de clase asociativa.

Una clase asociativa se representa como una clase colgada del símbolo de la
asociación por medio de una línea discontinua.

Dpto. Electrónica, Automática e Informática Industrial 101


Capítulo 4: UML estructural Apuntes de Informática Industrial

Los indicios de que se podría incluir clases de asociaciones en el diagrama de


clases son:

 Un atributo está relacionado con una asociación.

 El tiempo de vida de las instancias de la clase asociación depende de la


asociación.

 Existe una asociación de muchos a muchos entre dos conceptos e


información asociada con la propia asociación.

4.5 Comentarios

Un comentario es una anotación unida a


un elemento, carece de significado directo, pero
muestra una información significativa para el que
ha realizado el modelado. En UML, el comentario
se pone dentro de un rectángulo con un vértice
doblado, enlazado con una línea discontinua al
cual se refiere.

4.6 Paquetes

Un paquete (package) es sólo una caja o contenedor que contiene elementos


como clases, objetos, diagramas u otros paquetes. Si en el paralelismo con los sistemas
biológicos, las clases son la analogía a los tipos de célula; los paquetes son a los órganos
biológicos. Los paquetes agrupan las clases altamente cohesivas en la organización con
un objetivo particular.

En un paquete puede aparecer tanto elementos del modelo como diagramas. El


propósito general es la organización en grupos. Un paquete es usado para agrupar cosas
que tengan algo en común. Los paquetes se pueden anidar dentro de otros paquetes.
Gráficamente, un paquete es representado por UML como una carpeta.

Hay algunos elementos de un paquete que deben tener visibilidad para que
puedan ser reconocidos desde otros paquetes. Los paquetes se configuran como un
espacio de nombres de propósito general. Cada elemento del paquete es visible y
reconocido dentro del paquete donde se ha declarado y su nombre no puede estar
repetido dentro del paquete.

El nombre del elemento tiene que estar codificado junto con el identificador del
paquete; siendo la regla el nombre del paquete más dos puntos (:) y el nombre del
elemento.

Paquete : Elemento

102 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Véase cómo este concepto se aplica en C++ con el espacio de nombres,


utilizando el operador ámbito (::) :

#include <iostream> #include <iostream>

int main() //Definición del espacio de nombres


{ using namespace std;
//Uso del paquete estándar
//y sintaxis de C++ entre int main()
//el paquete y el elemento {
std::cout<< "Hola Mundo\n"; cout<< "Hola Mundo\n";

} }

4.6.1.1 Cómo dividir el modelo del sistema en paquetes

Ponga los elementos juntos dentro de un paquete sí:

• Se encuentran en la misma área de interés –estrechamente


relacionados por conceptos u objetivos-.

• Están juntos en una jerarquía de clases

• Participan en los mismos casos de uso.

• Están fuertemente asociados.

Resulta útil que todos los elementos relacionados con el modelo del dominio
tenga como raíz un paquete denominado Dominio. Todos los conceptos básicos o
comunes se definan en un paquete que se pueda llamar Elementos Básicos o Conceptos
Comunes.

Una forma de incrementar la estabilidad de los paquetes es reducir la


dependencia de clases concretas de otros paquetes. El diseño empujará a realizar
paquetes lo más autónomos posibles. Los paquetes estarán formados por clases
funcionalmente cohesivas (estos aspectos serán tratados con mayor detalle en el capítulo
del diseño orientado a objetos).

Hay que evitar la aparición de dependencias circulares, i.e. un paquete depende


de otro y a su vez, éste depende del anterior. En el caso de necesidad de dependencia
cíclica, se romperá el ciclo mediante la intersección de una interfaz estable.

Si los paquetes más responsables (de los que más se depende) son inestables,
existe un mayor riesgo de extender el impacto de los cambios a quienes depende de
estos paquetes. Hay que poner mucha atención al paquete que más se emplea. Sus
constantes revisiones pueden afectar al resto. Hay que saber aislar para producir un
diseño robusto.

Dpto. Electrónica, Automática e Informática Industrial 103


Capítulo 4: UML estructural Apuntes de Informática Industrial

En C++ se es más sensible a las dependencias que en Java. Un cambio en una


clase C++ tiene un fuerte impacto en las clases que dependan de ésta.

El acoplamiento interno del paquete o cohesión relacional puede identificarse


mediante:

Número de relaciones int ernas


CR 
Número de tipos

Donde el número de relaciones internas incluye las relaciones de atributos y


parámetros, herencia e implementaciones de interfaces. Un CR muy bajo indica falta de
cohesión.

En resumen, las formas de incrementar la estabilidad en un paquete son:

• Contiene sólo o en su mayor parte interfaces y clases abstractas.

• No depende de otro paquete o de otros muy estables.

• Contiene código relativamente estable y se refinó antes de lanzar la


versión.

• Es obligatorio una planificación a largo plazo de los cambios futuros.

Los paquetes son normalmente la unidad básica del trabajo de desarrollo y de


versiones.

4.6.2 Vista de gestión del modelo

La gestión del modelo describe la organización de los propios modelos en


unidades jerárquicas. El paquete es la unidad genérica de organización para los
modelos. Esta vista cruza las otras vistas de UML y las organiza para el trabajo de
desarrollo y el control de configuraciones.

Los paquetes son unidades para manipular el contenido de un modelo. Cada


elemento del modelo pertenece a un paquete. El modelo es una descripción completa del
sistema desde un punto de vista, con una determinada precisión. Puede haber varios
modelos de un sistema desde distintos puntos de vista; por ejemplo, un modelo de
análisis y un modelo de diseño.

La información de gestión del modelo se representa en diagramas de clase,


donde aparecen los paquetes y sus dependencias.

104 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Ejemplo 4.10

Vista de gestión del modelo o diseño arquitectónico de la aplicación de


respuesta en frecuencia.

Se propone realizar una división en paquetes de la aplicación según muestra el


diagrama de paquetes siguiente:

4.7 Diagramas de casos de uso

Los diagramas de casos de uso sirven para mostrar las funciones de un sistema
SW desde el punto de vista de sus interacciones con el exterior y sin entrar ni en la
descripción detallada ni en la implementación de estas funciones. Reparte la
funcionalidad del sistema en mensajes significativos entre los actores y el sistema. Un
caso de uso es una descripción lógica de una parte de funcionalidad del sistema. El
propósito de un caso de uso es definir una pieza de comportamiento coherente, sin
revelar la estructura interna. Se utilizan tanto en la fase de requisitos como de análisis.

No obstante, las especificaciones de los requisitos se hacen escribiendo los


documentos, no dibujando los casos de uso que es un paso opcional. El diagrama es sólo
para ayudar a comprenderlos o reducir duplicaciones.

4.7.1 Relaciones entre casos de uso

Cuando se implementa un caso de uso, su funcionamiento se basa en la


colaboración entre clases. Una clase puede participar en múltiples colaboraciones y por
tanto, en múltiples casos de uso, dando paso a relaciones entre los casos de uso.

Aunque cada instancia de un caso de uso es independiente, la descripción de un


caso de uso se puede descomponer en otros casos de uso más simple, apareciendo la
relación de inclusión. Se utilizará el estereotipo include cuando una actividad se está
repitiendo en dos o más casos de uso separados y se quiere evitar las repeticiones,

Dpto. Electrónica, Automática e Informática Industrial 105


Capítulo 4: UML estructural Apuntes de Informática Industrial

haciendo una factorización. Por tanto, la inclusión de casos de usos es esencialmente


una forma de reutilización. Habrá que factorizar algunas subfunciones de forma
separada y por tanto utilizar la relación include cuando:

 Estén duplicados en otros casos de uso

 Un caso de uso es muy complejo y largo y separarlo en subfunciones facilita la


compresión.

Un caso de uso se puede también definir como una extensión incremental de un


caso de uso base. A esta relación se le llama de extensión y se utiliza el estereotipo de
extend. Se dice que el caso de uso A extiende al B si dentro de B se ejecuta A cuando se
cumple una condición determinada. Un caso de uso A extendido tiene que ser también
ejecutable de forma separada de B.

Un caso de uso también se puede especializar en uno o más casos de uso. Esta
relación es la de generalización/especialización de casos de uso. Un caso de uso A es
una especialización de un caso de uso de B, cuando el A es un proceso más específico
que el de B.

En UML, la relación entre los actores y los casos de uso se representarán como
una asociación, indicando la comunicación bidireccional entre usuarios y sistema. Las
relaciones de inclusión y extensión se dibujan como flechas de líneas discontinuas con
la palabra clave <<include>> y <<extend>>, respectivamente. La relación de
inclusión apunta al caso de uso a ser incluido; la relación de extensión señala al caso de
uso que se extenderá. Las generalizaciones de casos de uso serán dibujadas mediante la
flecha de relaciones de herencia, la punta señalará al caso de uso de generalización.

En la figura de abajo se muestra un ejemplo de diagrama de casos de uso sobre


la gestión de un catálogo de ventas. En este diagrama aparecen todas las posibles
relaciones anteriormente comentadas.

106 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Solicitar catálogo sabe


donde hacer pedido,
pero hacer pedido no
sabe de donde viene... <<extend>>

Solicitar catálogo
<<include>>
Hacer Pedido

Vendedor
<<include>>
<<include>>
Pago compras

Obtener datos cliente

Pedir producto

Pago al contado
Pago crédito

Se recuerda que lo importante son los documentos de los casos de uso. No hay
que perder mucho tiempo en el diagrama de casos de uso. Es típico de los
desarrolladores noveles dedicarse a dibujar casos de uso más o menos sofisticados,
buscando relaciones y nuevas inclusiones, cuando lo importante es la captura de los
requisitos funcionales (ver capítulo dedicado a la recogida de documentación y
requisitos).

4.8 Problemas

1. Notación de UML sobre las clases.

2. Uso de las clases parametrizadas/instanciadas. Hágase un ejemplo sobre


las pinturas de una galería de arte.

3. Defina un paquete sobre objetos geométricos, tales como cuadrado,


rectángulo, triángulo,... Defina una interfaz.

4. Defina una jerarquía de clases para los objetos geométricos de la anterior


pregunta. Presente las superclases y las subclases.

5. Cuando emplear una relación de asociación, agregación, composición,


generalización y dependencia.

6. Cómo dividir una aplicación en paquetes.

7. Qué es la vista de gestión del modelo.

Dpto. Electrónica, Automática e Informática Industrial 107


Capítulo 4: UML estructural Apuntes de Informática Industrial

8. Relaciones en los diagramas de caso de uso.

Problema 4.1

Implementar en C++ la siguiente


clase Dinero definida en UML según
figura

Problema 4.2

Realizar una descripción textual del


siguiente diagrama de clases.

Motor Piloto Vendedor de billetes

1..4 1..2 1

1 * *
Avión 1 * Vuelo 1 * Reserva

1
Avión militar Avión comercial Línea aérea

Avión de carga Avión de pasajeros

108 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Problema 4.3

Realizar una aplicación gráfica en cuyo mundo esté definida una CAJA que
contiene un número indeterminado de ESFERAS. Se debe simular el rebote
entre las propias ESFERAS y éstas con los SEGMENTOS de la CAJA.

1. Lista de características.

2. Modelo del dominio

3. Vista de gestión.

4. Diagrama de clases de diseño.

La lista de características del sistema a dos niveles sería:

1. Simulación de esferas que rebotan dentro de una caja

1.a. Las esferas rebotan contra las paredes y barreras de la caja y con ellas
mismas.

1.b. La caja es cerrada y no se pueden escapar las esferas.

1.c. La caja está formada por cuatro paredes y un número indeterminado


de barreras.

Modelo del dominio:

La vista de gestión:

Dpto. Electrónica, Automática e Informática Industrial 109


Capítulo 4: UML estructural Apuntes de Informática Industrial

Diagrama de clase de diseño:

110 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 4: UML estructural

Derecho de Autor © 2014 Carlos Platero Dueñas.


Permiso para copiar, distribuir y/o modificar este documento bajo los términos
de la Licencia de Documentación Libre GNU, Versión 1.1 o cualquier otra
versión posterior publicada por la Free Software Foundation; sin secciones
invariantes, sin texto de la Cubierta Frontal, así como el texto de la Cubierta
Posterior. Una copia de la licencia es incluida en la sección titulada "Licencia de
Documentación Libre GNU".

La Licencia de documentación libre GNU (GNU Free Documentation License)


es una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
apuntes están cubiertos por esta licencia. La version 1.1 se encuentra en
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html

Dpto. Electrónica, Automática e Informática Industrial 111


5 UML. El modelo dinámico y de
implementación
UML estructural estaba basado esencialmente en los diagramas de clases. En el
modelo dinámico hay más variedad de diagramas, aunque no todos deben ser empleados
en el proyecto.

Los aspectos dinámicos o de evolución temporal de la aplicación se pueden


modelar con los siguientes diagramas:

• Diagramas de interacción (de secuencia y de colaboración)

• Diagramas de estado

• Diagramas de actividad

Mientras la implementación del proyecto emplea los gráficos de:

• Diagrama de componentes

• Diagrama de despliegue

Dpto. Electrónica, Automática e Informática Industrial 113


Capítulo 5: UML dinámico Apuntes de Informática Industrial

5.1 Diagramas de interacción

UML incluye los diagramas de interacción para ilustrar el modo en que los
objetos interactúan por medio de mensajes. Esta visión proporciona una vista integral
del comportamiento del sistema; muestra el flujo de control a través de los mensajes
entre objetos.

Se debería dedicar un tiempo y esfuerzo no trivial en la creación de los


diagramas de interacción. Es en esta etapa donde se requiere la aplicación de las
técnicas de diseño, en términos de patrones, estilos y principios. La creación de los
casos de uso, modelo del dominio y otros artefactos vistos resultan ser más sencillos que
las asignaciones de responsabilidades y su representación en los diagramas de
interacción. La realización de los diagramas de interacción, en otras palabras, decide
sobre los detalles del diseño de objetos, es una etapa muy creativa del AOO/D. Es
donde se suele aplicar los patrones, principios y estilos para mejorar la calidad de los
diseños.

Hay dos tipos de diagramas de interacción, ambos centrados en aspectos


complementarios:

• Diagramas de secuencia

• Diagrama de interacción

5.1.1 Notación general

Los objetos son representados por instancias de la clase con o sin identificador.

: ProcesadorImagenes elProcesador :
ProcesadorImagenes

Los mensajes emplearán una sintaxis igual que los servicios de las clases. De
hecho, la mayoría de los mensajes son los servicios de las clases:

Nombre-devolucion ‘:=’ nombre-mensaje’ (‘parámetro’:’tipo Parametro’):’tipo-devolucion

Ejemplo

laListaCaracteristica := procesarFichImag(nomFichImag:string):ListaCaracterística

5.1.2 Diagramas de secuencia

Un diagrama de secuencia muestra un conjunto de mensajes dispuestos en una


secuencia temporal. Se encuentra estructurado en dos dimensiones. El tiempo se
representa verticalmente y evoluciona hacia abajo. No suele estar representado

114 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

necesariamente a escala. En la dirección horizontal, hay franjas verticales sucesivas que


corresponde a los diferentes objetos que participan en la interacción.

La línea de vida de un objeto simboliza la existencia de éste en un cierto periodo


de tiempo. Se representa mediante una línea discontinua vertical que va desde su
creación hasta la destrucción.

Las actividades representan los tiempos de procesamiento de los objetos y se


representan mediante rectángulos verticales alargados insertados en las líneas de vida.

Los mensajes se indican con flechas que comienzan en una activación (al
principio de ésta o en una posición intermedia) y acaban en otra. También, se puede
indicar los mensajes de retorno al final de una activación, en forma de flecha
discontinua y punta abierta. Lo normal es que se excluyan por quienes utilizan UML.

El uso de un diagrama de secuencia es para mostrar la secuencia de


comportamiento de un caso de uso. Cuando se implementa el comportamiento del caso
de uso, cada mensaje en un diagrama de secuencia corresponde a:

1. Una operación en una clase.

2. A un evento externo.

3. A una transición de una máquina de estados.

Ejemplo 5.1

Para el caso de uso RespuestaFrecuencia realizar el diagrama de


secuencia del paquete del dominio.

Partiendo del Modelo del Dominio, DSS, contratos de operación y vista de


gestión, visto en el capítulo 3 y 4:

Dpto. Electrónica, Automática e Informática Industrial 115


Capítulo 5: UML dinámico Apuntes de Informática Industrial

116 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

Para indicar la creación de un objeto se emplea el mensaje create(), colocándose


el objeto a la altura del mensaje de creación. Mientras, el mensaje estereotipado con
<<destroy>>, con una gran X y la línea de vida cortada, indica la destrucción explícita
del objeto.

UML ofrece una rica notación para la representación de distintos tipos de


mensajes:

 Mensajes condicionales: el mensaje está condicionado a que se verifique


una condición, representa una bifurcación condicionada. UML emplea la
sintaxis para las condiciones de:

‘[‘ condición ‘]’

 Mensajes condicionales mutuamente exclusivos: Bifurcación del tipo if-


else de carácter excluyente. La notación es un tipo de línea de mensaje
con forma de ángulo que nace desde el mismo punto y se dirige a
diferentes actividades.

 Iteración para un único mensaje: representación de bucle de iteración. La


notación es emplear un índice que recorre desde una posición inicial
hasta otra final:

‘[‘ indice ‘=’ posición ‘]’

 Iteración sobre una colección (multiobjetos): La colección de objetos se


representa con una sobre línea en la parte superior del objeto.

 Mensaje a <<self>> o <<this>>: mensaje sobre el propio objeto. Se


representa mediante una flecha que se inicia en la actividad y termina
sobre ella.

En la figura adjunta se ha rescatado el diagrama de secuencia ofrecido en los


documentos de la OMG en la versión 1.3 de UML. En el diagrama se pretende mostrar
los distintos conceptos definidos.

Dpto. Electrónica, Automática e Informática Industrial 117


Capítulo 5: UML dinámico Apuntes de Informática Industrial

Figura 5. 1. Diagrama de secuencia: ejemplo tomado de la documentación de UML v1.3

5.1.3 Diagramas de colaboración

Una colaboración modela los objetos y los enlaces significativos dentro de una
interacción. Un enlace es un camino de conexión entre dos objetos; indica que es
posible alguna forma de navegación y visibilidad entre objetos. De manera más formal,
un enlace es una instancia de una asociación. A lo largo de un enlace pueden fluir
múltiples mensajes.

Cada mensaje entre objetos se representa con una expresión de mensaje, una
pequeña flecha que indica la dirección del mensaje y un número de secuencia para
mostrar el orden.

El orden de los mensajes se representa mediante números de secuencia. El


esquema de numeración realiza un anidamiento de los mensajes según el orden de
salida.

Ejemplo 5.2

118 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

Para el caso de uso Respuesta en frecuencia realizar el diagrama de


colaboración1.

Tanto los diagramas de secuencias como de colaboración muestran interacciones


entre los objetos pero acentúan aspectos diferentes. Un diagrama de secuencias muestra
secuencias en el tiempo, pero las relaciones entre roles son implícitas. Un diagrama de
colaboración presenta las relaciones de roles, pero las secuencias están menos claras,
porque vienen dadas por los números de secuencia. Cada diagrama debe ser utilizado
cuando su aspecto principal sea el foco de atención.

Para la creación de instancias, UML emplea el convenio de utilizar el mensaje


denominado create(), o bien emplear otro nombre de mensaje pero acompañándolo del
estereotipo <<create>>. Adicionalmente, podría añadirse la propiedad UML {new}
para resaltar la creación. Igualmente, UML tiene notación específica para los diferentes
tipos de mensajes, ya vistos anteriormente en el diagrama de secuencia.

1
Rational Rose convierte automáticamente los diagramas de secuencia a diagramas de
colaboración y viceversa.

Dpto. Electrónica, Automática e Informática Industrial 119


Capítulo 5: UML dinámico Apuntes de Informática Industrial

Figura 5. 2. Diagrama de colaboración: ejemplo tomado de la documentación de UML v1.3

5.2 Diagramas de estado

Una maquina de estados modela los posibles estados que puede tener en vida un
objeto de una clase. Cada objeto se trata como una entidad aislada que se comunica con
el resto del mundo recibiendo eventos y respondiendo a ellos.

Las máquinas de estados se muestran a través de los diagramas de estados. Éstos


están constituidos por eventos, estados y transiciones. Un evento es una ocurrencia
significativa o relevante. Un estado es la condición de un objeto en un instante de
tiempo; hace referencia a los valores de sus atributos en un determinado tiempo. Una
transición es una relación entre dos estados que indica cuando tiene lugar un evento; el
objeto pasa de su estado al siguiente.

Las transiciones se representan por flechas, etiquetadas con sus eventos. Los
estados se representan por rectángulos de esquinas redondeadas. Es habitual incluir un
pseudo-estado inicial que pasa automáticamente a otro estado cuando se crea la
instancia.

Una máquina de estados contiene los estados de un objeto conectados por


transiciones. Cada estado modela un periodo de tiempo, durante la vida de un objeto, en
el que se satisface ciertas condiciones. Cuando ocurre un evento se puede desencadenar
una transición que lleve al objeto a un nuevo estado. Al dispararse una transición se
puede ejecutar una acción unida a la transición.

Un diagrama de estado muestra el ciclo de vida de un objeto: qué eventos


experimenta, sus transiciones y los estados en los que se encuentran entre estos eventos.
No es necesario ilustrar todos los posibles estados. Por lo tanto, el diagrama de estado

120 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

describe el ciclo de vida de un objeto a un nivel de detalle arbitrario, simple o complejo


dependiendo de las necesidades.

El diagrama de estado servirá para:

 Comprobar que los eventos ocurren en orden correcto.

 Habilitar/deshabilitar elementos según el desarrollo del diagrama de


estados.

 En un dominio con muchos eventos del sistema, la concisión y


minuciosidad del diagrama de estado ayuda al diseñador asegurarse a que
no se ha omitido ninguno.

5.2.1 Notación adicional

Una transición puede provocar que se dispare una acción. En una


implementación SW, esto supone la invocación de un método de una clase. Las
acciones se representan mediante la barra invertida, /.

Una transición podría tener una condición de guarda –o condición booleana-.


Sólo ocurre la transición si se cumple la condición.

‘[‘ condición ‘]’

Un estado puede contener subestados. Los subestados heredan la transición del


estado al que pertenece. Esta utilidad permite tener varias vistas con diferentes niveles
de resolución o complejidad del modelo.

Dpto. Electrónica, Automática e Informática Industrial 121


Capítulo 5: UML dinámico Apuntes de Informática Industrial

Figura 5. 3. Diagrama de estado: ejemplo tomado de la documentación de UML v1.3

Ejemplo 5.3

Realizar el diagrama de estado para el juego del Pang.

En general, en las aplicaciones informáticas de gestión, las clases dependientes


del estado son una minoría. En cambio, en los proyectos de control de procesos o en
aplicaciones de telecomunicaciones son frecuentes que muchos objetos sean
dependientes de sus estados.

Tipos de eventos:

122 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

 Evento externo: También conocido como evento hacia el sistema, lo


origina algo fuera del sistema.

 Evento interno: Causado por algo dentro del sistema.

 Evento del tiempo: Causado por la ocurrencia de una fecha y hora


específicas. Un evento temporal lo dirige un reloj de tiempo real.

Es preferible utilizar los diagramas de estado para ilustrar los eventos externos y
de tiempo, y las reacciones a ellos; mientras los eventos internos son representados en
los diagramas de interacción.

Cuando se desear tener una idea más amplia de los efectos del comportamiento
dinámico de un sistema, se emplean las vistas de interacción. Por contra, las máquinas
de estados son útiles para entender los mecanismos de control, tales como interfaces de
usuario o controladores de dispositivos.

5.3 Diagrama de actividades

Un diagrama de actividades de UML ofrece una notación rica para representar


una secuencia de actividades. Podría aplicarse a cualquier propósito, pero se considera
especialmente útil para visualizar los flujos de trabajo y los procesos del negocio.
Formalmente, un diagrama de actividades se considera un tipo especial de diagrama de
estados de UML, en el que los estados son acciones y las transiciones de los eventos se
disparan automáticamente al completarse la acción. Un grafo de actividades describe
grupos secuenciales y concurrentes de actividades.

Un diagrama de actividades tiene el propósito de modelar los procesos reales de


una organización humana. El modelado de tales negocios es un propósito importante de
los diagramas de actividades, pero también se pueden utilizar para modelar actividades
software de alto nivel de ejecución de un sistema, sin profundizar en los detalles
internos de los mensajes.

Dpto. Electrónica, Automática e Informática Industrial 123


Capítulo 5: UML dinámico Apuntes de Informática Industrial

Figura 5. 4. Diagrama de actividades: ejemplo tomado de la documentación de UML v1.3

5.4 La vista física

Las vistas anteriores modelan los conceptos de la aplicación desde un punto de


vista lógico. Las vistas físicas describen las estructuras de implementación de la
aplicación, su organización en componentes y su despliegue en nodos de ejecución.
Estas vistas proporcionan una oportunidad de establecer correspondencias entre las
clases y los componentes de implementación y nodos. Pero además, los aspectos de
implementación son importantes para los propósitos de reutilización y rendimiento.
UML define dos tipos de vistas que se pueden utilizar para ilustrar los detalles de la
implementación: la vista de implementación y la vista de despliegue.

124 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

5.4.1 La vista de implementación

La vista de implementación muestra el empaquetado físico de las partes


reutilizables del sistema en unidades sustituibles, llamadas componentes. Una vista de
implementación muestra los elementos físicos del sistema mediante componentes, así
como sus interfases y dependencias entre componentes. Los componentes son piezas
reutilizables de alto nivel a partir de las cuales se pueden construir los sistemas.

El diagrama de componentes describe la descomposición física del sistema SW


en componentes, a efectos de construcción y funcionamiento. La descomposición del
diagrama de componentes se realiza en términos de componentes y de relaciones entre
los mismos. Los componentes identifican objetos físicos que hay en tiempos de
ejecución, de compilación o de desarrollo y tienen identidad propia con una interfaz
bien definida. Los componentes incluyen código en cualquiera de sus formatos, DLL,
Active X, bases de datos, ... Cada
componente incorpora la
implementación de ciertas clases del
diseño del sistema.

En un diagrama de
componentes se muestran las
diferentes relaciones de dependencia
que se pueden establecer entre
componentes. Los componentes bien
diseñados no dependen de otros
componentes. Un componente en un
sistema puede ser sustituido por otro
componente que ofrezca las interfaces
apropiadas.

Un componente se representa
mediante tres rectángulos. Figura 5. 5. Diagrama de componentes: ejemplo
tomado de la documentación de UML v1.3
Ejemplo 5.5

Realizar el modelo de componentes de la aplicación Respuesta en


frecuencias.

Dpto. Electrónica, Automática e Informática Industrial 125


Capítulo 5: UML dinámico Apuntes de Informática Industrial

5.4.2 La vista de despliegue

La vista de despliegue muestra la disposición física de los recursos de la


ejecución computacional, tales como los computadores y sus interconexiones. El
diagrama de despliegue permite mostrar la arquitectura en tiempo de ejecución del
sistema respecto al HW y SW. Es más limitado que el diagrama de componentes ya que
sólo se presenta en tiempo de ejecución. Sin embargo, resulta más amplio en el sentido
de que puede contener más clases de elementos.

Los nodos representan los objetos físicos existentes en tiempo de ejecución.


Éstos sirven para modelar recursos que tienen memoria y capacidad de proceso, los
cuales pueden ser computadores, dispositivos o personas. Los componentes participan
en los procesos mediante los nodos.

La vista de despliegue puede mostrar cuellos de botella para el rendimiento si las


instancias de los componentes con dependencia se ponen en distintos nodos.

Los nodos se presentan mediante paralelepípedos. Las asociaciones entre nodos


representan líneas de comunicación.

Figura 5. 6. Diagrama de despliegue: ejemplo tomado de la documentación de UML v1.3

126 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

5.5 Cuestiones

1. Diferencias entre el diagrama de secuencia con el de colaboración.

2. Obtener el diagrama de secuencias y de colaboración para la aplicación


Juego de dados: se lanzan dos dados, si la suma de sus caras es siete gana;
en caso contrario, pierde.

3. Utilidades de los diagramas de estado.

4. Cuándo se empleará un diagrama de estado y cuándo de interacción.

5. Sugiera un diagrama de componentes y otro de despliegue para una


aplicación de subasta por Internet, para una galería de arte.

5.6 Problemas

Ejercicio 1
Realizar una aplicación que ordene de forma creciente los números
dados por el usuario.
1. Caso de Uso
2. Modelo del dominio y DSS
3. Vista de Gestión.
4. Diagrama de secuencia y diagrama de clases de diseño
5. Implementación en C++
1. El caso de uso EBP se llama “OrdenarNumeros” y tendrá un curso de éxito
como:
I. Ordenar los números de forma creciente
I.a. Solicitar al usuario el vector de números a ordenar
I.b. Ordenar de forma creciente el vector
I.c. Visualizar los resultados

Dpto. Electrónica, Automática e Informática Industrial 127


Capítulo 5: UML dinámico Apuntes de Informática Industrial

2. Del análisis de los documentos aparece los conceptos de OrdenadorNumeros


y Número proponiéndose el siguiente Modelo del Dominio y DSS:

3. Se propone la siguiente arquitectura:

4. Diseño de la aplicación

128 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

5. Implementación en C++

Dpto. Electrónica, Automática e Informática Industrial 129


Capítulo 5: UML dinámico Apuntes de Informática Industrial

#if !defined(_ORDENADORNUMEROS__INCLUDED_)
#define _ORDENADORNUMEROS_INCLUDED_

#include <algorithm>
#include <vector>

class OrdenadorNumeros
{
public:
OrdenadorNumeros(std::vector<double> & elVectorNumeros)
{std::sort(elVectorNumeros.begin(),elVectorNumeros.end());}
};

#endif

#if !defined(_GUIORDENARNUMEROS__INCLUDED_)
#define _GUIORDENARNUMEROS__INCLUDED_

#include <vector>

class GUIOrdenarNumeros
{
public:
void visualizarResultados(std::vector<double> &);
void solicitarNumeros(std::vector<double> &);
};

#endif

#include "..\..\CABECERAS\VISUALIZADOR\GUIOrdenarNumeros.h"
#include <algorithm>
#include <iostream>
void GUIOrdenarNumeros::solicitarNumeros(std::vector<double> &elVectorNumeros)
{
bool introducirDatos = true; double valor;
std::cout<<"Esta aplicacion ordena los valores de forma creciente"<<std::endl;
std::cout<<"Introducir la lista de numeros y poner cero para salir"<<std::endl;
while(introducirDatos == true){
std::cin>>valor;
if(valor != 0)
elVectorNumeros.push_back(valor);
else
introducirDatos = false;
}
}
void visualizarDatos(double);
void GUIOrdenarNumeros::visualizarResultados(std::vector<double> &elVectorNumeros)
{
std::cout<<"Lista ordenada"<<std::endl;
std::for_each(elVectorNumeros.begin(),elVectorNumeros.end(),visualizarDatos);
}
void visualizarDatos(double valor)
{
std::cout<<valor<<std::endl;
}

130 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

#if !defined(_ORDENARNUMEROS_H__INCLUDED_)
#define _ORDENARNUMEROS_H__INCLUDED_

#include <vector>
#include "../Dominio/OrdenadorNumeros.h"
#include "../Visualizador/GUIOrdenarNumeros.h"

class OrdenarNumeros
{
GUIOrdenarNumeros elVisualizador;
std::vector<double> elVectorNumeros;
public:
void introducirDatos();
void visualizarResultados();
};

#endif

#include "..\..\CABECERAS\ORDENARNUMEROS\OrdenarNumeros.h"
void OrdenarNumeros::introducirDatos()
{
this->elVisualizador.solicitarNumeros(this->elVectorNumeros);
OrdenadorNumeros elOrdenador(this->elVectorNumeros);
}
void OrdenarNumeros::visualizarResultados()
{
this->elVisualizador.visualizarResultados(this->elVectorNumeros);
}

int main()
{
OrdenarNumeros elOrdenar;
elOrdenar.introducirDatos();
elOrdenar.visualizarResultados();
return 0;
}

Dpto. Electrónica, Automática e Informática Industrial 131


Capítulo 5: UML dinámico Apuntes de Informática Industrial

Ejercicio 2

Realizar una aplicación basadas en


OpenGL que permita dibujar un poblado. Las
reglas de urbanización, en esta primera
versión son muy simples, se creará el número
de casas ordenadas en una matriz de filas y
columnas. En la figura se muestra un ejemplo
de un poblado de 4 filas y cinco columnas. Se
pide:

1. Representación UML de las clases Techo y Bloque.

2. Diagrama de Clases de Diseño (DCD) de la solución.

3. Diagrama de Secuencias explicativo del dibujo de la escena.

4. Implementación C++.

1. Aplicando ingeniería inversa, las clases techo y bloque en UML quedan


como:

2. y 3. La solución se dará con el diagrama de clases de diseño, DCD, y con los


diagramas de interacción:

132 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

4. Una vez acabado el diseño, se pasará a su implementación desde las clases menos
acopladas hasta alcanzar a la función main():
#include <vector> #include "Bloque.h"
#include "Casa.h" #include "Techo.h"

class Urbanizacion class Casa


{ {
unsigned filasCasa, columnasCasa; Bloque laBase;
std::vector<Casa> laListaCasas; Techo elTecho;

public: public:
Casa(float,float,float);
Urbanizacion(unsigned, unsigned); virtual ~Casa();
virtual ~Urbanizacion(); void setPosicion(float,float,float);
void dibuja(); void dibuja();

}; };

Dpto. Electrónica, Automática e Informática Industrial 133


Capítulo 5: UML dinámico Apuntes de Informática Industrial

#include "..\..\INCLUDES\DOMINIO\Casa.h"
Casa::Casa(float ancho, float altoBase, float altoTejado)
{
this->laBase.setBase(ancho);
this->elTecho.setBase(ancho);

this->laBase.setAltura(altoBase);
this->elTecho.setAltura(altoTejado);

void Casa::setPosicion(float ax,float ay,float az)


{
this->laBase.setPosicion(ax,ay,az);
this->elTecho.setPosicion(ax,ay+(this->laBase.getAltura()),az);
}

void Casa::dibuja()
{
this->elTecho.dibuja();
this->laBase.dibuja();
}

#include "..\..\INCLUDES\DOMINIO\Urbanizacion.h"
#include "..\..\INCLUDES\comunes\glut.h"

#define ANCHO_BLOQUE 1.0f


#define ALTO_BLOQUE 0.5f
#define ANCHO_TECHO 1.0f
#define SEPARACION_CASA 3.0f

Urbanizacion::Urbanizacion(unsigned filas, unsigned columnas)


{
filasCasa = filas; columnasCasa = columnas;
for(unsigned i = 0; i<filas; i++)
for(unsigned j = 0; j<columnas; j++) {
this->laListaCasas.push_back(Casa(ANCHO_BLOQUE,ALTO_BLOQUE,ANCHO_TECHO));
this->laListaCasas[(i*columnas)+j].setPosicion(SEPARACION_CASA*j,
0,SEPARACION_CASA*i);
}
}

void Urbanizacion::dibuja()
{
float x_ojo=10;float y_ojo=7.5; float z_ojo=40;
gluLookAt(x_ojo, y_ojo, z_ojo, // posicion del ojo
0.0, y_ojo, 0.0, // hacia que punto mira (0,0,0)
0.0, 1.0, 0.0); // definimos hacia arriba (eje Y)

for (unsigned i=0;i<filasCasa*columnasCasa; i++)


this->laListaCasas[i].dibuja();

134 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

Ejercicio 3

Se pretende desarrollar un programa de simulación de un vapor de agua, para


el que se ha desarrollado ya la siguiente clase, que funciona correctamente y
no es necesario modificar:
class Atomo
{
public:
Atomo(int num);
virtual ~Atomo();
void Enlaza(Atomo* a);
void CalculaPosicion();
void Dibuja();
protected:
float x;
float y;
float z;
int numero_atomico;

Atomo* enlace;
};

Ejemplo del resultado final

Supóngase que el método CalculaPosicion() es capaz de calcular la


posición del átomo en el espacio teniendo en cuenta todas las interacciones
físicas, incluyendo la posibilidad que dicho átomo haya establecido un enlace
con otro átomo. El código para dibujar una molécula de agua utilizando la clase
Atomo sería el siguiente:

void main()
{
Atomo hidrogeno1(1);
Atomo hidrogeno2(1);
Atomo oxigeno(16);

hidrogeno1.Enlaza(&oxigeno);
hidrogeno2.Enlaza(&oxigeno);

oxigeno.CalculaPosicion();
hidrogeno1.CalculaPosicion();
hidrogeno2.CalculaPosicion();

hidrogeno1.Dibuja();
hidrogeno2.Dibuja();
oxigeno.Dibuja();
}

Donde es importante el orden de cálculo de las posiciones, es decir,


primero se calcula la posición del oxigeno, y después la de los átomos de
hidrogeno, que dependen del átomo de oxigeno. Cuando el programa este
completado, el código del main() debe quedar como:

Dpto. Electrónica, Automática e Informática Industrial 135


Capítulo 5: UML dinámico Apuntes de Informática Industrial

void main()
{
VaporAgua vapor(30); //30 moleculas de agua
vapor.CalculaPosicion();
vapor.Dibuja();
}

1. Diagrama de Clases de Diseño (DCD de la solución), que incluya


orientación a objetos para cada molécula de agua.

2. Un diagrama de secuencias del cálculo de la posición y el dibujo del


vapor, a partir de la función main().

3. Implementación de la solución en C++

Ejercicio 4

Diseñar el programa de una máquina expendedora de bebidas, de


manera que recibe el producto seleccionado y las monedas que entran en el
cajero desde un autómata programable. La aplicación debe de retornar la lista
de monedas mínimas a entregar al usuario.

Primero se realizará la jerarquía a dos niveles de las principales características:


1. El sistema debe de mostrar los productos que ofrece y sus precios
1.1 El usuario puede elegir uno de los productos ofertados
2. El sistema debe de reconocer las monedas que se le entrega
2.1 Debe de evaluar el crédito del cliente.
3. El sistema entregará el producto cuando el cliente tenga suficiente crédito.
3.1 El sistema devolverá las vueltas cuando hubiera exceso de crédito.

Seguidamente se procederá a rellenar los documentos de Visión y Alcance,


glosario y el caso de uso EBP: SolicitarProducto.

En el AOO se realizará el modelo del dominio y el DSS:

136 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

Durante DOO se planteará la solución lógico a través de la vista de gestión,


diagrama de clases de diseño, DCD, y los diagramas de interacción:

Dpto. Electrónica, Automática e Informática Industrial 137


Capítulo 5: UML dinámico Apuntes de Informática Industrial

138 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico

El código de test sería:

#include "../Cajero/HWCajero.h"
#include "../Dominio/Ingresos.h"
#include "../Dominio/Devoluciones.h"

class MaquinaExpendedora
{
public:
MaquinaExpendedora();
virtual ~MaquinaExpendedora();
void solicitarProducto();
};
//////////////////////////////////
void MaquinaExpendedora::solicitarProducto()
{
HWCajero miCajero;
Dinero elPrecioProducto = miCajero.solicitarProducto();
Ingresos miDinero;
while(miDinero.haySuficienteDinero(elPrecioProducto) == false)
miDinero.anyadirMoneda(miCajero.recibirMoneda());

Devoluciones elDineroEntregar(miDinero.getDinero(),elPrecioProducto);

std::vector<Moneda> laListaMonedas;
elDineroEntregar.calcularDevoluciones(laListaMonedas);
miCajero.entregarVueltas(laListaMonedas);
miCajero.entregarProducto();
}
//////////////////////////////
#include <iostream>
int main()
{
MaquinaExpendedora laMaquinaExpendedora;
bool continuar = true;char opcion;
while(continuar){
laMaquinaExpendedora.solicitarProducto();
std::cout<<"Nuevo producto (s/n): ";
std::cin>>opcion;
continuar = (opcion == 'n') || (opcion == 'N') ? false :true;
}
return 0;
}

La implementación de las clases de la menos acoplada a la más acoplada:


typedef enum{EURO,DOLAR,LIBRA} tipoDinero;
typedef enum{UN_CENT,DOS_CENT,CINCO_CENT,DIEZ_CENT,VEINTE_CENT,CINCUENTA_CENT,
UNO,DOS} tipoMoneda;
#define FACTOR_DINERO 100
class Dinero
{
tipoDinero elTipoDinero;
unsigned cantidad;
public:
Dinero() {cantidad=0;elTipoDinero=EURO;}
Dinero(unsigned
Derecho valor)Carlos
de Autor © 2014 {cantidad=valor;elTipoDinero=EURO;}
Platero Dueñas.
unsigned getCantidad(){return cantidad;}
tipoDinero getTipoDinero() {return elTipoDinero;}
Permiso
voidpara copiar, distribuir
operator+=(const y/omasDinero)
Dinero modificar este documento bajo los términos de la
{if(this->elTipoDinero
Licencia Documentación== Libre
masDinero.elTipoDinero)
de this->cantidad+=masDinero.cantidad;}
GNU, Versión 1.1 o cualquier otra versión
posterior
void publicada por la Free
operator-=(const Software
unsigned valor)Foundation; sin secciones invariantes, sin
texto {this->cantidad-=valor;}
de la Cubierta Frontal, así como el texto de la Cubierta Posterior. Una copia de
bool operator>=(const Dinero elPedido)
la licencia es incluida en la== sección
{if(this->elTipoDinero titulada "Licencia
elPedido.elTipoDinero) de Documentación Libre
return(
GNU". this->cantidad>=elPedido.cantidad?true:false);}
Dinero operator-(const Dinero elPedido)
{if(this->elTipoDinero == elPedido.elTipoDinero) return(Dinero(
this->cantidad-elPedido.cantidad));}
};

Dpto. Electrónica, Automática e Informática Industrial 139


Capítulo 5: UML dinámico Apuntes de Informática Industrial

class Moneda: public Dinero


{
tipoMoneda elTipoMoneda;
public:
Moneda(unsigned);
virtual ~Moneda();
};
La Licencia de documentación libre GNU (GNU Free Documentation License) es
/////////////////////////////////////////////////////
Moneda::Moneda(float cantidad):Dinero(cantidad)
una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
{
apuntesif(cantidad
están cubiertos por esta licencia.
== 1) this->elTipoMoneda La version 1.1 se encuentra en
= UN_CENT;
else if (cantidad == 2) this->elTipoMoneda = DOS_CENT;
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
else if (cantidad == 5) this->elTipoMoneda = CINCO_CENT;
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html
else if(cantidad == 10)this->elTipoMoneda = DIEZ_CENT;
else if (cantidad == 20) this->elTipoMoneda = VEINTE_CENT;
else if (cantidad == 50)this->elTipoMoneda = CINCUENTA_CENT;
else if (cantidad == 100)this->elTipoMoneda = UNO;
else if (cantidad == 200)this->elTipoMoneda = DOS;
else
; //Error

#include <vector>
#include "../Comunes/Moneda.h"
class HWCajero
{
public:
Moneda recibirMoneda();
Dinero solicitarProducto();
void entregarVueltas(std::vector<Moneda> &);
void entregarProducto();
};

////////////////////////////////////
Moneda HWCajero::recibirMoneda()
{
float cantidad;
std::cin >> std::setprecision(2)>> cantidad;
return(Moneda((unsigned)(cantidad*FACTOR_DINERO)));
}

Dinero HWCajero::solicitarProducto()
{
std::cout<<"Elegir tipo producto:"<<std::endl;
std::cout<<"====================="<<std::endl;
std::cout<<"1: Cafe 40 centimos"<<std::endl;
std::cout<<"2: Te 35 centimos"<<std::endl;
std::cout<<"3: Limon 50 centimos"<<std::endl;
unsigned opcion;unsigned valor;
std::cin>>opcion;
switch(opcion) {
case 1: valor = 40;break;
case 2: valor = 35;break;
default: valor = 50;
}
std::cout<<"Introducir monedas:"<<std::endl;
std::cout<<"==================="<<std::endl;
return(Dinero(valor));
}
void HWCajero::entregarVueltas(std::vector<Moneda> &laListaMonedas)
{
std::cout<<"Lista de monedas a devolver"<<std::endl;
for(unsigned i=0;i<laListaMonedas.size();i++)
std::cout<<((float)laListaMonedas[i].getCantidad())/FACTOR_DINERO
<<std::setprecision(2)
<<std::endl;
}
void HWCajero::entregarProducto()
{
std::cout<<"Recoja el producto seleccionado"<<std::endl;
}

140 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Capítulo 5: UML dinámico
#include "../Comunes/Moneda.h"

class Ingresos
{
Dinero elDineroIngresado;
public:
Ingresos();
virtual ~Ingresos();
void anyadirMoneda(Dinero nuevaMoneda)
{ elDineroIngresado += nuevaMoneda;}
bool haySuficienteDinero(Dinero elPrecioPedido)
{ return (elDineroIngresado>= elPrecioPedido ? true : false); }
Dinero getDinero(){return elDineroIngresado;}

};

#include <vector>
#include "../Comunes/Moneda.h"

class Devoluciones
{
Dinero elDineroAdevolver;
public:
Devoluciones();
Devoluciones(Dinero elIngreso,Dinero elPedido)
{elDineroAdevolver = elIngreso-elPedido;}
virtual ~Devoluciones()
void calcularDevoluciones(std::vector<Moneda> &);
};
/////////////////////////////////
void Devoluciones::calcularDevoluciones(std::vector<Moneda> &laListaMonedas)
{
if(this->elDineroAdevolver.getTipoDinero() == EURO){
while(this->elDineroAdevolver.getCantidad()>= 200){
laListaMonedas.push_back(Moneda(200));
this->elDineroAdevolver-=200;
}
while(this->elDineroAdevolver.getCantidad()>= 100){
laListaMonedas.push_back(Moneda(100));
this->elDineroAdevolver-=100;
}
//Repetición con el resto de monedas
//........
}
}

Derecho de Autor © 2014 Carlos Platero Dueñas.


Permiso para copiar, distribuir y/o modificar este documento bajo los términos
de la Licencia de Documentación Libre GNU, Versión 1.1 o cualquier otra
versión posterior publicada por la Free Software Foundation; sin secciones
invariantes, sin texto de la Cubierta Frontal, así como el texto de la Cubierta
Posterior. Una copia de la licencia es incluida en la sección titulada "Licencia de
Documentación Libre GNU".

La Licencia de documentación libre GNU (GNU Free Documentation License)


es una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
apuntes están cubiertos por esta licencia. La version 1.1 se encuentra en
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html

Dpto. Electrónica, Automática e Informática Industrial 141


6 Diseño orientado a objetos
En las etapas de captura de los requisitos y del análisis orientado a objetos se han
centrado en aprender a realizar la definición del proyecto sin decir cómo. En esta otra
etapa se pondrá el énfasis en implantar las especificaciones con eficiencia y fiabilidad.

En el Proceso Unificado, UP, por cada iteración, tendrá lugar una transacción
desde un enfoque centrado en los requisitos, a un enfoque centrado en el diseño y en la
implementación.
Iteración i
Iteración i+1

Requisitos
Requisitos
Diseño tiempo
Diseño
Implementación
Prueba Implementación
Prueba
Integración
Pruebas de sistema Integración
Pruebas de sistema

4 semana (por ejemplo) El sistema crece en


cada iteración

Figura 6. 1 evolución del proyecto por iteraciones

Dpto. Electrónica, Automática e Informática Industrial 145


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

El diseño orientado a objetos requiere tener conocimientos en:

 Los principios de asignación de responsabilidades.

 Los usos de los patrones de diseño.

Para el desarrollo de las técnicas de diseño se emplearán los diagramas de


interacción y los diagramas de clase de diseño, DCD. Ambos artefactos pertenecen a la
disciplina UP de Modelado del Diseño.

Este capítulo se organiza en tres apartados. El primero tratará sobre las bases del
diseño y de la implementación, para luego pasar a entrar de lleno en el diseño con
patrones. Los apartados segundo y tercero se estudiarán los patrones GRASP y GoF
respectivamente.

6.1 De los diagramas de clase de diseño a la implementación

Los diagramas de clase de diseño, DCD, se crean en paralelo con los diagramas
de interacción. En los DCD se encuentran reflejados:

 Las clases, asociaciones y atributos.

 Los patrones.

 Los interfaces, con sus operaciones y constantes.

 Los métodos o servicios.

 La información acerca del tipo de atributos.

 La navegabilidad.

 Las dependencias.

A diferencia de las clases conceptuales 1 del AOO, las clases de diseño de los
DCD muestran las esencias de las futuras clases implementadas o de software.

El primer paso para crear un DCD es identificar aquellas clases que participan en
la solución del paquete a diseñar. Se pueden encontrarlas examinando el modelo del
dominio, donde algunas clases conceptuales pueden ser tomadas como clases de diseño.
También pueden ser localizadas en los diagramas de interacción y listando las clases
que se mencionan.

1
Clases conceptuales  abstracciones de conceptos del mundo real

146 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

El siguiente paso es dibujar un diagrama de clases e incluir los atributos que se


identificaron previamente en el modelo del dominio que también se utilizan en el
diseño.

En cuanto a los servicios, éstos se pueden identificar analizando los diagramas


de interacción y observando los nombres de los mensajes mandados entre los objetos.

El mensaje “create()” es una forma de independizar UML de los lenguajes de


programación. En C++ implica la asignación dinámica con el operador new, seguido de
una llamada al constructor.

Los métodos de acceso a la información, capaces de recuperar (getX()) o de


establecer (setX()) los valores de atributo, son definidos automáticamente o
manualmente. En algunos lenguajes, como en Java, es un estilo común tener un get() y
un set() por cada atributo y declarar todos los atributos privados.

Un mensaje a un multiobjeto se interpreta como un mensaje al propio objeto


contenedor/colección. Normalmente, estas interfaces o clases de
contenedores/colecciones son elementos de las librerías predefinidas y no es útil mostrar
explícitamente estas clases en el DCD.

Los tipos de los atributos, los argumentos de los servicios y los valores de
retorno se podrían mostrar. La cuestión sobre si se muestra o no esta información se
debe de considerar en el siguiente contexto:

“Si se emplea alguna herramienta CASE con generación automática del código,
son necesarios todos los detalles. Si se hace para que lo lean los
desarrolladores, los detalles podrían influir negativamente por el ruido visual
que produce tanta información en los DCD.”

En el Modelo del Dominio sólo se expresaba relaciones semánticas entre las


clases conceptuales, intentando definir un diccionario visual del problema. Por el
contrario, en DCD se eligen las asociaciones de acuerdo al criterio de necesito conocer.
Es en el DCD donde tiene sentido emplear toda la rica notación de UML sobre
relaciones entre clases de diseño.

La visibilidad y las asociaciones entre clases de diseño se dan a conocer en el


DCD. Para su determinación se ayudara con los diagramas de interacción.

Ejemplo 6.1

Determinar el DCD del paquete del dominio de RespuestaFrecuencia


considerando el modelo del dominio y los diagramas de interacción, obtenidos
de anteriores ejercicios.

Dpto. Electrónica, Automática e Informática Industrial 147


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Del diagrama de interacciones se observa que el coordinador del paquete del


dominio recibe dos mensajes (ponerCircuito() y ponerParamResFr()). Del primero se
observa que se creará el objeto filtro con sus características que según el modelo del
dominio será la FDT de un sistema tipo LTI-SISO, constituyéndolo con dos polinomios,
uno en el numerador y otro en el denominador. Por tanto, son asociaciones de necesito
conocer y relaciones del todo con las partes. Se les pondrá flechas de navegación y de
tipo de agregación y composición. No se ha elegido, para este caso, relaciones de
generalización, por que es más robusto la composición que la herencia. Nótese que en
las clases conceptuales no se ha colocado ninguna relación jerárquica.

Cuando se recibe la información sobre los parámetros de respuesta en


frecuencia, el coordinador se lo pasará a RespuestaFrecuencia y éste deberá de calcular
el Bode. La conexión entre RespuestaFrecuencia y FiltroLineal, necesaria en el cálculo
de Bode, se realizará por argumento en este servicio, generando una relación de
dependencia.

148 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

6.1.1 Determinación de la visibilidad

La visibilidad es la capacidad de un objeto de tener una referencia a otro objeto.


Para que un objeto emisor envíe un mensaje a un objeto receptor2, el receptor debe ser
visible al emisor. Hay cuatro formas comunes de alcanzar la visibilidad:

1. Visibilidad de atributo: El emisor tiene entre sus atributos al receptor. Es una


visibilidad permanente porque persiste mientras existan el emisor y el
receptor. Ésta es una visibilidad muy común en AOO/D. Se usa el
estereotipo <<association>> para definir esta visibilidad en UML.

2. Visibilidad de argumento: El objeto-atributo es pasado como argumento en


un servicio solicitado a otro objeto. La visibilidad de parámetro desde el
emisor al receptor existe cuando el emisor pasa como un parámetro el
atributo al receptor. Es una visibilidad relativamente temporal. Es la segunda
forma más común en AOO/D. Es habitual transformar la visibilidad de
argumento en visibilidad local. El estereotipo UML para su identificación es
<<parameter>>.

3. Visibilidad local: El receptor es declarado dentro de algún servicio del


emisor. La visibilidad local, desde el emisor al receptor, existe cuando el
receptor se declara como un objeto local en un método del emisor. Es una
visibilidad relativamente temporal. Es la tercera forma de visibilidad más
común en POO. Se declara con el estereotipo <<local>>.

4. Visibilidad global: Cuando el receptor es un objeto global y puede ser


manejado por cualquier objeto de la aplicación. Es una visibilidad
permanente en el tiempo y es la forma menos común de visibilidad. El
método para conseguir visibilidad global es utilizar el patrón Singleton
[GoF]. Se declara con el estereotipo <<global>>.

2
Recuerde que el objeto receptor es el que realiza la operación.

Dpto. Electrónica, Automática e Informática Industrial 149


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

La navegabilidad implica visibilidad, normalmente, visibilidad del atributo. Las


asociaciones en DCD deberían adornarse con las flechas de navegación necesarias. Es
aquí donde tiene más sentido destacar las distintas relaciones que se establecen en
UML. Así, por ejemplo, en los diagramas de clase de diseño, la relación de dependencia
es útil para describir la visibilidad entre clases que no son de atributos, esto es, para
declarar una visibilidad de parámetro, local o global.

6.1.2 Modelo de implementación

Una vez finalizado los DCD se dispone de los suficientes detalles para generar el
código de la capa del dominio de los objetos.

Los artefactos UP creados durante el trabajo de diseño -diagramas de interacción


y los DCDs- se utilizarán como entradas en el proceso de generación de código.

En UP se define el Modelo de Implementación. Éste contiene los artefactos de


implementación como el código fuente, las definiciones de bases de datos, las páginas
XML/HTML, etc.

Una ventaja del AOO/D y la POO, cuando se utiliza UP, es que proporciona una
guía de principio a fin, esto es, se presenta un conjunto de artefactos, procedimientos y
técnicas que van desde los requisitos hasta la generación del código.

Durante el trabajo de diseño se tomaron algunas decisiones. Ahora, en la fase de


implementación, no es una etapa de generación de código trivial, más bien lo contrario.
En realidad, los resultados generados durante el diseño son un primer paso incompleto.
Durante la fase de producción del código aparecerán nuevas cuestiones que habrán de
resolverse in situ. Es una tarea que costará mucho tiempo, pero mucho menos que si no
se hubiera puesto esfuerzo en la captura de los requisitos, en el análisis y en el diseño.
Producir código sin realizar estos estudios es algo que es improductivo, tedioso y
extremadamente peligroso.

Después de haber acabado una iteración de UP, es deseable, para la siguiente


vuelta del ciclo, que los diagramas generados se actualicen de manera semiautomática
con el trabajo surgido de la implementación. Éste es un aspecto de la ingeniería inversa
(ver ejemplo 6.2). El código producido hará actualizar el modelo definido en el Proceso
Unificado.

6.1.3 Transformación del diseño al código

La transformación en un lenguaje OO requiere la escritura del código fuente


para:
 La definición de las clases e interfaces.
 Las definiciones de los métodos o servicios.
Para la creación de las definiciones de las clases se emplearán básicamente los
DCD. Las definiciones de los métodos y de los atributos simples son inmediatas de
obtener a partir de los DCD y de los diagramas de interacción. Sin embargo, para los

150 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

atributos complejos se emplearán atributos de referencia. Los atributos de referencia se


deducen de las asociaciones y de la navegabilidad de los diagramas de clases. Los
atributos de referencia de una clase a menudo están implícitos, en lugar de explícitos.
Cuando el atributo es simple, por ejemplo, un carácter, éste está de forma explícita en la
definición de la clase; pero cuando es complejo, como por ejemplo una frase, se utiliza
una referencia a una instancia de ese atributo complejo.

En este curso se ha ignorado el manejo de las excepciones en el desarrollo de la


solución. De hecho no se plantea la inserción de código para el control de excepciones.
Sin embargo, habrá que contemplarlas en la producción de código industrial.

El método para traducir los diagramas de clases de diseño y los diagramas


interacción a código se basará en el procedimiento “eXtreme Programming”, XP. Se
basa en escribir el código de pruebas antes que el código de producción. La secuencia es
escribir un poco de código de prueba, luego escribir un poco de código de producción,
hacer las pruebas y cuando éste se hayan superado, entonces se escribirá más código de
prueba y más de producción y así sucesivamente. Se empezará por implementar desde
las clases menos acopladas a las más acopladas.

Ejemplo 6.2

Implementar la aplicación Respuesta en Frecuencia v0.0.0

Primero se realizará el código de prueba, utilizando el diagrama de secuencia del


sistema (DSS), los contratos de operación y los diagramas de interacción empleados
anteriormente. Por tanto, se implementará la función main() y la clase Vista:

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL

#include <iostream>
using namespace std;

#include "../Dominio/CoordinadorFrecELAI.h"

class VistaFrecuenciaELAI
{
tipoFiltro elTipo;
float resistencia;
float condensador;
float frecInicial, frecFinal, frecIntervalo;
CoordinadorFrecELAI elCoordinador;

public:
void introducirCircuito(void);
void introducirParametrosRespFr(void);
}; /*VistaFrecuencia.h*/

Dpto. Electrónica, Automática e Informática Industrial 151


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#include "../../include/Vista/VistaFrecuenciaELAI.h"
void VistaFrecuenciaELAI::introducirCircuito(void)
{
cout << "Elegir entre:\n1.Filtro paso bajo primer orden.\n2.Filtro paso alto";
int eleccion;
cin >> eleccion;
elTipo = eleccion == 1 ? LF_1 : HF_1;
cout << "\nValor de la resistencia: ";
cin >> resistencia;
cout << "\nValor del condensador: ";
cin >> condensador;
elCoordinador.ponerCircuito(elTipo,resistencia,condensador);
}
void VistaFrecuenciaELAI::introducirParametrosRespFr(void)
{
cout << "\nCual es la frecuencia inicial [Hz]: ";
cin >> frecInicial;
cout << "\nCual es la frecuencia final [Hz]: ";
cin >> frecFinal;
cout << "\nCual es el intervalo empleado para el cálculo [Hz]: ";
cin >> frecIntervalo;
elCoordinador.ponerParamResFr(frecInicial,frecFinal,frecIntervalo);

//Visualizar los resultados


std::vector<double> elVectorModulo;
std::vector<double>::iterator iteradorModulo;
elCoordinador.getModuloRespFr(elVectorModulo);
iteradorModulo = elVectorModulo.begin();
for (unsigned i =0; i<elVectorModulo.size(); i++)
std::cout<<*(iteradorModulo+i)<<std::endl;
cout << "Pulsar cualquier tecla para finalizar";
}
void main(void)
{
VistaFrecuenciaELAI laVista;
laVista.introducirCircuito();
laVista.introducirParametrosRespFr();
}

El siguiente paso será escribir el código de las clases menos acopladas a las que
más lo están. Se implementarán por el siguiente orden: Polinomio, FDT, FiltroLTI,
RespuestaFrecuencia y Coordinador:

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#ifndef _POLINOMIO_INC_
#define _POLINOMIO_INC_
#include <vector>

class Polinomio
{
std::vector<double> coeficientes;
public:
Polinomio(){}
Polinomio(unsigned grado, double *pCoef)
{
for (unsigned i=0;
i<=grado;coeficientes.push_back(*(pCoef+i)),i++);
}
double getCoeficiente(unsigned n)
{return( coeficientes[n]));}
};

#endif /*Polinomio.h*/

152 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#ifndef _FDT_INC_
#define _FDT_INC_
#include "Polinomio.h"
class FDT
{
unsigned grado;
Polinomio numerador;
Polinomio denominador;
public:
FDT(unsigned n, double *pNum, double *pDen):
grado(n),numerador(n,pNum),denominador(n,pDen){}
unsigned getGrado(void){return grado;}
double getCoefNum(unsigned n)
{return n<=grado ? numerador.getCoeficiente(n) : 0;}
double getCoefDen(unsigned n)
{return n<=grado ? denominador.getCoeficiente(n) : 0;}
};

#endif /*FDT.h*/

#ifndef _FILTRO_LINEAL_INC_
#define _FILTRO_LINEAL_INC_
#include "FDT.h"
typedef enum{LF_1,HF_1} tipoFiltro;

class FiltroLineal
{
tipoFiltro elTipo;
FDT *pFDT;
public:
FiltroLineal(tipoFiltro, float, float);
unsigned getGradoFiltro(void){return pFDT->getGrado();}
double getCoefNum(unsigned n)
{return pFDT != NULL ? pFDT->getCoefNum(n) : 0;}
double getCoefDen(unsigned n)
{return pFDT != NULL ? pFDT->getCoefDen(n) : 0;}
~FiltroLineal(){if(pFDT) delete pFDT;}
};

#endif /*FiltroLineal.h*/

// "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#ifndef _RESPFREC_INC_
#define _RESPFREC_INC_
#include <vector>
#include "FiltroLineal.h"
class RespuestaFrecuencia
{
float freInicio, freFinal, freIntervalo;
std::vector<double> modulo;
std::vector<double> argumento;
double calcularModulo(float,FiltroLineal *);
double calcularArgumento(float,FiltroLineal *);
public:
RespuestaFrecuencia(float,float,float,FiltroLineal *);
float getFrInicio(void){return freInicio;}
float getFrFinal(void){return freFinal;}
float getFrIntervalo(void){return freIntervalo;}
void getModuloRespFr(std::vector<double> &elVectorModulo)
{elVectorModulo = modulo;}
};

#endif /*RespuestaFrecuencia.h*/

Dpto. Electrónica, Automática e Informática Industrial 153


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

// De: "Apuntes de Informática Industrial" Carlos Platero.


// Ver permisos en licencia de GPL
#ifndef _COORDINFRECELAI_INC_
#define _COORDINFRECELAI_INC_
#include "FiltroLineal.h"
#include "RespuestaFrecuencia.h"

class CoordinadorFrecELAI
{
FiltroLineal *pFiltro;
RespuestaFrecuencia *pRespFr;

public:
int ponerCircuito(tipoFiltro ,float , float );
int ponerParamResFr(float,float,float);
int getModuloRespFr(std::vector<double> &);
~CoordinadorFrecELAI()
{if(pFiltro) delete pFiltro; if(pRespFr) delete pRespFr;}

};

#endif /*Coordinador.h*/

Las algoritmias de los métodos serán implementados en los fuentes de las clases.
También de la menos acopladas a la de más acoplamiento. Se usa un código de test para
visualizarlo en consola.

// Ver permisos en licencia de GPL


#include "../../include/Dominio/FiltroLineal.h"
FiltroLineal::FiltroLineal(tipoFiltro tipo, float resistencia, float condensador)
{
elTipo = tipo;
double numerador[2]; double denominador[2];
if (elTipo == LF_1) {
numerador[0]=1; numerador[1]=0;
}
else{
numerador[0]=0; numerador[1]=resistencia*condensador;
}
denominador[0]= 1;denominador[1]=resistencia*condensador;
pFDT = new FDT(1,numerador,denominador);
}

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#include "../../include/Dominio/RespuestaFrecuencia.h"
#include <iostream>
#include <math.h>
#define PI 3.1416
#define PRUEBA_BODE
#ifdef PRUEBA_BODE
#include <iostream>
#endif
RespuestaFrecuencia::RespuestaFrecuencia(float frInicio, float frFin,float
frIntervalo,FiltroLineal *pFiltro)
{
for (float f=frInicio; f< frFin; f+=frIntervalo)
{
modulo.push_back(this->calcularModulo(f,pFiltro));
//argumento.push_back(this->calcularArgumento(f,pFiltro));
//A implementar
}
#ifdef PRUEBA_BODE
this->iteradorModulo = modulo.begin();
for (unsigned i =0; i<modulo.size(); i++)
std::cout<<*(iteradorModulo+i)<<std::endl;
#endif
}

double RespuestaFrecuencia::calcularModulo(float frecuencia,FiltroLineal *pFiltro)


{
//...
}
/* RespuestaFrecuencia.cpp*/

154 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#include "../../include/Dominio/CoordinadorFrecELAI.h"
int CoordinadorFrecELAI::ponerCircuito(tipoFiltro elTipo,float resistencia,
float condensador)
{
pFiltro = new FiltroLineal(elTipo,resistencia,condensador);
return(0);
}
int CoordinadorFrecELAI::ponerParamResFr(float frInicio,float frFinal,
float frIntervalo)
{
if (pFiltro == NULL) return (-1);
pRespFr = new RespuestaFrecuencia(frInicio,frFinal,frIntervalo,pFiltro);
return(0);
}
int CoordinadorFrecELAI::getModuloRespFr(std::vector<double> &elVectorModulo)
{
if (pRespFr == NULL) return (-1);
pRespFr->getModuloRespFr(elVectorModulo);
if(pFiltro) delete pFiltro;
if(pRespFr) delete pRespFr;
return (0);
}

/*coordinador.cpp*/
Una vez depurada la aplicación se procederá a aplicar ingeniería inversa para
obtener el nuevo DCD y pasar a la siguiente iteración UP:

Dpto. Electrónica, Automática e Informática Industrial 155


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

6.2 Diseño de objetos con responsabilidad

Para el diseño OO se requiere tener conocimientos en:

• Los principios de asignación de responsabilidades

• Patrones de diseño

Para su desarrollo se emplearán los diagramas de interacción y los diagramas de


clase, ambos artefactos forman parte del Modelo del Diseño.

Las responsabilidades están relacionadas con las obligaciones de un objeto en su


comportamiento. Estas obligaciones son de dos tipos: a) los objetos deben saber qué
información manejan (conocer) y b) las cosas qué deben de hacer.

Las responsabilidades se asignan a las clases de los objetos durante la etapa de


diseño. Una responsabilidad no es lo mismo que un método o servicio, pero los métodos
se implementan para llevar a cabo las responsabilidades. El objetivo de este capítulo es
aplicar sistemáticamente los principios fundamentales para asignar responsabilidades a
los objetos.

6.2.1 Patrones

En la tecnología de objetos, un patrón es una descripción de un problema y su


solución; a la que se le da un nombre y se puede aplicar a nuevos contextos. Son guías
sobre el modo en el que debería asignarse las responsabilidades a los objetos.

Resumiendo:

1. La asignación habilidosa de responsabilidad es extremadamente


importante en el diseño de objetos.

2. La decisión acerca de la asignación de responsabilidades tiene lugar


durante la creación de los diagramas de interacción, de los DCD y,
posteriormente, en la programación.

3. Los patrones son pares problemas/solución con un nombre que


codifican buenos consejos y principios relacionados, con frecuencia,
con la asignación de responsabilidades.

Dos tipos de patrones se explicarán: los patrones GRASP y los GoF. GRASP es
el acrónimo de General Responsibility Assignment Software Patterns. Se tratarán los
patrones: Experto en Información, Creador, Alta Cohesión, Bajo Acoplamiento,
Controlador, Polimorfismo, Indirección, Fabricación Pura y Variaciones Protegidas.

156 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Mientras GoF es la abreviatura de Gangs of Four, de los que se tratarán los patrones:
Adaptador, Factoría, Singleton, Estrategia, Composición y Observador.

6.3 Patrones GRASP

6.3.1 Experto en Información

Problema: ¿Cuál es el principio general para asignar responsabilidades?

Solución: Asignar la responsabilidad al que tenga la información.

El patrón Experto indica qué hacen los objetos con la información que
contienen. Sucede muchas veces que la información está dispersa por diferentes clases
de objetos. Esto implica que hay muchos expertos con información “parcial” que
colaboran en la tarea, mediante el paso de mensajes para compartir el trabajo. Por
ejemplo, se han visto varios ejemplos que cuando una tarea llega a un objeto, el trabajo
es distribuido a otros objetos asociados.

Para asignar la responsabilidad se emplearán las clases del DCD. En la primera


iteración se utilizará el Modelo del Dominio, en versiones posteriores se consultaran los
resultados de la ingeniería inversa de las iteraciones anteriores. La idea es ir ampliando
o actualizando las nuevas clases del diseño.

Si se empieza el trabajo del diseño se buscará los expertos en información en el


Modelo del Dominio. Hay que hacer una tabla de responsabilidades generando las
primeras clases de diseño.

Ejemplo 6.3

Realizar una tabla de responsabilidad sobre la aplicación


RespuestaFrecuencia
Clase de diseño Información Responsabilidad
Filtro Tiene la FDT del filtro y el tipo de Definir matemáticamente la estructura
filtro del filtro
RespuestaFrecuencia Los parámetros de frecuencia Aplicar los algoritmos para calcular
el Bode

Dpto. Electrónica, Automática e Informática Industrial 157


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

En algunos casos, el Experto en Información genera problemas de acoplamiento


y cohesión. Este problema se pone de manifiesto cuando el patrón Experto une los datos
del dominio, con los datos de la presentación. Por ejemplo, en una hoja de cálculo, el
Experto uniría los datos de la base de datos con la presentación en barras gráficas. El
patrón Experto se equivoca. Siempre hay que mantener separada la lógica de la
aplicación de la lógica de la base de datos o la lógica del dominio de la vista.

Beneficios del patrón experto:

 Mantiene el encapsulamiento de la información, puesto que los objetos


utilizan su propia información para llevar a cabo las tareas.

 Se distribuye el trabajo entre clases, haciéndolas más cohesivas y ligeras,


lo que conlleva a que sean más fáciles de entender y de mantener.

Este patrón también se conoce como: “Colocar la responsabilidad con los datos”,
“Eso que conoces, hazlo”, “Hacerlo yo mismo”, “Colocar los servicios con los atributos
con los que trabaja”.

6.3.2 Creador

Problema: ¿Quién debería ser el responsable de la creación de una nueva


instancia de una clase?

Solución: Asignar a la clase B la responsabilidad de crear una instancia de clase


A si se cumple uno o más de los siguientes casos:

 B contiene objetos de A

 B se asocia con objetos de A

 B registra instancias de objetos de A

 B utiliza más estrechamente objetos de A

 B tiene datos de inicialización que se pasarán a un objeto de A

El patrón creador está relacionado con la asociación y especialmente con la


agregación y la composición (relación del Todo con las Partes).

Estas responsabilidades se asignarán durante la elaboración de los diagramas de


interacción. A veces se encuentra el creador buscando las clases que tienen los datos de
inicialización que se pasará durante la creación.

A menudo, la creación requiere una complejidad significativa, como utilizar


instancias recicladas por motivos de rendimientos o crear instancias de forma

158 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

condicional. En estos casos es aconsejable delegar la creación a una clase auxiliar


denominada Factoría. Esta clase deriva del patrón Factoría (GoF) que se verá más
adelante.

Ejemplo 6.4

Utilizar el patrón creador en la aplicación RespuestaFrecuencia

// De: "Apuntes de Informática Industrial" Carlos Platero.


// Ver permisos en licencia de GPL
#include "../../include/Coordinador/CoordinadorFrecELAI.h"

int CoordinadorFrecELAI::ponerCircuito(tipoFiltro elTipo,float resistencia,


float condensador)
{
pFiltro = new FiltroLineal(elTipo,resistencia,condensador);
return(0);
}
int CoordinadorFrecELAI::ponerParamResFr(float frInicio,float frFinal,
float frIntervalo)
{
if (pFiltro == NULL) return (-1);
pRespFr = new RespuestaFrecuencia(frInicio,frFinal,frIntervalo,pFiltro);
return(0);
}
int CoordinadorFrecELAI::getModuloRespFr(std::vector<double> &elVectorModulo)
{
if (pRespFr == NULL) return (-1);
pRespFr->getModuloRespFr(elVectorModulo);
if(pFiltro) delete pFiltro;
if(pRespFr) delete pRespFr;
return (0);
}

/*coordinador.cpp*/

Dpto. Electrónica, Automática e Informática Industrial 159


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

6.3.3 Alta Cohesión

Problema: ¿Cómo mantener la complejidad manejable?

Solución: Asignar una responsabilidad de manera que la cohesión permanezca


alta.

En AOO/D, la cohesión es una medida de la fuerza con la que se relacionan los


elementos de un conjunto o paquete y del grado de focalización de sus
responsabilidades. Un elemento, concepción genérica de UML, de alta responsabilidad
y que no hace gran cantidad de trabajo, tiene alta cohesión. Estos elementos pueden ser
clases, paquetes, subsistemas, etc.

Una clase con baja cohesión hace muchas cosas no relacionadas o tareas
relacionadas pero con mucho trabajo. Las clases de baja cohesión adolecen de los
siguientes problemas:

 Difíciles de entender.

 Difíciles de reutilizar.

 Difíciles de mantener.

 Delicadas, constantemente afectadas por los cambios.

A menudo las clases con baja cohesión representan bien un grado grande de
abstracción o bien se les han asignado demasiadas responsabilidades que deberían de
haberse delegado en otras clases.

Se establece que existe alta cohesión funcional cuando los elementos de un


componente “trabajan todos juntos para proporcionar algún comportamiento bien
delimitado”.

Como regla empírica, una clase con alta cohesión tiene un número relativamente
pequeño de métodos, con funcionalidad altamente relacionada y no realiza mucho
trabajo. En el caso de que la tarea sea extensa, colaborará con otros objetos para
compartir el esfuerzo.

El Bajo Acoplamiento y la Alta Cohesión son viejos principios del diseño SW.
Otro de estos principios es promover el diseño modular. La modularilidad es la
propiedad del sistema de haberse descompuesto en un conjunto de módulos cohesivos y
débilmente acoplados. En UML se emplea la vista de gestión del proyecto para la
aplicación de la modularidad. Con un doble motivo: a) organización de las tareas entre
los desarrolladores que van a participar en el proyecto y b) diseño de componentes
altamente cohesivas y con bajo acoplamiento.

160 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Ejemplo 6.5

Visión arquitectónica o de gestión de la aplicación de Respuesta en


Frecuencia.

Los paquetes se deben de diseñar de forma altamente cohesiva y con bajo


acoplamiento. Esta tarea también servirá para la organización del trabajo entre los
desarrolladores de la aplicación.

En la práctica, el nivel de cohesión no se puede considerar de manera aislada a


otras responsabilidades y a otros principios como son los patrones Experto y Bajo
Acoplamiento.

Beneficios:

 Se incrementa la claridad y facilita la comprensión del diseño

 Se simplifica el mantenimiento y las mejoras

 Se soporta a menudo bajo acoplamiento

 El grano fino de funcionalidad altamente relacionada incrementa la


reutilización. Un paquete o clase altamente cohesiva puede ser aplicado en
otro contexto.

6.3.4 Bajo Acoplamiento

Pregunta: ¿Cómo soportar el bajo impacto del cambio e incrementar la


reutilización?

Dpto. Electrónica, Automática e Informática Industrial 161


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Solución: Asignar una responsabilidad de manera que el acoplamiento


permanezca bajo.

El acoplamiento es una medida de la fuerza con que un elemento está conectado


a otros elementos.

Una clase con alto acoplamiento confía en muchas otras clases. Tales clases
suelen ser no deseables. Estas clases adolecen de los siguientes problemas:

 Son difíciles de mantener de manera aislada.

 Los cambios en estas clases fuerzan cambios locales.

 Son difíciles de reutilizar.

Ejemplo 6.6

Un simulador de sistemas LTI-SISO requiere para su definición la FDT del


sistema. Por tanto, se puede emplear las clases de FDT y Polinomio que se han definido
en la Respuesta en Frecuencia para esta otra aplicación. Una definición de clases
altamente cohesivas y de bajo acoplamiento muestra su facilidad de reutilización.

En general, las clases que son muy genéricas y con una alta probabilidad de
reutilización alta, deberían de tener un acoplamiento especialmente bajo. Por ejemplo,
en el anterior ejercicio, se ha colocado las clases Polinomio y FDT para una aplicación
de Simulación que habían sido definidas en Respuesta en Frecuencia. Ambas se
caracterizan por un Bajo Acoplamiento.

No suele ser problema el acoplamiento alto entre objetos estables y elementos de


generalización. Se entiende como objetos estables aquellos que provienen de las
librerías estándar, tales como las STL o el uso de frameworks como las MFC o las Qt.

6.3.5 Controlador

Problema: ¿Quién debe ser el responsable de gestionar un evento de entrada al


sistema?

162 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Solución: Asignar la responsabilidad a una clase que represente una de las


siguientes opciones:

 Representa el sistema global, dispositivo o subsistema. Se le llamará


Controlador de Fachada.

 Representa un escenario de caso de uso. A menudo se denominan


Coordinador o Manejador o Sesión acompañado con el nombre del caso de
uso. Utilice la misma clase controlador para todos los eventos del sistema en
el mismo escenario de caso de uso.

Un controlador es un objeto que no pertenece al interfaz o vista, responsable de


recibir o manejar los eventos del sistema. Un controlador define un método para cada
operación del sistema. Sus servicios pueden ser establecidos a partir del Diagrama de
Secuencia del Sistema, DSS, o de los contratos de operación.

El controlador es una especie de fachada del paquete que recibe los eventos
externos y organiza las tareas. No sólo el interfaz genera eventos, también puede
hacerlo el tiempo, si es una aplicación en tiempo real. Otro caso son las aplicaciones de
control de procesos; los sensores y/o dispositivos generan interrupciones que se deben
de atender. Cada uno de estos eventos debería ser mandado al correspondiente
Coordinador.

Un error típico del diseño de los controladores es otorgarles demasiadas


responsabilidades. Normalmente, un controlador debería delegar en otros objetos el
trabajo que se necesita hacer, coordinar o controlar la actividad. No realiza mucho
trabajo por sí mismo.

La primera categoría de controlador es el controlador de fachada que representa


al sistema global, dispositivo o subsistema. Los controladores de fachada son adecuados
cuando no existen “demasiados” eventos del sistema. Si se elige un controlador de casos
de uso, entonces hay un controlador diferente para cada caso de uso.

Antiguamente se empleaban los conceptos de objetos frontera, objetos entidad y


objetos control. Precisamente los objetos control eran los manejadores de los casos de
uso y que se describen en este patrón. Las otras dos categorías pertenecían a los que se
relacionaban con la vista (frontera) y a los objetos del dominio (entidad).

Resumiendo, el controlador recibe la solicitud del servicio desde una capa


superior y coordina su realización, normalmente delegando a otros objetos, aumentando
el potencial para reutilizar. Se asegura que la lógica de la aplicación no se maneja en la
capa interfaz. También el controlador o coordinador sirve para analizar la “máquina de
estado” del sistema o de caso del uso, según sea el tipo.

Un corolario importante del patrón Controlador es que los objetos interfaz no


deberían ser responsables de manejar los eventos del sistema. Este patrón
incrementa el potencial de reutilización.

Dpto. Electrónica, Automática e Informática Industrial 163


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

El patrón Controlador crea un objeto artificial que no procede del análisis del
dominio. Se dice que es una Fabricación Pura, detalle que se analizará más adelante. La
implementación del Controlador hace uso de los patrones GRASP de Fabricación Pura
y de Indirección.

Signos de un controlador saturado:

 Existe una única clase controlador que recibe todos los eventos del sistema.

 El propio controlador realiza muchas de las tareas necesarias para llevar a


cabo los eventos del sistema, sin delegar trabajo. Lleva a la ruptura de los
patrones del Experto y Alta cohesión.

 Un controlador tiene muchos atributos y mantiene información significativa


sobre el sistema o el dominio.

Remedios:

1. Añadir más controladores.

2. Delegar las tareas a otros objetos.

3. Este patrón está relacionado con el patrón Comand [GoF],


Fachada [GoF], Capas [POSA] y Fabricación Pura [GRASP].

Ejemplo 6.7

Emplear un Coordinador para la aplicación de Respuesta en Frecuencia


que organice las tareas del escenario de caso de uso y que delegue las tareas.

164 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Informática Industrial" Carlos Platero.


// Ver permisos en licencia de GPL
#include "../../include/Dominio/CoordinadorFrecELAI.h"
int CoordinadorFrecELAI::ponerCircuito(tipoFiltro elTipo,float resistencia,
float condensador)
{
pFiltro = new FiltroLineal(elTipo,resistencia,condensador);
return(0);
}
int CoordinadorFrecELAI::ponerParamResFr(float frInicio,float frFinal,
float frIntervalo)
{
if (pFiltro == NULL) return (-1);
pRespFr = new RespuestaFrecuencia(frInicio,frFinal,frIntervalo,pFiltro);
return(0);
}
int CoordinadorFrecELAI::getModuloRespFr(std::vector<double> &elVectorModulo)
{
if (pRespFr == NULL) return (-1);
pRespFr->getModuloRespFr(elVectorModulo);
if(pFiltro) delete pFiltro;
if(pRespFr) delete pRespFr;
return (0);
}

6.3.6 /*coordinador.cpp*/
Polimorfismo

Problema: ¿Cómo manejar las alternativas basadas en tipo?, ¿Cómo crear


componentes software conectables (pluggable)? o ¿Cómo se puede sustituir un
componente servidor por otro, sin afectar al cliente?

Dpto. Electrónica, Automática e Informática Industrial 165


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Solución: Cuando las alternativas o comportamientos relacionados varían según


los tipos de los datos se debe de asignar la responsabilidad utilizando operaciones
polimórficas, de forma que varíe el comportamiento según el tipo. No hay que realizar
comprobaciones acerca del tipo del objeto. No se requiere emplear la lógica condicional
para llevar a cabo alternativas diferentes basadas en el tipo.

Si en un diseño se emplea las sentencias lógicas de bifurcación if-else o switch-


case, cada nueva variación requiere la modificación de esta lógica. Este enfoque
dificulta que el programa se extienda con facilidad.

El polimorfismo trata de asignar el mismo nombre de servicio pero con


diferentes objetos. El polimorfismo es un principio fundamental para designar cómo se
organiza el sistema para gestionar variaciones similares. Según el polimorfismo un
diseño basado en la asignación de responsabilidades puede extenderse fácilmente para
manejar nuevas variaciones.

Los desarrolladores diseñan sistemas con interfaces y polimorfismos para futuras


necesidades frente a posibles variaciones desconocidas. Esta forma de actuar se
analizará en el patrón de Variaciones Protegidas.

Beneficios:

 Se añaden fácilmente las extensiones necesarias para nuevas variaciones.

 Las nuevas implementaciones se pueden introducir sin afectar a los clientes.

6.3.7 Indirección

Problema: ¿Donde asignar una responsabilidad, para evitar el acoplamiento


directo entre dos o más lógicas de la aplicación?, ¿Cómo desacoplar los objetos de
manera que se soporte el Bajo Acoplamiento y el potencial de reutilización permanezca
alto?.

Solución: Asignar la responsabilidad a un objeto intermedio entre dos o más


elementos o paquetes de manera que no se acoplen directamente.

Algunos patrones como Adaptador (GoF), Controlador (GRASP), Observador


(GoF) y muchas Fabricaciones Puras se generan debido a la Indirección. El motivo de la
Indirección normalmente es el Bajo Acoplamiento y la Alta Cohesión. Se añade un
intermediario para desacoplar los servicios.

Beneficios:

 Disminuir el acoplamiento entre componentes y/o paquetes

166 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Patrones relacionados: Variaciones Protegidas, Bajo Acoplamiento, muchos


patrones GoF.

La mayoría de los intermediarios de Indirección son Fabricaciones Puras.

Ejemplo 6.9

En los programas de simulación donde los objetos cambian de dinámica


al chocar con otros objetos, ¿cómo se asignarían las responsabilidades?.
Supóngase que se desea simular cómo una esfera en caída libre es arrojada
desde una cierta altura respecto al suelo.

Suelo y Esfera son clases conceptuales y por tanto candidatas a ser clases de
diseño. Para evitar el acoplamiento entre ambas clases se añade un grado de indirección.
Se creará una clase interacción que resuelva la responsabilidad de la interacción entre
las instancias de las dos clases.

6.3.8 Fabricación Pura

Problema: ¿Qué objetos deberían de tener las responsabilidades cuando no se


quiere romper los objetivos de Alta Cohesión y Bajo Acoplamiento, pero las soluciones
que ofrece el Experto no son adecuadas?

Solución: Asignar responsabilidades altamente cohesivas a una clase artificial o


de conveniencia que no represente un concepto del dominio del problema. Algo
inventado para soportar Alta Cohesión, Bajo Acoplamiento y Reutilización.

El diseño de objetos se puede dividir, en general, en dos grandes grupos

1. Los escogidos de acuerdo a una descomposición de la representación.

2. Los seleccionados según una descomposición del comportamiento.

La descomposición en representación se emplea ya que favorece el objetivo de


salto en la representación reducida. En la descomposición por comportamiento se asigna
responsabilidades agrupando comportamientos sin estar relacionado con un concepto
del dominio del mundo real. En el caso de la aplicación Respuesta en Frecuencia, las
clases Polinomio, FDT, FiltroLineal, RespuestaFrecuencia están basadas en una

Dpto. Electrónica, Automática e Informática Industrial 167


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

descomposición de la representación del universo del problema. En cambio, la clase


CoordinadorRespuestaFrELAI está tomada como una descomposición del
comportamiento.

Véase el siguiente problema: el almacenamiento de instancias en una base de


datos. El Experto en Información decidiría que estuviera donde están los datos. Sin
embargo, rompería los patrones de Alta Cohesión y Bajo Acoplamiento, ya que quiebra
la separación de la lógica del problema de la lógica de la base de datos. La solución es
crear una nueva clase que sea capaz de almacenar los objetos en algún tipo de
almacenamiento persistente; al que se llamará Almacenamiento Persistente. Esta clase
no es parte del dominio, sino algo creado artificialmente o fabricado para facilitar las
cosas al desarrollar el software.

Ejemplo 6.10

Guardar la información de la respuesta en frecuencia en un fichero.

Para mantener alta la cohesión y no romper la lógica del dominio con el de la


base de datos se emplea una Fabricación Pura. Empleando un grado de Indirección se
introduce la clase AlmacenamientoPersistente. Ésta se encargará de guardar la
información en disco. También habrá que añadir este nuevo servicio al Coordinador.

168 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
#include "../../include/Dominio/AlmacenamientoPersistente.h"

AlmacenamientoPersistente::AlmacenamientoPersistente(RespuestaFrecuencia *pRespFr,
const char * pNomFich)
{
ofstream os(pNomFich);
os <<"Modulo de la respuesta en frecuencia"<<endl;
float fr;
for (fr = pRespFr->getFrInicio();fr <= pRespFr->getFrFinal();
fr+=pRespFr->getFrIntervalo())
os << fr << " :" << pRespFr->getModulo(fr)<<endl;
}

int CoordinadorFrecELAI::guardarResultadosRespFr(const char *pNomFich)


{
if (pRespFr == NULL) return (-1);
AlmacenamientoPersistente elAlmacen(this->pRespFr,pNomFich);
return (0);
}

Muchos de los patrones del DOO que se van a ver son ejemplos de Fabricación
Pura: Adaptador, Estrategia, Observador, etc. También lo es el Controlador (GRASP) o
Fachada (GoF).

Tiene como beneficio el Bajo Acoplamiento y la Alta Cohesión. Usualmente,


una Fabricación Pura asume responsabilidades de las clases del dominio a las que se les
asignaría esas responsabilidades en base al patrón Experto; pero que no se las da, debido
a que disminuiría en cohesión y aumentaría la dependencia.

La Fabricación Pura emplea el patrón de Indirección, al asignar a una clase


artificial o de comportamiento, las responsabilidades de una clase del dominio para
evitar el acoplamiento y mantener alta la cohesión.

Ejemplo de Fabricación Pura:

 Guardar información en una base de datos.

Dpto. Electrónica, Automática e Informática Industrial 169


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

 Separar la lógica del dominio de la vista (Observador-GoF).

 Coordinador o fachada.

6.3.9 Variaciones Protegidas

Problema: ¿Cómo diseñar objetos, subsistemas y sistemas de manera que las


variaciones e inestabilidades en estos elementos no tengan un impacto negativo en otros
elementos?

Solución: Identifique los puntos de variaciones previstas e inestabilidad; asigne


responsabilidades para crear una interfaz estable alrededor de ellos. Añadiendo
Indirección, Polimorfismo y una interfaz se consigue un sistema de Variaciones
Protegidas, VP. Las distintas implementaciones del componente y/o paquete ocultan las
variaciones internas a los sistemas clientes de éste. Dentro del componente, los objetos
internos colaboran en sus tareas con una interfaz estable.

El principal objetivo de este patrón es proteger a los clientes de las variaciones


de mejoras de los servicios dados por el componente servidor. Para tal fin se define los
puntos calientes y a éstos se les cubre con una interfaz estable, permitiendo variar el
componente sin interferir en las aplicaciones clientes.

Hay que distinguir dos tipos de variaciones:

 Puntos de variación: variaciones en el sistema actual.

 Puntos de evolución: puntos especulativos de variación que podrían


aparecer en el futuro, pero que no están presentes en los requisitos
actuales.

La aplicación de Variaciones Protegidas tiene un esfuerzo de diseño que siempre


hay que considerar. Si la necesidad de flexibilidad y protección de cambios es realista,
entonces está motivada la aplicación de VP. Un diseño debe ser un compromiso entre el
coste de cambio y su probabilidad.

La mayoría de los patrones y principios de diseño son mecanismos para


Variaciones Protegidas, entre los que se encuentran: Polimorfismo, Indirección,
Encapsulamiento y la mayoría de los patrones GoF.

Ejemplo 6.11

Realizar una aplicación que calcule el área de figuras geométricas. En


esta primera versión sólo se considera círculos y rectángulos.

170 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Debido a que el programa debe de crecer, el concepto de Figura debe ser


aplicado de forma genérica (interfaz). Se utiliza un punto de variación. De otro lado, la
subclase concreta se cargará dependiendo de la elección del usuario. Se empleará un
Método de Fabricación GoF (se verá más adelante).

Dpto. Electrónica, Automática e Informática Industrial 171


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

#ifndef _AREAS_FIGURA_INC_
#define _AREAS_FIGURA_INC_
typedef enum tipoFig {CIRCULO, RECTANGULO} tipoFigura;
class IFiguras
{
public:
virtual double getArea() = 0;
static IFiguras* MetodoFabricacionFiguras
(tipoFigura, double, double);
};
class Circulo: public IFiguras
{
double radio;
friend class IFiguras;
Circulo(double param1):radio(param1) {}
public:
virtual double getArea()
{return (3.1416*radio*radio);}
};

class Rectangulo: public IFiguras


{
double lado1;
double lado2;
friend class IFiguras;
Rectangulo(double param1, double param2):
lado1(param1),lado2(param2) {}
public:
virtual double getArea()
{return (lado1*lado2);}
};

#endif

IFiguras* IFiguras::MetodoFabricacionFiguras(tipoFigura elTipo,


double param1,double param2 = 0)
{
if (elTipo == CIRCULO) return new Circulo(param1);
else if(elTipo == RECTANGULO) return new Rectangulo(param1,param2);
else return 0;

}//////////////////////////////////////////////////////////////////////////

void CAreasFiguraDlg::OnCalcular()
{
UpdateData(TRUE);
IFiguras *pFigura= IFiguras::MetodoFabricacionFiguras(
this->m_Figura == true ? CIRCULO : RECTANGULO,
this->m_Param1,this->m_Param2);

this->m_Area = pFigura->getArea();
delete pFigura;
UpdateData(FALSE);

Otra aplicación de Variaciones Protegidas está en los intérpretes de líneas de


comando (script). El cliente tiene su sintaxis que se mantiene aunque varíe el servidor.
Hay muchos sistemas que ofrecen una línea de comandos para interactuar con él. Por
ejemplo, se podría pensar en Matlab. Es conocido que los comandos de las versiones

172 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

anteriores se pueden usar en las nuevas. El cliente las utiliza pero no sabe si éstas han
sido mejoradas. Más aun, los desarrolladores confían en estos servicios y crean
aplicaciones, de más alto nivel, basadas en ellas.

Ejemplos de Variaciones Protegidas


 Las máquinas virtuales son ejemplos complejos de Indirección para
conseguir VP.
 Lectura y escritura de datos de sistemas externos.
 Diseños dirigidos por un intérprete.

Ejemplo 6.12
El código entregado corresponde con la implementación del patrón
comando, de manera que encapsula un objeto y el cliente lo ve como si fuese
una función (muy utilizado en lenguajes script). Se pide:
1. Ingeniería inversa: Diagrama de clases.
2. Ingeniería inversa: Diagrama de secuencias de la función main().
3. Resultado de su ejecución en la consola.
4. Indicar los patrones GRASP empleados en este patrón.
5. Diseñar e implementar la clase Saludo, de manera que se
despida al añadirse al macro.
#include <iostream>
#include <vector>
using namespace std;

class Comando
{
public:
virtual void ejecutar() = 0;
};

class Hola : public Comando


{
public:
void ejecutar() { cout << "Hola "; }
};

class Mundo : public Comando


{
public:
void ejecutar() { cout << "Mundo! "; }
};

class Patron : public Comando


{
public:
void ejecutar() { cout << "Soy el comando patron!"; }
};

class Macro
{
vector<Comando*> Comandos;
public:
void incluir(Comando* c) { Comandos.push_back(c); }
void realizar() {
for(int i=0;i<Comandos.size();i++)
Comandos[i]->ejecutar();
}
};

int main()
{
Macro macro;
macro.incluir(new Hola);
macro.incluir(new Mundo);
macro.incluir(new Patron);
macro.realizar();
}

Dpto. Electrónica, Automática e Informática Industrial 173


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

1.

2.

3. Hola Mundo! Soy el comando patron!

4. El patrón Comando emplea Variaciones Protegidas (GRASP), de forma


que el cliente no ve las modificaciones que está realizando el
servidor.

174 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

5.

class Saludo : public Comando


{
public:
void ejecutar() { cout << " Un saludo. "; }
};

La sostenibilidad depende de las VP. Estas aplicaciones se basan en el principio


de sustitución de Liskov:

“El software que hace referencia a un tipo T debería de trabajar correctamente


con cualquier implementación o subclase T que la sustituya”.

Por otro lado, uno de los patrones antiguos GRASP era “No hable con
Extraños” o Ley de Demeter. Este patrón incide en evitar crear diseños que recorran
largos caminos de la estructura de los objetos. No se podía enviar mensajes a objetos
distantes, indirectos o extraños. Tales diseño son frágiles con respecto a los cambios en
las estructuras de los objetos.

No hable con Extraños establecía que un método, sólo, debería enviar mensajes
a los siguientes objetos:

1. A él mismo (objeto this).

2. A un parámetro de un servicio propio.

3. A un atributo de él.

4. A una colección de él.

5. A un objeto creado en un método propio.

La intención es evitar el acoplamiento entre un cliente con objetos indirectos.

Beneficios de No hable con Extraños:

Dpto. Electrónica, Automática e Informática Industrial 175


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

 Se añaden fácilmente las extensiones que se necesitan.

 Se puede introducir nuevas implementaciones sin afectar a los


clientes.

 Se reduce el acoplamiento.

 Se puede disminuir el impacto o coste de los cambios.

Hay que saber escoger las batallas. En sistemas maduros, la estructura es más
estable y se puede hablar con extraños. En cambio, en sistemas nuevos es recomendable
utilizar este antiguo patrón GRASP 3. Si se emplea Variaciones Protegidas es posible no
utilizar el patrón No hable con Extraños.

3
Para los programadores noveles se aconseja utilizar este patrón. Empléese en el trabajo de curso.

176 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

6.4 Patrones de diseño GoF

Uno de los hitos más importantes en el diseño orientado a objetos fue la


publicación del libro “Design Patterns” por Gamma, Helm, Johnson y Vlissides en
1995; conocidos como “Gang of Four”, GoF. En este libro se muestran 23 patrones
ampliamente utilizados. En este apartado se tratarán algunos de ellos.

6.4.1 Adaptador

Problema: ¿Cómo resolver interfaces incompatibles, o proporcionar una interfaz


estable para componentes parecidos con diferentes interfaces?

Solución: Convierta la interfaz original de una componente en otra, mediante un


objeto adaptador intermedio.

El propósito de este patrón es convertir la interfaz de una clase en otra interfaz


que es la que esperan los clientes. Este patrón permite que cooperen clases que de otra
forma no podrían colaborar por no tener compatibilidad entre ellas.

Debería usarse el patrón Adaptador cuando:

 Se quiere utilizar una clase existente y su interfaz no concuerda con lo


que se espera.

 Se quiere crear una clase reutilizable que coopere con clases no


relacionadas o que no han sido previstas, i.e. clases que no tienen por qué
tener interfaces compatibles.

Los participantes en este patrón realizan los siguientes roles:

 Objetivo: define los servicios del dominio que usa el cliente. Representa
un interfaz estable con los servicios tal cual espera el cliente.

 Cliente: utiliza los servicios del paquete a través del interfaz Objetivo.

 Adaptable: Implementa los servicios del paquete.

 Adaptador: adapta la interfaz de Adaptable a la interfaz Objetivo.

Dpto. Electrónica, Automática e Informática Industrial 177


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Los clientes llaman a operaciones a través de la interfase estable. A su vez el


adaptador llama a operaciones de Adaptable que son las que satisfacen las peticiones.

En una implementación en C++ de un adaptador de clases, Adaptador debería


heredar públicamente de objetivo y tener como atributo privado a un objeto de la clase
Adaptable.

Nótese que los nombres de los tipos incluyen el nombre de patrón “Adaptador”.

La aplicación del Adaptador es una especialización de Variaciones Protegidas,


Indirección y Polimorfismo. En GRASP es el polimorfismo, aquí es una especialización
que se llama Adaptador. Se puede analizar muchos patrones más complejos y
especializados en función de la familia GRASP. Existen muchos publicados y es el
alfabeto del DOO.

Ejemplo 6.13

La aplicación de Respuesta en Frecuencia no depende sólo del


algoritmo de calcular el módulo y argumento de un filtro, sino también de su
visualización en un diagrama de Bode. Realizar un diseño para el paquete de
representación gráfica.

Tal cual se presentó en la vista de gestión, la aplicación tenía un paquete para la


visualización del diagrama de Bode. Se había elegido una solución basada en software
prefabricado (ActiveX).

178 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Entre las posibles soluciones tecnológicas actuales se ha elegido NTGraph4. En


un diseño robusto, esta inserción supone un punto caliente. Por varios motivos:

 En el futuro se puede cambiar de componente, i.e. salto a otra nueva


tecnología.

 Ampliación de nuevos servicios en la representación del diagrama de


Bode.

La aplicación de Variaciones Protegidas supone, de momento, el uso de patrones


GoF: Adaptador y Factoría; mientras en GRASP implica Indirección, Polimorfismo y
Fabricación Pura.

4
http://www.codeproject.com/miscctrl/ntgraph_activex.asp

Dpto. Electrónica, Automática e Informática Industrial 179


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

// De: "Apuntes de Sistemas Informáticos Industrial" Carlos Platero.


// Ver permisos en licencia de GPL

#include "../../ntgraph.h"

//Tipos de visualizadores
enum PlataformaVisual{NTGRAPH} ;

class IAdaptadorVisualizar
{
public:
virtual void InicializarPlotXY(void) = 0;
virtual void PintarPlotXY(float,float,float, double *)= 0;
//Factoria de Visualizadores
static IAdaptadorVisualizar *factoriaVisualizadores(enum PlataformaVisual,
CNTGraph *p1 = NULL);

};

class AdaptadorVisualCNTGraph : public IAdaptadorVisualizar


{
CNTGraph *graph;
AdaptadorVisualCNTGraph(CNTGraph *gr): graph(gr){}
friend class IAdaptadorVisualizar;
public:
virtual void InicializarPlotXY(void);
virtual void PintarPlotXY(float,float,float, double *);
};

180 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Ejemplo 6.14

Las series de Fibonacci se hicieron famosas en la Edad Media por que


planteó el problema de procreación de los conejos de manera formal. Estudió
que si se partía de una pareja de conejos cómo éstos se multiplicaban con el
tiempo. La solución se encuentra en la Serie de Fibonacci. Ésta se construye
con la suma de los dos últimos valores. Los dos primeros términos de la serie
son el 1 y el 1. Los demás se obtienen con la regla mencionada, la suma de los
valores anteriores:

Fn  Fn 1  Fn  2

1 1 2 3 5 8 13 21 ...

Un generador de la serie de Fibonacci ha sido tomado de Bruce Eckel y


Check Allison5. Adaptarlo para emplear los algoritmos dados por las STL.

// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#ifndef FIBONACCIGENERATOR_H
#define FIBONACCIGENERATOR_H

class FibonacciGenerator {
int n;
int val[2];
public:
FibonacciGenerator() : n(0) { val[0] = val[1] = 1; }
int operator()() {
int result = n > 2 ? val[0] + val[1] : 1;
++n;
val[0] = val[1];
val[1] = result;
return result;
}
int count() { return n; }
};

#endif // FIBONACCIGENERATOR_H ///:~

Se trata de diseñar un adaptador que permita utilizar los algoritmos dados por las
STL como for_each( ) o accumulate(). Estos servicios requieren que la información esté
preparada como un tipo vector de las STL, std::vector<>. Para tal fin, se emplea el
patrón Adaptador:

5
"Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. (c) 1995-2004
MindView, Inc.

Dpto. Electrónica, Automática e Informática Industrial 181


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Se emplea el siguiente código de test:

182 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Las clases de los roles objetivo y adaptador quedarán definidas como:

// De: "Apuntes de Sistemas Informáticos Industriales" Carlos Platero.


// Ver permisos en licencia de GPL
//
// Ejemplo de adaptador GoF entre el generador de Fibonacci
// y las librerías STL
#ifndef _ADAPTADOR_FIBO_INC_
#define _ADAPTADOR_FIBO_INC_

#include <vector>
#include "FibonacciGenerator.h"

class IAdaptadorFibonacci
{
public:
virtual std::vector<unsigned> & getSerie() = 0;
static IAdaptadorFibonacci *factoriaFibonacci(unsigned grado);
};

class AdaptadorFibonacci: public IAdaptadorFibonacci


{
FibonacciGenerator f;
unsigned tamanyo;
std::vector<unsigned> elVectorFibon;
friend class IAdaptadorFibonacci;
AdaptadorFibonacci(unsigned num): tamanyo(num)
{
for (unsigned i=0;i<=tamanyo;i++)
elVectorFibon.push_back(f());
}
public:

virtual std::vector<unsigned> & getSerie()


{return elVectorFibon;}
};

#endif

El cliente, ahora, podrá emplear al generador de la serie de Fibonacci utilizando


las funciones algorítmicas de las STL.

Dpto. Electrónica, Automática e Informática Industrial 183


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

6.4.2 Factoría

Problema: ¿Quién debe ser responsable de la creación de los objetos cuando


existen consideraciones especiales, como una lógica de creación compleja, el deseo de
separar las responsabilidades de la creación para manejar la cohesión, etc.?

Solución: Crear un objeto de Fabricación Pura denominado Factoría que maneje


la creación.

Cuando aparece una nueva variación del tipo de los datos se aplica el patrón
Polimorfismo [GRASP], tal cual se comentó en el apartado 6.3.6. Al principio parece
que sólo es necesario implementarlo en el punto de la aplicación que se introduce la
variación. Sin embargo, mayoritariamente sucede que además se requiere un constructor
para la nueva variación y su repercusión se extiende por todo el código. Para estos casos
se debe aplicar Variaciones Protegidas. Por tanto, se considera la creación de un punto
de variación o punto caliente y se coloca una interfase estable a través del
Polimorfismo, la Indirección y el Adaptador. La construcción de estos objetos deben ser
forzados a ser creados en una única Factoría.

Por ejemplo, cuando al aplicar Variaciones Protegidas y Adaptador sobre la


representación en el diagrama de Bode de la aplicación Respuesta en Frecuencia, ¿quién
crea el adaptador de NTGraph? ¿Y cómo determinar qué clase de adaptador crear?. Si
los creará algún objeto del dominio, estas responsabilidades exceden de la pura lógica
de la aplicación y entra en otras cuestiones relacionadas con la conexión con
componentes de software externos.

Este punto subraya otro principio de diseño fundamental: mantener siempre una
separación de intereses. La elección de un objeto del dominio para crear los adaptadores
no está de acuerdo con los objetivos de separación de intereses. Además disminuye su
cohesión. La lógica de qué clase Adaptador se instancia es resuelto en la Factoría,
leyendo una fuente externa y después cargando la clase dinámicamente.

Una alternativa típica en este caso es aplicar el patrón Factoría. Los objetos
Factoría tienen varias ventajas:

 Separación de responsabilidades en la creación compleja en objetos de apoyo


cohesivo.

 Ocultan la lógica de creación potencialmente compleja.

 Permite introducir estrategias para mejorar el rendimiento de la gestión de la


memoria, como objetos caché o de reciclaje.

El cliente sólo utilizará las interfases de sus paquetes servidores, dejando que sea
la lógica externa quien decida sobre la implementación y la factoría quien crea los
objetos que implementan los servicios. A este patrón GoF se le llama Factoría Abstacta.
Se empleará cuando:

184 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

 un sistema debe ser independiente de cómo se crean, componen y


representan sus productos.

 un sistema debe ser configurado como una familia de productos entre


varias.

 quiere proporcionar una biblioteca de clases de productos y sólo quiere


revelar sus interfaces, no sus implementaciones.

La estructura del patrón queda reflejada en el siguiente diagrama de clases:

Los roles desempeñados son:

 Cliente: sólo usa interfaces declarados por las clases de Fabricación


Abstracta y Productos Abstractos

 Producto Abstracto: declara una interfaz para un tipo de objeto (p.ej.


IClaseA)

 Producto Concreto: define un objeto producto para que sea creado por la
Factoría correspondiente. Implementa la interfaz de Producto Abstracto.

 Factoría Abstracta: declara una interfaz para operaciones que crean


objetos productos abstractos

 Factoría Concreta: implementa las operaciones para crear objetos


producto concretos

Dpto. Electrónica, Automática e Informática Industrial 185


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Ejemplo 6.15

Se pretende simular el evento de sacar de una bolsa un


tornillo y una tuerca y saber si se pueden ensamblar. La bolsa
puede contener tornillos y tuercas de diferentes métricas.
Hágase para el caso concreto de elementos DIN84 y DIN316.

Se diseñará de manera que el cliente sólo utilice el concepto de


tornillos y tuercas. La responsabilidad de saber si pertenece a la misma
métrica quedará a los objetos concretos creados por las factorías
abstractas. El diseño sería:

186 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

typedef enum{DIN84, DIN316} metrica;


class FactoriaTuercas;
class ITuerca
{
public:
virtual metrica getMetrica() = 0;

};
class TuercaDIN84 : public ITuerca
{
metrica laMetrica;
friend class FactoriaTuercas;
TuercaDIN84() {laMetrica = DIN84;}
public:
virtual metrica getMetrica() {return laMetrica;}
};
class TuercaDIN316 : public ITuerca
{
metrica laMetrica;
friend class FactoriaTuercas;
TuercaDIN316() {laMetrica = DIN316;}
public:
virtual metrica getMetrica() {return laMetrica;}

};

class FactoriaTornillos;
class ITornillo
{
public:
virtual metrica getMetrica() = 0;
};
class TornilloDIN84 : public ITornillo
{
metrica laMetrica;
friend class FactoriaTornillos;
TornilloDIN84() {laMetrica = DIN84;}
public:
virtual metrica getMetrica() {return laMetrica;}
};
class TornilloDIN316 : public ITornillo
{
metrica laMetrica;
friend class FactoriaTornillos;
TornilloDIN316() {laMetrica = DIN316;}

public:
virtual metrica getMetrica() {return laMetrica;}

};

Dpto. Electrónica, Automática e Informática Industrial 187


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

class IFactoria
{
public:
virtual ITornillo * fabricacionTornillo(metrica) = 0;
virtual ITuerca * fabricacionTuerca(metrica) = 0;
};
class FactoriaTornillos : public IFactoria
{
public:
virtual ITornillo * fabricacionTornillo(metrica laMetrica)
{
if(laMetrica == DIN84) return new TornilloDIN84;
else if (laMetrica == DIN316) return new TornilloDIN316;
else return 0;
}
virtual ITuerca * fabricacionTuerca(metrica laMetrica)
{return 0;}
};
class FactoriaTuercas: public IFactoria
{
public:
virtual ITornillo * fabricacionTornillo(metrica laMetrica)
{return 0;}

virtual ITuerca * fabricacionTuerca(metrica laMetrica)


{
if(laMetrica == DIN84) return new TuercaDIN84;
else if (laMetrica == DIN316) return new TuercaDIN316;
else return 0;
}
};

#include "IFactoria.h"
#include <iostream>
#include <stdlib.h>

int main()
{
IFactoria *pFactoriaTornillos = new FactoriaTornillos;
IFactoria *pFactoriaTuercas = new FactoriaTuercas;
std::cout<<"Simulacion de sacar tornillo y tuerca de forma aleatoria" <<std::endl;
std::cout<<"La bolsa contiene tornillos y tuercas DIN84 y DIN316"<<std::endl;
std::cout<<"Pulsar c o C para sacar tornillo y tuerca"<<std::endl;
char opcion; std::cin>> opcion;
while(opcion == 'c' || opcion == 'C') {
ITornillo *pTornillo =
pFactoriaTornillos->fabricacionTornillo(rand() % 2 == 1 ? DIN84 : DIN316);
ITuerca *pTuerca =
pFactoriaTuercas->fabricacionTuerca(rand() % 2 == 1 ? DIN84 : DIN316);
if(pTornillo->getMetrica() == pTuerca->getMetrica()){
char *mensaje = pTuerca->getMetrica() == DIN84 ? "DIN84" : "DIN316";
std::cout<<"Ensamblaje correcto: metrica " << mensaje <<std::endl;
}else
std::cout<<"Ensamblaje incorrecto" << std::endl;

std::cout<<"Pulsar c o C para sacar tornillo y tuerca"<<std::endl;


std::cin>> opcion;
delete pTornillo, pTuerca;
}
delete pFactoriaTornillos, pFactoriaTuercas;
return 0;
}

Para la elaboración de las Factorías se emplea el patrón Método de Fabricación


(GoF). Se define una interfaz de factoría para crear los objetos, pero se deja que sean los
métodos de fabricación quien instancia las subclases. Se utiliza cuando:

188 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

 una clase no puede prever la clase de objetos que debe crear.

 una clase quiere que sean sus subclases quienes especifiquen los objetos que ésta
crea.

 las clases delegan la responsabilidad en una de entre varias clases auxiliares y se


desea localizar qué subclase de auxiliar concreta es en la que se delega.

Los roles que se desempeñan en este patrón son:

 Producto: Interfaz de los objetos que crea el método de fabricación

 ProductoConcreto: Realización de la interfaz Producto

 Factoría: Declara el servicio de MétodoFabricación que retorna un objeto


de tipo producto abstracto

 FactoríaConcreto: redefine el método de fabricación para devolver una


instancia de un ProductoConcreto

La Factoría se apoya en sus subclases para definir el método de fabricación de


manera que éste devuelva una instancia del producto concreto adecuado.

Hay que tener mucho cuidado con la creación con las Factorías. En C++ es el
programador el que debe posteriormente liberar, con posterioridad, el objeto creado en
la factoría.

A menudo se accede a las factorías con el patrón Singleton.

Dpto. Electrónica, Automática e Informática Industrial 189


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Ejemplo 6.16

Realizar una factoría de objetos de Nombres. El cliente utilizará la clase


abstracta INombre y las clases concretas serán empleando std::string, CString
y en estilo C (ver ejemplo 4.4).

Primera solución

Se empleará un diseño basado en Factoría Abstracta. El Cliente sólo utilizará los


interfases para recibir los servicios.

#ifndef _INOMBRE_INC_ // De: "Apuntes de Informática Industrial"


#define _INOMBRE_INC_ // Ver permisos en licencia de GPL
enum Plataforma{ESTANDAR_STL, ESTILO_C, #ifndef _INC_STDNOMBRE_
CADENA_MFC}; #define _INC_STDNOMBRE_

class INombre { #include <string>


public: #include "INombre.h"
virtual void setNombre (const char *) = 0; class FactoriaNombre;
virtual const char * getNombre () = 0; class STDNombre : public INombre
}; {
public:
#endif virtual void setNombre(const char *cadena)
{ elNombre = cadena; }
virtual const char * getNombre (void)
{ return (elNombre.c_str());}
#ifndef _INC_MFCNOMBRE_ private:
#define _INC_MFCNOMBRE_ std::string elNombre;
#include <afx.h> STDNombre () {}
#include "INombre.h" friend class FactoriaNombre;
class FactoriaNombre;
class MFCNombre : public INombre {
public:
};
virtual void setNombre(const char *cadena)
{ elNombre=cadena; } #endif
virtual const char * getNombre (void)
{ return (elNombre);}
private:
CString elNombre;
MFCNombre () {}
friend class FactoriaNombre;
};
#endif

};

#endif
190 Dpto. Electrónica, Automática e Informática Industrial
Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Informática Industrial" // Ver permisos en licencia de GPL


// Ver permisos en licencia de GPL #ifndef _IFACTORIA_INC_
#ifndef _INC_CNOMBRE_ #define _IFACTORIA_INC_
#define _INC_CNOMBRE_
#include "STDNombre.h"
#include <string> #include "CNombre.h"
#include "INombre.h" #include "MFCNombre.h"
class FactoriaNombre;
class CNombre : public INombre { class IFactoriaNombre
public: {
virtual void setNombre(const char *cadena) public:
{ strcpy (elNombre, cadena); } virtual INombre* MetodoFabricacionNombre
(enum Plataforma) = 0;
virtual const char * getNombre (void)
{ return (elNombre);} };
private:
char elNombre[80]; class FactoriaNombre: public IFactoriaNombre
CNombre () {} {
friend class FactoriaNombre; public:
virtual INombre* MetodoFabricacionNombre
}; (enum Plataforma tipo)
{
#endif if(tipo==ESTANDAR_STL)return new STDNombre;
else if(tipo==ESTILO_C) return new CNombre;
else if(tipo==CADENA_MFC) return new
// De: "Apuntes de Informática Industrial" MFCNombre;
// Ver permisos en licencia de GPL else return NULL;
#include <iostream>
#include "../includes/INombre.h"
}
#include "../includes/FactoriaNombres.h" };
#endif
using namespace std;

int main ( void )


{
//Solo utiliza referencias abstractas
IFactoriaNombre *pFactoria = new (FactoriaNombre);
INombre *pNombre1 = pFactoria->MetodoFabricacionNombre (ESTANDAR_STL);
INombre *pNombre2 = pFactoria->MetodoFabricacionNombre (ESTILO_C);
INombre *pNombre3 = pFactoria->MetodoFabricacionNombre (CADENA_MFC);

pNombre1->setNombre("Manolo Gonzalez");
pNombre2->setNombre("Pedro Lopez");
pNombre3->setNombre("Ana Rodriguez");

cout << pNombre1->getNombre() << endl;


cout << pNombre2->getNombre() << endl;
cout << pNombre3->getNombre() << endl;

delete pNombre1, pNombre2, pNombre3;


delete pFactoria;
return 0;
}

Segunda solución:

El método de fabricación se coloca como un servicio estático dentro de la clase


de interfase de Nombre. Para asegurarse de que sólo se utilizará este punto de creación
se ha colocado los constructores privados y se ha declarado a la clase abstracta como
amiga.

Dpto. Electrónica, Automática e Informática Industrial 191


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

// De: "Apuntes de Informática Industrial" // De: "Apuntes de Informática Industrial"


// Ver permisos en licencia de GPL // (R) 2005 Con licencia GPL.
// Ver permisos en licencia de GPL
#ifndef _INOMBRE_INC_ #ifndef _INC_STDNOMBRE_
#define _INOMBRE_INC_ #define _INC_STDNOMBRE_

typedef enum {ESTANDAR_STL, ESTILO_C, #include <string>


CADENA_MFC} tipoTiraCaracteres; #include "INombre.h"

class INombre { class STDNombre : public INombre


public: {
virtual void setNombre (const char *) = 0; public:
virtual const char * getNombre () = 0; virtual void setNombre(const char *cadena)
{ elNombre = cadena; }
//Factoria de objetos virtual const char * getNombre (void)
static INombre *factoriaObjetos { return (elNombre.c_str());}
(tipoTiraCaracteres a);
}; private:
#endif std::string elNombre;
STDNombre () {}//Desactivar al constructor
friend class INombre; // Sólo se fabrica
// De: "Apuntes de Informática Industrial" //desde el método de fabricación
// (R) 2005 Con licencia GPL. };
// Ver permisos en licencia de GPL #endif
#ifndef _INC_STDNOMBRE_
#define _INC_STDNOMBRE_
#ifndef _INC_MFCNOMBRE_
#include <string> #define _INC_MFCNOMBRE_
#include "INombre.h"
#include <afx.h>
class CNombre : public INombre #include "INombre.h"
{
public: class MFCNombre : public INombre
{
virtual void setNombre(const char *cadena) public:
{ strcpy (elNombre, cadena); } virtual void setNombre(const char *cadena)
{ elNombre=cadena; }
virtual const char * getNombre (void) virtual const char * getNombre (void)
{ return (elNombre);} { return (elNombre);}
private: private:
char elNombre[80]; CString elNombre;
}; };
#endif
#endif
};

#endif

192 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Informática Industrial"


// (R) 2005 Con licencia GPL.
// Ver permisos en licencia de GPL

#include <iostream>
#include "../includes/STDNombre.h"
#include "../includes/CNombre.h"
#include "../includes/MFCNombre.h"
//Método único para producir los objetos nombres
INombre* INombre::factoriaObjetos(tipoTiraCaracteres tipo)
{
if(tipo == ESTANDAR_STL) return new STDNombre;
else if(tipo == ESTILO_C) return new CNombre;
else if(tipo == CADENA_MFC) return new MFCNombre;
else return NULL;
}

using namespace std;

int main ( void )


{
INombre *pNombre1 = INombre::factoriaObjetos(ESTANDAR_STL);
INombre *pNombre2 = INombre::factoriaObjetos(ESTILO_C);
INombre *pNombre3 = INombre::factoriaObjetos(CADENA_MFC);

pNombre1->setNombre("Manolo Gonzalez");
pNombre2->setNombre("Pedro Lopez");
pNombre3->setNombre("Ana Rodriguez");

cout << pNombre1->getNombre() << endl;


cout << pNombre2->getNombre() << endl;
cout << pNombre2->getNombre() << endl;

delete pNombre1, pNombre2, pNombre3;


return 0;
}

6.4.3 Singleton

Problema: ¿Cómo garantizar que una clase sólo tenga una instancia y
proporciona un punto de acceso global a ella?.

Solución: Definir un método estático de la clase que devuelva el singleton.

Del uso del patrón Factoría surge un nuevo problema de diseño ¿quién crea a la
Factoría?. Sólo se necesita una única instancia de Factoría y ésta puede ser llamada
desde distintos lugares del código. Una solución sería ir pasando la instancia de Factoría
en los métodos, pero este proceder no es conveniente, ya que implica acoplamiento por
necesitar visibilidad. La solución está en el patrón Singleton.

Ocasionalmente es conveniente mantener visibilidad global o un único punto de


acceso a una única instancia de una clase. Es importante que algunas clases tengan
exactamente una instancia. Por ejemplo, aunque puede haber muchas impresoras, sólo
debería de haber una única cola de impresión. De la misma manera, en aplicaciones de
control de procesos, sólo debería de existir una única instancia para el driver del
convertidor analógico/digital, aunque pudieran existir varios filtros digitales. Son
ejemplos de este problema patrón.

Dpto. Electrónica, Automática e Informática Industrial 193


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

¿Cómo se puede asegurar que una clase tenga una única instancia y que sea
fácilmente accesible?. Una variable global hace accesible a un objeto, pero no se
previene de crear múltiples instancias de esta clase.

Una solución es hacer que sea la propia clase la responsable de su única


instancia. La clase debe garantizar que no se pueda crear ninguna otra instancia y
proporciona un modo de acceder a su instancia.

La clave del Singleton es evitar que el cliente no tenga el control sobre la vida
del objeto. Para tal fin se declaran todos los constructores como privados y se previene
para que el compilador no produzca constructores por defecto ni sobrecarga de
operadores de asignación. Se construye el servicio de tipo estático para obtener la
referencia Singleton, getInstancia(), y también se colocará como estática la propia
referencia. En la notación se puede emplear el estereotipo <<1>> para indicar que sólo
existe una única instancia de esta clase

#include <iostream>
using namespace std;

class Singleton {
int i; //Dato por ejemplo
Singleton(int x) : i(x) { }
void operator=(Singleton&); // Para desactivar
Singleton(const Singleton&); // Para desactivar
public:
static Singleton& getInstancia() {
static Singleton unicaInstancia(47); //P.ej valor 47
return unicaInstancia;
}
int getValor() { return i; }
void setValor(int x) { i = x; }
};
int main() {
Singleton& s = Singleton::getInstancia();
cout << s.getValor() << endl;
Singleton& s2 = Singleton::getInstancia();
s2.setValor(9);
cout << s.getValor() << endl;
return 0;
}

194 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Ejemplo 6.17

Realizar una única factoría de objetos Nombre que sea accesible en


cualquier parte de la aplicación (ver problema 6.12).

// De: "Apuntes de Informática Industrial" Carlos Platero.


// Ver permisos en licencia de GPL
#ifndef _IFACTORIA_INC_
#define _IFACTORIA_INC_

#include "STDNombre.h"
#include "CNombre.h"
#include "MFCNombre.h"

class FactoriaUnicaNombres
{
FactoriaUnicaNombres(){};
void operator=(FactoriaUnicaNombres&); // Para desactivar
FactoriaUnicaNombres(const FactoriaUnicaNombres&); // Para desactivar
public:
static FactoriaUnicaNombres& getInstancia()
{
static FactoriaUnicaNombres unicaInstancia;
return unicaInstancia;
}

INombre* MetodoFabricacionNombre (enum Plataforma tipo)


{
if(tipo == ESTANDAR_STL) return new STDNombre;
else if(tipo == ESTILO_C) return new CNombre;
else if(tipo == CADENA_MFC) return new MFCNombre;
else return NULL;
}
};

#endif

Dpto. Electrónica, Automática e Informática Industrial 195


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

// De: "Apuntes de Informática Industrial" Carlos Platero.


// Ver permisos en licencia de GPL
#include <iostream>
#include "../includes/INombre.h"
#include "../includes/FactoriaUnicaNombres.h"
using namespace std;
int main ( void )
{
//Solo utiliza referencias abstractas
void otrosNombres (void);
FactoriaUnicaNombres &laFactoria = FactoriaUnicaNombres::getInstancia();
INombre *pNombre1 = laFactoria.MetodoFabricacionNombre (ESTANDAR_STL);
INombre *pNombre2 = laFactoria.MetodoFabricacionNombre (ESTILO_C);

pNombre1->setNombre("Manolo Gonzalez");
pNombre2->setNombre("Pedro Lopez");

cout << pNombre1->getNombre() << endl;


cout << pNombre2->getNombre() << endl;

delete pNombre1, pNombre2;


otrosNombres();
return 0;
}

void otrosNombres ( void )


{
//Solo utiliza referencias
FactoriaUnicaNombres &laMismaFactoria = FactoriaUnicaNombres::getInstancia();
INombre *pNombre3 = laMismaFactoria.MetodoFabricacionNombre (CADENA_MFC);

pNombre3->setNombre("Ana Blanco");
cout << pNombre3->getNombre() << endl;

delete pNombre3;
}

6.4.4 Estrategia

Problema: ¿Cómo diseñar algoritmos que están relacionados? ¿Cómo diseñar


que estos algoritmos se puedan variar dinámicamente?

Solución: Defina cada algoritmo o estrategia en una clase independiente, con


una interfaz común.

Este patrón define una familia de algoritmos relacionados, los encapsula y los
hace intercambiables. La consecuencia de esta estructura es la variación dinámica de los
algoritmos sin que los clientes se vean afectados. Los roles de este patrón son:

 Estrategia: declara una interfaz común a todos los algoritmos permitidos.

 Estrategia concreta: implementa el algoritmo concreto usando la interfaz


Estrategia.

196 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

 Contexto: este objeto usa la interfaz Estrategia para llamar al algoritmo concreto
definido por una Estrategia Concreta. Tiene como atributo a un objeto de
Estrategia Concreta, a través de su interfaz.

Un objeto estrategia se agrega a un objeto de contexto, i.e. el objeto contexto


necesita tener visibilidad de atributo de su estrategia. Además es habitual que el objeto
contexto pase una referencia de él al objeto estrategia, de manera que la estrategia tenga
visibilidad de parámetro del objeto contexto para futuras colaboraciones.

Al existir diferentes algoritmos que cambian con el tiempo, la pregunta sería:


¿quién debería de crear la estrategia?. Un enfoque directo es aplicar, de nuevo, el patrón
Factoría. Una Factoría de Estrategias debe ser responsable de crear todas las estrategias
(algoritmos o políticas conectables o cambiantes). Con este diseño, uno puede cambiar
dinámicamente, m la estrategia de actuación, mientras se está ejecutando la aplicación.

Como con la mayoría de las factorías será construido empleando un Singleton y


se accederá mediante el patrón Singleton.

Con los patrones Estrategia y Factoría se ha conseguido Variaciones Protegidas


con respecto a las estrategias que varían dinámicamente. La Estrategia se fundamenta en
el Polimorfismo y en la interfaz para permitir algoritmos conectables en un diseño de
objetos.

Ejemplo 6.18

Siguiendo el Proceso
Unificado, diseñe una
aplicación que sea un
conversor de monedas. En
una primera versión inicial,
considere sólo euros, dólares y libras esterlinas. A la aplicación se le facilitará
los valores de conversión entre las monedas y la cantidad de una moneda
concreta a convertir en el resto de monedas.

Dpto. Electrónica, Automática e Informática Industrial 197


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

void CConversorMonedasDlg::OnCalcular()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
ConversorMoneda elConversor(this->m_factorDolar,this->m_factorLibra,
this->m_elTipo,this->m_Cantidad);
this->m_Euros = elConversor.getEuros();
this->m_Dolares = elConversor.getDolar();
this->m_Libras = elConversor.getLibras();
UpdateData(FALSE);

Solución

198 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

typedef enum {EURO,DOLAR,LIBRA} tipoMoneda;


class ConversorMoneda;
class IMoneda
{
public:
virtual double getEuros() = 0;
virtual double getDolar() = 0;
virtual double getLibras() = 0;
static IMoneda* MetodoFabricacion(tipoMoneda,double,ConversorMoneda *);
};
class ConversorMoneda
{
IMoneda *pMoneda; double coefDolar; double coefLibra;
public:
double convertirDolarAEuro() {return 1/coefDolar;}
double convertirLibraAEuro() {return 1/coefLibra;}
ConversorMoneda(double dolar, double libra, tipoMoneda elTipo, double cant):
coefDolar(dolar), coefLibra(libra)
{
pMoneda = IMoneda::MetodoFabricacion(elTipo, cant, this);
}
double getEuros() {return pMoneda->getEuros(); }
double getDolar() {return pMoneda->getDolar(); }
double getLibras(){return pMoneda->getLibras(); }
~ConversorMoneda()
{ delete pMoneda; }
};

class MonedaEuro: public IMoneda


{
double cantidad; ConversorMoneda *pConversor;
MonedaEuro(double valor, ConversorMoneda *pConver):
cantidad(valor), pConversor(pConver) {}
friend class IMoneda;
public:
virtual double getEuros() {return cantidad;}
virtual double getDolar()
{return cantidad/this->pConversor->convertirDolarAEuro();}
virtual double getLibras()
{return cantidad/this->pConversor->convertirLibraAEuro();}
};

class MonedaDolar: public IMoneda


{
double cantidad; ConversorMoneda *pConversor;
MonedaDolar(double valor, ConversorMoneda *pConver):
cantidad(valor), pConversor(pConver) {}
friend class IMoneda;
public:
virtual double getEuros()
{return cantidad*this->pConversor->convertirDolarAEuro();}
virtual double getDolar() {return cantidad;}
virtual double getLibras()
{return cantidad*this->pConversor->convertirDolarAEuro()/
this->pConversor->convertirLibraAEuro();}
};
class MonedaLibra: public IMoneda
{
double cantidad; ConversorMoneda *pConversor;;
MonedaLibra(double valor,ConversorMoneda *pConver):
cantidad(valor), pConversor(pConver) {}
friend class IMoneda;
public:
virtual double getEuros()
{return cantidad*this->pConversor->convertirLibraAEuro();}
virtual double getDolar()
{return cantidad*this->pConversor->convertirLibraAEuro()/
this->pConversor->convertirDolarAEuro();}
virtual double getLibras() {return cantidad;}
};

#endif

Dpto. Electrónica, Automática e Informática Industrial 199


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

6.4.5 Observador

Problema: Diferentes tipos de objetos receptores están interesados en el cambio


de estado o eventos de un objeto emisor y quieren reaccionar cada uno a su manera
cuando el emisor genere un evento. Además, el emisor quiere mantener bajo
acoplamiento con los receptores ¿qué hacer?

Solución: Defina una interfaz “suscriptor” u “oyente”. Los suscriptores


implementan esta interfaz. El emisor dinámicamente puede registrar los suscriptores que
están interesados en un evento y notificarles cuando ocurre un evento.

Este patrón define una dependencia de uno-a-muchos, de forma que cuando un


objeto cambie de estado se notifica y se actualiza automáticamente a todos los objetos
que dependan de él. También es conocido como Dependents (Dependientes), Publish-
Subscribe (Publicar-Suscribir).

Una consecuencia habitual de dividir un sistema en una colección de clases


cooperantes es la necesidad de mantener una consistencia entre los objetos relacionados.
No se desea alcanzar esa consistencia haciendo a las clases fuertemente acopladas, ya
que reduciría su reutilización. Por ejemplo, muchos interfaces gráficas de usuario
separan los aspectos de presentación del dominio del problema. Las clases que definen
los datos de las aplicaciones y las representaciones pueden utilizarse de forma
independiente. Así, un objeto de hoja de cálculo y un gráfico de barras pueden
representar una información contenida en el mismo objeto de datos del dominio. La
hoja de cálculo y el gráfico de barras no se conocen entre sí, permitiéndose de esta
manera reutilizarse, pero gracias a este patrón se comportan como si se conocieran.
Cuando el usuario cambia la información de la hoja de cálculo, la barra de gráfica
refleja los cambios inmediatamente y viceversa.

¿Por qué no se puede mandar un mensaje desde el dominio a la vista?. Esta


solución supone que los objetos del dominio deben saber el interfaz de la vista, por
tanto, se rompería el principio de Bajo Acoplamiento. La separación Dominio-Vista
mantiene Variaciones Protegidas con respecto a los cambios en la interfaz de usuario.

El patrón Observador describe cómo establecer estas relaciones. Los principales


objetos de este patrón son el Observable y el Observador. Un Observable puede tener
cualquier número de observadores dependientes de él. Cada vez que el Observable
cambia de estado se notificará a sus observadores. Este tipo de interacción también se
conoce como publicar-suscribir. El Observable es quien publica las notificaciones.
Envía estas notificaciones sin tener que conocer quiénes son sus observadores. Pueden
suscribirse un número indeterminado de observadores para recibir estas notificaciones.

Los roles que se desempeñan en este patrón son:

200 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

 Observable
o un Observable puede ser observado por cualquier número de objetos
Observador.
o proporciona una interfaz para asignar y quitar objetos Observador.
 Observador
o define una interfaz para actualizar los objetos que deben ser notificados
ante cambios en un sujeto observable.
 ObservableConcreto
o almacena el estado de interés para los objetos ObservadorConcreto.
o envía una notificación a sus observadores cuando cambia su estado.
 ObservadorConcreto
o mantiene una referencia a un objeto ObservableConcreto.
o guarda un estado que debería ser consistente con el sujeto observable.
o Implementa la interfaz de actualización del Observador para mantener su
estado consistente con el sujeto observable.
Así, el ObservableConcreto notifica a sus observadores cada vez que se produce
un cambio en su estado. Después de ser informado de un cambio en el
ObservableConcreto, un objeto ObservadorConcreto puede pedirle al observable más
información. ObservadorConcreto usa esta información para sincronizar su estado con
el del observable.

El siguiente diagrama de secuencias muestra los métodos entre el emisor y


receptor.

Dpto. Electrónica, Automática e Informática Industrial 201


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

El patrón Observador permite modificar los observables y los observadores de


forma independiente. Es posible reutilizar los observables sin conocer a sus
observadores y viceversa. Esto permite añadir observadores sin modificar al observable
u otros observadores.

Otras ventajas e inconvenientes del patrón Observador son los siguientes:

1. Acoplamiento abstracto entre Observable y Observador. Todo lo que un


Observable sabe es que tiene una lista de observadores, cada uno de los cuales se ajusta
a la interfaz simple de la clase abstracta Observador. El Observable no conoce la clase
concreta de ningún observador. Por tanto, el acoplamiento entre el sujeto observable y
los observadores es mínimo (patrón GRASP de Bajo Acoplamiento).

Gracias a que Observable y Observador no están fuertemente acoplados, pueden


pertenecer a diferentes capas de abstracción de un sistema. Un sujeto de bajo nivel
puede comunicarse e informar a un observador de más alto nivel, manteniendo de este
modo intacto la estructura de capas del sistema (patrón Capas de POSA).

2. Capacidad de comunicación mediante difusión. A diferencia de una petición


ordinaria, la notificación enviada por un Observable no necesita especificar su receptor
(patrón GRASP de Alta Cohesión). La notificación se envía automáticamente a todos
los objetos interesados que se hayan suscrito a ella. Al Observable no le importa
cuántos objetos interesados pudieran existir; su única responsabilidad es notificar a los
observadores. Esto da la libertad de añadir y quitar observadores en cualquier momento.
Se deja al observador manejar u obviar una notificación del observable.

3. Actualizaciones inesperadas. El mayor inconveniente de este patrón es que los


observadores no saben de la presencia de los otros observadores y no pueden saber el
coste último de cambiar el estado. Una operación aparentemente inofensiva sobre el
Observable puede dar lugar a una serie de actualizaciones en cascada de los
observadores y sus objetos dependientes. Más aún, los criterios de dependencia que no

202 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

están bien definidos o mantenidos suelen provocar falsas actualizaciones que pueden ser
muy difíciles de localizar.

6.4.5.1 Implementación
Dos tipos de objetos se utilizan para poner el patrón del observador. La clase
Observable que se encarga de que el estado del Observable concreto sea escuchado por
sus observadores y la clase Observer que está a la escucha. Primero, se presenta
Observer:
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
//
//: C10:Observer.h
// The Observer interface
#ifndef OBSERVER_H
#define OBSERVER_H

class Observable;
class Argument {};

class Observer {
public:
// Called by the observed object, whenever
// the observed object is changed:
virtual void update(Observable* o, Argument* arg) = 0;
virtual ~Observer() {}
};
#endif // OBSERVER_H ///:~

Puesto que el Observer obra recíprocamente con Observable, el Observable se


debe declarar primero. La clase Observer es la interfaz para cualquier observador
concreto. La clase Argument, declarada en este ejemplo como vacía, será la que defina
los atributos que van a estar a la escucha. El servicio update() es llamada por el objeto
que está en la escucha cuando se produce una notificación del emisor.

La clase Observable mantiene la lista de objetos que desean estar a la escucha de


las modificaciones que produce el emisor.
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
//
//: C10:Observable.h
// The Observable class.
#ifndef OBSERVABLE_H
#define OBSERVABLE_H
#include <set>
#include "Observer.h"

class Observable {
bool changed;
std::set<Observer*> observers;
protected:
virtual void setChanged() { changed = true; }
virtual void clearChanged() { changed = false; }
public:
virtual void addObserver(Observer& o) {
observers.insert(&o);
}
virtual void deleteObserver(Observer& o) {
observers.erase(&o);
}
virtual void deleteObservers() {
observers.clear();
}
virtual int countObservers() {
return observers.size();
}

Dpto. Electrónica, Automática e Informática Industrial 203


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

virtual bool hasChanged() { return changed; }


// If this object has changed, notify all
// of its observers:
virtual void notifyObservers(Argument* arg = 0) {
if(!hasChanged()) return;
clearChanged(); // Not "changed" anymore
std::set<Observer*>::iterator it;
for(it = observers.begin();it != observers.end(); it++)
(*it)->update(this, arg);
}
virtual ~Observable() {}
};
#endif // OBSERVABLE_H ///:~

El objeto Observable tiene un flag para indicar si ha cambiado el estado de los


atributos a escuchar. La colección de objetos observador se mantiene en un lista STL
set<Observer*> para prevenir los duplicados; los servicios de insert(), erase(), clear(),
y size() se exponen para permitir que se agreguen y se quiten a los observadores en
cualquier momento, proporcionando flexibilidad en tiempo de ejecución. La mayoría
del trabajo se hace en notifyObservers(). La clase Observable llama a la función
miembro notifyObservers() para cada observador en la lista de observadores a la
escucha.Mientras no se produzcan cambios, las llamadas repetidas al notifyObservers()
no hacen nada y no pierden el tiempo. Cuando hay un cambio en los atributos del
emisor se produce la llamada al update() de todos los observadores que estén en la lista.

6.4.5.2 Las clases internas

Tanto las clases que están a la escucha como las observables requieren interfaces
que las permitan mantener la propiedad de bajo acoplamiento. Para este fin se requiere
de algo que tiene Java y no C++: Las clases internas. Se trata de jerarquizar las clases de
forma que se puedan tener acceso a los datos de la clase que las contiene, i.e. una
instancia de la clase interna tenga acceso a datos de la clase que la ha creado, siendo la
clase interna una subclase de la interfaz deseada. Se presenta un ejemplo del idioma
interno. Véase cómo la clase Outer puede ser vista a través de dos interfaces distintos
Bingable y Poingable:

204 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
//
//: C10:InnerClassIdiom.cpp
// Example of the "inner class" idiom.
#include <iostream>
#include <string>
using namespace std;

class Poingable {
public:
virtual void poing() = 0;
};

class Bingable {
public:
virtual void bing() = 0;
};

class Outer {
string name;
// Define one inner class:
class Inner1;
friend class Outer::Inner1;
class Inner1 : public Poingable {
Outer* parent;
public:
Inner1(Outer* p) : parent(p) {}
void poing() {
cout << "poing called for "
<< parent->name << endl;
// Accesses data in the outer class object
}
} inner1;
// Define a second inner class:
class Inner2;
friend class Outer::Inner2;
class Inner2 : public Bingable {
Outer* parent;
public:
Inner2(Outer* p) : parent(p) {}
void bing() {
cout << "bing called for "
<< parent->name << endl;
}
} inner2;
public:
Outer(const string& nm)
: name(nm), inner1(this), inner2(this) {}
// Return reference to interfaces
// implemented by the inner classes:
operator Poingable&() { return inner1; }
operator Bingable&() { return inner2; }
};

void callPoing(Poingable& p) {
p.poing();
}

void callBing(Bingable& b) {
b.bing();
}

int main() {
Outer x("Ping Pong");
// Like upcasting to multiple base types!:
callPoing(x);
callBing(x);
} ///:~

Dpto. Electrónica, Automática e Informática Industrial 205


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

El ejemplo, previsto para demostrar la sintaxis más simple para el idioma


interno, comienza con los interfaces de Poingable y de Bingable (cada uno contiene
una sola función del miembro). Los servicios de callPoing() y de callBing() requieren
que el objeto entregue los interfaces de Poingable y de Bingable, respectivamente. La
clase Outer contiene ciertos datos confidenciales (nombre), y desea proporcionar un
interfaz de Poingable y un interfaz de Bingable, así que puede ser utilizado con el
servicio callPoing() y con callBing(). Para proporcionar un objeto de Poingable sin
derivar de Poingable, se utiliza el idioma interno de la clase. Primero, la clase interna se
declara y luego se la declara friend de la clase que la contiene, generándose la jerarquía
de clases. Note que la clase interna guarda un indicador de quien la creó, y este
indicador se debe inicializar en el constructor. El cual servirá para tener acceso a los
atributos de la clase “padre”.

6.4.5.3 Entre flores, abejas y colibríes


Armado con el interfaz observado, la clase observables y el idioma interno de las
clases, se propone un ejemplo del patrón del observador. Hay una instancia de ‘flor’ y
dos instancias de ‘abeja’ y ‘colibrí’. Cuando la flor abre sus pétalos, las abejas y colibrís
interesados en esa flor son notificados. Si cierra sus pétalos también será notificado a
quién esté interesado. Empleando el patrón observador y las clases internas, el DCD
queda determinado para este problema de la siguiente forma:

// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
//
//: C10:ObservedFlower.cpp
// Demonstration of "observer" pattern.
#include <algorithm>
#include <iostream>

206 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

#include <string>
#include <vector>
#include "Observable.h"
using namespace std;

class Flower {
bool isOpen;
public:
Flower() : isOpen(false),
openNotifier(this), closeNotifier(this) {}
void open() { // Opens its petals
isOpen = true;
openNotifier.notifyObservers();
closeNotifier.open();
}
void close() { // Closes its petals
isOpen = false;
closeNotifier.notifyObservers();
openNotifier.close();
}
// Using the "inner class" idiom:
class OpenNotifier;
friend class Flower::OpenNotifier;
class OpenNotifier : public Observable {
Flower* parent;
bool alreadyOpen;
public:
OpenNotifier(Flower* f) : parent(f),
alreadyOpen(false) {}
void notifyObservers(Argument* arg = 0) {
if(parent->isOpen && !alreadyOpen) {
setChanged();
Observable::notifyObservers();
alreadyOpen = true;
}
}
void close() { alreadyOpen = false; }
} openNotifier;
class CloseNotifier;
friend class Flower::CloseNotifier;
class CloseNotifier : public Observable {
Flower* parent;
bool alreadyClosed;
public:
CloseNotifier(Flower* f) : parent(f),
alreadyClosed(false) {}
void notifyObservers(Argument* arg = 0) {
if(!parent->isOpen && !alreadyClosed) {
setChanged();
Observable::notifyObservers();
alreadyClosed = true;
}
}
void open() { alreadyClosed = false; }
} closeNotifier;
};

class Bee {
string name;
// An "inner class" for observing openings:
class OpenObserver;
friend class Bee::OpenObserver;
class OpenObserver : public Observer {
Bee* parent;
public:
OpenObserver(Bee* b) : parent(b) {}
void update(Observable*, Argument *) {
cout << "Bee " << parent->name
<< "'s breakfast time!” << endl;
}
} openObsrv;
// Another "inner class" for closings:
class CloseObserver;
friend class Bee::CloseObserver;
class CloseObserver : public Observer {
Bee* parent;
public:

Dpto. Electrónica, Automática e Informática Industrial 207


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

CloseObserver(Bee* b) : parent(b) {}
void update(Observable*, Argument *) {
cout << "Bee " << parent->name
<< "'s bed time!” << endl;
}
} closeObsrv;
public:
Bee(string nm) : name(nm),
openObsrv(this), closeObsrv(this) {}
Observer& openObserver() { return openObsrv; }
Observer& closeObserver() { return closeObsrv;}
};

class Hummingbird {
string name;
class OpenObserver;
friend class Hummingbird::OpenObserver;
class OpenObserver : public Observer {
Hummingbird* parent;
public:
OpenObserver(Hummingbird* h) : parent(h) {}
void update(Observable*, Argument *) {
cout << "Hummingbird " << parent->name
<< "'s breakfast time!” << endl;
}
} openObsrv;
class CloseObserver;
friend class Hummingbird::CloseObserver;
class CloseObserver : public Observer {
Hummingbird* parent;
public:
CloseObserver(Hummingbird* h) : parent(h) {}
void update(Observable*, Argument *) {
cout << "Hummingbird " << parent->name
<< "'s bed time!” << endl;
}
} closeObsrv;
public:
Hummingbird(string nm) : name(nm),
openObsrv(this), closeObsrv(this) {}
Observer& openObserver() { return openObsrv; }
Observer& closeObserver() { return closeObsrv;}
};

int main() {
Flower f;
Bee ba("A"), bb("B");
Hummingbird ha("A"), hb("B");
f.openNotifier.addObserver(ha.openObserver());
f.openNotifier.addObserver(hb.openObserver());
f.openNotifier.addObserver(ba.openObserver());
f.openNotifier.addObserver(bb.openObserver());
f.closeNotifier.addObserver(ha.closeObserver());
f.closeNotifier.addObserver(hb.closeObserver());
f.closeNotifier.addObserver(ba.closeObserver());
f.closeNotifier.addObserver(bb.closeObserver());
// Hummingbird B decides to sleep in:
f.openNotifier.deleteObserver(hb.openObserver());
// Something changes that interests observers:
f.open();
f.open(); // It's already open, no change.
// Bee A doesn't want to go to bed:
f.closeNotifier.deleteObserver(
ba.closeObserver());
f.close();
f.close(); // It's already closed; no change
f.openNotifier.deleteObservers();
f.open();
f.close();
} ///:~

208 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Dpto. Electrónica, Automática e Informática Industrial 209


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Propósito Patrones de diseño GoF Tema que trata

De creación Factoría Abstracta Uso de familias de referencias abstractas,


ocultado las implementaciones concretas.
Método de Fabricación
Creación de las clases concretas.
Singleton
la única instancia de una clase

Estructurales Adaptador la interfaz de un objeto

Fachada la interfaz de un subsistema

De comportamiento Observador cómo se mantiene actualizado el objeto


dependiente
Estrategia
cómo se varía dinámicamente un algoritmo

6.5 Ejercicios

1. Habilidades necesarias para el diseño orientado a objetos.

2. Tipos de visibilidad en la programación orientada a objetos.

3. ¿Qué es la Programación Extrema, XP?.

4. ¿Qué se entiende por patrón en el diseño orientado a objetos?.

5. Describir el par problema/solución de los patrones GRASP y GoF


estudiados.

Problema 1

Realizar el primer diseño para


el simulador del sistema de control
de elevación de una aeronave (ver
este problema en los ejercicios de
los capítulos 2 y 3).

Un modelo simplificado del


control de elevación en transformadas
en Z está dado por la siguiente función
de transferencia:

210 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

0.0895z  0.085
M z  
z  1.883z  0.888
2

El periodo de muestreo es de 25ms. Por tanto, si la señal de mando se la denota


por k y el ángulo de elevación de la aeronave por k. El algoritmo de control está
definido por la siguiente ecuación en diferencias:

 k  0.0895  k  0.085  k 1  1.883 k 1  0.888 k 2

Como prueba de concepto se puede suponer una entrada en escalón unitario. La


dinámica de elevación de la aeronave seguirá la siguiente trayectoria:

k k k-1 k k-1 k-2


0 1 0 0.0895 0 0
1 1 1 0.173 0.0895 0
2 1 1 0.25 0.173 0.0895
3 1 1 0.323 0.25 0.173
Empleando Matlab, la solución quedaría como:

>> g1=tf([.0895 -.085],[1 -1.883 .888],.025)

>>step(g1)

Una vez realizado las pruebas de conceptos se pasa al


modelo del dominio y al DSS:

Dpto. Electrónica, Automática e Informática Industrial 211


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

: Sistema
Ingeniero de Control
: <Actor Name>
Se le pasará los
coeficientes de
la FDT del
introducirModelo() sistema

especificarExcitacion()

Se le dirá cuál es
mostrarSalida() el tipo de señal,
el tiempo final y
el intervalo...

La aplicación dará
los resultados en un
gráfico del tipo y=y(t)

Aplicando los patrones de Alta Cohesión, Bajo Acoplamiento y Modularidad-Capas, la


vista de gestión de la aplicación estaría formada por los siguientes paquetes:

VistaSimulador

DominioSimulador

Patrón Alta
GraficoPlot Cohesion, Bajo
Acoplamiento,
Capa

El diagrama de interacción y el DCD del paquete del dominio estará constituido


por:

212 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Patrón
Fachada
: Vista : CoordinadorSimulador
Patrón
Creador
introducirModelo( )

create() Patrón Experto


: ModeloSistema
en Información

especificarExcitacion( )

create()
: Senyal_Entrada

create()
: Simulador_LTI

Algoritmia para
calcularSalida( )
calcular la señal
de salida getCoefNum( )

getCoefDen( )

getValorInstantek( )

mostrarSalida( )

getSenyaSalida( )

Problema 2

Dpto. Electrónica, Automática e Informática Industrial 213


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Para el código adjuntado se pide:

a. Ingeniería inversa: Diagrama de clases.

b. Ingeniería inversa: Diagrama de secuencia.

c. Resultado de su ejecución en la consola.

d. Indicar los patrones GRASP empleados en este patrón.

e. Diseñar e implementar el servicio rotar( ), tal que

 x2   cos    sin     x1 
   
 y2   sin   cos     y1 

Empléese sobre el punto p2.

#include <iostream>
#include <string>
#include <cmath>
using namespace std;

class Punto {
public:
double x, y;
Punto(double xi, double yi) : x(xi), y(yi) {}
Punto(const Punto& p) : x(p.x), y(p.y) {}
Punto& operator=(const Punto& rhs) {
x = rhs.x;
y = rhs.y;
return *this;
}
friend ostream&
operator<<(ostream& os, const Punto& p) {
return os << "x=" << p.x << " y=" << p.y;
}
};

class Vector {
public:
double magnitud, direccion;
Vector(double m, double d) : magnitud(m), direccion(d) {}
};

class Espacio {
public:
static Punto trasladar(Punto p, Vector v) {
p.x += (v.magnitud * cos(v.direccion));
p.y += (v.magnitud * sin(v.direccion));
return p;
}
};

int main() {
Punto p1(1, 2);
Punto p2 = Espacio::trasladar(p1, Vector(3, 3.1416/3));
cout << "p1: " << p1 << " p2: " << p2 << endl;

return 0;
}

a) Diagrama de clases de la ingeniería inversa

214 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

b) Diagrama de secuencia de la ingeniería inversa

c) p1: x=1 y=2 p2: x=2.5 y=4.6

d) Se ha aplicado Experto de Información en la clase Punto y Vector. Para evitar


el acoplamiento entre ambas clases se ha aplicado el patrón Indirección y por tanto una
Fabricación Pura con la clase Espacio.

e)

Dpto. Electrónica, Automática e Informática Industrial 215


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

class Espacio {
public:
static Punto trasladar(Punto p, Vector v) {
p.x += (v.magnitud * cos(v.direccion));
p.y += (v.magnitud * sin(v.direccion));
return p;
}
static Punto rotar(Punto p, double theta) {
Punto res(0,0);
res.x = (p.x * cos(theta)) - (p.y *sin(theta));
res.y = (p.x * sin(theta)) + (p.y *cos(theta));
return res;
}
};

int main() {
Punto p1(1, 2);
Punto p2 = Espacio::trasladar(p1, Vector(3, 3.1416/3));
Punto p3 = Espacio::rotar(p2,3.1416/6);

cout << "p1: " << p1 << " p2: " << p2 << " p3: " << p3 <<endl;

return 0;
}

216 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Problema 3

En el cuadro se
entrega el código sobre un
generador de números
primos. Se trata de diseñar
un componente tal que el
cliente le entregue el
número límite de números
primos, n, y el servidor
retorne con un vector que
contenga los n primeros
números primos. En la
figura se presenta el
resultado del cliente. Se

#ifndef NUMEROSPRIMOS_H
#define NUMEROSPRIMOS_H

class NumerosPrimos {
unsigned elUltimoPrimo;
unsigned elNumero;
public:
NumerosPrimos() : elUltimoPrimo(1) { elNumero = elUltimoPrimo+1;}
unsigned getSiguientePrimo()
{
do{
for(unsigned divisor = 2;elNumero % divisor != 0; divisor++) ;
if (divisor == elNumero)
elUltimoPrimo = elNumero;
else
elNumero++;
} while ( elUltimoPrimo != elNumero );
elNumero++;
return (elUltimoPrimo);
}

};
#endif

pide:
1. Realizar ingeniería inversa sobre el generador de números primos.
2. Obtener el diagrama de clase de diseño, DCD, así como el diagrama de
secuencia del componente servidor.
3. Implementación del cliente en C++.
4. Implementación de las clases en C++ del componente servidor.

Dpto. Electrónica, Automática e Informática Industrial 217


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

218 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

#include <iostream>
#include "AdaptadorNumerosPrimos.h"
#include <numeric>
#include <algorithm>

IAdaptadorNumerosPrimos* IAdaptadorNumerosPrimos::metodoFabricacion(unsigned limite)


{
return (new AdaptadorNumerosPrimos(limite));

}
using namespace std;
void imprimir(unsigned);

int main()
{
unsigned elLimiteNumerosPrimos;
cout<<"Cuantos numeros primos desea que aparezcan : ";
cin >> elLimiteNumerosPrimos;

IAdaptadorNumerosPrimos *pAdaptadorNumPrimos =
IAdaptadorNumerosPrimos::metodoFabricacion(elLimiteNumerosPrimos);

cout << endl <<"Tabla de Numeros Primos" <<endl;


cout << "-----------------------" <<endl;

for_each(pAdaptadorNumPrimos->getNumerosPrimos().begin(),
pAdaptadorNumPrimos->getNumerosPrimos().end(),imprimir);
delete pAdaptadorNumPrimos;
return 0;
}

void imprimir(unsigned numPrimo)


{
static unsigned indice;
cout.width(5);
cout << numPrimo;
if(++indice % 10 == 0)
cout << endl;
}

#ifndef _ADAPTADOR_NUMEROSPRIMOS
#define _ADAPTADOR_NUMEROSPRIMOS

#include <vector>
#include "NumerosPrimos.h"

class IAdaptadorNumerosPrimos
{
public:
virtual std::vector<unsigned> & getNumerosPrimos() = 0;
static IAdaptadorNumerosPrimos *metodoFabricacion(unsigned);
};

class AdaptadorNumerosPrimos: public IAdaptadorNumerosPrimos


{
NumerosPrimos elGenerador;
unsigned elLimite;
std::vector<unsigned> elVectorNumerosPrimos;
friend class IAdaptadorNumerosPrimos;
AdaptadorNumerosPrimos(unsigned num): elLimite(num)
{
for (unsigned i=1;i<=elLimite;i++)
elVectorNumerosPrimos.push_back
(elGenerador.getSiguientePrimo());
}
public:
virtual std::vector<unsigned> & getNumerosPrimos()
{return elVectorNumerosPrimos;}
};

#endif

Dpto. Electrónica, Automática e Informática Industrial 219


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Problema 4

Se desea hacer una aplicación que sirva para calcular las nominas de
una compañía. Al salario base de cada empleado hay que quitarle un 20% de
retención del IRPF para calcular su salario neto. Como existen diferentes
políticas salariales en la empresa, se desea hacer un programa fácilmente
extensible a nuevas políticas. De momento se pretende abordar dos de ellas: a)
el sueldo ordinario b) el sueldo con bonus, consistente en aumentar el salario
base (antes de la retención) un 35%. De momento se ha desarrollado el
siguiente programa:

main()
{
Nomina* nomina;
cout<<"1. Nomina ordinaria"<<endl;
cout<<"2. Nomina con bonus"<<endl;
cin>>opcion;

//Completar codigo aqui

cout<<"Salario base: ";


float salario;
cin>>salario;
nomina->SetSalarioBase(salario);
float total=nomina->GetSueldoNeto();
cout<<"El salario neto es: "<<total<<endl;
}

Se pide:

1. Diagrama de Clases de Diseño de una arquitectura que permita una


fácil extensión a nuevas políticas. Indicar los patrones utilizados.

2. Implementación en C++ de la solución, completando el main().

220 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Problema 5

Para la aplicación informática de una sala de cine, se desea que un


taquillero introduzca el número de localidades que desea un comprador y se le
aplica el mejor descuento para el espectador. En esta primera versión se
considera que las monedas pueden ser EUROS, DOLARES y LIBRAS. Por
defecto, se considerará que el dinero se expresa en EUROS y el precio de
butaca es de 5€. Las políticas de ventas a introducir, en esta primera iteración,
son:
a) Si el día de la semana es miércoles se le aplicará un descuento del
50%.
b) En cualquier día de la semana, la compra de tres entradas será al
precio de dos. Esta política se aplica para número de localidades que sea
múltiplo de tres.
El arquitecto del programa ha realizado un primer borrador del diagrama
de clase de diseño. Obviamente no está toda la información para la
codificación.
int main() {
float precio;
cout <<"\nPrecio unitario de taquilla en euros: ";
cin >> precio;
Dinero elPrecioUnitario(precio);
float descuento;
cout <<"\nCual es el descuento del dia del espectador [\%]: ";
cin >> descuento;
VentaLocalidades laVentanilla(elPrecioUnitario,descuento/100);
//Bucle de taquilla
bool bSalir = false;
Dinero elValorVenta;
while (bSalir != true) {
int numeroLocalidades;
cout << "\nNumero de localidades a vender :";
cin >> numeroLocalidades;
elValorVenta = laVentanilla.getPrecio(numeroLocalidades);
cout << "A cobrar " << elValorVenta.getCantidad() <<" euros.";
cout << "\nIntroducir mas ventas (s/n) ?";
char eleccion;
cin >> eleccion;
bSalir = ((eleccion == 'n')||(eleccion == 'N')) ? true:false;
}
return 0;
}

Dpto. Electrónica, Automática e Informática Industrial 221


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

1. Implementar la clase Dinero (por defecto se considera que el tipo de


moneda es el EURO).

2. Para las estrategias de los precios se ha utilizado un interfaz, de


manera que las políticas de ventas se puedan variar en el futuro. Realizar su
implementación.

3. Implementar la clase de Venta de Localidades

222 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

#ifndef _DINERO_INC_
#define _DINERO_INC_

typedef enum {EURO, DOLAR, LIBRA} TipoDinero;

class Dinero
{
TipoDinero elTipoMoneda;
float cantidad;
public:
Dinero(): elTipoMoneda(EURO), cantidad(0) {}
Dinero(float valor, TipoDinero elTipo): elTipoMoneda(elTipo),cantidad(valor) {}

Dinero(Dinero &elValor)
{
elTipoMoneda = elValor.elTipoMoneda;
cantidad = elValor.cantidad;
}

Dinero& operator= (Dinero &elValor)


{
elTipoMoneda = elValor.elTipoMoneda;
cantidad = elValor.cantidad;
return(*this);
}

void setCantidad(float laCantidad){cantidad=laCantidad;}


float getCantidad(void){return cantidad;}
void setTipoDinero(TipoDinero elTipo){elTipoMoneda=elTipo;}
TipoDinero getTipoDinero(void){return elTipoMoneda;}
};

#endif

#ifndef _VENTA_LOCALIDADES_INC_
#define _VENTA_LOCALIDADES_INC_

#include "Fecha.h"
#include "Dinero.h"
#include "OfertasTaquillas.h"

class VentaLocalidades
{
Fecha elDiaSemana;
Dinero elPrecioUnitario;
float elDescuento;
IPrecioLocalidades *pPrecioLocalidades;

public:
VentaLocalidades(Dinero elPrecio, float descuento) :
elPrecioUnitario(elPrecio),elDescuento(descuento) {}
Dinero getPrecio(int numeroLocalidades)
{
pPrecioLocalidades =
IPrecioLocalidades::metodoFabricacionPrecios(elDiaSemana,elDescuento);
Dinero elDinero =
pPrecioLocalidades->getPrecioTotal(numeroLocalidades,elPrecioUnitario) ;
delete pPrecioLocalidades;
return(elDinero);
}
};

#endif

Dpto. Electrónica, Automática e Informática Industrial 223


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

#ifndef _OFERTAS_TAQUILLA_INC_
#define _OFERTAS_TAQUILLA_INC_
#include "Dinero.h"
#include "Fecha.h"

class IPrecioLocalidades
{
public:
virtual Dinero getPrecioTotal(int numeroLocalidades, Dinero elPrecioUnitario) = 0;
static IPrecioLocalidades *metodoFabricacionPrecios(Fecha &, float);
};

class DiaDelEspectador : public IPrecioLocalidades


{
float elDescuento;
friend class IPrecioLocalidades;
DiaDelEspectador(float descuento): elDescuento(descuento) {}
public:
virtual Dinero getPrecioTotal(int numeroLocalidades, Dinero elPrecioUnitario)
{
Dinero elValorTotal;
elValorTotal.setCantidad(elPrecioUnitario.getCantidad()*numeroLocalidades*elDescuento);
elValorTotal.setTipoDinero(elPrecioUnitario.getTipoDinero());
return (elValorTotal);
}
};

class DosXTres : public IPrecioLocalidades


{
friend class IPrecioLocalidades;
DosXTres() {}
public:
virtual Dinero getPrecioTotal(int numeroLocalidades, Dinero elPrecioUnitario)
{
Dinero elValorTotal;
int multiplosDeTres = 0;
for(int i=1;i<=numeroLocalidades;i++)
if( i%3 == 0)
multiplosDeTres++;
int localidadesSueltas = numeroLocalidades - (multiplosDeTres*3);
elValorTotal.setCantidad(elPrecioUnitario.getCantidad()*
(localidadesSueltas+(multiplosDeTres*2)));
elValorTotal.setTipoDinero(elPrecioUnitario.getTipoDinero());
return (elValorTotal);
}
};

#endif

#include "includes/VentaLocalidades.h"

IPrecioLocalidades * IPrecioLocalidades::metodoFabricacionPrecios
(Fecha &hoy, float descuento = 0)
{
if ((hoy.isMiercoles() == true ) && (descuento > 100/3) )
return new DiaDelEspectador(descuento);
else return new DosXTres;
}

224 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Problema 6

Desarrollar una aplicación que


convierta las magnitudes de longitud de
un sistema a otro, sabiendo que:
1 milla = 1609 m
1 pulgada = 25.4 mm
1 pie = 30.48 cm
Se pide:
1. AOO: Modelo del dominio.
2. DOO: Diagrama de clases de diseño. Indicar los patrones que se están
aplicando.
3. Implementación en C++.

Convierte de
un tipo de
longitud a otro Longitudes
(from ConversorLongitudes)

es un tipo de medida de
ConversorLongitud
(from ConversorLongitudes)
Pies
es un tipo de medida de (from ConversorLongitudes)

es un tipo de medida de
es un tipo de medida de
Pulgadas
(from ConversorLongitudes)

Metros
(from ConversorLongitudes)
Millas
(from ConversorLongitudes)

Dpto. Electrónica, Automática e Informática Industrial 225


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Los patrones utilizados son: Estrategia(GoF) que incluye Variaciones Protegidas


(GRASP), Método de Fabricación (GoF) y Polimorfismo (GRASP)

El código de test sería:

void CConversorLongitudesDlg::OnCalcular()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);

ConversorLongitud elConversor(this->m_tipoLongitud,this->m_longitud);
this->m_Metros = elConversor.getMetros();
this->m_Millas = elConversor.getMillas();
this->m_Pulgadas = elConversor.getPulgadas();
this->m_Pies = elConversor.getPies();

UpdateData(FALSE);
}

Mientras que el interfaz, el conversor y las subclases de longitudes serían:


#if !defined(AFX_LONGITUDES_H)
#define AFX_LONGITUDES_H

typedef enum {METROS,MILLAS,PULGADAS,PIES} tipoLongitudes;

class ConversorLongitud;
class ILongitudes
{
public:
virtual float getMetros() = 0;
virtual float getMillas() = 0;
virtual float getPulgadas() = 0;
virtual float getPies() = 0;
static ILongitudes * metodoFabricacion(tipoLongitudes,float,
ConversorLongitud *);
};
#endif
--------------------------------------------------------------------------------------------------------------------------------------------------------
#if !defined(AFX_CONVERSORLONGUITUDES_H)
#define AFX_CONVERSORLONGUITUDES_H

#include "Longitudes.h"

class ConversorLongitud
{
ILongitudes *plongitudes;
float millaMetro;
float pulgadaMetro;
float pieMetro;

public:
ConversorLongitud(tipoLongitudes,float);
virtual ~ConversorLongitud();

float getMetros() { return plongitudes->getMetros(); }


float getMillas() { return plongitudes->getMillas(); }
float getPulgadas() { return plongitudes->getPulgadas(); }
float getPies() { return plongitudes->getPies(); }

float factorMillaMetro() {return millaMetro;}


float factorPulgadaMetro() {return pulgadaMetro;}
float factorPieMetro() {return pieMetro;}

};

#endif

226 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

#if !defined(AFX_LONGUITUDES_SIS_H)
#define AFX_LONGUITUDES_SIS_H

#include "ConversorLongitud.h"

class Metros : public ILongitudes


{
float cantidad; ConversorLongitud *pConversor;
Metros(float valor,ConversorLongitud *pC):
cantidad(valor), pConversor(pC) {}
friend class ILongitudes;
public:
float getMetros() { return cantidad;}
float getMillas() {return cantidad/pConversor->factorMillaMetro();}
float getPulgadas() {return cantidad/pConversor->factorPulgadaMetro();}
float getPies() {return cantidad/pConversor->factorPieMetro();}
};

class Millas : public ILongitudes


{
float cantidad; ConversorLongitud *pConversor;
Millas(float valor,ConversorLongitud *pC):
cantidad(valor), pConversor(pC) {}
friend class ILongitudes;
public:
float getMetros() { return cantidad*pConversor->factorMillaMetro();}
float getMillas() {return cantidad;}
float getPulgadas() {return cantidad*pConversor->factorMillaMetro()
/pConversor->factorPulgadaMetro();}
float getPies() {return cantidad*pConversor->factorMillaMetro()
/pConversor->factorPieMetro();}
};

class Pulgadas : public ILongitudes


{
float cantidad; ConversorLongitud *pConversor;
Pulgadas(float valor,ConversorLongitud *pC):
cantidad(valor), pConversor(pC) {}
friend class ILongitudes;
public:
float getMetros() { return cantidad*pConversor->factorPulgadaMetro();}
float getMillas() {return cantidad*pConversor->factorPulgadaMetro()
/pConversor->factorMillaMetro();}
float getPulgadas() {return cantidad;}
float getPies() {return cantidad*pConversor->factorPulgadaMetro()
/pConversor->factorPieMetro();}
};

class Pies : public ILongitudes


{
float cantidad; ConversorLongitud *pConversor;
Pies(float valor,ConversorLongitud *pC):
cantidad(valor), pConversor(pC) {}
friend class ILongitudes;
public:
float getMetros() { return cantidad*pConversor->factorPieMetro();}
float getMillas() {return cantidad*pConversor->factorPieMetro()
/pConversor->factorMillaMetro();}
float getPulgadas() {return cantidad*pConversor->factorPieMetro()
/pConversor->factorPulgadaMetro();}
float getPies() {return cantidad;}

};
#endif

Dpto. Electrónica, Automática e Informática Industrial 227


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Problema 7

Cálculo de una integral sobre una función monovariable (en este caso,
sólo polinómica), pudiendo elegir la estrategia de integración: a) Lineal o b)
Bilineal.
a) Caso de uso
b) Modelo del dominio
c) DSS
d) Vista de gestión
e) Diagramas de interacción
f) DCD
g) Implementación

Calculo de Integrales
(from <Use Case Name>)

<Actor Name>
<<include>>
(f rom Actors)

definir la funcion

El cálculo de la integral requiere saber cual es la función a quien se le va aplicar


el operador. Un modelo del dominio podría quedar reflejado como:

En esta aplicación habrá que definir la función y los parámetros de la


integración. Se propone el siguiente DSS:

228 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

: Sistema
Usuari o Matematico :
<Actor Name>

definirLaFuncion()

calcularLaIntegral()

retornar_valor_integral()

En esta fase se dividirá el modelo en dos paquetes:

VistaIntegral DominioIntegral

Desgranado el DSS y aplicando los patrones se proponen los diagramas de


interacción y de clases de diseño:

Vista : Valores de la Creación con


CoordinadorIntegrales función Factoría de tipo
Singleton
definirLaFuncion( )
create()
:
IFuncionMonoVar

Parámetros
de la funcion

calcularLaIntegral( )

create()
:
ContextoIntegral

Pasar valores de
los intervalos, de
la diferencial y
de la estrate...
Se le pasa la función
y el tipo de
estrategia en el
cálculo de la integral

Dpto. Electrónica, Automática e Informática Industrial 229


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

230 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Informática Industrial" Carlos Platero.


// Ver permisos en licencia de GPL
#ifndef _INTEGRADOR_INC_
#define _INTEGRADOR_INC_
#include "../Funcion/FuncionMonoVar.h"
typedef enum tipoEstr{LINEAL,BILINEAL} TipoEstrategia;
class IIntegrador
{
public:
virtual double calcularIntegral(IFuncionMonoVar *, float intInf,
float intSup, float diferencial) = 0;
};
class IntegradorLineal: public IIntegrador
{
public:
virtual double calcularIntegral(IFuncionMonoVar * pLaFuncion, float intInf,
float intSup, float diferencial){
double resultado = 0;
for(float i= intInf;i<=intSup;i+=diferencial)
resultado += pLaFuncion->calcularValor(i)*diferencial;
return (resultado);
}
};
class IntegradorBilineal: public IIntegrador
{
public:
virtual double calcularIntegral(IFuncionMonoVar * pLaFuncion, float intInf,
float intSup, float diferencial){
double resultado = 0;
for(float i= intInf;i<=intSup;i+=diferencial)
resultado +=
(pLaFuncion->calcularValor(i)+pLaFuncion->calcularValor
(i-diferencial))/2 *diferencial;
return (resultado);
}
};
class ContextoIntegrador
{
IIntegrador* pEstrategia;
public:
ContextoIntegrador
(IIntegrador* pTipodeIntegrador) : pEstrategia(pTipodeIntegrador) {}
double calcularIntegral(IFuncionMonoVar* pLaFuncion, float intInf,
float intSup, float diferencial)
{return(pEstrategia->calcularIntegral(pLaFuncion,inInf,intSup,diferencial));}
};

#endif

Dpto. Electrónica, Automática e Informática Industrial 231


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

#ifndef _IFUNCION_MONO_INC_
#define _IFUNCION_MONO_INC_
#include <vector>
#include <math.h>
typedef enum tipoFun{POLINOMIO,TRIGONOMETRICA} TipoFuncion;
class IFuncionMonoVar
{
public:
virtual double calcularValor(float) = 0;
virtual void setValoresFuncion( unsigned , double *) = 0;

};
class Polinomio : public IFuncionMonoVar
{
std::vector<double> coeficientes;
std::vector<double>::iterator iteratorCoeficientes;

double getCoeficiente(unsigned n)
{return(*(iteratorCoeficientes+n));}

public:
Polinomio(){}
Polinomio(unsigned grado, double *pCoef){
for (unsigned i=0;i<=grado;coeficientes.push_back(*(pCoef+i)),i++);
iteratorCoeficientes = coeficientes.begin();
}
virtual double calcularValor(float valorInd){
double resultado = 0;
for(int i=0;i<= this->coeficientes.size() ;i++)
resultado += getCoeficiente(i)*pow(valorInd,i);
return resultado;
}
virtual void setValoresFuncion( unsigned grado, double *pCoef){
for (unsigned i=0;i<=grado;coeficientes.push_back(*(pCoef+i)),i++);
iteratorCoeficientes = coeficientes.begin();
}
};
#endif

#ifndef _FACTORIA_INC_
#define _FACTORIA_INC_
#include "../Funcion/FuncionMonoVar.h"
#include "../Integrador/Integrador.h"
class FactoriaServicios
{
FactoriaServicios(){};
void operator=(FactoriaServicios&); // Para desactivar
FactoriaServicios(const FactoriaServicios&); // Para desactivar
public:
static FactoriaServicios& getInstancia(){
static FactoriaServicios unicaInstancia;
return unicaInstancia;
}
//Factoria de funciones matematicas
IFuncionMonoVar* FactoriaServicios::
MetodoFabricacionFuncion(TipoFuncion elTipoFuncion){
if (elTipoFuncion == POLINOMIO) return new Polinomio();
else return NULL;
}
//Factoria de estrategias
IIntegrador* FactoriaServicios::
MetodoFabricacionEstrategia(TipoEstrategia elTipoEstr){
if (elTipoEstr == LINEAL) return new IntegradorLineal;
else if (elTipoEstr == BILINEAL) return new IntegradorBilineal;
else return NULL;
}
};

#endif

232 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

// De: "Apuntes de Informática Industrial" Carlos Platero.


// (R) 2005 Con licencia GPL.
// Ver permisos en licencia de GPL
#include "../../include/Coordinador/CoordinadorIntegrales.h"
int CoordinadorIntegrales::definirLaFuncion(TipoFuncion elTipoFun,unsigned grado,
double *pCoef)
{
FactoriaServicios &laFactoria = FactoriaServicios::getInstancia();
this->pFuncionMono = laFactoria.MetodoFabricacionFuncion (elTipoFun);
if (this->pFuncionMono == NULL)
return (-1);
this->pFuncionMono->setValoresFuncion(grado,pCoef);
return 0;
}
double CoordinadorIntegrales::calcularLaIntegral(float intInf,
float intSup, float diferencial, TipoEstrategia elTipoIntegral)
{
if (this->pFuncionMono == NULL)
return (0);
FactoriaServicios &laFactoria = FactoriaServicios::getInstancia();
IIntegrador *pEstrategia = laFactoria.MetodoFabricacionEstrategia(elTipoIntegral);
if (pEstrategia == NULL)
return (0);

ContextoIntegrador elIntegrador(pEstrategia);
double resultado = elIntegrador.calcularIntegral( pFuncionMono,
intInf, intSup, diferencial );
delete pEstrategia;
return(resultado);

Problema 8

Realizar un juego de batalla los hombres contra los dragones. Los


hombres lanzan cuchillos y los dragones bolas de fuego. Los dragones se
mueven en el área izquierda de la pantalla y los hombres en el lado derecho.
En mitad de la batalla aparecen paredes móviles que se desplazan en el centro
de la pantalla. El número de luchadores puede ser variable y dinámico. Se pide:

1. Jerarquía a dos niveles de las características principales.

2. Modelo del dominio.

3. Diagrama de clases de diseño.

4. Implementación en C++ de los ficheros de cabecera de las clases.


1. Video juego de los hombres que luchan contra los dragones
1.1 Los hombres se mueven en un área restringida de la derecha.
1.2 Los dragones se mueven en un área restringida de la izquierda.
1.3 Los hombres lanzan cuchillos que se clavan en la pared o que matan
al dragón o que pasan sin hacer daño.
1.4 Los dragones lanzan bolas de fuego que no pueden atravesar las
paredes y que si tocan a un hombre lo mata.
1.5 Los dragones desaparecen de la pantalla al morir.
1.6 Los hombres desaparecen de la pantalla al morir.

Dpto. Electrónica, Automática e Informática Industrial 233


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Luchador Arma
ParedMovil

1
mata detiene 1
1 detiene
Dragón
lanza 1
1..n
1 Cuchillo
0..n BolaFuego 1 1
lucha contra

mata 1 0..n
1..n
lanza
1
Hombre
1

234 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

#ifndef _LUCHADORES_INC_ #ifndef _ARMAS_INC_


#define _LUCHADORES_INC_ #define _ARMAS_INC_

class FactoriaObjetos; class FactoriaObjetos;

typedef enum{HOMBRE,DRAGON} typedef enum {BOLAFUEGO,CUCHILLO}


TipoLuchadores; TipoArmas;

class ILuchador class IArmas


{ {
public: public:
virtual void lanzarArma() = 0; virtual void moverseTrayectoria() = 0;
virtual void moverse() = 0; virtual bool haChocadoObjeto() = 0;
virtual bool haRecibidoDisparo() = 0; virtual void pintar() = 0;
virtual void pintar() = 0; };
};
class BolaFuego : public IArmas
class Hombre : public ILuchador {
{ friend class FactoriaObjetos;
friend class FactoriaObjetos; BolaFuego();
Hombre(); public:
public: virtual void moverseTrayectoria();
virtual void lanzarArma(); virtual bool haChocadoObjeto();
virtual void moverse(); virtual void pintar();
virtual bool haRecibidoDisparo(); };
virtual void pintar();
}; class Cuchillo : public IArmas
{
class Dragon : public ILuchador friend class FactoriaObjetos;
{ Cuchillo();
friend class FactoriaObjetos; public:
Dragon(); virtual void moverseTrayectoria();
public: virtual bool haChocadoObjeto();
virtual void lanzarArma(); virtual void pintar();
virtual void moverse(); };
virtual bool haRecibidoDisparo();
virtual void pintar();
}; #endif

#endif

Dpto. Electrónica, Automática e Informática Industrial 235


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

#ifndef _OBSTACULOS_INC_ #ifndef _FACTORIA_INC_


#define _OBSTACULOS_INC_ #define _FACTORIA_INC_

class FactoriaObjetos; #include "Luchadores.h"


#include "Armas.h"
typedef enum {PAREDMOVIL}
Derecho de Autor ©TipoObstaculos;
2007 Carlos Platero Dueñas.
#include "Obstaculos.h"

class IObstaculo class FactoriaObjetos {


{ Permiso para copiar, distribuir y/o modificar este documento
FactoriaObjetos(){}; // Para desactivarbajo los términos
public:
de la Licencia de Documentación Libre void operator=(FactoriaObjetos&)
GNU, Versión 1.1{}; o cualquier otra
virtual void moverseAleatoriamente() = 0; FactoriaObjetos(const FactoriaObjetos&) {};
versión
virtual posterior
void pintar() publicada por la Free
= 0; public:Software Foundation; sin secciones
}; static FactoriaObjetos&
invariantes, sin texto de la Cubierta Frontal, así comogetInstance()
el texto{ de la Cubierta
static FactoriaObjetos unicaInstancia;
Posterior. Una copia de la
class ParedMovil : public IObstaculolicencia es incluida en la
return unicaInstancia;sección titulada "Licencia de
{ Documentación Libre GNU". }
friend class FactoriaObjetos; IArma* metodoFabricacionArmas (TipoArmas tipo) {
ParedMovil(); if(tipo == BOLAFUEGO) return new BolaFuego;
public: else if(tipo == CUCHILLO) return new Cuchillo;
virtual void moverseAleatoriamente() = 0; else return NULL;}
virtual void pintar() = 0; ILuchador* metodoFabricacionLuchadores (TipoLuchador tipo)
}; {
La Licencia de documentación libre GNUif(tipo (GNU Freereturn
== HOMBRE) Documentation
new Hombre; License)
es una licencia con copyleft para contenidoselse if(tipo == DRAGON)
abiertos. return new
Todos losDragon;
contenidos de
#endif else return NULL;}
estos apuntes están cubiertos por esta IObstaculo
licencia. La version 1.1 se (TipoObstaculos
* metodoFabricacionObstaculos encuentra en
http://www.gnu.org/copyleft/fdl.html. La tipo){traducción (no oficial) al castellano de
if(tipo == PAREDMOVIL) return new ParedMovil;
la versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html
else return NULL;}
};
#endif
Problema 9

Se tienen las siguientes clases pertenecientes a unas librerías C++,


desarrolladas por los fabricantes de impresoras, y que sirven para imprimir un
archivo cualquiera en una impresora de un determinado fabricante.

Por tanto, las dos clases anteriores no se pueden modificar, tocar o


cambiar. Se desea hacer un programa que permita al usuario teclear el nombre
de un archivo, el nombre de la impresora de destino, y que el programa utilice
automáticamente la clase de la librería correspondiente. La función main de
ese programa (incompleta) seria. Se pide:
1. Diagrama UML de las clases existentes .
2. Diagrama de Clases de Diseño (DCD) de la solución.
3. Explicación (breve, con notas en el anterior diagrama) de los patrones
usados.
4. Implementación C++ de la solución propuesta (no olvidar completar el
main).

236 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

class EpsonPrinterDriver
{
public:
bool Print(char filename[]);
};
class HPControladorImpresora
{
public:
//este metodo devuelve 1 en caso de exito y -1 en caso de error
int ImprimeFichero(char* nombre_fichero);
};

int main()
{
char fichero[255],nombre_impresora[255];

cout<<"Introduzca en nombre de fichero: ";


cin>>fichero;
cout<<"Introduzca nombre impresora: HP o EPSON: ";
cin>>nombre_impresora;

Impresora* impresora=NULL;

//AQUÍ COMPLETAR CODIGO DE CREACION DE LA IMPRESORA ADECUADA


// en funcion de "nombre_impresora"

if(impresora==NULL)
{
cout<<"Impresora no existe"<<endl;
return -1;
}
if(impresora->Imprime(fichero))
cout<<"Impresion correcta"<<endl;
else
cout<<"Impresion fallida"<<endl;
return 1;
}

Dpto. Electrónica, Automática e Informática Industrial 237


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

Problema 10

Una nueva mejora se propone para el videojuego Pang de las prácticas


de la asignatura. Se pretende implementar una ÚNICA factoría para la creación
compleja de objetos (disparos, esferas, …). Siguiendo el Proceso Unificado, se
pide:
1. Ingeniería inversa de la versión actual del videojuego sobre las clases de
los disparos.
2. DCD de la nueva mejora, indicando los patrones que se emplean.
3. Ficheros de cabecera en C++ de la nueva versión.
4. Utilice las nuevas prestaciones en el servicio Mundo::Tecla(), sabiendo
que hombre.GetNumBonus() retorna el número de bonus. Si tiene más
de uno se generará lanzas, con un bonus se creará ganchos especiales
y sin bonus se construirán ganchos.

#if !defined(_DISPARO_INC_) #if !defined(_LANZA_INC_)


#define _DISPARO_INC_ #define _LANZA_INC_

typedef
enum{GANCHO,GANCHO_ESPECIAL,LANZA} #include "Disparo.h"
tipoDisparo;
class Lanza : public Disparo
class Disparo {
{ public:
public: void Dibuja();
Disparo(); Lanza();
virtual ~Disparo(); virtual ~Lanza();

tipoDisparo GetTipo(); protected:


virtual void Dibuja()=0; float largo;

protected: };
tipoDisparo tipo;
}; #endif

#endif

#if !defined(_GANCHO_INC_) #if


#define _GANCHO_INC_ !defined(_GANCHO_ESPECIAL_INC_)
#define _GANCHO_ESPECIAL_INC_
#include "Disparo.h"
#include "Gancho.h"
class Gancho : public Disparo
{ class GanchoEspecial : public
public: Gancho
void SetPos(float x, float y); {
void Dibuja(); public:
Gancho(); void Dibuja();
virtual ~Gancho(); GanchoEspecial();
float GetRadio(){return radio;} virtual ~GanchoEspecial();

protected: };
float radio;
#endif
};

#endif

238 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

void Mundo::Tecla(unsigned char key)


{
switch(key)
{
case ' ': if(disparos.GetNumero()<MAX_DISPAROS)
{
Disparo* d=Factoria::CrearDisparo(hombre);
disparos.Agregar(d);
}
break;
}
}

Se ha empleado los siguientes patrones: Singleton (GoF), Método de


Fabricación(GoF) y Factoría Abstracta(GoF).

Dpto. Electrónica, Automática e Informática Industrial 239


Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial

#if !defined(_DISPARO_INC_) #if !defined(_LANZA_INC_)


#define _DISPARO_INC_ #define _LANZA_INC_

typedef
enum{GANCHO,GANCHO_ESPECIAL,LANZA} #include "Disparo.h"
tipoDisparo;
class Lanza : public Disparo
class Disparo {
{ public:
public: void Dibuja();
virtual ~Disparo(); virtual ~Lanza();

tipoDisparo GetTipo(); protected:


virtual void Dibuja()=0; float largo;
friend class FactoriaObjetos;
protected: Lanza();
tipoDisparo tipo;
Disparo(); };
};
#endif
#endif

#if !defined(_GANCHO_INC_) #if


#define _GANCHO_INC_ !defined(_GANCHO_ESPECIAL_INC_)
#define _GANCHO_ESPECIAL_INC_
#include "Disparo.h"
#include "Gancho.h"
class Gancho : public Disparo
{ class GanchoEspecial : public
public: Gancho
void SetPos(float x, float y); {
void Dibuja(); public:
virtual ~Gancho(); void Dibuja();
float GetRadio(){return radio;} virtual ~GanchoEspecial();

protected: protected:
float radio; GanchoEspecial();
Gancho(); friend class FactoriaObjetos;
friend class FactoriaObjetos;
};
};
#endif
#endif

#if !defined(_FACTORIA_INC_)
#define _FACTORIA_INC_
#include "GanchoEspecial.h"
#include "Lanza.h"

class FactoriaObjetos
{
FactoriaObjetos() {}
public:
static FactoriaObjetos &getInstancia() {
static FactoriaObjetos laFactoria;
return (laFactoria);
}
Disparo * metodoFabricacionDisparo(tipoDisparo tipo) {
if(tipo == GANCHO) return new Gancho;
else if(tipo == GANCHO_ESPECIAL) return new
GanchoEspecial;
else if(tipo == LANZA) return new Lanza;
else return 0;
}
};
#endif

240 Dpto. Electrónica, Automática e Informática Industrial


Apuntes de Informática Industrial Carlos Platero

Derecho de Autor © 2014 Carlos Platero Dueñas.


Permiso para copiar, distribuir y/o modificar este documento bajo los términos de la
Licencia de Documentación Libre GNU, Versión 1.1 o cualquier otra versión
posterior publicada por la Free Software Foundation; sin secciones invariantes, sin
texto de la Cubierta Frontal, así como el texto de la Cubierta Posterior. Una copia de
la licencia es incluida en la sección titulada "Licencia de Documentación Libre
GNU".

La Licencia de documentación libre GNU (GNU Free Documentation License)


es una licencia con copyleft para contenidos abiertos. Todos los contenidos de estos
apuntes están cubiertos por esta licencia. La version 1.1 se encuentra en
http://www.gnu.org/copyleft/fdl.html. La traducción (no oficial) al castellano de la
versión 1.1 se encuentra en http://www.es.gnu.org/Licencias/fdles.html

Dpto. Electrónica, Automática e Informática Industrial 241

Você também pode gostar