Requisitos. tiempo. Integración Pruebas de sistema. 4 semana (por ejemplo) El sistema crece en cada iteración

Tamaño: px
Comenzar la demostración a partir de la página:

Download "Requisitos. tiempo. Integración Pruebas de sistema. 4 semana (por ejemplo) El sistema crece en cada iteración"

Transcripción

1 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 Requisitos Diseño Implementación Prueba tiempo Integración Pruebas de sistema Iteración i+1 Requisitos Diseño Implementación Prueba 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 143

2 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. Y en 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 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 coactadas a 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 144 Dpto. Electrónica, Automática e Informática Industrial

3 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 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, 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 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 145

4 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial RespuestaFrecuencia modulos : std::vector<double> argumentos : std::vector<double> frinicio : float frfinal : float frintervalo : float necesita conocer FDT grado : int esta definido por 1 FiltroLineal tipofiltro : int esta formado por 2 Polinomio coeficientes : std::vector<double> Patrón Fachada : Ingeniero electrónico introducircircuito() Vista : CoordinadorRespFr ponercircuito() Patrón creador create() : FiltroLineal create() : FDT introducirparametrosrespfr() ponerparamresfr() create() : RespuestaFrecuencia getmodulorespfr( ) getmodulorespfr() visualizarbode() 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 SISO, constituyéndolo con dos polinomios. 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 146 Dpto. Electrónica, Automática e Informática Industrial

5 Apuntes de Informática Industrial Carlos Platero de Bode, se realizará por argumento en este servicio, generando una relación de dependencia. CoordinadorRespFr ponercircuito() ponerparamresfr() getmodulorespfr() RespuestaFrecuencia frecuenciainicio : float frecuenciafin : float intervalofrec : float modulo : vector<double> argumento : vector<double> getmodulorespfr() Patrón Experto (GRASP) FiltroLineal tipofiltro : int FDT grado : unsigned 1 2 Polinomio coeficientes : vector<double> 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 receptor 2, 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 2 Recuerde que el objeto receptor es el que realiza la operación. Dpto. Electrónica, Automática e Informática Industrial 147

6 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial método para conseguir visibilidad global es utilizar el patrón Singleton [GoF]. Se declara con el estereotipo <<global>>. 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 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 Transformación del diseño al código para: La transformación en un lenguaje OO requiere la escritura del código fuente La definición de las clases e interfaces. Las definiciones de los métodos o servicios. 148 Dpto. Electrónica, Automática e Informática Industrial

7 Apuntes de Informática Industrial Carlos Platero 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 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 Informática Industrial" Carlos Platero. // (R) 2004 Con licencia GPL. // 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; void introducircircuito(void); void introducirparametrosrespfr(void); ; /*VistaFrecuencia.h*/ Dpto. Electrónica, Automática e Informática Industrial 149

8 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 "../../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 Informática Industrial" Carlos Platero. // Ver permisos en licencia de GPL #ifndef _POLINOMIO_INC_ #define _POLINOMIO_INC_ #include <vector> class Polinomio std::vector<double> coeficientes; 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*/ 150 Dpto. Electrónica, Automática e Informática Industrial

9 Apuntes de Informática Industrial Carlos Platero // De: "Apuntes de Informática Industrial" 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; 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*/ // De: "Apuntes de Informática Industrial" Carlos Platero. // Ver permisos en licencia de GPL #ifndef _FILTRO_LINEAL_INC_ #define _FILTRO_LINEAL_INC_ #include "FDT.h" typedef enumlf_1,hf_1 tipofiltro; class FiltroLineal tipofiltro eltipo; FDT *pfdt; 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*/ // De: "Apuntes de Informática Industrial" 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 *); 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 151

10 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; int ponercircuito(tipofiltro,float, float ); int ponerparamresfr(float,float,float); int getmodulorespfr(std::vector<double> &); ~CoordinadorFrecELAI() if(pfiltro) delete pfiltro; if(prespfr) delete prespfr; ; 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. // (R) 2006 Con licencia GPL. // 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 Informática Industrial" Carlos Platero. // Ver permisos en licencia de GPL #include "../../include/dominio/respuestafrecuencia.h" #include <iostream> #include <math.h> #define PI #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) // Dpto. Electrónica, Automática e Informática Industrial

11 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); 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: RespuestaFrecuencia VistaFrecuenciaELAI introducircircuito() introducirparametrosrespfr() CoordinadorFrecELAI 1 1 calcularmodulo() calcularargumento() RespuestaFrecuencia() getfrinicio() getfrfinal() getfrintervalo() getmodulo() getmodulorespfr() <<typedef>> tipofiltro vector<double> 1 1 Polinomio Polinomio() Polinomio() getcoeficiente() CoordinadorFrecELAI() ponercircuito() ponerparamresfr() getmodulorespfr() ~CoordinadorFrecELAI() 1 1 FiltroLineal FiltroLineal() getgradofiltro() getcoefnum() getcoefden() 1 1 FDT FDT() FDT() getgrado() getcoefnum() getcoefden() 1 2 Dpto. Electrónica, Automática e Informática Industrial 153

12 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 ayudar a aplicar sistemáticamente los principios fundamentales para asignar responsabilidades a los objetos Patrones En 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. 154 Dpto. Electrónica, Automática e Informática Industrial

13 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 Experto en Información Problema: Solución: Cuál es el principio general para asignar responsabilidades? 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, en el problema 3 del capítulo anterior, cuando había que mandar a dibujar la urbanización, esta tarea era dividida por cada casa y cada casa por su tejado y bloque. Para asignar la responsabilidad se emplearán las clases del DCD. En una primera iteración, se utilizará el Modelo del Dominio, en versiones posteriores se consultaran los DCD generados en las iteraciones anteriores. La idea es ir ampliando o actualizando las nuevas clases del diseño. Si se empieza el trabajo del diseño y no hay nada en el modelo 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 filtro Definir matemáticamente la estructura del filtro RespuestaFrecuencia Los parámetros de frecuencia Aplicar los algoritmos para calcular el Bode RespuestaFrecuencia frecuenciainicio : float frecuenciafin : float intervalofrec : float modulo : vector<double> argumento : vector<double> calcularbode() Patrón Experto (GRASP) FiltroLineal tipofiltro : int FDT grado : unsigned 1 2 Polinomio coeficientes : vector<double> Dpto. Electrónica, Automática e Informática Industrial 155

14 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 separado la lógica de la aplicación con la lógica de la base de datos o la lógica del dominio con el 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 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. 156 Dpto. Electrónica, Automática e Informática Industrial

15 Apuntes de Informática Industrial Carlos Platero A menudo, la creación requiere una complejidad significativa, como utilizar instancias recicladas por motivos de rendimientos o crear instancias de forma 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 : CoordinadorRespFr Patrón creador ponercircuito() create() : FiltroLineal create() : FDT ponerparamresfr() create() : 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); Dpto. Electrónica, Automática e Informática Industrial 157

16 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Alta Cohesión Problema: Cómo mantener la complejidad manejable? alta. Solución: Asignar una responsabilidad de manera que la cohesión permanezca 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 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. Otros 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. Ejemplo Dpto. Electrónica, Automática e Informática Industrial

17 Apuntes de Informática Industrial Carlos Platero 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. ActiveX-Bode VistaFrecuencia ELAI MFC (.NET) DominioFrecunc iaela STL-ANSI C++ 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. 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 muestra su facilidad de reutilización. Dpto. Electrónica, Automática e Informática Industrial 159

18 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial CoordinadorSimulador FDT <<create>> setcoeficientesfdt() 1 2 Polinomio (f rom Analysis Model) coeficientes introducirmodelo() especificarexcitacion() mostrarsalida() notificarresultados() tiempofinal intervalotiempo valoressalida Simulador_LTI (from Analysis Model) tiposenyal SenyalExcitacion calcularsalida() <<create>> setsimulador(lafdt : FDT, lasenyalexc : SenyalEscalon) <<create>> setsenyalexcitacion() Bajo Acoplamiento Pregunta: Cómo soportar el bajo impacto del cambio e incrementa la reutilización? 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, o tiene conocimiento de, o confía en otros elementos. Una clase con alto acoplamiento confía en muchas otras clases. Tales clases podrían no ser deseables; 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. 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 han 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 Acomplamiento. 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 Controlador Problema: Quién debe ser el responsable de gestionar un evento de entrada al sistema? 160 Dpto. Electrónica, Automática e Informática Industrial

19 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 el método para la 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. 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. El controlador es una especie de fachada del paquete que recibe los eventos externos y organiza las tareas. 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. 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 y la capa interfaz, no deberían ser responsables de manejar los eventos del sistema. Incrementa el potencial de reutilización. Dpto. Electrónica, Automática e Informática Industrial 161

20 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 violación 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. 162 Dpto. Electrónica, Automática e Informática Industrial

21 Apuntes de Informática Industrial Carlos Platero : VistaFrecuenciaELAI : FiltroLineal 1: ponercircuito(tipofiltro, float, float) 3: ponerparamresfr(float, float, float) create() 2: FiltroLineal(tipoFiltro, float, float) : CoordinadorFrecELAI 4: RespuestaFrecuencia(float, float, float, FiltroLineal*) create() : RespuestaFrecuencia RespuestaFrecuencia VistaFrecuenciaELAI introducircircuito() introducirparametrosrespfr() CoordinadorFrecELAI 1 1 calcularmodulo() calcularargumento() RespuestaFrecuencia() getfrinicio() getfrfinal() getfrintervalo() getmodulo() getmodulorespfr() <<typedef>> tipofiltro vector<double> 1 1 Polinomio Polinomio() Polinomio() getcoeficiente() CoordinadorFrecELAI() ponercircuito() ponerparamresfr() getmodulorespfr() ~CoordinadorFrecELAI() 1 1 FiltroLineal FiltroLineal() getgradofiltro() getcoefnum() getcoefden() 1 1 FDT FDT() FDT() getgrado() getcoefnum() getcoefden() 1 2 // 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); Dpto. Electrónica, Automática e Informática Industrial 163

22 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial 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? Solución: Cuando las alternativas o comportamientos relacionados varían según los tipos de los datos, asignar la responsabilidad para el comportamiento utilizando operaciones polimórficas, de forma que varía 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 switchcase, 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. Beneficios: Se añaden fácilmente las extensiones necesarias para nuevas variaciones. Las nuevas implementaciones se pueden introducir sin afectar a los clientes. Ejemplo 6.8 En el ejemplo de la urbanización, cómo asignaría la responsabilidad de una casa con garaje?. Se diseñaría una relación de generalización-especialización y se aplicaría polimorfismo en el servicio de dibuja(). 164 Dpto. Electrónica, Automática e Informática Industrial

