Story Transcript
MODELO DE OBJETOS 1.− Evolución histórica. La génesis de UML: El nacimiento de la notación UML (Unified Modeling Language) se debe al esfuerzo de J. Rumbaugh, G. Booch e I. Jacobson para unificar o estandarizar de alguna manera las diferentes metodologías en una nueva que englobe las mejores características de las demás. UML propone un conjunto más rico de seis modelos (clases, estados, casos, interacción, realización y distribución) que se expresan por medio de nueve diagramas (clases, secuencia, colaboración, objetos, transición de estados, actividades, casos de uso, componentes y distribución). Los métodos de análisis y diseño: Un método define un sistema reproducible para obtener resultados fiables. Al igual que un arquitecto dibuja planos para reproducir un edificio, un método de elaboración de programas describe cómo modelar y construir sistemas de programas de manera fiable y reproducible. Los métodos permiten construir modelos a partir de elementos de modelado. La aproximación orientada a objetos propone los objetos para la representación de los programas. Los métodos también definen algún tipo de representación (generalmente gráfica) para manipular fácilmente los modelos y poder intercambiar información. Un método define también las reglas de implementación que describen el encadenamiento de las acciones, la ordenación de las tareas, etc. La proliferación de los métodos orientados a objetos: La primera mitad de los años 90 ha visto florecer unos cincuenta métodos de objetos. Esta proliferación es signo de la gran vitalidad del objeto, pero también es fruto de una multitud de interpretaciones sobre los objetos. El inconveniente obvio de todo esto es que favorece la confusión. Mediante el examen de los métodos dominantes se extrae un consenso de ideas comunes, que si se ven reforzadas por la experiencia proporcionan unos elementos metodológicos muy apreciados por los usuarios. Por ejemplo las versiones Booch93 y OMT−2 de los métodos de Booch y OMT respectivamente presentan más parecidos que diferencias. Los dos métodos ofrecen una cobertura completa del ciclo de vida, pero con la diferencia de que Booch insiste en la construcción y OMT se concentra en el análisis y la abstracción. La unificación de los métodos: Debido a que las diferencias entre los métodos cada vez son más pequeñas y que la lucha entre ellos no hace más que frenar su expansión, los autores Booch, Rumbaugh y Jacobson decidieron, a finales de 1994, unificar sus trabajos en el UML. Se fijaron 4 objetivos: • Representar sistemas completos por conceptos de objetos. • Establecer una relación explícita entre los conceptos y los artefactos ejecutables. • Tener en cuenta los factores de escala inherentes a los sistemas complejos y críticos. • Crear un lenguaje de modelado utilizable tanto por los humanos como por las máquinas. Los esfuerzos se enfocaron hacia la definición de un lenguaje universal para el modelado de objetos y hacia la estandarización del proceso de desarrollo. La notación UML ha sido pensada para servir de lenguaje de modelado de objetos, independientemente del método implementado. De esta manera puede substituir, sin pérdida de información, a las notaciones de los métodos de Booch, OMT, etc. UML es una notación abierta, general y simple, sin ser simplista. Modelo y metamodelo: El esfuerzo inicial se centra en la identificación y definición de la semántica de los conceptos fundamentales que forman los módulos básicos del modelado de objetos. Para facilitar este trabajo los diferentes conceptos se han modelado a su vez con UML. Esta definición recursiva llamada metamodelo describe de manera formal los elementos de modelado y la sintaxis y la semántica de la notación que permite 1
manipularlos, es decir, sirve como una descripción de referencia para la construcción de herramientas y para compartir modelos entre herramientas diferentes. Un modelo es una descripción abstracta de un sistema o de un proceso. El término modelado se emplea a menudo como sinónimo de análisis, es decir, de descomposición en elementos simples, más fáciles de comprender. En informática, el modelado consiste en describir un problema, luego en describir la solución de este problema; estas actividades se llaman respectivamente análisis y diseño. La forma del modelo depende del metamodelo, ya que metamodelo define elementos de modelado y reglas para la descomposición de estos elementos de modelado. UML define varios modelos para la representación de los sistemas: • El modelo de clases que captura la estructura estática. • El modelo de estados que expresa el comportamiento dinámico de los objetos. • El modelo de casos de uso que describe las necesidades del usuario. • El modelo de despliegue que precisa el reparto de procesos... Los modelos o partes del mismo son vistos y manipulados por los usuarios por medio de vistas gráficas. A cada vista corresponden uno o varios diagramas. UML define nueve tipos de diagramas diferentes: • Diagramas de clases. • Diagramas de secuencia. • Diagramas de colaboración. • Diagramas de objetos. • Diagramas de actividades... 2.− Conceptos: Los objetos y las clases. Los objetos: Un objeto es una unidad atómica formada por la unión de un estado y de un comportamiento. Proporciona la propiedad de encapsulación la cual asegura una cohesión interna muy fuerte y un débil acoplamiento con el exterior. Los objetos pueden corresponder a todo tipo de elementos del mundo real, tanto físicos, como por ejemplo una rueda como conceptuales, como por ejemplo una cuenta bancaria. Pero también pueden pertenecer a mundos virtuales, por ejemplo, en asociación con Internet, para crear comunidades de personas que no están situadas en el mismo punto geográfico. Al igual que los seres vivos, los objetos tienen un ciclo de vida que se representa en el modelado. Los objetos se representan mediante un rectángulo con el nombre del objeto en el interior. A menudo no es sencillo encontrar un nombre para designar un objeto, por lo que la notación permite utilizar un nombre genérico en lugar de un nombre individual. En el ejemplo siguiente los dos puntos indican que se trata de un objeto anónimo. Características fundamentales de un objeto: Todo objeto presenta las tres características siguientes: estado, comportamiento e identidad. Un objeto sin estado o comportamiento puede existir marginalmente, pero en todos los casos un objeto posee una identidad. Estado: Sabiendo que un atributo es una información que cualifica al objeto que la contiene, el estado de un objeto, en un instante dado, corresponde con la agrupación de los valores de todos sus atributos. Comportamiento: El comportamiento agrupa todas las competencias del objeto y describe las acciones y reacciones de ese objeto. Este comportamiento se encuentra formado por operaciones que se desencadenan a 2
consecuencia de un estímulo externo, representado en forma de mensaje enviado por otro objeto. El estado y el comportamiento están relacionados: el comportamiento de un instante dado depende del estado actual, y el estado puede ser modificado por el comportamiento. Identidad: Además de su estado, el objeto posee una identidad que caracteriza su propia existencia. La identidad permite distinguir a los objetos de forma no ambigua, independientemente de su estado (para distinguir por ejemplo dos objetos con los atributos idénticos). La identidad es un concepto, no se representa de manera específica en modelado, aunque en la fase de realización se construye la identidad a partir de un identificador procedente del ámbito del problema. Este tipo de identificador (véase matrícula de un coche o DNI) se denomina también clave natural y se puede añadir al estado de los objetos para distinguirlos. Restricciones de realización: Las características anteriormente mencionadas son muy generales y los objetos pueden poseer otro tipo de características más "informáticas", relacionadas por ejemplo con las bases de datos o la distribución de programas. La persistencia por ejemplo permite a un objeto trascender en el tiempo el espacio de tal manera que se puede parar el proceso que lo ha creado sin perder la información representada por el objeto. Los objetos de modo predeterminado se consideran como no persistentes, es decir, como objetos transitorios. Debido a que los lenguajes orientados a objetos no proponen soporte para objetos persistentes hay que recurrir a soluciones externas, como las que proponen las bases de datos orientadas a objetos (ya sea de forma total o híbrida). Otras características son la migración (mediante la cual la descripción del objeto se transmite a través del soporte de comunicación para que un clon del mismo pueda ser reconstruido en el destino) y los objetos espejo (el cliente manipula un objeto espejo como si manipulara un objeto remoto, disminuyendo toda la complejidad de la comunicación). Comunicación entre objetos: El comportamiento global de una aplicación se basa en la comunicación entre los objetos que la componen. Los objetos interactúan para realizar las funciones de la aplicación. Según la naturaleza de las interacciones, es decir, según la dirección de los mensajes intercambiados es posible describir el comportamiento de los objetos. Se pueden observar tres categorías de comportamiento: Los actores son siempre objetos en el origen de una interacción. Son gene-ralmente objetos activos, es decir, que poseen un hilo de ejecución (thread) y que son quienes pasan el testigo a los otros objetos. Los servidores, por el contrario, no son nunca el origen de una interacción, sino que son siempre los destinatarios de los mensajes. A menudo son obje-tos pasivos que esperan que otro objeto requiera sus servicios. En este caso, el flujo de control se pasa al servidor para el objeto que envía el mensaje y se recupera tras la ejecución del servicio. Los agentes reúnen las características de los actores y los servidores. Los agentes aíslan a los objetos clientes de los objetos proveedores. De esta manera, un cliente puede comunicar con un servidor que no conoce directamente y, además, el servidor puede cambiar entre dos pasos de mensajes. El concepto de mensaje: La unidad de comunicación entre objetos se llama mensaje. El mensaje es el soporte de una relación de comunicación que vincula, de forma dinámica, los objetos que han sido separados por el proceso de descomposición. El mensaje es un integrador dinámico que permite reconstituir una función de la aplicación por la puesta en marcha de la cola-boración en un grupo de objetos. Adquiere toda su fuerza de integración cuando se asocia al polimorfismo y al enlace dinámico. Los mensajes se representan por flechas colocadas a lo largo de los enlaces que unen los objetos. Es un concepto abstracto que puede implementarse según numerosas variantes, como la llamada de procedimien-to, el evento discreto, la interrupción, el datagrama 3
UDP, la búsqueda diná-mica, etc. El diagrama siguiente describe completamente un mensaje. La flecha simple indica el flujo de control y las flechas decoradas con pequeños círculos mues-tran los flujos de datos. Categorías de mensajes: Existen cinco categorías principales de mensajes: • los constructores que crean objetos; • los destructores que destruyen objetos; • los selectores que devuelven todo o parte del estado de un objeto; • los modificadores que cambian todo o parte del estado de un objeto; • los iteradores que visitan el estado de un objeto o el contenido de una estructura de datos que contiene varios objetos. Formas de sincronización de mensajes: Las formas de sincronización de mensajes describen la naturaleza de los mecanismos de comunicación que permiten el paso de mensajes de un obje-to hacia otro objeto. La noción de sincronización toma todo su interés cuando varios objetos están activos simultáneamente y es necesario, por ejemplo, proteger el acceso a objetos compartidos Existen cinco grandes categorías de envío de mensajes: Envío de mensaje s¡mple: Esta categoría conviene para los sistemas de un solo flujo de ejecución, en los que está activo un solo objeto a la vez. El paso del control se efectúa en el envío de un mensaje del objeto activo hacia un objeto pasivo. Un envío de mensaje simple se representa por una flecha simple. Envío de mensaje síncrono: Un mensaje síncrono sólo desencadena una operación cuando el destinatario acepta el mensaje. Una vez el mensaje enviado, el expedidor se bloquea hasta que el destinatario acepta el men-saje. Un envío de mensaje síncrono se representa por una flecha tachada. Envío de mensaje esperado: Un mensaje esperado desencadena una ope-ración sólo si el destinatario está previamente esperando el mensaje. Este tipo de sincronización corresponde a una tolerancia de espera inversa a la del envío de un mensaje síncrono. En el caso de un mensaje síncrono, el expedidor acepta esperar; en el caso de un mensaje esperado, el destina-tario acepta esperar. Un envío de mensaje esperado se representa por una flecha que se vuelve hacia el expedidor. Envío de mensaje cronometrado: Un mensaje cronometrado bloquea al expedidor durante un tiempo dado, esperando que sea atendido por el des-tinatario. El expedidor se libera si no ha sido atendido al cabo del tiempo especificado en la descripción del envío del mensaje cronometrado. Un envío de mensaje cronome-trado se representa por una flecha decorada con un reloj simbolizado por un pequeño circulo. Envío de mensaje asíncrono: Un mensaje asíncrono no interrumpe la ejecu-ción del expedidor. El expedidor envía el mensaje sin saber cuándo, ni siquiera si el mensaje será tratado por el destinatario. Desde el punto de vista del destinatario, un envío asíncrono debe poder ser atendido en cualquier momento. Un envío de mensaje asíncrono se representa por media flecha. Representación de las interacciones entre los objetos: Los objetos interactúan para realizar colectivamente los servicios ofrecidos por las aplicaciones. Los 4
diagramas de interacción representan los objetos unos respecto a los otros y muestran cómo se comunican en una interacción. Cada interacción posee un nombre y un contexto de validez que conviene precisar de manera textual. Existen dos tipos de diagramas de interacción: los diagramas de colaboración y los diagramas de secuencia. Los diagramas de colaboración Los diagramas de colaboración corresponden a los diagramas utilizados en los ejemplos anteriores. Estos diagramas muestran algunos objetos en una situación dada. Los objetos se representan en forma de rectángulos, los obje-tos que se conocen (es decir, que pueden interactuar) se unen mediante enla-ces y los mensajes intercambiados por los objetos se representan a lo largo de dichos enlaces. El orden de envío de los diferentes mensajes se materializa por un número colocado al principio del mensaje. El diagrama anterior se lee de la manera siguiente: "el escenario empieza por un objeto A que envía un mensaje X a un objeto B, luego el objeto B envía un mensaje Y a un objeto C y, finalmente, C se envía un mensaje z." El mensaje Z es un artificio de notación para representar una actividad que tiene lugar en el objeto C. Los diagramas de secuencia Los diagramas de secuencia muestran más o menos las mismas informacio-nes que los diagramas anteriores, pero se pone el acento en la comunicación, en detrimento de la estructura espacial. Cada objeto se representa por una barra vertical. El tiempo transcurre de arriba abajo, de modo que la numera-ción de los mensajes es opcional. El paso de un diagrama al otro es posible automáticamente, por cuanto que sólo se conservan las informaciones de presencia de objetos y de comunica-ción. Los dos tipos de diagramas de interacción son interesantes para el modelado de objetos. El diagrama de secuencia está particularmente bien adaptado para la representación de interacciones, debido a su forma casi tabular. El diagra-ma de colaboración se presta mejor al descubrimiento de las abstracciones, porque permite mostrar los objetos del ámbito en una disposición física pró-xima a la realidad Las clases: El mundo real está constituido por numerosos objetos en interacción. Estos objetos constituyen amalgamas a menudo demasiado complejas para ser comprendidas en su integridad a primera vista. Para reducir esta complejidad y comprender así el mundo que la envuelve, el ser humano ha aprendido a agrupar los elementos que se parecen y a distin-guir estructuras de mayor nivel de abstracción, despojadas de detalles inútiles. El método de abstracción: La abstracción es una facultad de los seres humanos que consiste en concen-trar la reflexión en un elemento de una representación o de una noción, cen-trando especialmente la atención en él y olvidando todos los demás. El método de abstracción es arbitrario: se define respecto a un punto de vista. Así, un objeto del mundo real puede ser visto a través de abstracciones diferentes, lo cual implica que es importante determinar cuáles son los criterios pertinentes en el ámbito de aplicación considerado. La clase describe el ámbito de definición de un conjunto de objetos. Cada objeto pertenece a una clase. Las 5
generalidades están contenidas en la clase y las particularidades están contenidas en los objetos. Los objetos informáti-cos se construyen a partir de la clase por un proceso llamado instanciación. De este modo, todo objeto es una instancia de clase. Los lenguajes orientados a objetos permiten describir y manipular clases y sus instancias. Ello significa que el usuario puede construir en la máquina una representación informática de las abstracciones que suele manipular mental-mente, sin traducción hacia conceptos de más bajo nivel (como las funciones o los procedimientos de los lenguajes de programación procedurales). Representación gráfica de las clases: Cada clase se representa bajo la forma de un rectángulo dividido en tres com-partimentos. El primer compartimento contiene el nombre de la clase; el segundo, los atributos, y el último, las operaciones. De modo predeterminado, los atributos son ocultos y las operaciones son visibles. La clase Motocicleta contiene los atributos Color, Cilindrada y Velocidad máxima. La clase agrupa también las operaciones aplicables a las instancias de la clase, como aquí las operaciones Arrancar(), Acelerar() y Frenar(). Una transacción bancaria es una abstracción de una operación inmaterial, que refleja una interacción entre un cliente y un banco. Los detalles de realización de las transacciones habituales, como el reintegro o el ingreso, no son conoci-dos por el cliente, quien se limita a indicar la cuenta sobre la que desea operar y el montante en cuestión. La cuenta es otra abstracción del ámbito bancario. La abstracción disimula la complejidad de la gestión de las cuentas, de modo que las transacciones pueden ser realizadas simplemente por el propio clien-te, desde un cajero automático o por Internet. Todos los tipos de datos abstractos manipulados por los informáticos son, como su nombre indica, abstracciones descritas en términos de operaciones aplicables sobre valores. Este género de abstracción pertenece típicamente al diseño, y no aparece jamás en el análisis, donde el término colección es sufi-ciente para designar las agrupaciones de objetos. La descripción de las clases se divide en dos partes: La especificación de una clase que describe el ámbito de definición y las propiedades de las instancias de esta clase, y que corresponde a la noción de tipo tal como se define en los lenguajes de programación clásicos; La realización que describe cómo se realiza la especificación y que contie-ne el cuerpo de las operaciones y los datos necesarios para su funciona-miento. Una clase firma un contrato con otras clases: se compromete a proporcionar los servicios publicados en su especificación y las demás clases se compro-meten a no hacer uso de otros conocimientos que los descritos en dicha espe-cificación. Los lenguajes modulares permiten la compilación separada de la especifica-ción y de la realización, de modo que es posible validar primero la coheren-cia de las especificaciones (llamadas también interfaces) y dedicarse más adelante a la realización. Según los lenguajes de programación, los conceptos de tipo, de descripción y de módulos están más o menos integrados en el concepto de clase: En C++ la clase se realiza directamente por una cons-trucción sintáctica que engloba las nociones de tipo, de descripción y de módulo. La clase puede degradarse a fin de obtener un módulo separado, añadiendo la 6
palabra clave static delante de todas las operaciones. En Java, como en C++, la clase es la integración de las nociones de tipo, de descripción y de módulo, pero existe además una noción de módulo más amplia (el paquete) que puede contener varias clases. La separación entre la especificación y la realización de las clases participa en la elevación del nivel de abstracción. La oculta-ción de los detalles de realización se llama encapsulación. La encapsulación presenta una doble ventaja. Por una parte, los datos encap-sulados en los objetos se protegen de los accesos improcedentes (lo cual per-mite garantizar su integridad) y, por otra parte, los usuarios de una abstrac-ción no dependen de la realización de la abstracción sino solamente de su especificación, lo que reduce la vinculación en los modelos. De modo predeterminado, los valores de atributos de un objeto se encapsu-lan en el objeto y no pueden ser manipulados directamente por los demás objetos. Todas las interacciones entre los objetos se efectúan desencadenan-do las diversas operaciones declaradas en la especificación de la clase y acce-sibles desde los demás objetos. Las reglas de visibilidad completan o precisan la noción de encapsulación. Así, es posible flexibilizar el grado de encapsulación y también de protec-ción. El interés de romper la encapsula-ción es, por ejemplo, reducir el tiempo de acceso a los atributos suprimiendo la necesidad de recurrir a operaciones de tipo selector. Los tres niveles distintos de encapsulación habitualmente utilizados corres-ponden a los propuestos por el lenguaje de programación C++: El nivel más fuerte es el llamado nivel privado (private); la parte privada de la clase es totalmente opaca y sólo los amigos (en el sentido de C++) pueden acce-der a los atributos colocados en la parte privada. Es posible suavizar ligeramente el nivel de encapsulación colocando cier-tos atributos en la parte protegida (protected) de la clase. Estos atributos son visibles a la vez para los amigos y las clases derivadas de la clase proveedora. Para todas las demás clases, los atributos siguen siendo invisibles. El nivel más bajo se obtiene colocando los atributos en la parte pública (public) de la clase. Esto equivale a romper la noción de encapsulación y hacer visi-bles los atributos para todas las clases. El nivel de visibilidad puede precisarse en las representaciones gráficas de las clases mediante los caracteres +, # y −, que corresponden, respectivamente, a los niveles público, protegido y privado. La encapsulación reduce la vinculación en el interior del modelo, favorece la modularidad y facilita el mantenimiento de los programas. La encapsulación actúa como un: los defectos quedan encerrados en la clase afectada, no se propagan por todo el modelo. Los criterios de encapsulación se basan en la coherencia interna en el interior de una clase y en la baja vinculación entre las clases. 3.− Las relaciones entre clases. Los enlaces particulares que relacionan los objetos pueden verse de manera abstracta en el mundo de las clases: a cada familia de enlaces entre objetos corresponde una relación entre las clases de estos mismos objetos. Al igual que los objetos son instancias de las clases, los enlaces entre objetos son ins-tancias de las relaciones entre clases. La asociación: 7
Expresa una conexión semántica bidireccional entre clases. Una asociación es una abstracción de los enlaces que existen entre los obje-tos instancias de las clases asociadas. El diagrama siguiente representa objetos relacionados entre sí y las clases asociadas correspondientes. Las asociacio-nes se representan de la misma manera que los enlaces. La distinción entre un enlace y una asociación se opera en función del contexto del diagrama. Los enlaces entre las universidades y los estudiantes son todos instancias de la asociación entre la clase Universidad y la clase Estudiante. Para mejorar la legibilidad de los diagramas, la asociación puede ir acom-pañada por una forma verbal activa o pasiva. Es posible precisar la función de una clase en el interior de una asociación: puede especificarse un nombre de función en ambos lados de la asociación. El ejemplo siguiente muestra dos asociaciones entre la clase Universidad y la clase Persona. El diagrama precisa que ciertas personas cumplen la función de estudiante, mientras que otras personas cumplen la función de docente. La segunda asociación tiene también un nombre de función al lado de la clase Universidad para indicar que la universidad cumple la función de contratante para sus docentes. El nombrado de las funciones toma todo su interés cuando varias asociaciones enlazan las dos mismas clases. Las funciones contienen también una información de multiplicidad que pre-cisa el número de instancias que participan de la relación. La información de multiplicidad aparece en los diagramas de clases en la proximidad de la fun-ción afectada. La tabla siguiente resume los valores de multiplicidad más habituales: 1 0..1 M..N * 0..* 1..*
Uno y solo uno Cero o uno De M a N (enteros naturales) De cero a varios De cero a varios De uno a varios
El diagrama siguiente da un ejemplo de representación de los valores de mul-tiplicidad. El diagrama anterior se lee de la manera siguiente: "una universidad dada agrupa numerosas personas; algunas cumplen la fun-ción de estudiante, otras la función de docente. Un estudiante dado pertene-ce a una sola universidad, un docente dado puede estar en activo o no". La agregación: De modo predeterminado, la asociación expresa un acoplamiento débil, las clases asociadas siguen siendo relativamente inde-pendientes una de otra. La agregación es una forma particular de asociación que expresa un acoplamiento más fuerte entre clases. Una de las clases cum-ple una función más importante que la otra en la relación. La agregación per-mite representar relaciones de tipo amo y esclavos, todo y partes o compues-to y componentes. Las agregaciones representan conexiones bidireccionales asimétricas. El con-cepto de agregación es una noción puramente lógica, completamente inde-pendiente de las opciones de representación que derivan del diseño detallado y no del modelado. Matemáticamente, la agregación es una relación transiti-va, no simétrica y reflexiva. 8
El ejemplo siguiente muestra que una persona puede ocuparse de varios hijos. La relación es de naturaleza asimétrica en el ámbito considerado: el adulto es responsable de los hijos. La relación es también reflexiva: ciertas personas cumplen la función de padres, otras cumplen la función de hijo. Una agregación se representa como una asociación, con el añadido de un pequeño rombo colocado al lado del agregado. Correspondencias entre diagramas de clases y diagramas de objetos: Un diagrama de clases muestra una abstracción de la realidad, concentrada desde un punto de vista general. Un diagrama de objetos representa más bien un caso particular, una situación concreta en un instante dado; expresa a la vez la estructura estática y un comportamiento. Las reglas siguientes gobiernan la transición entre los dos tipos de diagrama: cada objeto es instancia de una clase y la clase del objeto no puede cam-biar durante la vida del objeto; ciertas clases (llamadas clases abstractas) no pueden ser instanciadas; cada enlace es instancia de una relación; los enlaces vinculan los objetos, las relaciones vinculan las clases; un enlace entre dos objetos implica una relación entre las clases de los dos objetos; • un enlace entre dos objetos indica que los dos objetos se conocen y que pueden intercambiar mensajes; los diagramas de objetos que contienen objetos y enlaces son instancias de diagramas de clases que contienen clases y relaciones. En la práctica, los diagramas de objetos y los diagramas de clases se cons-truyen en paralelo, con numerosas idas y venidas entre las dos representacio-nes. No hay ninguna razón para definir las clases antes que los objetos. Es cierto que cada objeto es instancia de una clase, pero la determinación de la clase puede ser perfectamente posterior a la de los objetos. El mundo real que nos envuelve contiene objetos y no clases: parece natural, pues, buscar pri-mero los objetos y luego abstraer las clases. En realidad, no existe una regla general; en ciertos casos, la estructura de las clases es evidente y, en otros, los objetos son más fáciles de identificar que las clases. Las jerarquías de clases: Las jerarquías de clases o clasificaciones permiten gestionar la complejidad ordenando los objetos dentro de árboles de clases de abstracción creciente. Generalización y especialización: La generalización y la especialización son puntos de vista centrados en las jerarquías de clases. La generalización consiste en factorizar los elementos comunes (atributos, operaciones y restricciones) de un conjunto de clases en una clase más gene-ral llamada superclase. Las clases se ordenan según una jerarquía; una super-clase es una abstracción de sus subclases. La generalización es un método bastante difícil porque exige una buena capa-cidad de abstracción. La depuración de una jerarquía óptima es delicada e ite-rativa. Los árboles de clases no crecen a partir de su raíz. Por el contrario, se determinan partiendo de las hojas porque éstas pertenecen al mundo real mientras que los niveles superiores son abstracciones construidas para orde-nar 9
y comprender. El ejemplo siguiente muestra una jerarquía de medios de transporte. La flecha que simboliza la generalización entre dos clases apunta a la clase más general. La especialización permite capturar las particularidades de un conjunto de objetos no discriminados por las clases ya identificadas. Las nuevas carac-terísticas se representan por una nueva clase, subclase de una de las clases existentes. La especialización es una técnica muy eficaz para la extensión coherente de un conjunto de clases. La generalización y la especialización expresan en qué sentido se utiliza una jerarquía de clases. En toda aplicación real, los dos puntos de vista se implementan simultáneamente. La generalización se emplea preferentemente una vez que los elementos del ámbito han sido identificados a fin de aislar una descrip-ción separada de las soluciones. La especialización, por su parte, se encuen-tra en la base de la programación por extensión y de la reutilización. Las nue-vas necesidades se encapsulan en subclases que extienden armoniosamente las funciones existentes. La identificación de las superclases utiliza ante todo la capacidad de abstracción, independientemente de los conocimientos técnicos, mientras que la realiza-ción de las subclases exige especialmente una experiencia profunda de un ámbito particular. Resulta más difícil encontrar las superclases, pero los programas escritos en esos términos son más simples de desarrollar. Es bastante fácil encontrar las subclases, pero es difícil reali-zarlas. La generalización no recibe ningún nombre particular, sino que significa siempre: "es un o es una especie de". La generalización sólo afecta a las clases, no es instanciable en enlaces y, de hecho, no recibe ninguna indicación de multiplicidad. En el ejemplo siguiente, el león es una especie de carnívoro y un león no puede ser varias veces un carnívoro: un león es un carnívoro. La generalización es una relación no reflexiva: una clase no puede derivar de sí misma. La generalización es una relación no simétrica: si una clase B deriva de una clase A, entonces la clase A no puede derivar de la clase B. La generalización es por el contrario una relación transitiva: si C deriva de una clase B que deriva a su vez de una clase A, entonces C deriva también de A. De los conjuntos a las clases: La noción de clase es muy próxima a la noción de conjunto. La especifica-ción de una clase es una descripción abstracta, análoga a la descripción en comprensión de un conjunto. Los objetos instancias de una clase comparten características generales, expresadas en la clase en forma de atributo, de ope-ración y de restricción. Estas características constituyen la propiedad característica del conjunto de instancias. La propiedad característica de un conjunto X se anota P(X). El conjunto X puede dividirse en subconjuntos, a fin de distinguir, por ejem-plo, particularidades suplementarias compartidas solamente por algunos de los elementos de x. Las clases y las subclases son el equivalente de los conjuntos y subconjuntos. La generalización de las clases corresponde a la relación de inclusión de los conjuntos. De este modo, los objetos instancias de una clase dada son descri-tos por la propiedad característica de su clase, pero también por las propieda-des características de todas las clases antecesoras de su clase. Las subclases no pueden negar las propiedades características de sus clases antecesoras. 10
El diagrama siguiente ilustra un ejemplo concreto. Existen muchísimos libros; algunos se dirigen particularmente a los niños, otros tienen como obje-tivo la enseñanza. La clasificación no es exhaustiva: los libros que no se diri-gen ni a los niños ni a la enseñanza no se distinguen y pertenecen colectiva-mente a la clase de los libros. Las propiedades generales de los libros, como el nombre del autor o el número de páginas, se definen en la superclase Libro. Cada subclase recibe estas características y puede añadir otras nue-vas, como espectro de edad de los lectores en el caso del libro para niños. Una clase abstracta es una clase que no da lugar directamente a objetos, sino que sirve de especificación más abstracta para los objetos instancias de sus sub-clases. El principal interés de este método es reducir el nivel de detalle en las descripciones de las subclases. El nombre de una clase abstracta va en cursi-va en los diagramas de clases. Las clases abstractas facilitan la elaboración de programas genéricos, fácil-mente extensibles por creación de subclases. El conjunto de mecanismos que sirven de armazón para las funciones de las aplicaciones se construyen a par-tir de los elementos generales proporcionados por las clases abstractas. Las especificidades y las extensiones se encapsulan en subclases concretas. Sobre la dificultad de clasificar: Las clasificaciones deben, ante todo, discriminar claramente los objetos. Las buenas clasificaciones son estables y extensibles. Ocurre que comportan excepciones inclasificables según los criterios observados. El gran panda, por ejemplo, forma parte de la familia de los 0505 mientras que el pequeño panda está más próximo a los ratones lavadores. El ornitorrinco pertenece a la fami-lia de los mamíferos aun siendo ovíparo. Las clasificaciones se efectúan según criterios dependientes del punto de vista. No hay pues una sola clasificación, sino diversas clasificaciones, cada una adaptada a un uso dado. La determinación de los criterios pertinentes y del orden en que deben aplicarse no siempre resulta fácil. Una vez establecidos los criterios, hay que seguirlos de manera coherente y uniforme según el orden determinado. El orden de aplicación de los criterios a menudo es arbitrario y conduce a descomposiciones covariantes (clasificar animales en primer lugar por el criterio de la estación y posteriormente hacerlo en primer lugar según su alimentación). Esto produce diferentes soluciones no satisfactorias porque el fenómeno de covariación induce puntos de mantenimiento múltiples en el modelo. La generalización múltiple aporta una solución elegante para la construcción de clasificaciones con criterios independientes, difíciles de ordenar. Los criterios independientes determinan diferentes dimensiones de especialización y las clases concretas se obtienen por producto cartesiano de las diferentes dimensiones. La forma clásica de la relación de generalización de clases introduce un aco-plamiento estático muy fuerte en el modelo, no mutable, como el enlace entre un objeto y su clase. Desde este punto de vista, la generalización no está adaptada para representar las metamorfosis. La solución para la representación de las mariposas consiste en extraer el ele-mento mutable. En nuestro caso, la apariencia de una mariposa dada se tra-duce por un enlace hacia un objeto específico que describe su estadio. La herencia: Existen numerosas maneras de realizar la clasificación. En programación de objetos, la técnica más utilizada se basa en la herencia entre clases. Principio general: La herencia es una técnica ofrecida por los lenguajes de programación para construir una clase a partir de una o varias otras clases, compartiendo atribu-tos, operaciones y, en ocasiones, restricciones, 11
dentro de una jerarquía de cla-ses. Las clases hijas heredan las características de sus clases antecesoras; los atributos y las operaciones declaradas en la clase madre son accesibles en la clase hija, como si se hubieran declarado localmente. La herencia se utiliza para satisfacer dos necesidades distintas: la clasificación y la construcción. Esta ambivalencia de la relación de herencia, que puede a la vez clasificar y construir, es la fuente de muchas incoherencias de progra-mación. En programación, con un lenguaje Orientado a objetos como C++, la clasifi-cación se realiza a menudo por una relación de herencia entre la clase más general y la clase más específica. La herencia propaga las características de la clase madre en las clases hijas, de modo que varias clases pueden compar-tir una misma descripción. Desde este punto de vista, la herencia permite una descripción económica de un conjunto de clases enlazadas por una relación de clasificación. La construcción de componentes por herencia es una técnica de programación perfectamente respetable, siempre que materialice claramente el hecho en el programa. Cuando el programador construye por herencia, debe indicar que la relación de herencia afectada se utiliza para la construcción y no para la clasificación. El lenguaje C++, por ejemplo, per-mite distinguir la herencia para la clasificación de la herencia para la cons-trucción, por medio de las palabras clave public y private. La herencia múltiple debe mane-jarse con grandes precauciones, porque las técnicas de realización de la herencia pueden inducir a problemas de colisión de nombres en la propaga-ción de atributos y operaciones de las clases antecesoras hacia las subclases. Esta situación es lo bastante molesta para que ciertos lenguajes orientados a objetos, como Java o Ada 95, no ofrezcan herencia múltiple. En la práctica, la herencia múltiple puede emplearse sin excesivos problemas cuando su imple-mentación ha acompañado a la elaboración del modelo desde el inicio. Por el contrario, es muy improbable que la herencia múltiple sea la manera de efectuar una fusión entre dos conjuntos de clases construidos de manera totalmente inde-pendiente. En conclusión: ¡el uso de la herencia múltiple debe anticiparse! La delegación: La herencia no es una necesidad absoluta y siempre puede reemplazarse por la delegación. La delegación presenta la ventaja de reducir el acoplamiento en el modelo: por una parte, el cliente no conoce directamente al proveedor, y por otra, el proveedor puede ser modificado sobre la marcha. Esta aproxi-mación permite implementar la generalización múltiple con los lenguajes que sólo poseen la herencia simple. El principio de sustitución: La clasificación propaga el estado, el comportamiento y las restricciones. No existen medias tintas: todas las propiedades de la clase madre son válidas íntegramente para la clase hija. La necesidad de heredar parcialmente es el signo de que la relación de herencia considerada no realiza verdaderamente una relación de clasificación. El principio de sustitución, enunciado originariamente por Liskow, permite determinar si una relación de herencia se emplea correctamente para la clasi-ficación. El principio de sustitución afirma que: "debe ser posible sustituir cualquier objeto instancia de una subclase por cualquier objeto instancia de una superclase sin que la semántica del pro-grama escrito en los términos de la superclase se vea afectado". El Polimorfismo:
12
El término polimorfismo describe la característica de un elemento que puede tomar varias formas, como el agua que se encuentra en estado sólido, líquido o gaseoso. En informática, el polimorfismo designa un concepto de la teoría de los tipos, según el cual un nombre de objeto puede designar instancias de clases diferentes surgidas de un mismo árbol. Principio general: Las interacciones entre objetos se escriben según los términos de las especi-ficaciones definidas, no en las clases de los objetos, sino en sus superclases. Ello permite escribir un código más abstracto, separado de las particularida-des de cada clase, y obtener mecanismos lo bastante generales para seguir siendo válidos en el futuro, cuando se creen nuevas clases. El término polimorfismo designa en este caso particular el polimorfismo de operación, es decir, la posibilidad de desencadenar operaciones diferentes en respuesta a un mismo mensaje. Cada subclase hereda de la especificación de las operaciones de sus superclases, pero tiene la posibilidad de modificar localmente el comportamiento de estas operaciones, a fin de tener en cuenta mejor las peculiaridades relacionadas con un nivel de abstracción dado. Desde este punto de vista, una operación dada es polimorfa porque su reali-zación puede tomar varias formas. El polimorfismo es un mecanismo de desacoplamiento que actúa en el tiem-po. Los beneficios del polimorfismo se recogen principalmente durante el mantenimiento. El polimorfismo no influye en el análisis, pero depende de él: su implementación eficaz se basa en la identificación de mecanismos abstractos, aplicables de manera uniforme a objetos instancias de subclases dife-rentes. No hay que pensar el análisis en términos de polimorfismo, hay que pensarlo en términos de abstracción y así, por efecto secundario beneficioso de esta abstracción, hacer posible el polimorfismo. Aplicación: Todos los animales saben dormir, pero cada raza tiene sus costumbres particulares. La especificaci6n del animal dice que los ani-males pueden dormir. Las subclases particularizan la operación Dormir () según los gustos de cada raza. El diagrama siguiente muestra cómo acostum-bra a dormir cada raza de animales. Los mecanismos generales escritos según la especificación del zoo no nece-sitan conocer los gustos particulares de cada género de animal para invocar la operación Dormir() . Así, al caer la noche, el guarda se pasea a través del zoo e informa a cada animal que es hora de dormir. En términos más informáticos, esto equivale a visitar la colección Zoo utili-zando eventualmente un iterador (un objeto asociado a una colección que permite visitar todos sus elementos sin desvelar su estructura interna), y enviar el mensaje Dormir a cada animal. 4.− El modelo dinámico: Introducción: los elementos del modelo dinámico Las relaciones dinámicas son difíciles de comprender. Lo mejor para entender un sistema es examinar primero su estructura estática, esto es, la estructura de sus objetos y sus relaciones entre sí en un momento dado. Después se examinan los cambios de los objetos y sus relaciones con el tiempo. Los aspectos del sistema que están relacionados con el tiempo y con los cambios constituyen el modelo dinámico, por contraste con el modelo estático o de objetos. El modelo dinámico está configurado por los conceptos que están relacionados con el flujo de control, con las interacciones y con la secuencia de las operaciones en un sistema de objetos concurrentemente activos. El control es aquella parte del sistema que describe las secuencias de operaciones que se producen en 13
respuesta a estímulos externos, sin tener en cuenta los que hagan las operaciones, aquello a lo que afectan, ni la forma en que se desarrollen. Los conceptos más importantes del modelado dinámico son los sucesos, que representan estímulos externos, y los estados, que representan los valores de los objetos. El diagrama de estados permite representar gráficamente el modelo dinámico de un sistema mostrando como un objeto que recibe un suceso sufre un cambio de estado. El estudio del modelo dinámico tiene poca relevancia para desarrollar aplicaciones de gestión, sin embargo es fundamental para desarrollar aplicaciones de control. Dentro del desarrollo de las aplicaciones de gestión el modelo dinámico tiene importancia cuando hay que modelar la interfaz de usuario si es del tipo Windows. Esta interfaz está basado en la existencia de objetos que emiten y reciben eventos: si se pulsa un botón se realiza una determinada tarea, si el programa se encuentra en un cierto estado, entonces un conjunto de opciones del menú quedan inhabilitadas, etc. En este contexto tanto el diseño como la programación están basadas en una jerarquía de clases de objetos ya existentes con un conjunto de propiedades y de eventos predefinidos y que con frecuencia se manejan a través de asistentes y de otro tipo de ayudas que permiten ocultar gran parte de su complejidad. La noción de suceso: Un estimulo individual proveniente de un objeto y que llega a otro es un suceso. Por definición se considera instantáneo, sin duración temporal, aunque los sucesos reales tengan duración aunque sea muy pequeña. Un suceso es una transmisión de información del objeto que llama al objeto llamado. Un objeto que envía un suceso a otro objeto puede esperar una respuesta, pero la respuesta es otro suceso distinto, bajo el control del segundo objeto, que puede decidir si lo envía o no lo envía. Por ejemplo: "el usuario pulsa el botón izquierdo", "el vuelo 123 sale para Valencia". Paralelismo entre "objetos/clase de objetos" y "sucesos/clases de sucesos": Para describir los sucesos dentro del ámbito del modelo dinámico realizaremos una distinción entre suceso y clase de sucesos semejante a la que hicimos en el ámbito del modelo de objetos distinguiendo entre objeto y clase de objetos. Por ejemplo: la clase de sucesos "salida de vuelo" está compuesta, entre otros, por los sucesos concretos: "el vuelo 123 sale de Valencia" y "el vuelo 456 sale de Roma". Los sucesos elementales se agrupan en Clases de sucesos que se definen por su estructura y su comportamiento. Las clases de sucesos pueden tener atributos: Una clase de sucesos puede tener atributos que indican la información que aportan. Por ejemplo, la clase de sucesos "salida de un vuelo" tiene los atributos línea aérea, número de vuelo, ciudad de destino. El momento en el que se produce el suceso es un atributo implícito de todos los sucesos. Todo suceso aporta información de un objeto a otro. Algunas clases pueden ser simplemente señales de que ha sucedido algo, mientras que otras clases de sucesos aportan valores de datos. Los valores de datos aportados por un suceso son sus atributos, al igual que los valores de datos que contienen los objetos. Relación causal entre sucesos:
14
Un suceso puede preceder o seguir lógicamente a otro, o bien los dos sucesos pueden no estar relacionados. Por ejemplo: "El vuelo 123 debe de salir de Madrid antes de que pueda llegar a Valencia". Los dos sucesos están relacionados causalmente. "El vuelo 123 puede salir antes o después de que el vuelo 456 salga para Roma". Los dos sucesos carecen de relación causal. Cuando no existe una relación causal entre dos sucesos, se dice que son concurrentes. Cuando se representan en un diagrama se dibujan en paralelo indicando que no se conoce el orden temporal en el que se ejecutan. La descripción de un sistema distribuido debe incluir sucesos y actividades concurrentes. Representación gráfica de los sucesos entre estados: Los atributos se muestran entre paréntesis, después del nombre de la clase de suceso. Mostrar los atributos es opcional. La noción de estado: Un estado es una abstracción de los valores de los atributos y de los enlaces de un objeto. Los conjuntos de valores se agrupan dentro del estado de acuerdo con aquellas propiedades que afecten al comportamiento microscópico del objeto. Los estados son los resultados acumulados del comportamiento de un objeto. Un estado es una de las condiciones posibles en las que puede existir un objeto; abarca todas las propiedades (normalmente estáticas) del objeto más los valores actuales (normalmente dinámicos) de cada una de esas propiedades. Un estado especifica la respuesta del objeto a los sucesos entrantes. La respuesta a un suceso recibido por un objeto puede variar cuantitativamente, dependiendo de los valores exactos de sus atributos, pero cualitativamente la respuesta es la misma para todos los valores dentro del mismo estado, y puede ser distinta para valores de distintos estados. La respuesta de un objeto a un suceso puede incluir una acción o un cambio de estado por parte del objeto. Por ejemplo: si se marca un dígito en el estado "señal de marcar" la línea deja de producir la señal de marcar y entra en el estado Marcando; si el receptor se cuelga en el estado "señal de marca", la línea se desconecta y pasa al estado Libre. Un estado corresponde al intervalo entre dos sucesos recibidos por un objeto. Los sucesos representan puntos temporales, los estados representan intervalos de tiempo. Por ejemplo, una vez que el receptor se descuelga, y antes de que se marque el primer número, la línea telefónica se encuentra en el estado "señal de marcar". El estado de un objeto depende de la sucesión anterior de sucesos que haya recibido, pero en la mayoría de los casos los pasados quedan ocultos eventualmente por los subsiguientes. Los estados tienen duración, ocupan un intervalo de tiempo. Los sucesos y los estados son duales entre sí, un suceso separa a dos estados, y un estado separa a dos sucesos. Ejemplo de estado: la alarma de un despertador El siguiente esquema muestra los distintos modos de caracterizar el estado "suena la alarma" de un reloj. Estado: Suena la alarma. Descripción: la alarma del reloj suena para indicar hora deseada.
15
Secuencia de sucesos que produce el estado: fijar la alarma (hora deseada) cualquier secuencia que no incluya desactivar alarma hora actual = hora deseada Relación de generalización y herencia entre estados: Los diagramas de estado se pueden anidar en niveles cada vez más concreto del mismo modo que los diagramas de flujo de datos. Un conjunto de diagramas de estados anidados se pueden considerar como una representación de una relación de generalización y herencia. La generalización representa una relación optativa, es decir, un objeto que se encuentre en un estado del diagrama de alto nivel tiene que estar precisamente en uno de los estados del diagrama anidado. Debe de estar en el primer estado, o bien en el segundo, o bien en alguno de los demás. Todos los estados del diagrama anidado constituyen refinamientos del estado del diagrama de nivel superior. Los estados pueden poseer subestados que hereden las transiciones de sus superestados, del mismo modo que las clases poseen subclases que heredan los atributos y operaciones de sus superclases. Toda transición o acción que sea aplicable a un estado es aplicable también a todos sus subestados, a no ser que sea invalidada por una transición equivalente del subestado. La transición de estado: A lo largo del tiempo las clases de objetos se estimulan mútuamente, dando lugar a una serie de cambios en sus estados. La respuesta a un suceso depende del estado del objeto que lo recibe, y puede incluir un cambio de estado o el envío de otro suceso al remitente o a un tercer objeto. Un evento es un suceso capaz de provocar un cambio de estado en un sistema. Este cambio de estado se llama transición de estados y se representa con una flecha etiquetada con el nombre del evento que lo provoca y la acción que se produce. A continuación describimos brevemente algunas transiciones de estado que tiene una estructura característica como son: acciones de entrada y salida, acciones internas, transiciones automáticas, y el envío de sucesos. Acciones de entrada y de salida: Cuando un objeto recibe un evento que produce una acción tenemos un esquema semejante al de una información que entra en un proceso y provoca un resultado; es semejante al modelo clásico de entrada/proceso/salida. Por ejemplo, una "puerta cerrada" de un garaje, cuando recibe la señal del mando a distancia pasa a "puerta abriéndose", un estado transitorio que desemboca en el estado "puerta abierta". Acciones internas: Un suceso puede dar lugar a que se lleve a cabo una acción sin producir un cambio de estado. Cuando se produce uno de estos sucesos, su acción se ejecuta, pero no se ejecutan las acciones de entrada o salida para el estado. Por tanto, existe una diferencia entre una acción interna y una autotransición; la autotransición da lugar a que se ejecuten las acciones de entrada y salida para el estado. El nombre del suceso se escribe dentro del cuadro de estado, y va seguido por una "/" y el nombre de la acción (las palabras reservadas entrada, salida y hacer son palabras reservadas dentro del cuadro de estado). 16
Transición automática: Con frecuencia, el único propósito de un estado es llevar a cabo una actividad secuencial. Cuando finaliza esa actividad, se dispara una transición a otro estado. Una flecha sin nombre de suceso indica una transición automática que se dispara cuando ha concluido la actividad asociada con el estado original. Envío de sucesos: Los objetos pueden llevar a cabo la acción consistente en enviar un mensaje a otro objeto. Los sistemas de objetos interactúan intercambiando sucesos. Representación gráfica de las transiciones de estado: En una transición de estados intervienen los objetos con su estado concreto, los eventos que les llegan la acciones con las que reaccionan y el paso a otro estado. En la construcción de aplicaciones de control es muy importante la correcta descripción gráfica de la evolución de los objetos del sistema a lo largo del tiempo. El diagrama más sencillo recibe el nombre de escenario, la descripción más completa la realiza el diagrama de estados. Un escenario es una secuencia de sucesos que se produce durante una ejecución concreta de un sistema. La representación del escenario muestra el nivel más sencillo para indicar la trama de sucesos, estados y transiciones de estados que componen el modelo dinámico de un sistema. A continuación mostramos la representación del escenario de utilización de una línea telefónica. • el locutor descuelga el receptor • comienza el tono para marcar • el locutor marca el número (5) • finaliza el tono de marcar • el locutor marca el número (5) ... El diagrama de estados, además de recoger la información del diagrama de seguimiento de sucesos, especifica la secuencia de estados producida por una secuencia de sucesos. Un diagrama de estados es un grafo cuyos nodos son estados, y cuyos arcos dirigidos son transiciones rotuladas con nombres de sucesos. Un diagrama de estados relaciona sucesos y estados. Cuando se recibe un suceso, el estado siguiente depende del actual, así como del suceso. Un cambio de estado causado por un suceso es lo que se llama una transición. Si un objeto se encuentra en un cierto estado y se produce un suceso cuyo nombre corresponda al de una de sus transiciones, entonces el objeto pasa al estado que se encuentra en el extremo de destino de la transición. Se dice que la transición se dispara. Si hay más de una transición que sale de un estado, entonces el primer suceso que se produzca dará lugar a que se dispare la transición correspondiente. Si se produce un suceso que no tiene ninguna transición que salga del estado actual, entonces el suceso se ignora. Una secuencia de sucesos se corresponde con un camino a través del grafo. Relación entre los modelos de objetos y dinámico: El modelo dinámico especifica las secuencias admisibles de cambios para los objetos procedentes del modelo 17
de objetos. Los diagramas de estado describen en todo o en parte el comportamiento de un objeto de una clase dada. Los estados son clases de equivalencia de atributos y de valores de enlace para el objeto. Los sucesos se pueden representar como operaciones en el modelo de objetos. La estructura del modelo dinámico esta relacionada con la del modelo estático, y queda limitada por este último. Los subestados refinan los valores de atributos y de enlaces que puede tener el objeto. Cada subestado restringe los valores que puede tener el objeto. Una jerarquía de estados de un objeto es equivalente a una jerarquía de restricción de la clase del objeto. Los modelos y lenguajes orientados a objetos no suelen apoyar la restricción en la jerarquía de generalización, así que el modelo dinámico es el lugar correcto para representarla. Tanto la generalización de clases como la de estados fragmentan el conjunto de posibles valores del objeto. Un solo objeto puede tener distintos estados a lo largo del tiempo (el objeto mantiene su identidad) pero no puede tener distintas clases. Las diferencias inherentes entre objetos son modeladas correctamente, por tanto, como clases distintas, mientras que las diferencias temporales son modeladas correctamente como distintos estados de una misma clase. Un estado compuesto es la agregación de más de un subestado concurrente. Dentro del modelo de objetos hay tres fuentes de concurrencia. La primera es la agregación de objetos: cada componente de una agregación tiene su propio estado independiente, así que se puede considerar que el subsistema tiene un estado que es la suma de los estados de todos sus componentes. Lo segunda fuente es la agregación dentro de un objeto: los atributos y los enlaces de un objeto son sus partes, y los grupos que de ellos se forman definen subestados concurrentes del estado del objeto compuesto. La tercera fuente es el comportamiento concurrente de un objeto. Las tres fuentes de concurrencia suelen ser intercambiables. Por ejemplo, un objeto podría contener un atributo para indicar que estaba realizando una cierta actividad. El modelo dinámico de una clase es heredado por sus subclases. A su vez éstas heredan tanto de los estados de su antecesor como las transiciones. Las subclases pueden tener sus propios diagramas de estados. El diagrama de estados de la subclase debe de ser un refinamiento del diagrama de estados de la superclase. Todo estado del diagrama de estados predecesor puede ser generalizado o partido en partes concurrentes, pero no se pueden introducir directamente nuevos estados o transiciones en el diagrama predecesor porque debe de ser una proyección del diagrama descendiente. Aun cuando es posible el refinamiento de diagramas de estados heredados, lo normal es que el diagrama de estados de una subclase sea una adición independiente, ortogonal y concurrente al diagrama de estados heredado de la superclase, y debe de estar definido con un conjunto de atributos distinto (que normalmente son los que se habrán añadido en la subclase). 5.− UML y Rational Rose (Herramienta Case): Actualmente cualquier técnica informática útil para el desarrollo de aplicaciones tiene una o más herramientas CASE que ayudan al ingeniero informático para utilizarla mejor. Rumbaugh, Booch y Jacobson ya habían hecho sus propuestas individuales y al sintetizar sus métodos de modelado consideraron que era esencial ofrecer una herramienta CASE que soportara todas las técnicas de modelado propuestas. Esta herramienta se llama Rational Rose y la empresa "Desarrollo y Macroinformación" la distribuye en España. Por todos es conocido que existen muchas metodologías OO que se utilizan en la empresa y que paralelamente apare-cen cientos de herramientas CASE que las usan como base para el diseño de apli-caciones de todo tipo. Algunas de las me-todologías más importantes son la Booch '93, la OMT (Object Modeling Technique) con sus actualizaciones (como la OMT−2) y la OOSE (Object Oriented Software Engineer). Y precisamente los principa-les autores de estas metodologías y no-taciones gráficas − en la creación de las metodologías suelen intervenir varias personas − llevan algunos años trabajan-do para conseguir que sus principios se unifiquen y establecer un estándar sobre el cual trabajar. Las razones para esta unificación son varias pero una de las principales es el clima de confusión que se estaba generando: los diseñadores co-gían a su antojo las características que necesitaban, buscando suplir las caren-cias de los métodos que utilizaban. Así, la utilización de varios métodos a la vez para aprovechar las ventajas de unos y 18
otros era una práctica generalizada, lo cual constituye una mecánica de trabajo, cuando menos, peligrosa, al conducir a una situación en la que los propios desa-rrolladores no son capaces de discernir qué características procedían de qué métodos. Los principales creadores de UML son Grady Booch, Jim Rumbaugh e Ivar Jacobson. Como objetivos principales de la consecución de un nuevo método que aunara los mejores aspectos de sus predecesores, sus protagonistas se marcaron los siguientes: • El método debía ser capaz de modelar no sólo sistemas software si no otro tipo de sistemas reales de la empresa, siempre utilizando los conceptos de la orientación a objetos. • Crear un lenguaje para modelado utilizable a la vez por máquinas y por personas. • Establecer un acoplamiento explícito de los conceptos y los artefactos ejecutables. • Manejar los problemas típicos de los sistemas complejos de misión críti-ca. Durante 1996, varias compañías se unieron a los esfuerzos de creación de la definición del UML. La importancia de estas empresas puede ayudarnos intuir la relevancia que puede llegar a adquirir el UML: lntellicorp, IBM, Oracle, HP, Digital Equipment, Unisys, etc, forman el consorcio para el desarrollo del UML. Con su participación se ha preten-dido obtener otras perspectivas al formar parte activa del proyecto. Así se incluyen en UML perspectivas sugeridas por el OMG, semántica de má-quina de estado (mediante la incorpora-ción de diagramas de estado), tipos, inter-faces, colaboraciones, refinamiento, dis-tribución y un metamodelo para definir otros modelos. EL resultado fue la versión final 1.0 (por el momento), que se encuentra en fase de ser aceptada como estándar por el OMG. La creación del UML pretende conseguir ade-más dos objetivos claramente definidos: por un lado, que los lenguajes que se aplican siguiendo los métodos más utili-zados sigan evolucionando en conjunto y no por separado, como estaba ocurriendo hasta ahora, y se concluyan de esta for-ma las diferencias entre ellos; y por otro lado, y lo que puede en determinadas si-tuaciones ser de extrema importancia, unificar las perspectivas entre diferentes tipos de sistemas (no sólo software, sino también de ámbito de negocio), al aclarar las fases de desarrollo, los requerimien-tos del análisis, el diseño, la implementa-ción y los conceptos internos de la 00. UML1.O: La versión de UML final hasta el momen-to es la 1.O que constituye una versión es-table y utilizable, cuya especificación completa se encuentra a disposición del público en Internet El UML es un lenguaje para especifi-car, construir, visualizar y documentar los artefactos de un sistema de software 00. Un artefacto es una información que es utilizada o pro-ducida mediante un proceso de desarrollo de software. Definida la palabra que quizá causara mayor confusión en la definición de UML, el resto no deja sitio para la ambigüedad, el UML se quiere convertir en un lenguaje estándar con el que sea posi-ble modelar todos los componentes del proceso de desarrollo de aplicaciones, pero no pretende definir un proceso estándar de desarrollo sino únicamente un lenguaje de modelado. Otros métodos de modelado como OMT o Booch sí definen procesos concretos. El método del UML recomienda utilizar los procesos que otras metodologías tienen definidos. El modelado de objetos: En la especificación del UML podemos comprobar que una de las partes que lo componen es un metamodelo formal pero, ¿qué es un metamodelo?. Un metamodelo es un modelo que define el lenguaje para expresar otros modelos. Un modelo en OO es una abstracción cerrada semánticamente de un sistema y un sistema es 19
una colección de unidades conectadas que son organizadas para realizar un propósito es-pecifico. Un sistema puede ser descrito por uno o más modelos, posiblemente desde distintos puntos de vista. A la vista de tales definiciones po-dríamos deducir que una parte de UML define una abstracción con significado de un lenguaje para expresar otros modelos. Lo que en principio puede pare-cer complicado no lo es tanto si pensamos que uno de los objetivos del UML es lle-gar a convertirse en una manera de defi-nir modelos, no sólo establecer una forma de modelo, de esta forma simplemente estamos diciendo que UML, además, defi-ne un lenguaje con el que podemos abstraer cualquier tipo de modelo. El modela-do no es más que la construcción de un modelo a partir de una especificación. Un modelo es una abstracción de algo, que se elabora para comprender ese algo antes de construirlo. El modelo omite detalles que no resultan esenciales para la com-prensión del original y por tanto facilita dicha comprensión. La OMT, por ejemplo, intenta abstraer la realidad utili-zando tres clases de modelos 00: el mo-delo de objetos, que describe la estructu-ra estática; el modelo dinámico, con el que describe las relaciones temporales entre objetos; y el modelo funcional que describe las relaciones funcionales entre valores. Mediante estas tres fases de construcción de un modelo, se consigue una abstracción de la realidad que tiene en sí misma información sobre las princi-pales características de ésta. Los modelos, además, al no ser una representación que incluya todos los de-talles de los originales, permiten probar más fácilmente los sistemas que modelan y determinar los errores (es posible enseñar al cliente una aproximación de lo que será el pro-ducto final, proporcionan una primera aproximación al problema que permite visualizar cómo quedará el resultado y reducen la complejidad del original en subconjuntos que son fácilmente trata-bles por separado). Se consigue un mo-delo completo de la realidad cuando el modelo captura los aspectos importan-tes del problema y omite el resto. En OMT, como ya hemos comentado, se mo-dela un sistema desde tres puntos de vista diferentes donde cada uno representa una parte del sistema y su unión lo describe de forma completa. UML utiliza parte de este planteamiento obteniendo distintos puntos de vista de la realidad que modela mediante los distintos tipos de diagramas que posee. Un diagrama es una representación gráfica de una colección de elementos del modelo, que habitualmente toma forma de grafo donde los arcos que conectan sus vértices son las relaciones entre los objetos y los vértices se corresponden con otros elementos del modelo. Los distintos puntos de vista de un sistema real que se quieren representar para obtener el mo-delo se dibujan de forma que se resaltan los detalles necesarios para entender el sistema. Artefactos para el desarrollo de proyectos: Un artefacto, como decíamos antes, es una información que es utilizada o pro-ducida mediante un proceso de desarrollo de software. Pueden ser artefactos: un modelo, una descripción o un software. Los artefactos de UML se especifican en forma de diagramas, éstos, junto con la documentación sobre el sistema, que forma parte del modelo, constituyen los artefactos principales que el modelador puede observar, aunque el UML además es capaz de proporcionar puntos de vis-ta alternativos. UML utiliza los siguientes diagramas gráficos para obtener estos distintos puntos de vista de un sis-tema: • diagramas de casos de uso • diagramas de clases • diagramas de comportamiento o inte-racción • diagrama de estado • diagrama de actividad • diagrama de secuencia
20
• diagrama de colaboración • diagramas de implementación • diagrama de componente • diagrama de plataforma Nuevas Características del UML: Los conceptos que se incluyen en UML son en su mayoría extraídos de los mé-todos de diseño anteriores, UML sólo los ha juntado para que sirvan a un propósito común: llegar desde la abstracción de un problema hasta su solución de forma completa e inteligible por todos los componentes de un equipo de desarrollo. Pero además de los conceptos extraídos de métodos anteriores, se han añadido otros nuevos que vienen a suplir carencias de las antiguas metodologías de modelado. Estos nuevos conceptos son los siguien-tes: • Definición de estereotipos: un este-reotipo es una nueva clase de ele-mento de modelado que debe basarse en ciertas clases ya existentes en el metamodelo y constituye un me-canismo de extensión del modelo. • Responsabilidades. • Mecanismos de extensibilidad: este-reotipos. valores etiquetados y res-tricciones. • Tareas y procesos. • Distribución y concurrencia (para modelar, por ejemplo ActiveX, DCOM y CORBA) • Patrones/colaboraciones. • Diagramas de actividad (para reinge-niería de proceso de negocio). • Clara separación de tipo, clase e ins-tancia. • Refinamiento (para manejar relacio-nes entre niveles de abstracción). • Interfaces y componentes. El proceso de Desarrollo: Como comentábamos antes, los autores de UML no han definido un proceso con-creto que determine las fases de desarro-llo de un sistema, las empresas pueden utilizar UML como lenguaje para definir sus propios procesos y lo único que ten-drán en común con otras organizaciones que utilicen UML serán los tipos de dia-gramas. El proceso debe ser determinado según las necesidades propias de la apli-cación a desarrollar. UML es un método independiente del proceso lo cual no significa que sus autores no reconozcan la importancia de que exista un proceso concreto. Determinar correctamente las fases de desarrollo es de vital trascendencia en el desarrollo software sin embargo, consi-deran que los procesos de desarrollo de-ben ser definidos dentro del contexto donde se van a implementar los sistemas. UML puede soportar los procesos que otras metodologías tienen definidos, los procesos de Booch, OMT y OOSE pue-den ser utilizados en UML, sin embargo no existe una estandarización al respecto y no es objetivo de UML el conseguirla. Rational Rose C++: UML es útil para obtener modelos que describan supuestos particulares, pero la definición de un estándar es también de vital importancia en el desarrollo de soft-ware debido a que posibilita la generación de herramientas CASE que se fundamen-tan en dichos estándares y que se utilizan de forma generalizada. Los creadores de UML tienen muy presente este hecho: todos los métodos 00 cuya utilización está extendida en el mercado disponen de herramientas que facilitan el diseño de los sistemas. A la ho-ra de trabajar sobre la creación de UML sus desarrolladores han tenido siempre en mente cómo debía ser esa herramien-ta CASE que soportara como anillo al de-do su especificación. Rational Rose es la herramienta CASE que comercializan los creadores del UML y que soporta de forma completa la especificación del UML 1.0. 21
Rational Rose propone la utiliza-ción de cuatro tipos de modelo para rea-lizar un diseño del sistema, utilizando una vista estática y otra dinámica de dos modelos del sistema, uno lógico y otro físico. La herramienta permite crear y refinar estas vistas creando de esta for-ma un modelo completo que representa el dominio del problema y el sistema software. El modelo contiene clases, pa-quetes lógicos, objetos, operaciones, pa-quetes de componentes, módulos, pro-cesadores, dispositivos y las relaciones que se establecen entre ellos. Cada uno de estos componentes tiene propieda-des que los identifican y los caracterizan y que permiten abstraer los detalles re-levantes del sistema. La herramienta proporciona un icono gráfico para representar cada uno de estos componentes del modelo y sus re-laciones, conforme a la notación que se especifica en el documento de definición del UML 1.0. Un modelo también con-tiene diagramas y sus especificaciones, que proporcionan la manera de visuali-zar y manipular los componentes del modelo y sus propiedades. Estos diagra-mas ilustran las múltiples vistas del modelo mientras que los iconos represen-tan un componente que puede aparecer una, varias o ninguna vez en los diagra-mas del modelo. Rational Rose permite controlar qué componentes, relaciones e iconos de pro-piedad aparecen en cada diagrama, utili-zando las facilidades que proporciona su ventana de aplicación, donde se muestra cada diagrama en una ventana de diagra-ma y cada especificación en una ventana de especificación. Además de utilizar la herramienta para realizar el diseño la abundante ayuda en línea que proporcio-na puede resultar muy interesante como complemento para estudiar los elementos de UML. Desarrollo Iterativo: A pesar de que el UML no identifica un proceso de desarrollo concreto, Rational Rose utiliza un proceso de desarrollo ite-rativo, donde el desarrollo se lleva a cabo en una secuencia de iteracio-nes. Cada iteración comienza con una pri-mera aproximación del análisis, diseño e implementación para identificar los ries-gos del diseño, los cuales se utilizan para conducir la iteración, primero se identifi-can los riesgos y después se prueba la aplicación para que éstos se hagan míni-mos. Cuando la implementación pasa to-das las pruebas que se determinan en el proceso, ésta se revisa y se añaden los elementos modificados al modelo de aná-lisis y diseño. Una vez que la actualiza-ción del modelo se ha modificado, se rea-liza la siguiente iteración. Trabajo en grupo: Rose permite que haya varias personas trabajando a la vez en el proceso iterativo controlado, para ello posibilita que cada desarrollador opere en un espacio de tra-bajo privado que contiene el modelo com-pleto y tenga un control exclusivo sobre la propagación de los cambios en ese espa-cio de trabajo. Además utiliza ficheros pa-ra el modelo que son independientes de la plataforma, para conseguir un almacena-miento persistente de las unidades con-troladas y proporciona mecanismos para permitir a los ficheros que intervienen en el modelo ser copiados de un espacio de trabajo a otro. También es posible descomponer el modelo en unidades controladas e in-tegrarlas con un sistema para realizar el control de proyectos que permite man-tener la integridad de dichas unidades. Generador de Código: Una vez que se dispone de un diseño (le modelo, la herramienta permite generar código utilizando la opción del Generador de Código. Este código utiliza la informa-ción que se define en el modelo UML (Rose en Rational Rose). El código que se genera viene determinado por la especifi-cación de los componentes y las propieda-des del modelo, siendo las propiedades las que proporcionan la información específica que necesita el lenguaje en el que se ge-nera el código, en este caso el C++ pero se está trabajando en generadores de có-digo en Ada, Smalltalk y otros. Ingeniería inversa: Rational Rose proporciona mecanismos para realizar la denominada ingeniería in-versa, es decir; a partir del código de un programa, se puede obtener información sobre su diseño. El paquete Analizador de Rational extrae la información y la utiliza para construir un modelo que representa la estructura lógica y física de la aplicación. Rational Rose permite ver y mani-pular este modelo utilizando la notación UML para realizar el análisis y diseño 00. Para ello incluye un Analizador de C++ (en este caso), como un 22
paquete ejecuta-ble separado que se llama independiente-mente de la herramienta principal. 6.− Metodología de desarrollo (Visión general del Análisis): Planteamiento del Análisis: La definición del problema El análisis comienza con la definición de un problema generada por clientes y, posiblemente, por los desarrolladores. La definición puede ser incompleta o informal; el análisis hace que sea más precisa y expone las ambigüedades e incongruencias y no debería de tomarse como inmutable, sino que tiene que servir como base para refinar los requisitos reales. Comprensión del mundo real que describe la definición A continuación, es preciso comprender el sistema del mundo real que describe la definición del modelo, y hay que abstraer sus características esenciales para formar dicho modelo. Las sentencias escritas en lenguaje natural suelen ser ambiguas, incompletas e incongruentes. El modelo de análisis es una representación precisa y concisa del problema, que permite responder a preguntas y construir una solución. Los pasos subsiguientes de diseño hacen alusión al modelo de análisis, más que a la vaga definición original del problema. Hay algo que quizá sea aun más importante, y es que el proceso de construcción de un modelo riguroso del dominio del problema obliga al desarrollador a enfrentarse a los errores de comprensión en una fase temprana del proceso de desarrollo, momento en el cual todavía es fácil corregirlos. Las tres facetas del modelo del análisis El modelo de análisis se aplica a los tres aspectos de los objetos: • estructura estática (modelo de objetos), • secuencia de interacciones (modelo dinámico) y • transformación de datos (modelo funcional). Los tres submodelos no tienen el mismo peso en todos los problemas. Casi todos tienen modelos de objetos útiles que se derivan de entidades del mundo real. Los tres submodelos aportan operaciones que se resumen en el modelo de objetos. Observaciones El análisis no siempre se puede efectuar en una secuencia rígida. Los modelos grandes se van construyendo iterativamente. Primero, se construye un subconjunto del modelo, que después se va extendiendo hasta que se ha comprendido el problema completo. La mayoría de las definiciones de problemas carecen de información esencial, que debe obtenerse a partir del solicitante o del conocimiento que el analista tenga del dominio del problema en el mundo real. La comunicación analista/solicitante es muy importante. El analista debe comunicarse con el solicitante para clarificar ambigüedades y errores conceptuales. Los modelos de análisis facilitan una comunicación precisa. 23
Inicio del análisis: (la definición del problema) El primer paso para desarrollar cualquier cosa consiste en establecer los requisitos. Esto se aplica tanto a la investigación pura, como a la construcción de programas sencillos, como a los esfuerzos realizados por grandes equipos. Cuando se tiene una idea vaga del objetivo, lo único que se está haciendo es posponer las decisiones a una etapa en la cual los cambios serán mucho más costosos. Esquema de la visión general del proceso de análisis • Exposición de requisitos • Ámbito del problema • Qué se necesita • Contexto de la aplicación • Suposiciones • Necesidades de rendimiento • Diseño y construcción • Enfoque general • Algoritmos • Estructuras de datos • Arquitectura • Optimizaciones La definición del problema debería indicar lo que hay que hacer, y no cómo hay que hacerlo. Debe ser una exposición de nuestras necesidades, y no una propuesta de solución. Documentación que puede recoger la definición del problema Un manual del usuario para el sistema que se desea es una buena definición del problema. El solicitante debería indicar qué características son obligatorias, así como las que sean opcionales, para evitar restringir en demasía las decisiones de diseño y evitar describir las características internas del sistema, por cuanto esto le resta flexibilidad a la realización. Las especificaciones de rendimiento y los protocolos de interacción con sistemas externos son requisitos legítimos. Los estándares de ingeniería del software, tal como una construcción modular, un diseño adecuado para las pruebas, y la previsión de futuras extensiones, son también adecuados. Cribar los buenos requisitos Hay muchas definiciones de problemas (procedentes de individuos, empresas privadas y organismos de la administración) que mezclan los verdaderos requisitos con decisiones de diseño. En algunas ocasiones, puede existir alguna razón de peso para que se requiera un ordenador concreto o un lenguaje de programación particular, pero no suele estar justificado el especificar la utilización de un algoritmo determinado. El analista debe separar los requisitos verdaderos de las decisiones de diseño y de realización disfrazadas de requisitos y atacar a estos pseudorrequisitos, porque restringen la flexibilidad. Cuando haya razones políticas o de organización para los pseudorrequisitos, por lo menos, el analista debería reconocer que estas decisiones 24
de diseño impuestas externamente no son características esenciales del dominio del problema. Grado de detalle de la definición del problema La definición de un problema puede tener un grado mayor o menor de detalle. Un requisito para un producto convencional, como un programa de nómina o un sistema de facturación, puede tener muchos detalles; sin embargo, un requisito para investigar un aspecto nuevo puede carecer de muchos detalles, aunque cabe suponer que la investigación tendrá algún objetivo, con lo que éste deberá de exponerse con claridad. Calidad de la definición del problema La mayoría de las definiciones de problema son ambiguas, están incompletas, y no son ni siquiera congruentes. Hay algunos requisitos que están, simplemente, mal. Algunos, aun cuando se hayan expuesto con precisión, tendrán consecuencias desagradables para el comportamiento del sistema, o bien impondrían unos costes de realización irracionales. Otros parecen razonables en primera aproximación, pero no funcionan tan bien como podría pensar el solicitante. Carácter provisional de la definición del problema La definición del problema es solamente un punto inicial para comprenderlo, y no un documento inmutable. El diálogo analista/solicitante para depurar la definición del problema. El analista debe trabajar con el solicitante para refinar los requisitos, de tal forma que representen se verdadera intención. Esto implica cuestionar los requisitos y buscar la información que falta. Primera actividad: el modelado de objetos: Introducción El primer paso para analizar los requisitos es construir un modelo de objetos. El modelo de objetos muestra la estructura estática de datos correspondiente al sistema del mundo real, y la organiza en segmentos manejables describiendo clases de objetos del mundo real, y sus relaciones entre sí. El modelo de objetos precede al dinámico y al funcional porque las estructuras estáticas suelen estar mejor definidas, siendo menos dependientes de los detalles de la aplicación, más estables a medida que evoluciona la solución y más fáciles de entender para los seres humanos. Fuentes para construir el modelo de objetos La información del modelo de objetos proviene • de la definición del problema, • del conocimiento de expertos acerca del dominio de la aplicación, y • del conocimiento general del mundo real. Si el diseñador no es un experto del dominio, será preciso obtener la información a partir de un experto de la aplicación, y habrá que confrontar repetidamente el modelo con esta información. Identificación de las clases y las asociaciones Primero se identifican las clases y las asociaciones, por cuanto afectan a la estructura global y a la aproximación al problema; después se añaden atributos para describir aun más la red básica de clases y asociaciones; más tarde se combinan y organizan las clases utilizando la herencia. 25
Los intentos de especificar directamente la herencia sin describir primero las clases de bajo nivel con sus atributos suelen distorsionar la estructura de dichas clases, adaptándola a unas nociones preconcebidas. Identificación inicial de las operaciones de las clases Después de identificar los atributos de las clases se añaden operaciones a las clases teniendo en cuenta que su obtención es un producto secundario de la construcción de los modelos dinámico y funcional. Las operaciones modifican objetos, y por tanto no se pueden especificar por completo mientras no se haya comprendido la dinámica y la funcionalidad. Necesidad de dar vueltas antes de tener el modelo definitivo Lo mejor es ir anotando ideas en papel antes de intentar organizarlas demasiado, aún cuando sean redundantes e incongruentes, para no perder detalles importantes. Es probable que el modelo de análisis inicial contenga defectos que deberán de ser corregidos en iteraciones posteriores. No es necesario construir uniformemente todo el modelo. Algunos aspectos del problema se podrán analizar en profundidad a lo largo de varias iteraciones, mientras que habrá otros que sigan siendo poco claros. Es muy raro que el análisis y el diseño sean completamente lineales. Pasos para construir el modelo de objetos Para construir un modelo de objetos, se llevan a cabo los pasos siguientes: Paso 1: Identificar los objetos y las clases El primer paso para construir un modelo de objetos es identificar las clases de objetos relevantes en el dominio de la aplicación. Entre éstos se cuentan las entidades físicas, tales como casas, empleados y máquinas, así como conceptos como itinerarios, reservas de asientos y planes de pago. Todas las clases tienen que tener sentido en el dominio de la aplicación; hay que evitar las estructuras de realización propias de la computadora como puedan ser listas enlazadas y subrutinas. Hay que empezar por enumerar los candidatos a clases de objetos que se encuentren en la descripción escrita del problema. No hay que ser demasiado selectivo; escriba todas las clases que se le pasen por la cabeza. Con frecuencia, las clases se corresponden con nombres (sustantivos). Por ejemplo, en la sentencia "un sistema de reservas para vender entradas de actuaciones en distintos teatros", las posibles clases serían Reservas, Sistema, Entrada, Actuación y Teatro. No se preocupe demasiado por la herencia, ni por las clases de alto nivel; lo primero es obtener bien las clases específicas, para que no se eliminen detalles de forma subconsciente en un intento de hacer que coincidan con una estructura preconcebida. Luego procederemos a descartar las clases innecesarias o incorrectas: − Clases redundantes: Si se dan dos clases que expresan la misma información, hay que retener la que tenga el nombre más descriptivo. Por ejemplo, aún cuando el cliente pudiera describir a una persona que hace un vuelo en una compañía, la palabra pasajero es más descriptiva. − Clases irrelevantes: Deben eliminarse las clases que tienen poco o nada que ver con el problema. Esto implica utilizar nuestro propio criterio, porque en otro contexto la clase podría resultar importante. Por ejemplo, en un sistema de reservas para entradas de teatro, la ocupación de quienes compren las 26
entradas son irrelevantes, pero la ocupación del personal del teatro sí pueden serlo. − Clases vagas: Una clase debe de ser algo específico. Ciertas clases candidatas pueden tener unos límites mal definidos, o pueden tener un ámbito excesivo. − Clases que son Atributos: Los nombres que describen sobre todo objetos individuales deben considerarse atributos. Por ejemplo, nombre, edad, peso y dirección suelen ser atributos. Si la existencia independiente de una propiedad es importante, haremos de ella una clase y no un atributo. Por ejemplo, el despacho de un empleado sería una clase en una aplicación para asignar despachos después de una reorganización. − Clases que son Operaciones: Si un nombre describe una operación que se aplica a objetos y que no es propiamente manipulada en sí, entonces no es una clase. Por ejemplo, una llamada telefónica es una secuencia de acciones que implican a quien hace la llamada y a la red de teléfonos. Si estamos construyendo teléfonos, Llamada es una parte del modelo dinámico y no una clase de objetos. Sin embargo, toda operación que posea características propias debe modelarse como una clase. Por ejemplo, en un sistema de facturación para llamadas telefónicas, una Llamada sería una clase importante con atributos tales como fecha, hora y destino. − Clases que son Roles: El nombre de una clase debería reflejar su naturaleza intrínseca, y no el rol o papel que desempeñe en una asociación. Por ejemplo, Propietario sería un mal nombre para una clase en la base de datos de un fabricante de coches. ¿Qué pasa si después se añade una lista de conductores? ¿Qué pasa con las personas que alquilan coches? La clase adecuada es Persona (o posiblemente Cliente), ya que ésta puede asumir distintos papeles tales como propietario, conductor y arrendatario. − Estructuras de realización: Deben eliminarse del modelo de análisis las estructuras extrañas al mundo real. Quizá se necesiten en una fase posterior del diseño, pero no ahora. Por ejemplo, el procesador, las subrutinas, procesos, algoritmos e interrupciones son estructuras de realización para la mayoría de las aplicaciones, aún cuando sean clase legítimas para un sistema operativo. Las estructuras de datos tales como listas enlazadas, árboles, matrices y tablas, son casi siempre de realización. Paso 2: Preparar el diccionario de datos Las palabras aisladas tienen demasiadas interpretaciones, así que hay que preparar un diccionario de datos para todas las entidades de modelado. Hay que escribir un párrafo que describa con precisión cada clase de objetos. El diccionario de datos también describe las asociaciones, atributos y operaciones. Por ejemplo: Clase Cuenta
Cajero automático
Descripción Cuenta individual de un banco a la cual se le pueden aplicar transacciones. Las cuentas pueden ser de varios tipos; como mínimo, serán de ahorro o a la vista. Un cliente puede tener más de una. Punto que permite a los clientes introducir sus propias transacciones empleando una tarjeta de crédito como identificación. El CA interacciona con el cliente para obtener información de la transacción, la envía a la computadora central para su verificarla y procesarla, y suministra dinero al usuario. Suponemos que el CA no necesita funcionar independientemente de la red...
Paso 3: Identificar las asociaciones y retener las asociaciones correctas A continuación, se identifican las asociaciones entre clases. Toda dependencia entre dos o más clases es una asociación; una referencia de una clase a otra también lo es. Por ejemplo, la clase Persona no debería tener 27
como atributo empresario; hay que relacionar las clases Persona y Compañía mediante la asociación Trabaja−para. Las asociaciones muestran dependencias entre clases con el mismo nivel de abstracción que las clases en sí, mientras que los atributos cuyos valores son objetos ocultan las dependencias, y desdibujan su naturaleza bidireccional. Las asociaciones suelen corresponderse con verbos de estado o con locuciones verbales que muestren, por ejemplo: • la ubicación física (junto a, parte de, o contenido en), • las acciones dirigidas (conduce), Para empezar hay que extraer todos los candidatos dados en la definición del problema y apuntarlos, no emplear demasiado tiempo intentando distinguir entre asociación y agregación. Ésta no es más que una asociación con connotaciones adicionales, luego debemos descartar las asociaciones innecesarias o incorrectas, empleando los criterios siguientes: − Asociaciones entre clases eliminadas. Si se ha eliminado una de las clases de la asociación es preciso eliminarla o hay que restaurarla en términos de otras clases. − Asociaciones irrelevantes o de realización. Hay que eliminar toda asociación que se encuentre fuera del dominio del problema, o que afecte a estructuras de realización. Por ejemplo, El sistema gestiona accesos concurrentes es un concepto de realización. Los objetos del mundo real son inherentemente concurrentes; lo que se necesita que sea concurrente es la realización del algoritmo de acceso. − Acciones. Las asociaciones deberían describir propiedades estructurales del dominio de la aplicación, y no sucesos transitorios. Por ejemplo, El cajero automático admite tarjetas de crédito describe parte del ciclo de interacción entre un cajero automático y su cliente, y no una relación permanente entre los cajeros automáticos y las tarjetas de crédito. − Asociaciones ternarias. La mayoría de las asociaciones entre tres o más clases se pueden descomponer en asociaciones binarias, o bien se les puede dar el aspecto de asociaciones cualificadas. Por ejemplo: • El cajero introduce las transacciones para la cuenta se puede descomponer en • El cajero introduce las transacciones y • Las transacciones conciernen a cuentas. Si un término de una asociación ternaria es puramente descriptivo y no posee características propias entonces 28
es un atributo de enlace en una asociación binaria. En algunas ocasiones, se necesita una asociación ternaria general. − Asociaciones derivadas. Hay que omitir las asociaciones que puedan ser definidas en términos de otras porque son redundantes. Por ejemplo, Abuelo se puede definir en términos de una pareja de asociaciones Padre de. También hay que omitir las asociaciones definidas por condiciones aplicadas a atributos de objetos. Por ejemplo, más joven que expresa una condición acerca de las fechas de nacimiento de dos personas, y no una información adicional. Especificación más detallada de las asociaciones Hay que especificar todavía más la semántica de las asociaciones, actuando de la siguiente manera: − Asociaciones de nombre incorrecto. No se debe indicar cómo o por qué se produce una situación; hay que decir lo que es. Los nombres son importantes para la comprensión, y hay que seleccionarlos con mucho cuidado. Por ejemplo: La computadora del banco mantiene las cuentas es una afirmación de acción; debe cambiar por El banco tiene cuentas. − Nombres de rol. Tienen que añadirse donde convenga. Los nombres de rol describen el papel desempeñado por la asociación desde el punto de vista de la otra clase. Se pueden omitir los nombres de rol. − Asociaciones cualificadas. Normalmente, el nombre identifica al objeto en un cierto contexto; la mayoría de los nombres son únicos desde el punto de vista global. El contexto se combina con el nombre para identificar de forma única al objeto. Por ejemplo, en su momento, existió la Standard Oil Company en Ohio, Indiana, California y Nueva Jersey. El nombre de la compañía cualifica a la asociación El estado contrata a la compañía; aquí Estado y nombre de compañía identifican a Compañía de forma única. El calificador distingue a los objetos del lado "muchos" de la asociación. − Multiplicidad. Hay que especificarla, pero no hay que esforzarse demasiado por determinarla exactamente, porque la multiplicidad suele cambiar durante el análisis. Por ejemplo, la asociación un Administrador administra a muchos empleados hace imposible la administración conjunta o que haya un empleado cuyas responsabilidades estén divididas. − Asociaciones implícitas. Añada las asociaciones implícitas que descubra. Paso 4: Buscar los atributos y retener los correctos A continuación, se identifican los atributos de los objetos.
29
Análisis gramatical del texto de la definición del problema (CA) Los atributos suelen corresponderse con nombres seguidos por frases posesivas, tal como "el color del coche" o "la posición del cursor". Los adjetivos suelen representar valores de atributos específicos, como pueden ser rojo, encendido o caducado. Completar el análisis con el conocimiento del dominio de la aplicación A menudo es preciso recurrir a nuestro conocimiento del dominio de la aplicación, y del mundo real, para encontrarlos. Afortunadamente, los atributos solo afectan en raras ocasiones a la estructura básica del problema. Hay que tomar primero los atributos más importantes; los detalles y matices se pueden añadir posteriormente. Durante el análisis, hay que evitar aquellos que sean solamente para la realización y asegurarse de que se da a cada uno un nombre significativo. Omitir los atributos derivados Los atributos derivados deben ser omitidos o bien deben ser marcados claramente. Por ejemplo, edad se ha derivado de fecha de nacimiento y de fecha actual (que es una propiedad del entorno). Identificar los atributos de enlace Hay que identificar también los atributos de enlace. Un atributo de enlace es una propiedad del enlace entre dos objetos, en lugar de ser una propiedad de un objeto individual. Eliminar los atributos innecesarios o incorrectos Hay que eliminar los atributos innecesarios e incorrectos mediante los criterios siguientes: • Atributos que son realmente objetos • Atributos que son calificadores • Los nombres deben ser normalmente calificadores y no atributos • Eliminar los atributos que tienen el carácter de identificador • Eliminar los atributos de enlace • Eliminar los tributos que representan valores internos • Eliminar atributos de un detalle excesivo Paso 5: Organizar y simplificar las clases de objetos empleando la herencia El paso siguiente es organizar las clases empleando la herencia para compartir una estructura común. Caminos para descubrir la relación de generalización o herencia La herencia se puede añadir siguiendo dos direcciones: • Generalizando aspectos comunes de clases existente en una superclase (refinamiento ascendente) o bien • refinando las clases existentes para dar subclases especializadas (refinamiento descendente). Se puede descubrir la herencia por refinamiento ascendente buscando clases con atributos, asociaciones u operaciones similares. Para cada generalización, se define una superclase para compartir características comunes. Por ejemplo, Transacción remota y Transacción de cajero son similares, salvo por su iniciación, y se pueden generalizar por medio de Transacción. 30
Es posible que sea necesario redefinir ligeramente algunos atributos, o incluso algunas clases, para que encajen. Las especializaciones por refinamiento progresivo suelen verse directamente a partir del dominio de la aplicación. Búsquense expresiones compuestas por el nombre de la clase y diferentes adjetivos calificativos: lámpara fluorescente, lámpara incandescente, menú abatible, menú deslizante. Debe evitarse un exceso de refinamiento. Si las especializaciones propuestas son incompatibles con una clase existente dicha clase existente podría haber sido formulada de forma incorrecta. Por ejemplo, una cuenta de los cajeros automáticos se podría refinar para dar Cuenta corriente y Cuenta de ahorro. Aun cuando sea indudablemente útil en algunas aplicaciones bancarias, esta distinción no afecta al comportamiento dentro de la aplicación de cajeros automáticos; se puede hacer que el tipo de cuenta sea un simple atributo de Cuenta. − Prudencia con la herencia múltiple La herencia múltiple se puede utilizar para compartir más, pero sólo si es necesario, porque incrementa tanto la complejidad conceptual como la de realización. Al utilizar la herencia múltiple suele ser posible indicar una superclase primaria que proporciona la mayor parte de la estructura y comportamiento heredados. Las superclases secundarias añaden detalles ortogonales. Por ejemplo, Transacción se introduce tanto en Terminal de cajero como en los cajeros automáticos; terminal de entrada generaliza a Terminal de cajero y a cajero automático. En algunas ocasiones, las clases no tienen nada en común salvo la asociación, pero con más frecuencia se descubre una generalización subyacente que antes se había pasado por alto. Paso 6: Comprobar que existen las vías de acceso adecuadas para las consultas previstas Hay que seguir las vías de acceso por el diagrama del modelo de objetos para ver si tiene unos resultados razonables. Cuando se espera un valor único, ¿hay una vía que proporcione un resultado único?. Para la multiplicidad "muchos", ¿hay una forma de seleccionar valores únicos cuando sea necesario?. Piense las preguntas que le gustaría hacer. ¿Hay preguntas útiles a las cuales no pueda responder? estas indican la información que falta. Si algo que parece sencillo en el mundo real resulta complicado en el modelo es que se ha pasado por alto alguna cosa (pero hay que asegurarse de que la complejidad no forme parte del mundo real). Paso 7: Repetir el ciclo del modelo de objetos Es raro que un modelo de objetos sea correcto a la primera pasada. Todo el proceso de desarrollo de aplicaciones informáticas implica repetir pasos anteriores. Las distintas partes del modelo se encuentran en diferentes fases de acabado. Si se encuentra un error, hay que volver a una etapa anterior, si es necesario, para corregirlo. Algunos refinamientos sólo pueden realizarse después de completar los modelos dinámico y funcional. Entre los síntomas de que se han pasado por alto algunos objetos se cuentan los que siguen: • Asimetrías en las asociaciones y generalizaciones: Hay que añadir clases nuevas por analogía. • Hay atributos y operaciones dispares en una clase: Se debe fraccionar la clase para que ambas partes sean coherentes. • Dificultades para hacer una organización limpia: Quizá haya una clase que desempeñe dos papeles. Fragméntese, y es posible que una de las partes encaje correctamente. • Una operación que no tiene una clase destino adecuada: Añádase la clase destino que falte... 31
Entre los síntomas de las clases innecesarias se cuentan: • Carencia de atributos, operaciones y asociaciones de esa clase: ¿Por qué es necesaria? Entre los síntomas de asociaciones omitidas se cuentan: • La falta de vías de acceso para alguna operación: Hay que añadir nuevas asociaciones para que sea posible responder a las consultas. Entre los síntomas de asociaciones innecesarias se cuentan: • Información redundante en las asociaciones: Hay que eliminar aquellas asociaciones que no añadan nueva información, o hay que marcarlas como derivadas. • Carencia de operaciones que recorran una asociación: Si no hay operaciones que empleen un cierto camino es posible que la información no se necesite. Esta comprobación deberá esperar a que se especifiquen las operaciones. Entre los síntomas de una colocación incorrecta de asociaciones se tienen: • Nombres de roles que son demasiado amplios o demasiado precisos para sus clases: Hay que trasladar la asociación hacia arriba o hacia abajo dentro de la jerarquía. Entre los síntomas de colocación incorrecta de atributos se cuentan: • La necesidad de acceder a un objeto por el valor de uno de sus atributos: Considere una asociación cualificada. Paso 8: Agrupar las clases en módulos El último paso de la fase del modelado de objetos es agrupar las clases en folios y módulos. Los diagramas se pueden dividir en folios de tamaño uniforme por comodidad para dibujarlos, imprimirlos y estudiarlos. Un módulo es un conjunto de clases (uno o más folios) que captura algún subconjunto lógico del modelo completo. Por ejemplo, un modelo del sistema operativo de una computadora podría contener módulos para el control de procesos, control de dispositivos, mantenimiento de ficheros y administración de memoria. Los módulos pueden tener distintos tamaños. Toda asociación debe mostrarse, en general, en un solo folio, aunque algunas clases deberán mostrarse más de una vez para conectar distintos folios. Busque los puntos de corte entre las clases: una clase que sea la única conexión entre dos partes que si no serían inconexas de la red de objetos. Tales clases forman el puente entre dos folios o módulos. Por ejemplo, en un sistema de mantenimiento de ficheros, éstos son el punto de corte entre la estructura de directorios y el contenido del fichero. Segunda actividad: el modelado dinámico: El modelo dinámico muestra la forma en que el comportamiento del sistema y de los objetos de que consta va variando con el tiempo. Comience el análisis dinámico buscando los sucesos que son estímulos y respuestas visibles externamente. Después hay que resumir las secuencias de sucesos admisibles para todos los objetos que tengan un diagrama de estados. 32
Durante la realización del modelado dinámico no hay que preocuparse del almacenamiento estático de los datos en una base de datos aunque esto tenga gran importancia en el desarrollo de aplicaciones de sistemas de gestión empresarial. Para la mayoría de los problemas, la corrección lógica depende de las secuencias de las interacciones, y no de los momentos exactos de las mismas. Los sistemas de tiempo real tienen ciertamente requisitos temporales específicos que afectan a las interacciones, y que hay que tener en cuenta durante el análisis. En este libro no se trata las peculiaridades del análisis para desarrollar aplicaciones informáticas de tiempo real. En resumen, para construir un modelo dinámico se llevan a cabo los pasos siguientes: Paso 1: Preparar escenarios Prepare uno o más diálogos típicos entre el usuario y el sistema para hacerse a la idea del comportamiento que se espera del sistema. Estos escenarios muestran • las interacciones principales, • los formatos de visualización externa y • los intercambios de información. Por ejemplo, la definición del problema de los cajeros automáticos indica la necesidad de obtener datos de la transacción a partir del usuario, aunque resulta poco clara sobre qué parámetros que se necesitan y sobre el orden en que deben solicitarse. La definición del problema puede especificar una información necesaria dejando abierta la forma en que se obtendrá esa información. En muchas aplicaciones, la captación de información es una tarea principal, y a veces, la única tarea realmente importante. En tales aplicaciones, el modelo dinámico resulta crucial. • En primer lugar se preparan escenarios para casos "normales", esto es, interacciones sin ninguna entrada extraña y sin situaciones de error. • Después se consideran los casos "especiales", tales como secuencias de entrada que se omiten, valores máximos y mínimos, y valores repetidos. • Luego se consideran casos en los que el usuario cometa un error, incluyendo los valores incorrectos y los casos en que no hay respuesta. Para muchas aplicaciones interactivas, el manejo de errores es la parte más difícil de la realización. Si es posible se debe permitir que el usuario aborte una operación o que vuelva a un punto inicial bien definido a cada paso. • Por último, hay que considerar otras clases de interacciones que se puedan superponer a las interacciones básicas, como pueden ser solicitudes de ayuda y consultas de estado. Un escenario es una secuencia de sucesos. Los sucesos se producen siempre que se intercambia información entre un objeto del sistema y un agente externo, tal como un usuario, un sensor o alguna otra tarea. Cada vez que entra o sale información del sistema, se produce un suceso. Los valores de información intercambiados son parámetros del suceso. Por ejemplo, el suceso contraseña introducida tiene como parámetro el valor de la contraseña. Los sucesos sin parámetros son significativos, e incluso frecuentes. Por ejemplo el escenario normal de un cajero automático es el siguiente: • El cajero automático pide al usuario que inserte una tarjeta; el usuario inserta una tarjeta de crédito • El cajero automático admite la tarjeta y lee su número de serie. • El cajero automático solicita la contraseña; el usuario escribe "1234". 33
• Él verifica el número de serie y la contraseña con el consorcio; éste la comprueba con el banco "39" y notifica la aceptación al CA... En definitiva, el análisis debería concentrarse en el flujo y control de información, más que en el formato de presentación. Si los detalles superficiales se aíslan cuidadosamente una misma lógica de programa podrá admitir entradas procedentes de la línea de órdenes, archivos, botones de ratón, paneles táctiles, botones físicos o enlaces remotos. El modelo dinámico captura la lógica de control de la aplicación. Paso 2: Identificar sucesos Hay que examinar los escenarios para identificar todos los sucesos externos. Entre estos se cuentan todas las señales, entradas, decisiones, interrupciones, transacciones y acciones procedentes o destinadas al usuario o a dispositivos externos. Los pasos internos de cálculo no son sucesos, salvo por los puntos de decisión que interactúen con el mundo exterior. Deben utilizarse escenarios para hallar los sucesos normales, pero no hay que olvidarse de las condiciones de error y de los sucesos poco corrientes. Una acción por parte de un objeto que transmita información es un suceso. Por ejemplo, introducir contraseña es un suceso enviado desde el agente externo Usuario hasta el objeto cajero automático de la aplicación. Hay que asignar cada tipo de suceso a las clases de objetos que lo envían y lo reciben. El suceso es de salida para el remitente y de entrada para el destinatario. En algunas ocasiones, un objeto se envía a sí mismo un suceso, en cuyo caso es a la vez de entrada y de salida para la misma clase. Todo escenario debe mostrarse como una traza de sucesos, esto es, una lista ordenada de entre distintos objetos asignados a las columnas de una tabla. Paso 3: Desarrollar el diagrama de flujo de sucesos Hay que mostrar los sucesos entre un grupo de clases (tal como un módulo) mediante un diagrama de flujo de sucesos. Este diagrama resume los sucesos habidos entre clases, sin tener en cuenta la secuencia. Deben incluirse los sucesos procedentes de todos los escenarios, incluyendo sucesos de error. Paso 4: Construir el diagrama de estados Prepárese un diagrama de estados para todas las clases de objetos que tengan un comportamiento dinámico no trivial. Este diagrama deberá mostrar los sucesos enviados y recibidos por el objeto. Todo escenario o seguimiento de sucesos se corresponde con una vía a través del diagrama de estados. Cada rama del flujo de control se representa por medio un estado con más de una transición de salida. Se empieza por los diagramas de seguimiento de sucesos que afectan a la clase que se está modelando y se toma un rastro que muestre una interacción típica, considerándose solamente los sucesos que afecten a un único objeto. El diagrama inicial será una secuencia de sucesos y estados. Si el escenario se pude repetir indefinidamente, hay que cerrar el camino en el diagrama de estados. Buscar ahora bucles dentro del diagrama. Si se puede repetir indefinidamente una secuencia de sucesos éstos forman un bucle. Sustituya las secuencias finitas de sucesos por bucles siempre que sea posible. En un bucle, el primer estado y el último son idénticos. Si el objeto "recuerda" que ha recorrido un bucle los dos estados no son realmente idénticos, y el bucle simple es incorrecto. Por lo menos uno de los estados de cada bucle tiene que tener múltiples transacciones que salgan de él, o bien el bucle no terminará nunca. Fusionar ahora los demás escenarios en el diagrama de estados. Buscar el punto de cada escenario en el cual éste diverja de los demás escenarios. Este punto se corresponde con un estado existente en el diagrama. Asignar la nueva secuencia de sucesos al estado existente como vía alternativa. Cuando esté examinando los estados y los escenarios pueden ocurrir otros posibles sucesos que se puedan producir en cada estado; 34
añádanse también al diagrama de estados. Lo más difícil es decidir en qué estado vuelve a unirse con el diagrama existente una vía alternativa. Una vez que se han considerado los sucesos normales, se añaden los casos límite y los especiales. Deben considerarse los sucesos que se producen en momentos inoportunos, como por ejemplo una solicitud de cancelar una transacción después de haberla enviado para su procesamiento. El diagrama de estados de una clase estará terminado cuando abarque todos los escenarios, y cuando maneje todos los sucesos que puedan afectar a un objeto de esta clase en todos y cada uno de sus estados. Paso 5: Buscar la correspondencia entre sucesos y objetos Cuando los diagramas de estados para todas las clases estén completos habrá que comprobar si el sistema está completo y es consistente. • Todo suceso debería de tener un emisor y un receptor, que ocasionalmente serán un mismo objeto. • Los estados sin predecesores o sucesores resultan sospechosos; hay que asegurarse de que representen puntos iniciales o finales de la secuencia de interacción. • Siga los efectos de un suceso de entrada de objeto en objeto a través del sistema, para asegurarse de que todo coincide con los escenarios. • Los objetos son inherentemente concurrentes; tenga cuidado con los errores de sincronización cuando se produzca una entrada en un momento inoportuno. • Hay que asegurarse de que los sucesos correspondientes de distintos diagramas de estados sean congruentes. El conjunto de diagramas de estados para las clases de objetos que tienen un comportamiento dinámico importante es lo que constituye el modelo dinámico de una aplicación. Tercera actividad: el modelado funcional El modelo funcional muestra la forma en que se calculan los valores, sin tener en cuenta las secuencias, decisiones o estructura de los objetos. El modelo funcional muestra que valores dependen de que otros valores, y las funciones que los relacionan. Los diagramas de flujo de datos resultan útiles para mostrar dependencias funcionales. Las funciones se expresan de diferentes formas, incluyendo el lenguaje natural, las ecuaciones matemáticas y el pseudocódigo. Los procesos de un diagrama de flujo de datos se corresponden con actividades o acciones de los diagramas de estados de las clases. Los flujos de un diagrama de flujo de datos se corresponden con objetos o con valores de atributos de un diagrama de objetos. Para construir un modelo funcional hay que dar los pasos siguientes: Paso 1. Identificar los valores de entrada y de salida Se empieza por enumerar los valores de entrada y de salida. Estos valores son los parámetros de los sucesos que se intercambian entre el sistema y el mundo exterior. Hay que examinar la definición del problema para buscar todos los valores de entrada o salida que pudiéramos haber omitido.
35
Paso 2. Construir los diagramas de flujo de datos Ahora se construye un diagrama de flujo de datos que muestra la forma en que se calcula cada valor de salida a partir de los de entrada. Los diagramas de flujo de datos suelen construirse por capas. La superior puede constar de un solo proceso, o quizá de uno para obtener entradas, otro para calcular valores y un tercero para generar salidas. Dentro de cada capa del diagrama de flujo de datos, se va retrocediendo desde cada valor de salida para determinar la función que lo calcula. Cuando las entradas de la operación son en su totalidad entradas de todo el diagrama se da por concluido este paso. En caso contrario, algunas de las entradas de la operación son valores intermedios que deben ser a su vez seguidos hacia atrás. También se puede rastrear hacia adelante, partiendo de las entradas para llegar a las salidas aunque suele ser más difícil identificar todas las aplicaciones de una entrada que hacerlo con todas las fuentes de una salida. Los diagramas de flujo de datos solamente especifican dependencias entre operaciones. No muestran las decisiones ni la secuencia de operaciones; de hecho, algunas de estas operaciones pueden ser opcionales o mutuamente exclusivas. Por ejemplo, la contraseña debe verificarse antes de actualizar la cuenta; si la verificación no es positiva no se actualiza la cuenta. Estas decisiones en la realización de la secuencia forman parte del modelo dinámico, y no del modelo funcional. Las funciones de decisión se pueden mostrar en el diagrama de flujo de datos, pero sus salidas son señales de control, que se indican mediante flechas de salida discontinuas. Estas funciones son "sumideros de datos" dentro del diagrama de flujo de datos; sus salidas afectan al flujo de control en el modelo dinámico y no sacan valores directamente. Por ejemplo, verificar contraseña es una función de decisión. Se ha mostrado la señal de error que puede producir, pero dejando implícita la flecha de control que va al proceso actualizar cuenta. Si se desea, se puede dibujar una flecha de control que vaya hasta el proceso controlado por una decisión. Paso 3 Describir las funciones Cuando se ha refinado lo suficiente el diagrama de flujo de datos, hay que escribir una descripción de cada función. Tal descripción puede estar • en lenguaje natural, • en ecuaciones matemáticas, • en pseudocódigo, • en tablas de decisión o • en algún otro formato adecuado. La descripción puede ser declarativa o de procedimientos. Las descripciones declarativas especifican las relaciones entre los valores de entrada y los de salida, y las relaciones entre valores de salida. Una descripción de procedimental especifica la función dando un algoritmo para calcularla. El propósito de éste es solamente especificar lo que hace la función; durante la realización, se puede reemplazar dicho algoritmo por cualquier otro que calcule los mismos valores. Las descripciones declarativas son preferibles a las de procedimentales, porque no implican una realización, pero si la descripción procedimental es mucho más fácil de escribir, debemos utilizarla. Paso 4. Identificar las restricciones entre objetos
36
Hay que identificar las restricciones entre objetos. Las restricciones entre objetos son dependencias funcionales entre objetos que no están relacionados por una dependencia entrada−salida. Las restricciones pueden afectar a dos clases a la vez, a dos objetos de una misma clase en momentos diferentes (un invariante) o entre objetos de diferentes clases y en momentos diferentes (aunque esto último suelen ser funciones de entrada−salida). Las condiciones previas (precondiciones) aplicadas a funciones son restricciones que deben satisfacer los valores de entrada, y las posteriores postcondiciones son restricciones que se garantiza que serán cumplidas por los valores de salida. Una restricción del problema del CA es que "no se admiten saldos negativos". Si añadimos cuentas con la posibilidad de descubiertos la restricción pasa a ser "ningún descubierto podrá superar el límite de crédito". Estas restricciones no especifican lo que hay que hacer si se intenta hacer una retirada excesiva de fondos; el analista debe agregar la restricción al modelo dinámico y al funcional para completar la especificación. Paso 5 Especificar los criterios de optimización Hay que especificar los valores que deban ser maximalizados, minimizados u optimizados de alguna otra forma. Si hay varios criterios de optimización que entran en conflicto, se debe indicar cómo se va a decidir la posible compensación. No es necesario precisarlo ya que normalmente, no será posible hacerlo, y en todo caso es probable que cambien los criterios antes de que concluya el proyecto. Entre los criterios de optimización para el CA se podrían incluir: • Minimizar el número de mensajes físicos que se envíen entre distintos puntos y • minimizar el tiempo durante el que la cuenta queda bloqueada por cuestiones de concurrencia. Resumen del análisis orientado a los objetos El propósito del análisis es exponer y comprender el problema y el dominio de la aplicación, para que sea posible construir un diseño correcto. Un buen análisis captura las características esenciales del problema sin introducir artefactos de realización que restrinjan de forma prematura las decisiones de diseño. Lo primero es escribir una definición inicial del problema, consultando a los solicitantes y a expertos del dominio. Los requisitos deberían describir lo que hay que hacer, y no como se va a implementar. La definición del problema puede ser incompleta, ambigua y errónea: No es más que un punto de partida. El modelo de objetos muestra la estructura estática del mundo real. En primer lugar, se identifican las clases de objetos y luego las asociaciones entre objetos, incluyendo las agregaciones. También hay que hacerlo con los atributos de los objetos y los enlaces, aunque se pueden dejar para más adelante los que sean menos importantes. Es preciso utilizar la herencia para organizar y simplificar la estructura de clases. Las clases y asociaciones fuertemente acopladas se organizan en módulos. La información del modelo de objetos debe ser complementada empleando breves descripciones textuales, que incluyan el propósito y el ámbito de cada entidad. El modelo dinámico muestra el comportamiento del sistema y, en especial, la secuencia de interacciones. En primer lugar, se prepararan escenarios de sesiones típicas y excepcionales. A continuación se identifican los sucesos externos entre el sistema y el mundo real. Se construye un diagrama de estados para cada objeto activo, diagrama que mostrará las tramas de sucesos que reciba y envíe, junto con las acciones que lleve a cabo. Hay que comparar sucesos entre los diagramas de estado para comprobar la congruencia; el conjunto resultante de diagramas de estado constituye el modelo dinámico. El modelo funcional muestra la derivación funcional de valores, sin tener en cuenta el momento en que sean 37
calculados. En primer lugar se identifican los valores de entrada y de salida del sistema como parámetros de sucesos externos. Después se construyen diagramas de flujo de datos para mostrar el cálculo de cada valor de salida a partir de otros valores y de valores de entrada. Los diagramas de flujo de datos interactúan con objetos internos que sirven como almacenes de datos entre iteraciones. Por último, se especifican las restricciones y los criterios de optimización. Las operaciones se derivan de distintas fuentes en esta metodología, y no resulta útil agruparlas durante el análisis. Sólo las operaciones del modelo funcional (y posiblemente las operaciones de lista de la compra) necesitan ser mostradas en el diagrama de objetos. Las metodologías nunca son tan lineales como aparecen en los libros. Ésta no es una excepción. Todo análisis complejo es construido por iteración en múltiples niveles. No es necesario desarrollar con igual velocidad todas las partes del modelo. El resultado del análisis sustituye a la definición original del problema, y sirve como base para el diseño. 24 Pedro 00060957 4−Mar− ( 24 ) Estado interno objeto Comportamiento visible Cada objeto contiene un estado interno que le es propio y un comportamiento accesible a los demás objetos. :Alumno Azul 979 kg 120 cv COCHE El estado agrupa los valores de los diferentes atributos que caracterizan al objeto. Por regla general el estado de un objeto es variable y puede verse como la consecuencia de sus comportamientos pasados. Un objeto Otro objeto msg Operación 1
38
{...} Operación 2 {...} Contexto B Contexto A Un Objeto Un Espejo Un Cliente Un actor Un servidor Un agente Objeto1 Objeto2 Mensaje Dato1 Dato2 Un Expedidor Un Destinatario Un Expedidor Un Destinatario Un Expedidor Un Destinatario A B C 3:Z
39
2:Y 1:X A B C M1 M2 M3 M4 M5 M6 M7 Motocicleta Color Cilindrada Velocidad Máxima Arrancar() Frenar() Acelerar() Libreta de ahorro Saldo Tasa Ingresar() Retirar() Cuenta corriente Saldo
40
Ingresar() Retirar() Depósito Montante Fecha Depósito Montante Fecha Efectuado en Efectuado a partir Mulhouse: Universidad Purdue: Universidad Pedro: Estudiante J. Luis: Estudiante Enrique: Estudiante Enlaces Estudiante Universidad Asociación Alberga> Universidad Estudiante
41
Universidad Estudiante Patrón Patrón Docente Docente Estudiante Universidad Estudiante 1 0..1 * * Persona Hijos Padre * 0..2
42
Coche Libro Autor Número de páginas León Oveja Conejo Carnívoro Herbívoro Animal Libro para niños Horquilla de edad Libro para la docencia Disciplina Nivel Animal Herbívoro Cuadrúpedo Bípedo Carnívoro Pluma Pelo Conejo Estación Alimentación Protección
43
Ejemplo de reducción de la covariación por generación múltiple Mariposa Estadio Lepidóptero Crisálida Oruga Aspecto Zoo Animal Dormir() León Tigre Oso Dormir() { Sobre el vientre } Dormir() { Sobre la espalda } Dormir() { En un árbol } Estado 1
44
Hacer: Activ. 1 Estado 2 Suceso1 (atributos) [condición 1] acción1
45