23 Apuntes de Informática Industrial Carlos Platero Casa Casa() <<virtual>> ~Casa() setposicion() <<virtual>> dibuja() CasaConGaraje CasaConGaraje() dibuja() 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 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. Dpto. Electrónica, Automática e Informática Industrial 165

24 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Suelo y Esfera son clases conceptuales y por tanto candidatas a 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. Interaccion interaccionesferasuelo() Esfera Suelo Fabricación Pura Problema: Qué objetos deberían de tener las responsabilidades cuando no se quiere violar 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 por que favorece el objetivo de salto en la representación reducida. En la descomposición por comportamiento se asigna responsabilidades agrupando comportamiento o algoritmos, 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 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. 166 Dpto. Electrónica, Automática e Informática Industrial

25 Apuntes de Informática Industrial Carlos Platero Muchos de los patrones 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. Separar la lógica del dominio de la vista (Observador-GoF). Coordinador o fachada. 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. AlmacenamientoPersistente AlmacenamientoPersistente() <<local>> <<parameter>> CoordinadorFrecELAI ponercircuito() ponercircuito() ponerparamresfr() guardarresultadosrespfr() ponerparamresfr() ~CoordinadorFrecELAI() RespuestaFrecuencia getmodulo() calcularmodulo() calcularargumento() RespuestaFrecuencia() getfrinicio() getfrfinal() getfrintervalo() Dpto. Electrónica, Automática e Informática Industrial 167

26 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial : AlmacenamientoPersistente : VistaFrecuenciaELAI 3: getmodulo(float) 1: guardarresultadosrespfr(const char*) create() : RespuestaFrecuencia 2: AlmacenamientoPersistente(RespuestaFrecuencia*, const char*) : CoordinadorFrecELAI // De: "Apuntes de Informática Industrial" Carlos Platero. // (R) 2005 Con licencia GPL. // 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); 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 definen 168 Dpto. Electrónica, Automática e Informática Industrial

27 Apuntes de Informática Industrial Carlos Platero 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 que debe de soportar a la vez. 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. Debido a que el programa debe de crecer, el concepto de Figura debe ser aplicado de forma genérica (interfase). 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 169

28 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial <<typedef>> tipofigura <<interface>> IFiguras <<abstract>> getarea() <<static>> MetodoFabricacionFiguras() Circulo radio : double Circulo() <<virtual>> getarea() Rectangulo lado1 : double lado2 : double Rectangulo() <<virtual>> getarea() #ifndef _AREAS_FIGURA_INC_ #define _AREAS_FIGURA_INC_ typedef enum tipofig CIRCULO, RECTANGULO tipofigura; class IFiguras virtual double getarea() = 0; static IFiguras* MetodoFabricacionFiguras (tipofigura, double, double); ; class Circulo: public IFiguras double radio; friend class IFiguras; Circulo(double param1):radio(param1) 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) virtual double getarea() return (lado1*lado2); ; #endif 170 Dpto. Electrónica, Automática e Informática Industrial

29 Apuntes de Informática Industrial Carlos Platero 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 versiones 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. 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. 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. Dpto. Electrónica, Automática e Informática Industrial 171

30 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial #include <iostream> #include <vector> using namespace std; class Comando virtual void ejecutar() = 0; ; class Hola : public Comando void ejecutar() cout << "Hola "; ; class Mundo : public Comando void ejecutar() cout << "Mundo! "; ; class Patron : public Comando void ejecutar() cout << "Soy el comando patron!"; ; class Macro vector<comando*> Comandos; 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(); 172 Dpto. Electrónica, Automática e Informática Industrial

31 Apuntes de Informática Industrial Carlos Platero 1) vector<comando*> <<interface>> Comando <<abstract>> ejecutar() : void 2) Macro incluir() realizar() principal incluir(new Hola) : Macro : Hola Hola ejecutar() Mundo ejecutar() Patron ejecutar() incluir(new Patron) : Patron realizar( ) ejecutar( ) ejecutar( ) 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. 5) vector<comando*> <<interface>> Comando <<abstract>> ejecutar() : void Macro incluir() realizar() Saludo ejecutar() Hola ejecutar() Mundo ejecutar() Patron ejecutar() class Saludo : public Comando 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. Dpto. Electrónica, Automática e Informática Industrial 173

32 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Por otro lado, uno de los patrones antiguos GRASP era No hable con Extraños o Ley de Demeter. Significa 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. Pero ahora, con el principio de Variaciones Protegidas, se sustituye a No hable con Extraños. 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: 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. Ejemplos de Variaciones Protegidas Las máquinas virtuales son ejemplos complejos de Indirección para conseguir VP. 3 Para los programadores noveles se aconseja utilizar este patrón. Empléese en el trabajo de curso. 174 Dpto. Electrónica, Automática e Informática Industrial

33 Apuntes de Informática Industrial Carlos Platero Lectura y escritura de datos de sistemas externos. Diseños dirigidos por un intérprete. 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). ActiveX-Bode VistaFrecuencia ELAI MFC (.NET) DominioFrecunc iaela STL-ANSI C++ Entre las posibles soluciones tecnológicas actuales, se ha elegido NTGraph 4. En un diseño robusto, esta inserción supone un punto caliente. Por varios motivos: En el futuro se puede cambiar de componente, esto es, 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 Indireción, Polimorfismo y Fabricación Pura. 4 Dpto. Electrónica, Automática e Informática Industrial 175

34 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial CRespFrMFCDlg Cliente del paquete Visualizador Constructor privado Método de Fabricacion (GoF) <<interface>> IAdaptadorVisualizar <<abstract>> InicializarPlotXY() <<abstract>> PintarPlotXY() <<static>> factoriavisualizadores() AdaptadorVisualCNTGraph AdaptadorVisualCNTGraph() <<virtual>> InicializarPlotXY() <<virtual>> PintarPlotXY() Interfaz estable Solución tecnológica CNTGraph // De: "Apuntes de Informática Industrial" Carlos Platero. // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL #include "../../ntgraph.h" //Tipos de visualizadores enum PlataformaVisualNTGRAPH ; class IAdaptadorVisualizar 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; virtual void InicializarPlotXY(void); virtual void PintarPlotXY(float,float,float, double *); ; 176 Dpto. Electrónica, Automática e Informática Industrial

35 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; llamados comúnmente Gang of Four, GoF. En este libro se muestran 23 patrones ampliamente utilizados. En este apartado se tratarán algunos de ellos 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. Dpto. Electrónica, Automática e Informática Industrial 177

36 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial 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, es decir, 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. Cliente <<interface>> Objetivo Implementación del servicio Adaptador Adaptable 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. 178 Dpto. Electrónica, Automática e Informática Industrial

37 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: F n = F + n 1 Fn Un generador de la serie de Fibonacci ha sido tomado de Bruce Eckel y Check Allison 5. Adaptarlo para emplear los algoritmos dados por las STL. // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) MindView, Inc. All Rights Reserved. // See source code use permissions stated in the file 'License.txt', // distributed with the code package available at #ifndef FIBONACCIGENERATOR_H #define FIBONACCIGENERATOR_H class FibonacciGenerator int n; int val[2]; 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 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) MindView, Inc. Dpto. Electrónica, Automática e Informática Industrial 179

38 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial <<interface>> IAdaptadorFibonacci <<abstract>> getserie() <<static>> factoriafibonacci() AdaptadorFibonacci tamanyo : unsigned FibonacciGenerator n : int val[2] : int AdaptadorFibonacci() <<virtual>> getserie() 1 1 FibonacciGenerator() operator()() count() Las clases de los roles objetivo y adaptador quedarán definidas como: // De: "Apuntes de Informática Industrial" Carlos Platero. // (R) 2004 Con licencia GPL. // 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 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()); ; virtual std::vector<unsigned> & getserie() return elvectorfibon; 180 Dpto. Electrónica, Automática e Informática Industrial

39 Apuntes de Informática Industrial Carlos Platero El cliente, ahora, podrá emplear al generador de la serie de Fibonacci utilizando las funciones algorítmicas de las STL. // De: "Apuntes de Informática Industrial" Carlos Platero. // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL // //Ejemplo del patrón GoF de adaptador //Desde un generador de números de Fibonnaci, dado en FibonacciGenerator.h, //Adaptación para emplear las STL //Código de prueba (XP) #include <iostream> #include "AdaptadorFibonacci.h" #include <numeric> #include <algorithm> IAdaptadorFibonacci* IAdaptadorFibonacci::factoriaFibonacci(unsigned grado) return (new AdaptadorFibonacci(grado)); using namespace std; void imprimir(unsigned); int main() const unsigned numerofibo = 20; IAdaptadorFibonacci *padaptadorfibo = IAdaptadorFibonacci::factoriaFibonacci(numeroFibo); cout << "Tabla de Fibonacci" <<endl; cout << " " <<endl; for_each(padaptadorfibo->getserie().begin(),padaptadorfibo->getserie().end(), imprimir); //Ver GRASP "No hable con extraños" y el código maduro cout << "Valor acumulado total: " << accumulate(padaptadorfibo->getserie().begin(), padaptadorfibo->getserie().end(), 0) << endl; return 0; void imprimir(unsigned numfibo) static unsigned indice; cout << indice++ << ": " << numfibo <<endl; Dpto. Electrónica, Automática e Informática Industrial 181

40 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial 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 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 182 Dpto. Electrónica, Automática e Informática Industrial

41 Apuntes de Informática Industrial Carlos Platero objetos que implementan los servicios. A este patrón GoF se le llama Factoría Abstacta. Se empleará cuando: 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: <<interface>> IProductoA Cliente ProductoA1 ProductoA2 <<interface>> IProductoB <<interface>> IFactoriaObjetos MetodoFabricacion() FactoriaConcretaA MetodoFabricacion() ProductoB2 ProductoB1 FactoriaConcretaB 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. Dpto. Electrónica, Automática e Informática Industrial 183

42 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Factoría Abstracta: declara una interfaz para operaciones que crean objetos productos abstractos Factoría Concreta: implementa las operaciones para crear objetos producto concretos 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: ITuerca <<abstract>> getmetrica() ITornillo <<abstract>> getmetrica() IFactoria <<abstract>> fabricaciontornillo() <<abstract>> fabricaciontuerca() TornilloDIN84 FactoriaTornillos TuercaDIN84 TuercaDIN84() <<virtual>> getmetrica() TornilloDIN84() <<virtual>> getmetrica() TuercaDIN316 <<virtual>> getmetrica() <<virtual>> fabricaciontornillo() <<virtual>> fabricaciontuerca() TornilloDIN316 TornilloDIN316() <<virtual>> getmetrica() FactoriaTuercas <<virtual>> fabricaciontornillo() <<virtual>> fabricaciontuerca() <<typedef>> metrica 184 Dpto. Electrónica, Automática e Informática Industrial

43 Apuntes de Informática Industrial Carlos Platero typedef enumdin84, DIN316 metrica; class FactoriaTuercas; class ITuerca virtual metrica getmetrica() = 0; ; class TuercaDIN84 : public ITuerca metrica lametrica; friend class FactoriaTuercas; TuercaDIN84() lametrica = DIN84; virtual metrica getmetrica() return lametrica; ; class TuercaDIN316 : public ITuerca metrica lametrica; friend class FactoriaTuercas; TuercaDIN316() lametrica = DIN316; virtual metrica getmetrica() return lametrica; ; class FactoriaTornillos; class ITornillo virtual metrica getmetrica() = 0; ; class TornilloDIN84 : public ITornillo metrica lametrica; friend class FactoriaTornillos; TornilloDIN84() lametrica = DIN84; virtual metrica getmetrica() return lametrica; ; class TornilloDIN316 : public ITornillo metrica lametrica; friend class FactoriaTornillos; TornilloDIN316() lametrica = DIN316; virtual metrica getmetrica() return lametrica; ; Dpto. Electrónica, Automática e Informática Industrial 185

44 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial class IFactoria virtual ITornillo * fabricaciontornillo(metrica) = 0; virtual ITuerca * fabricaciontuerca(metrica) = 0; ; class FactoriaTornillos : public IFactoria 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 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: 186 Dpto. Electrónica, Automática e Informática Industrial

45 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. <<interface>> IFactoriaObjetos MetodoFabricacion() : IProductoA <<interface>> IProductoA FactoriaConcretaA MetodoFabricacion() ProductoA1 ProductoA2 return new ProductoConcreto 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 187

46 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. Cliente (from Logical View) <<interface>> INombre <<abstract>> setnombre() <<abstract>> getnombre() <<enum>> Plataforma <<interface>> IFactoriaNombre <<abstract>> MetodoFabricacionNombre() STDNombre <<virtual>> setnombre() <<virtual>> getnombre() STDNombre() CNombre elnombre[80] : char <<virtual>> setnombre() <<virtual>> getnombre() CNombre() MFCNombre (from MetodoFabriacion) <<virtual>> setnombre() <<virtual>> getnombre() MFCNombre() FactoriaNombre <<virtual>> MetodoFabricacionNombre() #ifndef _INOMBRE_INC_ #define _INOMBRE_INC_ enum PlataformaESTANDAR_STL, ESTILO_C, CADENA_MFC; class INombre virtual void setnombre (const char *) = 0; virtual const char * getnombre () = 0; ; #endif #ifndef _INC_MFCNOMBRE_ #define _INC_MFCNOMBRE_ #include <afx.h> #include "INombre.h" class FactoriaNombre; class MFCNombre : public INombre virtual void setnombre(const char *cadena) elnombre=cadena; virtual const char * getnombre (void) return (elnombre); private: CString elnombre; MFCNombre () friend class FactoriaNombre; ; #endif // De: "Apuntes de Informática Industrial" // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL #ifndef _INC_STDNOMBRE_ #define _INC_STDNOMBRE_ #include <string> #include "INombre.h" class FactoriaNombre; class STDNombre : public INombre virtual void setnombre(const char *cadena) elnombre = cadena; virtual const char * getnombre (void) return (elnombre.c_str()); private: std::string elnombre; STDNombre () friend class FactoriaNombre; ; #endif 188 Dpto. Electrónica, Automática e Informática Industrial

47 Apuntes de Informática Industrial Carlos Platero // De: "Apuntes de Informática Industrial" // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL #ifndef _INC_CNOMBRE_ #define _INC_CNOMBRE_ #include <string> #include "INombre.h" class FactoriaNombre; class CNombre : public INombre virtual void setnombre(const char *cadena) strcpy (elnombre, cadena); virtual const char * getnombre (void) return (elnombre); private: char elnombre[80]; CNombre () friend class FactoriaNombre; ; // De: "Apuntes de Informática Industrial" // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL #include <iostream> #include "../includes/inombre.h" #include "../includes/factorianombres.h" // Ver permisos en licencia de GPL #ifndef _IFACTORIA_INC_ #define _IFACTORIA_INC_ #include "STDNombre.h" #include "CNombre.h" #include "MFCNombre.h" class IFactoriaNombre virtual INombre* MetodoFabricacionNombre (enum Plataforma) = 0; ; class FactoriaNombre: public IFactoriaNombre virtual 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 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 189

48 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial <<interface>> INombre <<abstract>> setnombre() <<abstract>> getnombre() STDNombre <<virtual>> setnombre() <<virtual>> getnombre() STDNombre() CNombre elnombre[80] : char <<virtual>> setnombre() <<virtual>> getnombre() CNombre() MFCNombre (from MetodoFabriacion) <<virtual>> setnombre() <<virtual>> getnombre() MFCNombre() // De: "Apuntes de Informática Industrial" // Ver permisos en licencia de GPL #ifndef _INOMBRE_INC_ #define _INOMBRE_INC_ enum PlataformaESTANDAR_STL, ESTILO_C, CADENA_MFC; class INombre virtual void setnombre (const char *) = 0; virtual const char * getnombre () = 0; //Factoria de objetos static INombre *MetodoFabricacionNombre(enum Plataforma); ; #endif // De: "Apuntes de Informática Industrial" // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL #ifndef _INC_STDNOMBRE_ #define _INC_STDNOMBRE_ #include <string> #include "INombre1.h" class CNombre : public INombre virtual void setnombre(const char *cadena) strcpy (elnombre, cadena); virtual const char * getnombre (void) return (elnombre); private: char elnombre[80]; ; #endif // De: "Apuntes de Informática Industrial" // (R) 2005 Con licencia GPL. // Ver permisos en licencia de GPL #ifndef _INC_STDNOMBRE_ #define _INC_STDNOMBRE_ #include <string> #include "INombre.h" class STDNombre : public INombre virtual void setnombre(const char *cadena) elnombre = cadena; virtual const char * getnombre (void) return (elnombre.c_str()); private: std::string elnombre; STDNombre () //Desactivar al constructor friend class INombre; // Sólo se fabrica //desde el método de fabricación ; #endif #ifndef _INC_MFCNOMBRE_ #define _INC_MFCNOMBRE_ #include <afx.h> #include "INombre.h" class MFCNombre : public INombre virtual void setnombre(const char *cadena) elnombre=cadena; virtual const char * getnombre (void) return (elnombre); private: CString elnombre; ; #endif 190 Dpto. Electrónica, Automática e Informática Industrial

49 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::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; 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; 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 191

50 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 <<1>> Singleton <<static>> unicainstancia : Singleton datosdelsingleton retorna unicainstancia Singleton() operator=() <<static>> getinstancia() operacionesdatossingleton() #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 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; 192 Dpto. Electrónica, Automática e Informática Industrial

51 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). Cliente1 Cliente2 <<interface>> INombre <<abstract>> setnombre() <<abstract>> getnombre() <<1>> FactoriaUnicaNombres FactoriaUnicaNombres() operator=() FactoriaUnicaNombres() <<static>> getinstancia() MetodoFabricacionNombre() MFCNombre <<virtual>> setnombre() <<virtual>> getnombre() <<enum>> Plataforma CNombre <<virtual>> setnombre() <<virtual>> getnombre() MFCNombre <<virtual>> setnombre() <<virtual>> getnombre() // 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 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 193

52 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial // De: "Apuntes de Informática Industrial" Carlos Platero. // (R) 2005 Con licencia GPL. // 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 abstractas FactoriaUnicaNombres &lamismafactoria = FactoriaUnicaNombres::getInstancia(); INombre *pnombre3 = lamismafactoria.metodofabricacionnombre (CADENA_MFC); pnombre3->setnombre("ana Blanco"); cout << pnombre3->getnombre() << endl; delete pnombre3; Estrategia Problema: Cómo diseñar diversos algoritmos o políticas que están relacionadas? Cómo diseñar que estos algoritmos o políticas se puedan variar dinámicamente? Solución: Defina cada algoritmo/política/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. 194 Dpto. Electrónica, Automática e Informática Industrial

53 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 EstrategiaConcreta, a través de su interfaz. Contexto <<interface>> IEstrategia EstrategiaConcretaA EstrategiaConcretaB Un objeto estrategia se agrega a un objeto de contexto, esto es, el objeto contexto necesita tener visibilidad de atributo de su estrategia. Además es habitual que el objeto contexto pase una referencia de él mismo al objeto estrategia, de manera que la estrategia tenga visibilidad de parámetro de 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, mientras se está ejecutando la aplicación, la política de actuació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 políticas que varían dinámicamente. La Estrategia se fundamenta en el Polimorfismo y en las intefaces 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 195

54 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 ConversorMoneda convertirdolaraeuro() convertirlibraaeuro() ConversorMoneda() geteuros() getdolar() getlibras() 1 1 <<interface>> IMoneda <<abstract>> geteuros() <<abstract>> getdolar() <<abstract>> getlibras() <<static>> MetodoFabricacion() <<typedef>> tipomoneda MonedaLibra cantidad : double MonedaEuro cantidad : double MonedaEuro() <<virtual>> geteuros() <<virtual>> getdolar() <<virtual>> getlibras() MonedaDolar cantidad : double MonedaDolar() <<virtual>> geteuros() <<virtual>> getdolar() <<virtual>> getlibras() MonedaLibra() <<virtual>> geteuros() <<virtual>> getdolar() <<virtual>> getlibras() 196 Dpto. Electrónica, Automática e Informática Industrial

55 Apuntes de Informática Industrial Carlos Platero typedef enum EURO,DOLAR,LIBRA tipomoneda; class ConversorMoneda; class IMoneda 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; 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; 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; 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; 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 197

56 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Observador Problema: Diferentes tipos de objetos receptores subscritores 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 subscriptores Qué hacer?. Solución: Defina una interfaz subscriptor u oyente. Los subscriptores implementan esta interfaz. El emisor dinámicamente puede registrar subscriptores que están interesados en un evento y notificarles cuando ocurre un evento. Este patrón define una dependencia de uno-a-muchos entre objetos, de forma que cuando un objeto cambie de estado se notifique y se actualicen automáticamente a todos los objetos que dependen 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 de la interfaz de usuario del dominio del problema. Las clases que definen los datos de las aplicaciones y las representaciones pueden utilizarse de forma independiente. Así en un objeto hoja de cálculo y un gráfico de barras pueden representar la 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 Modelo-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 notifica a sus observadores. En respuesta, cada observador consultará al Observable para sincronizar su estado con el estado de éste. 198 Dpto. Electrónica, Automática e Informática Industrial

57 Apuntes de Informática Industrial Carlos Platero 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 notificaciones. Los roles que se desempeñan en este patrón son: 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. 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 del sujeto. o Implementa la interfaz de actualización del Observador para mantener su estado consistente con el del sujeto. Así, el ObservableConcreto notifica a sus observadores, cada vez que se produce un cambio. 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. Observable <<interface>> Observer <<virtual>> ~Observer() <<abstract>> update() ObservadorConcreto <<parameter>> <<virtual>> ~Observable() <<virtual>> notifyobservers() <<virtual>> haschanged() <<virtual>> countobservers() <<virtual>> deleteobservers() <<virtual>> deleteobserver() <<virtual>> addobserver() <<virtual>> clearchanged() <<virtual>> setchanged() SujetoConcreto Dpto. Electrónica, Automática e Informática Industrial 199

58 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial El siguiente diagrama de secuencias muestra los métodos entre el emisor y receptor. : SujetoConcreto : ObservadorConcreto addobserver(observer&) notifyobservers(argument*) update(observable*, Argument*) 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 al Observador. El Observable no conoce la clase concreta de ningún observador. Por tanto el acoplamiento entre sujetos y observador 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 haya; 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. 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 200 Dpto. Electrónica, Automática e Informática Industrial

59 Apuntes de Informática Industrial Carlos Platero observadores y sus objetos dependientes. Más aún, los criterios de dependencia que no están bien definidos o mantenidos suelen provocar falsas actualizaciones que pueden ser muy difíciles de localizar 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. El patrón del Observer permite que se modifique desde fuera el código y luego se le indica al patrón del Observer, en ejecución, que haga las correspondientes actualizaciones. La clase Observable llama a la función miembro notifyobservers() para cada observador en la lista de observadores a la escucha. Primero, se presenta el Observer: // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) MindView, Inc. All Rights Reserved. // //: C10:Observer.h // The Observer interface. #ifndef OBSERVER_H #define OBSERVER_H class Observable; class Argument ; class Observer // 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. Además, la clase de la discusión es virtual y es una superclase empleada para cualquier tipo de atributos que se desean pasar durante una actualización. 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) 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; virtual void addobserver(observer& o) observers.insert(&o); Dpto. Electrónica, Automática e Informática Industrial 201

60 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial virtual void deleteobserver(observer& o) observers.erase(&o); virtual void deleteobservers() observers.clear(); virtual int countobservers() return observers.size(); 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. En un diseño más simple, no habría indicador; si sucedió algo, cada uno sería notificado. La colección de objetos del 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(). 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 Las clases internas Las clases que están a la escucha requieren de una interfaz que las permitan tener la propiedad de ser observables. 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 no estático de la clase que las contiene implícitamente, esto es, una instancia de la clase interna tenga acceso a datos de la clase que la ha creado. Se presenta un ejemplo del idioma interno: // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) MindView, Inc. All Rights Reserved. // //: C10:InnerClassIdiom.cpp // Example of the "inner class" idiom. #include <iostream> #include <string> using namespace std; class Poingable virtual void poing() = 0; ; void callpoing(poingable& p) p.poing(); class Bingable virtual void bing() = 0; ; void callbing(bingable& b) 202 Dpto. Electrónica, Automática e Informática Industrial

61 Apuntes de Informática Industrial Carlos Platero b.bing(); class Outer string name; // Define one inner class: class Inner1; friend class Outer::Inner1; class Inner1 : public Poingable Outer* parent; 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; Inner2(Outer* p) : parent(p) void bing() cout << "bing called for " << parent->name << endl; inner2; 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; ; int main() Outer x("ping Pong"); // Like upcasting to multiple base types!: callpoing(x); callbing(x); ///:~ 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 Entre flores, abejas y colibríes Armado con el observador, los archivos de observables y el idioma interno de la clase, ahora podemos mirar un ejemplo del patrón del observador: Dpto. Electrónica, Automática e Informática Industrial 203

62 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) MindView, Inc. All Rights Reserved. // //: C10:ObservedFlower.cpp // Demonstration of "observer" pattern. #include <algorithm> #include <iostream> #include <string> #include <vector> #include "Observable.h" using namespace std; class Flower bool isopen; 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; 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; 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; 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; CloseObserver(Bee* b) : parent(b) void update(observable*, Argument *) cout << "Bee " << parent->name 204 Dpto. Electrónica, Automática e Informática Industrial

63 Apuntes de Informática Industrial Carlos Platero << "'s bed time! << endl; closeobsrv; 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; 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; CloseObserver(Hummingbird* h) : parent(h) void update(observable*, Argument *) cout << "Hummingbird " << parent->name << "'s bed time! << endl; closeobsrv; 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(); ///:~ Propósito Patrones de diseño GoF Tema que trata Dpto. Electrónica, Automática e Informática Industrial 205

64 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial De creación Estructurales De comportamiento Factoría Abstracta Método de Fabricación Singleton Adaptador Fachada Observador Estrategia Uso de familias de referencias abstractas, ocultado las implementaciones concretas. Creación de las clases concretas. la única instancia de una clase la interfaz de un objeto la interfaz de un subsistema cómo se mantiene actualizado el objeto dependiente 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: M ( z) = z z 1.883z Dpto. Electrónica, Automática e Informática Industrial

65 Apuntes de Informática Industrial Carlos Platero 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 δ δ = k k k 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 Empleando Matlab, la solución quedaría como: >> g1=tf([ ],[ ],.025) >>step(g1) Una vez realizado las pruebas de conceptos se pasa al modelo del dominio y al DSS: ModeloSistema tiene definido el sistema mediante un Simulador_LTI tiempofinal periodomuestreo valoressalida esta definido por FDT grado : unsigned Senyal_Entrada eltipoentrada estimula al sistema con getvalorinstantek() Dpto. Electrónica, Automática e Informática Industrial 207

66 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Ingeniero de Control : <Actor Name> : Sistema introducirmodelo() Se le pasará los coeficientes de la FDT del sistema especificarexcitacion() mostrarsalida() Se le dirá cuál es 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 GraficoPlot Patrón Alta Cohesion, Bajo Acoplamiento, Capa por: El diagrama de interacción y el DCD del paquete del dominio estará constituido 208 Dpto. Electrónica, Automática e Informática Industrial

67 Apuntes de Informática Industrial Carlos Platero : Vista introducirmodelo( ) : CoordinadorSimulador Patrón Fachada Patrón Creador create() : ModeloSistema Patrón Experto en Información especificarexcitacion( ) create() : Senyal_Entrada create() : Simulador_LTI Algoritmia para calcular la señal de salida getcoefnum( ) getcoefden( ) calcularsalida( ) getvalorinstantek( ) mostrarsalida( ) getsenyasalida( ) CoordinadorSimulador (f rom Design Model) introducirmodelo() especificarexcitacion() mostrarsalida() notificarresultados() Senyal_Entrada (from Analysis Model) eltipoentrada getvalorinstantek() ModeloSistema (from Analysis Model) getcoefnum() getcoefden() FDT (from Analysis Model) grado : unsigned 1 2 Polinomio (from Analysis Model) coeficientes : std::vector<double> Simulador_LTI (f rom Analysis Model) tiempofinal periodomuestreo valoressalida calcularsalida() getsenyasalida() Problema 2 Dpto. Electrónica, Automática e Informática Industrial 209

68 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 Empléese sobre el punto p2. ( θ ) sin ( θ ) ( θ ) cos( θ ) x2 cos x1 = y2 sin y1 #include <iostream> #include <string> #include <cmath> using namespace std; class Punto 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 double magnitud, direccion; Vector(double m, double d) : magnitud(m), direccion(d) ; class Espacio 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)); cout << "p1: " << p1 << " p2: " << p2 << endl; return 0; a) Diagrama de clases de la ingeniería inversa 210 Dpto. Electrónica, Automática e Informática Industrial

69 Apuntes de Informática Industrial Carlos Platero Espacio <<static>> trasladar(p : Punto, v : Vector) : Punto x y Punto Punto(xi : double, yi : double) Punto(p : const Punto&) operator=(rhs : const Punto&) : Punto& <<friend>> operator<<(os : ostream&, p : const Punto&) : ostream& magnitud direccion Vector Vector(m : double, d : double) b) Diagrama de secuencia de la ingeniería inversa : main : Espacio Punto(double, double) p1 : Punto Vector(double, double) : Vector trasladar(punto, Vector) Punto(const Punto&) p2 : Punto 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 211

70 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial class Espacio 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)); Punto p3 = Espacio::rotar(p2,3.1416/6); cout << "p1: " << p1 << " p2: " << p2 << " p3: " << p3 <<endl; return 0; 212 Dpto. Electrónica, Automática e Informática Industrial

71 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 pide: #ifndef NUMEROSPRIMOS_H #define NUMEROSPRIMOS_H class NumerosPrimos unsigned elultimoprimo; unsigned elnumero; 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 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 Implementación de las clases en C++ del componente servidor. NumerosPrimos elultimoprimo : unsigned elnumero : unsigned NumerosPrimos() getsiguienteprimo() : unsigned Dpto. Electrónica, Automática e Informática Industrial 213

72 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Cliente <<interface>> IAdaptadorNumerosPrimos <<abstract>> getnumerosprimos() <<static>> metodofabricacion() AdaptadorNumerosPrimos AdaptadorNumerosPrimos() <<virtual>> getnumerosprimos() AdaptadorNumerosPrimos() NumerosPrimos elultimoprimo : unsigned elnumero : unsigned NumerosPrimos() getsiguienteprimo() : unsigned : Cliente metodofabricacion(unsigned) : IAdaptadorNumerosPrimos AdaptadorNumerosPrimos( ) : AdaptadorNumerosPrimos : NumerosPrimos getnumerosprimos( ) getnumerosprimos( ) getsiguienteprimo( ) 214 Dpto. Electrónica, Automática e Informática Industrial

73 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 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()); virtual std::vector<unsigned> & getnumerosprimos() return elvectornumerosprimos; ; #endif Dpto. Electrónica, Automática e Informática Industrial 215

74 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial Problema 4 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. : Vista VentaLocalidades(Dinero, float) : VentaLocalidades getprecio(int) metodofabricacionprecios(fecha&, float) : IPrecioLocalidades getpreciototal(int, Dinero) 216 Dpto. Electrónica, Automática e Informática Industrial

75 Apuntes de Informática Industrial Carlos Platero Vista VentaLocalidades eldescuento : float VentaLocalidades() getprecio() <<interface>> IPrecioLocalidades <<abstract>> getpreciototal() <<static>> metodofabricacionprecios() Fecha ismiercoles() DiaDelEspectador DiaDelEspectador() <<virtual>> getpreciototal() DosXTres DosXTres() <<virtual>> getpreciototal() Dinero cantidad : float eltipomoneda : TipoDinero Dinero() Dinero() Dinero() operator=() setcantidad() getcantidad() settipodinero() gettipodinero() <<typedef>> TipoDinero 1. Implementar la clase Dinero (por defecto se considera que el tipo de moneda es el EURO). Dinero cantidad : float eltipomoneda : TipoDinero Dinero() Dinero(valor : float, eltipo : TipoDinero) Dinero(elValor : Dinero&) operator=(elvalor : Dinero&) : Dinero& setcantidad(lacantidad : float) : void getcantidad( : void) : float settipodinero(eltipo : TipoDinero) : void gettipodinero( : void) : TipoDinero 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. Dpto. Electrónica, Automática e Informática Industrial 217

76 Capítulo 6: Diseño orientado a objetos Apuntes de Informática Industrial <<interface>> IPrecioLocalidades <<abstract>> getpreciototal(numerolocalidades : int, elpreciounitario : Dinero) : Dinero <<static>> metodofabricacionprecios(hoy : Fecha&, descuento : float) : IPrecioLocalidades* eldescuento : float DiaDelEspectador DiaDelEspectador(descuento : float) <<virtual>> getpreciototal(numerolocalidades : int, elpreciounitario : Dinero) : Dinero DosXTres DosXTres() <<virtual>> getpreciototal(numerolocalidades : int, elpreciounitario : Dinero) : Dinero 3. Implementar la clase de Venta de Localidades VentaLocalidades eldescuento : float eldiasemana : Fecha elpreciounitario : Dinero ppreciolocalidades : IPrecioLocalidades * VentaLocalidades(elPrecio : Dinero, descuento : float) getprecio(numerolocalidades : int) : Dinero 218 Dpto. Electrónica, Automática e Informática Industrial

77 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; 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; 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 219

78 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 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) 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() 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; 220 Dpto. Electrónica, Automática e Informática Industrial

79 Apuntes de Informática Industrial Carlos Platero Problema 5 Desarrollar una aplicación que convierta las magnitudes de longitud de un sistema a otro, sabiendo que: Se pide: 1 milla = 1609 m 1 pulgada = 25.4 mm 1 pie = cm 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) ConversorLongitud (from ConversorLongitudes) es un tipo de medida de es un tipo de medida de Pies (from ConversorLongitudes) es un tipo de medida de es un tipo de medida de Pulgadas (from ConversorLongitudes) Metros (from ConversorLongitudes) Millas (from ConversorLongitudes) ConversorLongitud millametro : float pulgadametro : float piemetro : float ConversorLongitud() <<virtual>> ~ConversorLongitud() getmetros() getmillas() getpulgadas() getpies() factormillametro() factorpulgadametro() factorpiemetro() 1 1 Metros cantidad : float Metros() getmetros() getmillas() getpulgadas() getpies() <<interface>> ILongitudes <<abstract>> getmetros() <<abstract>> getmillas() <<abstract>> getpulgadas() <<abstract>> getpies() <<static>> metodofabricacion() Millas cantidad : float Millas() getmetros() getmillas() getpulgadas() getpies() Pulgadas cantidad : float Pulgadas() getmetros() getmillas() getpulgadas() getpies() Pies cantidad : float Pies() getmetros() getmillas() getpulgadas() getpies() Dpto. Electrónica, Automática e Informática Industrial 221

6 Diseño orientado a objetos

6 Diseño orientado a objetos 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

Más detalles

CLASE 9: DISEÑO CON PATRONES. Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez

CLASE 9: DISEÑO CON PATRONES. Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez CLASE 9: DISEÑO CON PATRONES Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez Diseño de Objetos Identificar requerimientos, crear un modelo del dominio, agregar métodos a las clases

Más detalles

CLASE 9: DISEÑO CON PATRONES. Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez

CLASE 9: DISEÑO CON PATRONES. Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez CLASE 9: DISEÑO CON PATRONES Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez Diseño de Objetos Identificar requerimientos, crear un modelo del dominio, agregar métodos a las clases

Más detalles

Patrones de Software para la Asignación de Responsabilidades

Patrones de Software para la Asignación de Responsabilidades Patrones de Software para la Asignación de Responsabilidades Unidad 2 Patrones de Diseño de Software Patrones Un patrón es una descripción de un problema y cómo resolverlo Descripción Escenario Solución

Más detalles

Capítulo III: AOO. Modelo del Dominio. Ejemplo 3.2

Capítulo III: AOO. Modelo del Dominio. Ejemplo 3.2 Capítulo III: AOO UP->fase de Elaboración Descubrir la mayoría de los requisitos. Estabilizar la arquitectura Implementar el núcleo de la aplicación Buenas prácticas en la Elaboración Llevar a cabo iteraciones

Más detalles

Capítulo 16. Diagrama de Clases UML

Capítulo 16. Diagrama de Clases UML Capítulo 16. Diagrama de Clases UML Florentino TORRES M. CINVESTAV-Tamaulipas 15 de Oct del 2012 Florentino TORRES M. (CINVESTAV) 15 de Oct del 2012 1 / 70 1 Capítulo 16. Diagrama de Clases UML Aplicando

Más detalles

Diseño de la Arquitectura Lógica con Patrones. mayo de 2008

Diseño de la Arquitectura Lógica con Patrones. mayo de 2008 Diseño de la Arquitectura Lógica con Patrones mayo de 2008 Agenda Definición de Arquitectura Dimensiones de Arquitectura Categorías de Patrones Patrón de Arquitectura Organización de Paquetes Análisis

Más detalles

Variantes del conceptos de clases(1/2)

Variantes del conceptos de clases(1/2) Capítulo IV: UML (UnifiedModelingLanguage) Vistas (artefactos que representan un aspecto del sistema) Estructural: estructura lógica (Diagramas de clase y de casos de uso) Dinámico: Interacciones entre

Más detalles

Capítulo 22. Herramientas UML y UML como un plano.

Capítulo 22. Herramientas UML y UML como un plano. Capítulo 22. Herramientas UML y UML como un plano. Miguel RDZ. GUILLÉN CINVESTAV-Tamaulipas 22 de Oct del 2012 Miguel RDZ. GUILLÉN (CINVESTAV) 22 de Oct del 2012 1 / 65 1 Capítulo 22. Herramientas UML

Más detalles

CC61J / CC Taller de UML Apuntes de Clase

CC61J / CC Taller de UML Apuntes de Clase CC61J / CC5404 - Taller de UML Apuntes de Clase Prof. Andrés Muñoz Ordenes 08/06/2011 Agenda Motivación Diseño del Problema Diagrama de Colaboración Conceptos Notación y Sintaxis Usos Ejemplo: Caja de

Más detalles

Patrones. Patrones GRASP GRASP GRASP. Curso de Arquitecturas de Software. Programación Orientada a Objetos Patrones GRASP

Patrones. Patrones GRASP GRASP GRASP. Curso de Arquitecturas de Software. Programación Orientada a Objetos Patrones GRASP Curso de Arquitecturas de Software Programación Orientada a Objetos Patrones GRASP Patrones Es una solución a un problema recurrente Capturan las mejores prácticas establecidas para diseño Describen un

Más detalles

Introducción a la Ingeniería de la Programación. Carlos Platero C-305

Introducción a la Ingeniería de la Programación. Carlos Platero C-305 Introducción a la Ingeniería de la Programación Carlos Platero (carlos.platero@upm.es) C-305 Introducción a la Ingeniería del Software Aplicaciones SW: Industrial, Telecomunicaciones, ocio, Medicina,...

Más detalles

Alumnos BAJO ACOPLAMIENTO Y ALTA COHESION. Un patrón intenta codificar el conocimiento, expresiones y los principios existentes.

Alumnos BAJO ACOPLAMIENTO Y ALTA COHESION. Un patrón intenta codificar el conocimiento, expresiones y los principios existentes. Alumnos Laguna Montes jose Israel Mendoza pona Diego Nina Layme Ronald Valdez Diaz Luis PATRÓNES DE DISEÑO BAJO ACOPLAMIENTO Y ALTA COHESION Qué es un Patrón? En la tecnología de objetos un Patrón es una

Más detalles

Tema: Funciones Virtuales y Polimorfismo.

Tema: Funciones Virtuales y Polimorfismo. Programación II. Guía No. 10 1 Facultad: Ingeniería Escuela: Computación Asignatura: Programación II Tema: Funciones Virtuales y Polimorfismo. Objetivos Comprender que es ligadura e identificar sus tipos.

Más detalles

Apuntadores en C y C++

Apuntadores en C y C++ Apuntadores en C y C++ Universidad de Carabobo Facultad Experimental de Ciencias y Tecnología Prof. Marcos A. Gil T. 8 de diciembre de 2004 1. Introducción Los apuntadores en C y C++ son una herramienta

Más detalles

Tema: Funciones Virtuales y Polimorfismo.

Tema: Funciones Virtuales y Polimorfismo. Programación II. Guía 10 1 Facultad: Ingeniería Escuela: Computación Asignatura: Programación II Tema: Funciones Virtuales y Polimorfismo. Objetivos Específicos Comprender que es ligadura e identificar

Más detalles

PRÁCTICA DE LABORATORIO 4 Programación Orientada a Objetos

PRÁCTICA DE LABORATORIO 4 Programación Orientada a Objetos ESCUELA DE INGENIERÍA DE SISTEMAS DEPARTAMENTO DE COMPUTACIÓN PROGRAMACIÓN 2 PRÁCTICA DE LABORATORIO 4 Programación Orientada a Objetos Contenido Introducción...1 Objeto...2 Atributo...2 Métodos...2 Clase...3

Más detalles

Diplomado Programación orientada a objetos con C++ y UML. Las empresas necesitan contar con sistemas de información modernos, ágiles y de calidad para alcanzar sus objetivos y ser cada vez más competitivos

Más detalles

Programación. Orientada a Objetos. Prof. Angela Di Serio. Universidad Simón Bolívar Especialización en Telemática

Programación. Orientada a Objetos. Prof. Angela Di Serio. Universidad Simón Bolívar Especialización en Telemática Programación Orientada a Objetos Prof. Angela Di Serio Universidad Simón Bolívar Especialización en Telemática Agenda Clase 2 Qué es Orientado a Objetos? Conceptos: objeto, clase, instancias, mensajes

Más detalles

Introducción a la Orientación a Objetos

Introducción a la Orientación a Objetos Introducción a la Orientación a Objetos Breve historia de la OO 1960s. Simula incorpora características propias de la OO. 1970s. Smalltalk. Lenguaje totalmente OO. 1990s. Boom de la OO. 2000-Hoy. Época

Más detalles

Programación orientada a objetos I

Programación orientada a objetos I Introducción Programación orientada a objetos I Curso INEM. Programación en C++ Santiago Muelas Pascual smuelas@fi.upm.es Qué es la POO? Un paradigma de programación Un paradigma es una forma de afrontar

Más detalles

TEMA 4. PROCESO UNIFICADO

TEMA 4. PROCESO UNIFICADO TEMA 4. PROCESO UNIFICADO Definición El Proceso Unificado de Desarrollo Software es un marco de desarrollo de software que se caracteriza por estar dirigido por casos de uso, centrado en la arquitectura

Más detalles

Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 2

Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 2 Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 2 Contenidos: 1. Definición de clases 2. Implementación de los métodos 3. Constructores y destructores 4. Objetos

Más detalles

PROGRAMACION ORIENTADA A OBJETOS EN C++

PROGRAMACION ORIENTADA A OBJETOS EN C++ PROGRAMACION ORIENTADA A OBJETOS EN C++ 1- INTRODUCCIÓN El lenguaje C++ representa el resultado de los esfuerzos realizados para proporcionar las ventajas de la programación Orientada a Objetos a un lenguaje

Más detalles

Conceptos Básicos. Programación Orientada a Objetos 2

Conceptos Básicos. Programación Orientada a Objetos 2 Programación Orientada a Objetos Conceptos Básicos de Objetos Ing. Julio Ernesto Carreño Vargas MsC. Conceptos Básicos Las aproximaciones ADOO y POO, proveen a los objetos como el principal medio para

Más detalles

DIAGRAMAS DE CLASES. Clases, asociaciones y atributos. Interfaces con sus operaciones y constantes. Información acerca del tipo de los atributos.

DIAGRAMAS DE CLASES. Clases, asociaciones y atributos. Interfaces con sus operaciones y constantes. Información acerca del tipo de los atributos. Completando los diagramas de interacción, es posible identificar la especificación de las clases que participarán en la solución indicando detalles de su implementación, como por ejemplo los métodos. Entradas

Más detalles

CAPÍTULO 5 DESARROLLO DEL SISTEMA

CAPÍTULO 5 DESARROLLO DEL SISTEMA DESARROLLO DEL SISTEMA CAPÍTULO 5 DESARROLLO DEL SISTEMA 5.1 IMPLEMENTACIÓN DE BASE DE DATOS La implementación de la base de datos se realizó usando el manejador de Bases de datos Microsoft SQL Server

Más detalles

Ingeniería del Software de Gestión II 2 de febrero de 2005 Pág: 1/8. Apellidos: Nombre: Núm.:

Ingeniería del Software de Gestión II 2 de febrero de 2005 Pág: 1/8. Apellidos: Nombre: Núm.: Ingeniería del Software de Gestión II 2 de febrero de 2005 Pág: 1/8 Apellidos: Nombre: Núm.: PD1 (4 Ptos.): Responda razonadamente a las siguientes cuestiones: 1. Qué diferencia existe entre un diagrama

Más detalles

Abstracción. Encapsulamiento. Polimorfismo. Objeto. método / objeto / clase / módulo. Separación de las propiedades de un

Abstracción. Encapsulamiento. Polimorfismo. Objeto. método / objeto / clase / módulo. Separación de las propiedades de un Abstracción Encapsulamiento Separación de las propiedades de un método / objeto / clase / módulo de la implementación del mismo Ocultamiento de información No es necesario dar conocer los detalles de la

Más detalles

Tema 6. Patrones de diseño.

Tema 6. Patrones de diseño. Ingeniería del Software II 2011 Tema 6. Patrones de diseño. Introducción. Durante el diseño Orientado a Objetos es frecuente encontrarse repetidamente con ciertos tipos de problemas, para analizar, compartir

Más detalles

Capítulos 2 y 5: Modelación con UML y Modelo Objeto

Capítulos 2 y 5: Modelación con UML y Modelo Objeto Capítulos 2 y 5: Modelación con UML y Modelo Objeto Agenda Recordar: Modelo de Sistema: modelo objeto + modelo funcional + modelo dinámico Ultima Clase: Modelo Objeto Definir el concepto de Modelo de Clases

Más detalles

4/15/2010. Requerimientos de Software UARG.UNPA Requerimientos de Software. Requerimientos de Software

4/15/2010. Requerimientos de Software UARG.UNPA Requerimientos de Software. Requerimientos de Software UARG.UNPA 2009 Un caso de uso es una interacción típica entre un usuario y un sistema computacional.(fowler) Un caso de uso especifica el comportamiento deseado del sistema (objetivos del usuario). (Jacobson)

Más detalles

INGENIERÍA DE SOFTWARE. Sesión 10: Diagramas de comunicación

INGENIERÍA DE SOFTWARE. Sesión 10: Diagramas de comunicación INGENIERÍA DE SOFTWARE Sesión 10: Diagramas de comunicación Contextualización Los diagramas son parte importante en el desarrollo de aplicaciones, pues con éstos se puede visualizar la forma en que funcionará

Más detalles

Tema: Arreglos de Objetos en C++.

Tema: Arreglos de Objetos en C++. Programación II. Guía 5 1 Facultad: Ingeniería Escuela: Computación Asignatura: Programación II Tema: Arreglos de Objetos en C++. Objetivos Específicos Describir la implementación de arreglos de Objetos.

Más detalles

Introducción a OOP. Programación Orientada a Objeto

Introducción a OOP. Programación Orientada a Objeto Introducción a OOP Programación Orientada a Objeto Evolución Programación no Estructurada, Programación procedimental, Programación modular y Programación orientada a objetos. Programación no Estructurada

Más detalles

Patrones de Diseño. Ing. Miguel Angel Cedeño Garcidueñas

Patrones de Diseño. Ing. Miguel Angel Cedeño Garcidueñas Patrones de Diseño Ing. Miguel Angel Cedeño Garcidueñas miguelcedega@correo.fie.umich.mx Patrones de Diseño Diseñar software orientado a objetos es difícil, pero diseñar software orientado a objetos reutilizable

Más detalles

Programación Orientada o Objetos

Programación Orientada o Objetos Programación Orientada o Objetos Programación digital II Escuela de Sistemas Facultad de Ingeniería Profesor: Gilberto Diaz Programación Orientada a Objetos En 1970 Dennis Ritchie y Brian Kernigan crearon

Más detalles

Programación Avanzada CONCEPTOS BÁSICOS DE IMPLEMENTACIÓN EN C++

Programación Avanzada CONCEPTOS BÁSICOS DE IMPLEMENTACIÓN EN C++ Programación Avanzada CONCEPTOS BÁSICOS DE IMPLEMENTACIÓN EN C++ OBJETIVO En este documento se presentan las construcciones básicas de orientación a objetos del lenguaje de programación C++, y recomendaciones

Más detalles

Programación orientada a objetos

Programación orientada a objetos Programación orientada a objetos Dra. Elisa Schaeffer elisa@yalma.fime.uanl.mx 12 de febrero de 2007 MECAS512 Estructura de Datos en C++ PROGRAMACIÓN ORIENTADA A OBJETOS un paradigma de programación programa

Más detalles

! Qué es la POO?! Un paradigma de programación. ! No hay paradigmas mejores ni peores! Todos tienen sus ventajas e inconvenientes

! Qué es la POO?! Un paradigma de programación. ! No hay paradigmas mejores ni peores! Todos tienen sus ventajas e inconvenientes Introducción Programación orientada a objetos Curso INEM. Programación en Java Santiago Muelas Pascual smuelas@fi.upm.es! Qué es la POO?! Un paradigma de programación! Un paradigma es una forma de afrontar

Más detalles

PATRONES DE DISEÑO FRAMEWORKS

PATRONES DE DISEÑO FRAMEWORKS PATRONES DE FRAMEWORKS Definiciones Finalidades Características Diseño de software basado en patrones Descripción Utilización de los patrones en el diseño Clasificación FRAMEWORKS Basado en la reutilización

Más detalles

Programación Orientada a Objetos en C++

Programación Orientada a Objetos en C++ Unidad I Programación Orientada a Objetos en C++ Programación Orientada a Objetos en C++ Programación I - 0416202 Contenido Esta lección abarca los siguientes temas: Estructura y declaración de una clase

Más detalles

Modelado Estructural F E B R E R O,

Modelado Estructural F E B R E R O, Modelado Estructural F E B R E R O, 2 0 1 4 Modelado Estructural Sirve para describir los diferentes tipos y relaciones estáticas existentes entre los diferentes objetos de un sistema. A la hora de desarrollar

Más detalles

Capítulo VI: DOO (Parte I) (C-305)

Capítulo VI: DOO (Parte I) (C-305) Capítulo VI: DOO (Parte I) carlos.platero@upm.es (C-305) DOO AOO (describir) & DOO (solución) Implementar las especificaciones con eficiencia y fiabilidad Herramientas: Diagramas de interacción & DCD (en

Más detalles

UML (Unified Modeling Language) Octubre de 2007

UML (Unified Modeling Language) Octubre de 2007 UML (Unified Modeling Language) Octubre de 2007 UML un modelo o pieza de información producido en el proceso de desarrollo de software Un lenguaje para especificar, visualizar y construir artefactos de

Más detalles

1. Asignar Responsabilidades a componentes de software es la habilidad más importante del AOO. Porque:

1. Asignar Responsabilidades a componentes de software es la habilidad más importante del AOO. Porque: Análisis y Diseño O.O. Preguntas del diseño : Cómo podrían asignarse responsabilidades a las clases de los objetos? Cómo podrían interactuar los objetos? Qué deberían hacer las clases? Patrones : Ciertas

Más detalles

CONCEPTOS BÁSICOS PROGRAMACIÓN ORIENTADA A OBJETOS. Ing. Martha Tello

CONCEPTOS BÁSICOS PROGRAMACIÓN ORIENTADA A OBJETOS. Ing. Martha Tello CONCEPTOS BÁSICOS PROGRAMACIÓN ORIENTADA A OBJETOS Ing. Martha Tello Introducción Cuando hacemos referencia a la programación orientada a objetos estamos hablando de una nueva forma de pensar acerca del

Más detalles

SILABO DEL CURSO DISEÑO DE SOFTWARE 1. DATOS GENERALES

SILABO DEL CURSO DISEÑO DE SOFTWARE 1. DATOS GENERALES SILABO DEL CURSO DISEÑO DE SOFTWARE 1. DATOS GENERALES 1.1. Facultad : Ingeniería 1.2. Carrera Profesional : Ingeniería de Sistemas 1.3. Departamento : Ingeniería de Sistemas 1.4. Tipo de Curso : Obligatorio

Más detalles

Diagramas De Casos De Uso

Diagramas De Casos De Uso Estáticos Diagramas De Casos De Uso Los diagramas de casos de uso documentan el comportamiento de un sistema desde el punto de vista del usuario.. Por lo tanto los casos de uso determinan los requisitos

Más detalles

Patrón Façade Patrón Template Method Conclusiones

Patrón Façade Patrón Template Method Conclusiones Tema 3.3.1 Patrones: Façade y Template Method Ingeniería del Software II J. Peña (Teoría) Índice Patrón Façade Patrón Template Method Conclusiones Índice Patrón Façade Patrón Template Method Conclusiones

Más detalles

USO DE SUBRUTINAS, TRANSMISIÓN DE PARÁMETROS Y COMPILACIÓN CONDICIONAL EN C++

USO DE SUBRUTINAS, TRANSMISIÓN DE PARÁMETROS Y COMPILACIÓN CONDICIONAL EN C++ USO DE SUBRUTINAS, TRANSMISIÓN DE PARÁMETROS Y COMPILACIÓN CONDICIONAL EN C++ Bruno López Takeyas Instituto Tecnológico de Nuevo Laredo Reforma Sur 2007, C.P. 88250, Nuevo Laredo, Tamps. México http://www.itnuevolaredo.edu.mx/takeyas

Más detalles

TEMA 7: Ficheros. TEMA 7: Ficheros. 7.1.-Concepto de fichero

TEMA 7: Ficheros. TEMA 7: Ficheros. 7.1.-Concepto de fichero TEMA 7: Ficheros 7.1.-Concepto de fichero Todas las estructuras de datos que hemos visto hasta ahora utilizan memoria principal. Esto tiene dos limitaciones importantes: 1. Los datos desaparecen cuando

Más detalles

Unidad 2. Elementos Intermedios del Lenguaje

Unidad 2. Elementos Intermedios del Lenguaje Unidad 2 Elementos Intermedios del Lenguaje Paradigmas de Programación Un paradigma de programación se refiere a la forma en que se entiende, diseña y desarrolla una aplicación Imperativo Declarativo Funcional

Más detalles

INTRODUCCIÓN AL PARADIGMA DE LA PROGRAMACIÓN ORIENTADA A OBJETOS CON JAVA

INTRODUCCIÓN AL PARADIGMA DE LA PROGRAMACIÓN ORIENTADA A OBJETOS CON JAVA Objetivo: Identificar los concentos principales en java POO, que es una clase, un objeto así como sus características principales abstracción, modularidad, encapsulamiento, herencia, polimorfismo. INTRODUCCIÓN

Más detalles

TEMA 4. PROCESO UNIFICADO

TEMA 4. PROCESO UNIFICADO TEMA 4. PROCESO UNIFICADO Diseño El objetivo final del diseño es producir un Modelo Lógico del sistema a implementar. Diferencia entre Análisis y Diseño del Proceso Unificado Modelo de Análisis Modelo

Más detalles

Conclusiones y recomendaciones

Conclusiones y recomendaciones Conclusiones y recomendaciones El MD5C otorga, al grupo de desarrollo, 3 vistas claramente definidas en base a: a. Los tipos de presentación y subpresentación que tiene la aplicación. b. Las 5 capas que

Más detalles

Modelo Dinámico del Diseño del Software y Representación en UML. UNIDAD 9 Análisis y Diseño de Sistemas de Información

Modelo Dinámico del Diseño del Software y Representación en UML. UNIDAD 9 Análisis y Diseño de Sistemas de Información Modelo Dinámico del Diseño del Software y Representación en UML UNIDAD 9 Análisis y Diseño de Sistemas de Información El Modelo Dinámico El objetivo del modelo Dinámico es presentar o describir el comportamiento

Más detalles

UNIVERSIDAD DE SAN CARLOS DE GUATEMALA FACULTAD DE INGENIERIA ESCUELA DE CIENCIAS Y SISTEMAS

UNIVERSIDAD DE SAN CARLOS DE GUATEMALA FACULTAD DE INGENIERIA ESCUELA DE CIENCIAS Y SISTEMAS UNIVERSIDAD DE SAN CARLOS DE GUATEMALA FACULTAD DE INGENIERIA ESCUELA DE CIENCIAS Y SISTEMAS PROGRAMA DEL CURSO DE INTRODUCCION A LA PROGRAMACION DE COMPUTACION 2 CODIGO: 771 CREDITOS: 5 ESCUELA: Ciencias

Más detalles

UNIVERSIDAD AUTÓNOMA DE CHIAPAS LICENCIATURA EN SISTEMAS COMPUTACIONALES

UNIVERSIDAD AUTÓNOMA DE CHIAPAS LICENCIATURA EN SISTEMAS COMPUTACIONALES UNIVERSIDAD AUTÓNOMA DE CHIAPAS LICENCIATURA EN SISTEMAS COMPUTACIONALES Área de formación: Disciplinaria Unidad académica: Programación Orientada a Objetos Ubicación: Cuarto Semestre Clave: 2087 Horas

Más detalles

PNFSI. Asignatura: Desarrollo de Software. Tema 1: Programación Orientada a Objetos

PNFSI. Asignatura: Desarrollo de Software. Tema 1: Programación Orientada a Objetos PNFSI Asignatura: Desarrollo de Software Tema 1: Programación Orientada a Objetos Ing. Zamantha González Abril, 2008 Contenido Conceptos básicos Clase Objeto o instancia Atributos Métodos Constructores

Más detalles

CAPÍTULO 2: CARACTERÍSTICAS DE LA PROGRAMACIÓN ORIENTADA A OBJETOS. ABSTRACCIÓN. ENCAPSULAMIENTO. PRINCIPIO DE OCULTACIÓN. HERENCIA. POLIMORFISMO.

CAPÍTULO 2: CARACTERÍSTICAS DE LA PROGRAMACIÓN ORIENTADA A OBJETOS. ABSTRACCIÓN. ENCAPSULAMIENTO. PRINCIPIO DE OCULTACIÓN. HERENCIA. POLIMORFISMO. 1 UNIDAD 1: ORIENTACIÓN A OBJETOS. CAPÍTULO 1: INTRODUCCIÓN. HISTORIA. ESPÍRITU DEL PARADIGMA ORIENTADO A OBJETOS. CONCEPTOS BÁSICOS: OBJETO, ATRIBUTO, MÉTODO, MIEMBRO, MENSAJE, CLASE, EVENTO. CAPÍTULO

Más detalles

MODULO IV. Análisis y Diseño de Sistemas de Información INF-162 II. METODOLOGIAS. Análisis y Diseño OO. Facilitador: Miguel Cotaña

MODULO IV. Análisis y Diseño de Sistemas de Información INF-162 II. METODOLOGIAS. Análisis y Diseño OO. Facilitador: Miguel Cotaña MODULO IV Análisis y Diseño de Sistemas de Información INF-162 II. METODOLOGIAS Análisis y Diseño OO Facilitador: Miguel Cotaña 1 INTRODUCCION METODO: Es un proceso disciplinado para generar un conjunto

Más detalles

La Herencia. La primera línea de cada declaración debe incluir la sintaxis siguiente:

La Herencia. La primera línea de cada declaración debe incluir la sintaxis siguiente: La Herencia Es la capacidad de compartir atributos y métodos entre clases. Es la propiedad que permite definir nuevas clases usando como base clases ya existentes. La nueva clase (clase derivada) hereda

Más detalles

Unidad V. Ya veremos qué poner en "algunas_palabras" y "algo_más", por ahora sigamos un poco más.

Unidad V. Ya veremos qué poner en algunas_palabras y algo_más, por ahora sigamos un poco más. Implementación Orientada a Objetos. Unidad V 5.1 Estructura de una clase. Una clase consiste en: algunas_palabras class nombre_de_la_clase [algo_más] { [lista_de_atributos] [lista_de_métodos] Lo que está

Más detalles

mayo de 2008 Persistencia

mayo de 2008 Persistencia mayo de 2008 Persistencia Mecanismos de Almacenamiento BDO: No se necesita servicios de persistencia. BDR: Se requiere un servicio de correspondencia entre objetos y relaciones. XML, archivos, BD jerárquicas,

Más detalles

Introducción a C++ y Code::Blocks

Introducción a C++ y Code::Blocks Introducción a C++ y Práctica Imperativo Clase 1 Luis Agustín Nieto Departamento de Computación, FCEyN,Universidad de Buenos Aires. 28 de mayo de 2010 Menu de esta Tarde Funcional Vs. Imperativo (Intérprete

Más detalles

INGENIERIA DE SOFTWARE ING. FRANCISCO RODRIGUEZ

INGENIERIA DE SOFTWARE ING. FRANCISCO RODRIGUEZ INGENIERIA DE SOFTWARE ING. FRANCISCO RODRIGUEZ TEMA 3: PROCESO UNIFICADO DE DESARROLLO CONTENIDO 1. Proceso de Software 2. Proceso de Desarrollo de Software 3. Proceso Unificado de Desarrollo de Software

Más detalles

3.- Resolución a) Salida por pantalla A B B says Ladra! C C says Ladra! D

3.- Resolución a) Salida por pantalla A B B says Ladra! C C says Ladra! D 3. Indicar la salida por pantalla (2 puntos-20 minutos) NOTA: La clase string es un tipo especial de contenedor diseñado para manipular secuencias de caracteres. a) #include #include

Más detalles

Introducción a la Ingeniería de Software

Introducción a la Ingeniería de Software Introducción a la Ingeniería de Software Diseño Software Engineering 7ed Addison Wesley Ian Sommerville Diseño Durante el diseño se refina la arquitectura El diseño es un plano de una solución para el

Más detalles

Ingeniería de Software

Ingeniería de Software Ingeniería de Software ANÁLISIS Y DISEÑO DE SISTEMAS CON Auxiliar: Andrés Neyem aneyem@dcc.uchile.cl Oficina 418 de Doctorado Auxiliar - 10 de Abril de 2007 Repaso Historia de los lenguajes de modelamiento

Más detalles

Conceptos. ELO329: Diseño y Programación Orientados a Objetos. ELO 329: Diseño y Programación Orientados a Objetos 1

Conceptos. ELO329: Diseño y Programación Orientados a Objetos. ELO 329: Diseño y Programación Orientados a Objetos 1 Conceptos ELO329: Diseño y Programación Orientados a Objetos ELO 329: Diseño y Programación Orientados a Objetos 1 Paradigmas de Programación Historia: Los computadores parten cableados por hardware, Luego

Más detalles

Los diagramas de clases y de objetos sirven para modelar diversos aspectos estructurales o estáticos de un sistema: Modelado - Vocabulario del Sistema

Los diagramas de clases y de objetos sirven para modelar diversos aspectos estructurales o estáticos de un sistema: Modelado - Vocabulario del Sistema Modelado Los diagramas de clases y de objetos sirven para modelar diversos aspectos estructurales o estáticos de un sistema: Vocabulario del Sistema Distribución de Responsabilidades Semántica de una Clase

Más detalles

Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 1

Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 1 Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 1 Contenidos: 1. Características generales de C++ 2. Entrada/salida estándar 3. Variables y tipos de datos

Más detalles

Clases y Objetos en C++

Clases y Objetos en C++ Informática II Clases y Objetos en C++ Introducción Las variables de los tipos fundamentales de datos no son suficientes para modelar adecuadamente objetos del mundo real. alto, ancho y longitud para representar

Más detalles

Unidad IV. Este tipo de codificación nos es permitido gracias a la sobrecarga, la cual se aplica a métodos y constructores.

Unidad IV. Este tipo de codificación nos es permitido gracias a la sobrecarga, la cual se aplica a métodos y constructores. Unidad IV Métodos. 4.1 Definición de un método. El polimorfismo, en programación orientada a objetos, se refiere a la posibilidad de acceder a un variado rango de funciones distintas a través del mismo

Más detalles

CLASE 3: UML DIAGRAMAS CASOS DE USO. Universidad Simón Bolívar. Ingeniería de Software. Prof. Ivette Martínez

CLASE 3: UML DIAGRAMAS CASOS DE USO. Universidad Simón Bolívar. Ingeniería de Software. Prof. Ivette Martínez CLASE 3: UML DIAGRAMAS CASOS DE USO Universidad Simón Bolívar. Ingeniería de Software. Prof. Ivette Martínez UML UML es un lenguaje para especificar, visualizar, construir y documentar los artefactos de

Más detalles

Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 3

Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 3 Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º SEMINARIO DE C++ Sesión 3 Contenidos: 1. Funciones y clases genéricas 2. Excepciones 3. Asertos 4. El puntero this 5. Redefinición

Más detalles

acceso Implementación de conceptos P.O.O. en Java Orientada a Objetos 2. Modificadores de en Java Temario

acceso Implementación de conceptos P.O.O. en Java Orientada a Objetos 2. Modificadores de en Java Temario Implementación de conceptos P.O.O. en Java Temario 2. Conceptos de Programación Orientada a Objetos 1. Conceptos de P.O.O. 2. Implementación de conceptos P.O.O en Java 1. Creación de clases y objetos 2.

Más detalles

Específicamente los elementos de un patrón de diseño son [ 3 ] :

Específicamente los elementos de un patrón de diseño son [ 3 ] : Patrones de Diseño Marco Teórico Introductorio Diego Andrés Asenjo González Alejandro Ríos Peña Contenido Qué son los patrones de Diseño?...1 Clasificación de los patrones de diseño...3 Patrones de Creación.....4

Más detalles

Especificación de Requerimientos <Nombre del Proyecto> Nombre del Grupo de Desarrollo o Asignatura Nombre del Autor

Especificación de Requerimientos <Nombre del Proyecto> Nombre del Grupo de Desarrollo o Asignatura Nombre del Autor Especificación de Requerimientos Nombre del Grupo de Desarrollo o Asignatura [Este documento es la plantilla base para elaborar el documento Especificación de Requerimientos. Los textos que aparecen entre

Más detalles

Tema 2: Clases y Objetos

Tema 2: Clases y Objetos Tema 2: Clases y Objetos Anexo: tipo de datos Pila Programación Orientada a Objetos Curso 2017/2018 Características del paradigma OO Curso 2017/2018 Programación Orientada a Objetos 2 Características del

Más detalles

Conceptos de Programación Orientada a Objetos

Conceptos de Programación Orientada a Objetos Paradigmas de programación Prog. orientada a objetos Conceptos de Programación Orientada a Objetos Abstracción de Programación estructurada Programación imperativa 2 Programación estructurada (I) Programación

Más detalles

Guía de estilo y buenas prácticas de programación en C/C++

Guía de estilo y buenas prácticas de programación en C/C++ Guía de estilo y buenas prácticas de programación en C/C++ Introducción A la hora de escribir código fuente en un determinado lenguaje de programación es aconsejable seguir unas guías de estilo. Esto te

Más detalles

Procesos e Hilos en C

Procesos e Hilos en C Procesos e Hilos en C 6 de febrero de 2012 En esta sesión vamos a escribir programas en lenguaje C que utilicen hilos y procesos para comparar el rendimiento del sistema ante la gestión de unos y otros.

Más detalles

UNIDAD 2: INTRODUCCION AL PARADIGMA ORIENTADO A OBJETOS. MODELADO DE OBJETOS USANDO DIAGRAMA DE CLASES

UNIDAD 2: INTRODUCCION AL PARADIGMA ORIENTADO A OBJETOS. MODELADO DE OBJETOS USANDO DIAGRAMA DE CLASES UNIDAD 2: INTRODUCCION AL PARADIGMA ORIENTADO A OBJETOS. MODELADO DE OBJETOS USANDO DIAGRAMA DE CLASES RELACIONES ENTRE OBJETOS Los objetos interactúan entre ellos por medio de mensajes para solicitar

Más detalles

Programación 1 Tema 3. Información, datos, operaciones y expresiones

Programación 1 Tema 3. Información, datos, operaciones y expresiones Programación 1 Tema 3 Información, datos, operaciones y expresiones Índice Datos y tipos de datos Datos primitivos en C++ Expresiones e instrucción de asignación Datos y tipos de datos Problema información

Más detalles

Tema 4g: Proceso Unificado: Implementación

Tema 4g: Proceso Unificado: Implementación Tema 4g: Proceso Unificado: Implementación Marcos López Sanz Índice Visión general Artefactos Componentes Subsistemas de implementación Interfaces Descripción de la arquitectura (vista del modelo de implementación)

Más detalles

ALGORITMICA Y PROGRAMACION POR OBJETOS I

ALGORITMICA Y PROGRAMACION POR OBJETOS I ALGORITMICA Y PROGRAMACION POR OBJETOS I Nivel 1 Problemas, Soluciones y Programas Marcela Hernández Hoyos Solucionar un Problema = Construir un Programa Problema Programador Herramientas y Lenguajes Análisis

Más detalles

MODULO IV. Análisis y Diseño de Sistemas de Información INF-162 III. UML. 4.9 Diagramas de Componentes

MODULO IV. Análisis y Diseño de Sistemas de Información INF-162 III. UML. 4.9 Diagramas de Componentes MODULO IV Análisis y Diseño de Sistemas de Información INF-162 III. UML 4.9 Diagramas de Componentes Facilitador: Miguel Cotaña 30 de Noviembre 2009 1 Componentes Pertenecen al mundo físico, es decir,

Más detalles

Tema 1 Introducción al paradigma de programación orientado a objetos

Tema 1 Introducción al paradigma de programación orientado a objetos Tema 1 Introducción al paradigma de programación orientado a objetos Programación Orientada a Objetos Curso 2013/2014 Contenido Paradigmas de programación vs. Lenguajes de programación. Evolución de los

Más detalles

Programación estructurada (Introducción a lenguaje C)

Programación estructurada (Introducción a lenguaje C) Programación estructurada (Introducción a lenguaje C) M. en C. Sergio Luis Pérez Pérez UAM CUAJIMALPA, MÉXICO, D. F. Trimestre 15-I Sergio Luis Pérez (UAM CUAJIMALPA) Curso de programación estructurada

Más detalles

IMPLEMENTACIÓN DE PILAS CON LISTAS EN C++

IMPLEMENTACIÓN DE PILAS CON LISTAS EN C++ IMPLEMENTACIÓN DE PILAS CON LISTAS EN C++ Fichero nodo.h #ifndef NODO_H #define NODO_H const int cantidad_nodos = 10; class Nodo private: string dato; Nodo* siguiente; public: Nodo(); void setdato(string

Más detalles

Qué es Java? Un lenguaje de programación Un entorno de desarrollo Un entorno de aplicación Un entorno de despliegue Es similar en sintaxis de C + +.

Qué es Java? Un lenguaje de programación Un entorno de desarrollo Un entorno de aplicación Un entorno de despliegue Es similar en sintaxis de C + +. APUNTES DE JAVA Agenda Bienvenida Conociendo Java La Maquina Virtual Descargar e instalar el compilador El entorno de trabajo El paradigma de la programación orientada a objetos Qué es Java? Un lenguaje

Más detalles

Tema: Plantillas en C++.

Tema: Plantillas en C++. Programación II. Guía 11 1 Facultad: Ingeniería Escuela: Computación Asignatura: Programación II Tema: Plantillas en C++. Objetivos Específicos Conocer los tipos de plantillas Utilizar las plantillas de

Más detalles

APLICACIONES MOVILES NATIVAS. Sesión 5: Objetos, mensajes y clases. Abstracción, encapsulamiento, herencia y polimorfismo

APLICACIONES MOVILES NATIVAS. Sesión 5: Objetos, mensajes y clases. Abstracción, encapsulamiento, herencia y polimorfismo APLICACIONES MOVILES NATIVAS Sesión 5: Objetos, mensajes y clases. Abstracción, encapsulamiento, herencia y polimorfismo Contextualización Los lenguajes de programación orientada a objetos tienen varios

Más detalles

Contenido. 1. El proceso 2. Los modelos 3. Los diagramas 4. Ejemplo

Contenido. 1. El proceso 2. Los modelos 3. Los diagramas 4. Ejemplo Tutorial Contenido 1. El proceso 2. Los modelos 3. Los diagramas 4. Ejemplo 1. El proceso Fases soportadas por UML Análisis de requisitos de usuario Análisis de requisitos de software Diseño de la plataforma

Más detalles

IMPLEMENTACIÓN DE CONCEPTOS P.O.O. EN JAVA

IMPLEMENTACIÓN DE CONCEPTOS P.O.O. EN JAVA IMPLEMENTACIÓN DE CONCEPTOS P.O.O. EN JAVA Implementación de conceptos P.O.O. en Java Temario 2. Conceptos de Programación Orientada a Objetos 1. Conceptos de P.O.O. 2. Implementación de conceptos P.O.O

Más detalles