Diagramas de clases: crea diagramas estructurales con UML
Los diagramas de clases son diagramas estructurales del lenguaje unificado de modelado o UML (unified modeling language). Este lenguaje de modelado visual es un estándar ISO para visualizar los sistemas de la programación orientada a objetos, aunque también permite visualizar procesos de negocio. Con ayuda de elementos gráficos, UML muestra los estados de los sistemas y describe las interacciones entre los elementos que lo componen. Para poder hacerlo, la notación UML define las formas y las líneas para 14 tipos de diagrama.
Los diagramas de clases UML
Este lenguaje de metamodelado describe tanto a los elementos del lenguaje como al lenguaje mismo, definiendo unidades lingüísticas para diferentes niveles. Una de estas unidades en este lenguaje visual es, por ejemplo, el comportamiento, que describe al mismo tiempo a una metaclase y a una denominación genérica para todos los factores dinámicos dentro de un sistema. Otra de estas unidades es el objeto, el elemento fundamental de la programación orientada a objetos. Los diagramas de clases UML modelan los objetos como instancias de clases. Esto convierte a los diagramas de clases en uno de los diagramas UML más utilizados y de mayor importancia.
Según su función, los diagramas se dividen en dos grandes categorías: los de comportamiento (dinámicos) y los estructurales (estáticos). Los diagramas de comportamiento visualizan procesos dinámicos. El diagrama de actividades, por ejemplo, muestra gráficamente cómo interactúan las diversas acciones contenidas en un proceso. Por el contrario, los diagramas estructurales muestran estados estáticos, ilustran los elementos que integran un sistema y qué dependencias tienen entre sí.
Entre los diagramas de comportamiento, los diagramas de interacción no se limitan a modelar el comportamiento general de un sistema, sino que centran su atención en los flujos de información entre los objetos durante la ejecución de un proceso. Aquí se incluyen, por ejemplo, los diagramas de secuencia, que modelan la secuencia cronológica de los mensajes que intercambian los objetos en un caso de uso.
El más utilizado entre los estructurales o estáticos, el diagrama de clases asigna clases a las instancias de objeto en función de sus propiedades, lo que implica una cierta dependencia jerárquica. Al mismo tiempo existen relaciones entre las diferentes clases o entre objetos.
Áreas de aplicación de los diagramas de clases UML
Los diagramas de clases utilizan elementos de sistemas para representar estados gráficamente y, al desglosar las estructuras hasta la instancia más pequeña, son idóneos para visualizar arquitecturas de software detalladas de las que pueden derivarse pasos concretos de programación. Algunos entornos de programación asistidos por software convierten los diagramas UML en marcos de código. Gracias a aplicaciones de team sharing, los desarrolladores pueden comunicarse entre sí dentro de la misma empresa o con otros responsables. Para los profanos, un diagrama UML proporciona una vista general de las estructuras y los procesos que se han planificado. También pueden formularse requisitos de sistema para que los implementen los desarrolladores. Los expertos de TI pueden modelar y modificar los diagramas sin tener que programar entornos o procesos complejos ya en la fase de planificación.
¿Cuáles son las áreas de aplicación de los diagramas de clases?
- Describen tipos dentro de un sistema. El aspecto visual no está vinculado a la aplicación que vaya a utilizarse en el futuro, sino que puede implementarse con diferentes lenguajes de programación y entornos.
- Modelan arquitecturas de software que ya existen. Si se han de montar más componentes, los diagramas muestran las estructuras donde podrían integrarse. Para los elementos de sistema futuros, los diagramas de clases crean una guía para el código de programa, que puede ser más o menos detallada según se requiera.
- Representan visualmente modelos de datos. Son adecuados para sistemas de diferente complejidad.
- En aplicaciones con muchas anidaciones, la documentación y el mantenimiento pueden ser muy complejos. Los diagramas de clases muestran una vista general del esquema.
- Representan los requisitos de un software. Pueden enviarse como archivo de imagen en canales internos, permitiendo a los expertos de departamentos diferentes comentar e intercambiar opiniones sobre la arquitectura.
- El estándar UML utiliza diagramas de clases para representar visualmente su propia notación.
Diagramas de clases: notación según UML
Los diagramas de clases UML se componen de clases, instancias (objetos) e interfaces y visualizan relaciones jerárquicas, así como las asociaciones entre estos elementos. La notación de este tipo de diagrama es la base para la mayor parte del resto de diagramas estructurales.
UML 2 define a los diagramas de estructura como clasificadores. Dentro del metamodelado UML, los diagramas de paquetes, de componentes, etc., son subclases del diagrama de estructura, pero este mismo no se modela, puesto que se trata de una clase abstracta.
El diagrama de clases está indicado sobre todo como ejemplo para un diagrama de estructura. Otros diagramas de esta categoría utilizan componentes modificados del diagrama de clases para su notación.
UML considera al clasificador (Classifier) como una metaclase abstracta que sirve para clasificar los elementos de un lenguaje de modelado bajo un concepto común. Esto recibe el nombre de generalización y permite formular el estándar de forma general. Si la especificación aborda un determinado elemento, solo se ha de especificar esta particularidad.
La clase
En los diagramas de clases, la clase es un elemento-modelo y una especialización del clasificador encapsulado (EncapsulatedClassifier) y del clasificador de comportamiento (BehavioredClassifier). Comprende un conjunto de instancias. Las instancias-objeto dentro de una clase comparten las mismas propiedades (Attributes) y comportamientos (Methods), así como la misma semántica, es decir, utilizan los mismos caracteres con el mismo significado. Esto convierte a la clase en una especie de plantilla para sus objetos, “instanciando” los objetos y definiendo su conducta en el sistema.
La instancia es una manifestación concreta de un elemento abstracto. Ejecuta un comportamiento prescrito dentro de los parámetros dados. UML designa a muchas instancias de forma explícita. Así, el objeto es una instancia designada de la clase. Los atributos de las instancias se modelan con diagramas a nivel de las instancias. En lugar de un diagrama de clases, se dibuja por ejemplo un diagrama de objetos.
Los clasificadores encapsulados amplían a los llamados clasificadores estructurados, que tienen la particularidad de que pueden prescribir una estructura e incorporar elementos conectados. Estos elementos (metaclase: ConnectableElements) influyen en el comportamiento de los clasificadores. Cada elemento conectado representa a un participante del comportamiento en el clasificador, por eso se dice que estos elementos asumen un rol. El clasificador encapsulado posee, por su parte, un puerto (Port), con el que puede aislarse del sistema sin perder la conexión.
Los clasificadores de comportamiento ostentan a menudo una conexión a un punto de contacto, la InterfaceRealization o ejecución de la interfaz. Soportando todas las funciones de la interfaz, el clasificador acepta de forma implícita sus condiciones. Para representar gráficamente a la InterfaceRealization (también llamada “Lollipop”), se utiliza un círculo vacío que se une a la clase con una línea.
Estas metaclases clasifican a los objetos. La clase es la manifestación específica de estas metaclases, determinando aún más la clasificación y concretizando a cada uno de los componentes que conforman la estructura y el comportamiento de los objetos.
Las clases poseen propiedades que las definen tanto a ellas como a sus objetos subordinados, entre ellas:
- Propiedades (Properties o Attributes, si pertenecen a la clase)
- Operaciones o métodos (Operations, pueden invocarse para un objeto)
- Receptores (Receptions) desde UML 2.0
- Conexiones (Ports) desde UML 2.0
- Conectores (Connectors)
Cuando se crea un diagrama de clases, estas propiedades se añaden a la notación. En UML, las clases se representan como un rectángulo dibujado con línea continua y compuesto por tres filas horizontales. Solo es obligatorio modelar la superior porque aquí se define el nombre de la clase. Las otras dos, una que contiene a los atributos (intermedio) y una que expresa las operaciones o los métodos que puede utilizar la clase (inferior) son opcionales. Añadiendo a los nombres de estos miembros (atributos y métodos) uno de los símbolos que se detallan a continuación (modificadores de acceso a miembros), se especifica su visibilidad:
- + = pública
- - = privada
- # = protegida
- / = derivada (
- ~ = paquete
- * = aleatoria
Propiedades
Las propiedades son elementos interdependientes. Los atributos propios de la clase (ownedAttributes) son siempre roles y se conectan por medio de conectores. Si poseen la propiedad isComposite= true (“está compuesto = verdad”), reciben el nombre de partes (Parts).
La propiedad UML es una característica de las estructuras que puede tener aplicaciones diferentes. Además de la función de atributo en una clase, también puede representar los extremos en las relaciones de asociación.
El tipo de propiedad se deriva del nombre del clasificador, pero también se puede especificar un valor estándar para una propiedad, y los modificadores pueden concretar cómo se comporta:
- Ordenado (notación: isOrdered = true)
- Único (isUnique = true)
- No único (isUnique = false)
- Protegido contra escritura (la propiedad solo puede leerse: isReadOnly = true)
- Secuencia (la propiedad es una colección ordenada: isUnique = false e isOrdered = true)
- Asociación (derivada de subconjuntos: union)
- ID (pertenece a la denominación de su clasificador, id)
- Limitación de propiedad (una limitación que influye en la propiedad: property-constraint)
- Redefinición de una propiedad (redefine a una propiedad heredada: redefines [Merkmalsname])
- Subconjunto de la propiedad (simboliza a una propiedad que es un subconjunto de una propiedad: subsets [Merkmalsname])
Operaciones
Las operaciones son funciones de comportamiento y se utilizan en clases, en tipos de datos o en interfaces. Las operaciones invocan la instancia de una clase y especifican estos aspectos de una llamada:
- Nombre
- Tipo
- Parámetro
- Limitaciones
La operación pertenece al clasificador al cual se subordina, que podría modificarla redefiniendo el tipo o el parámetro.
Antes de que una operación se ejecute, se ha de cumplir una serie de condiciones previas, pero UML no define cómo se comporta la llamada de comportamiento si no se cumplen las condiciones previas. Se han de especificar también las condiciones posteriores que se han de cumplir si la operación finaliza. Las condiciones de campo restringen el valor devuelto a un valor que se calcula a partir de sus especificaciones y que ha de cumplir con las condiciones posteriores. Pero mientras se ejecuta, la operación también puede invocar una excepción. Si esto sucede, probablemente no pueda cumplir con las condiciones posteriores.
La notación para diagramas de clases prescribe que las operaciones se escriban en el cuerpo de la clase. Si bien son datos obligatorios según el estándar UML, puede prescindirse de ellos. Solo el nombre es imperativo.
Receptores
El receptor muestra que un clasificador está preparado para recibir una señal y define qué tipos de señal aceptan las instancias de la clase. El receptor recibe el mismo nombre que su señal. Los datos correspondientes se anotan en el cuerpo de la clase en una fila bajo las operaciones.
Puertos
Los puertos son conectores para clasificadores encapsulados. Representan el punto en el que los clasificadores interactúan con su entorno. Exceptuando los puertos, los clasificadores encapsulados son un sistema cerrado en sí mismo. El hecho de que tanto su estructura como sus elementos de comportamiento estén aislados del sistema restante permite que puedan especificarse libremente. Siempre y cuando un sistema cumpla las restricciones del puerto, el clasificador encapsulado puede utilizarse en entornos diferentes.
UML permite a los clasificadores tener varios puertos. Para cada uno de ellos pueden definirse reglas específicas. El puerto es una propiedad del clasificador, por lo que las reglas se definen en el campo de las propiedades. Entre estas se incluyen los servicios que ofrece el clasificador a su entorno y los que necesita. Para diferenciar flujos de información diferentes se ha de identificar a los puertos que se han utilizado para ellos.
Los mismos puertos también tienen propiedades. Si un puerto ejecuta funciones públicas del clasificador, se indica con la propiedad isService. Si isService = true, el puerto se considera un componente imprescindible de las funciones visibles hacia fuera del clasificador. Si isService = false, el puerto no forma parte de las funciones principales y, al igual que cualquier otra función interna, puede modificarse o eliminarse.
Los puertos también interactúan con interfaces, que pueden ser necesarias o puestas a disposición (ver apartado Interfaces). La interfaz conectada al puerto especifica las interacciones que tienen lugar a través del puerto. Como el conector es una propiedad, tiene un tipo. El valor de isConjugated media entre los tipos y la interfaz del puerto. Si el valor es verdadero, la interfaz requerida puede derivarse del tipo de puerto o del conjunto de interfaces que realiza el tipo del puerto. La interfaz proporcionada se deriva del conjunto de las interfaces. Si isConjugated es verdadero, esta interfaz de deriva del tipo.
Si un clasificador encapsulado genera una instancia, también se crean las instancias correspondientes para cada uno de sus puertos. Un puerto mantiene a cada instancia en concordancia con su tipo y su multiplicidad (ver más adelante). UML denomina a las instancias puntos de interacción. Cada instancia posee referencias únicas que le sirven para diferenciar las distintas solicitudes para funciones de comportamiento que se dirigen a sus puertos.
Los puertos con la cualidad isBehavior = true envían una petición a la instancia del clasificador. Esta petición asume el comportamiento especificado de la instancia, y es que estos puertos llamados de comportamiento no envían las peticiones al interior del clasificador. Si en el diagrama de clases no se ha definido ningún comportamiento, los mensajes dirigidos a estos puertos se pierden.
Los puertos se modelan como un pequeño cuadrado en el marco del clasificador al cual pertenece. En el puerto se dibujan las interfaces necesarias o puestas a disposición. Si no especificas ninguna propiedad especial para el puerto, la interfaz se dibuja sin puerto.
Conectores
Los conectores definen conexiones entre dos o más instancias. La especificación permite que se comuniquen. Al contrario que las relaciones, como la asociación, los conectores no unen cualquier tipo de instancia, sino solo aquellas definidas como elementos de conexión. Los conectores se modelan como líneas con al menos dos finales que corresponden a las instancias participantes que asignan un tipo a los elementos susceptibles de conectarse.
Multiplicidades
Este parámetro prescribe cuántas instancias puede formar una clase estructurada y restringe los atributos y las operaciones. Es una parte de la estructura interna, un elemento prescrito en el cuerpo de la clase, y se escribe detrás de los atributos y las operaciones. En este campo también se incluye la topología. Para unir los nodos (instancias objeto) se utilizan rutas de comunicación (CommunicationPaths) a redes de topología.
Las multiplicidades se escriben así:
<multiplicidad> : <restricción de multiplicidad> [<Denominación de orden> , <Denominación de unicidad>]
Mediante la restricción de multiplicidad se designa un valor fijo o un rango:
- 0 = La clase no desarrolla instancias (poco frecuente)
- 0..1 = Una o ninguna instancia
- 1 o 1..1 = Solo una instancia
- 0..* o * = Ninguna instancia o varias con un valor máximo indefinido
- 1..* = Una instancia o más con valor máximo indefinido
El ordenamiento o el carácter de unicidad puede expresarse como conjunto (set) o con términos separados por coma. En función de si los nodos en el conjunto son únicos o están ordenados, el conjunto obtiene una descripción de tipo. En la notación, los conjuntos se describen como ordered/unordered (ordenado / no ordenado) o unique/not unique (único / no único).
Tipo de conjunto | Único | Ordenado |
---|---|---|
Secuencia | No | Sí |
Multiconjunto (bolsa) | No | No |
Conjunto ordenado | Sí | Sí |
Conjunto | Sí | No |
Restricción
En las versiones antiguas de UML, la restricción (Constraint) se incluía entre las relaciones. En la actualidad, UML la define como un elemento que puede empaquetarse, es decir, que puede pertenecer a un paquete. También establece estas relaciones con otros elementos (con clases y atributos), si bien no modifica la notación. La restricción representa para su poseedor una condición o un seguro. Puede influir en uno o más elementos.
El elemento propietario necesita tener acceso a la restricción. Con ello comprueba si es válida y se ha cumplido, aunque de él depende cuándo lo hace. Algunos elementos, como las operaciones, verifican las restricciones antes de ejecutarse, en algún momento intermedio o después. Poseen condiciones previas, de campo y posteriores. UML denomina Kontext a la especificación que indica cuándo un elemento comprueba su restricción, pero no ha de confundirse con la especificación en sí: la especificación describe qué elemento delimita la restricción, qué aspecto evalúa y qué evento espera que se produzca. La especificación exacta recibe una restricción por medio de una especificación de valor booleana.
La notación se compone de una cadena de texto en esta forma:
<Nombre del elemento restringido> ::= { <Nombre de la restricción> : <Expresión booleana> }
UML no prescribe ningún lenguaje, de modo que el usuario puede escoger la restricción y el lenguaje que quiera emplear para crear un diagrama de clases: un lenguaje de programación como Java, una lengua natural o un lenguaje que puedan leer las máquinas como XML. El Objetct Management Group (OMG), que especifica el estándar UML, publica la especificación del Object Constraint Language (OCL), lenguaje que define restricciones compatibles con UML. Su ventaja es que las integra de forma orgánica en la notación.
Algunos elementos restringidos se escriben en UML como texto, como un atributo de una clase. La restricción se escribe entre corchetes detrás del elemento de texto. Si el propietario es un elemento representado por un símbolo, la restricción se coloca lo más cerca posible de este, de modo que quede claro que ambos elementos están relacionados semánticamente. Aunque si quieres que la conexión quede aún más clara, escribe la restricción en un símbolo de nota adhesiva y conéctala a su propietario con una línea discontinua.
Si la restricción afecta a dos elementos, se enlaza a los dos propietarios con una línea discontinua y se escribe en ella la restricción entre corchetes. Si se dibuja una punta de flecha en un extremo, se señaliza la posición del propietario dentro de un conjunto de elementos restringidos (constrainedElements). La flecha señaliza un movimiento que va de la primera posición a la segunda. Si más de dos elementos poseen la restricción, debes utilizar el símbolo de la nota adhesiva y conectar a cada elemento con la restricción.
Las líneas conectoras también se incluyen dentro de los elementos que se restringen. Si modelas más de dos líneas del mismo tipo, arrastra la línea discontinua a través de todas las líneas que representan a todos los elementos implicados.
Estereotipos
Los estereotipos definen a extensiones de las metaclases. Siguiendo la especificación UML, pertenecen a los perfiles. Si un estereotipo describe propiedades de varias metaclases, solo puede describir las instancias de una en una mientras se ejecuta. Entre las metaclases, el estereotipo siempre asume un papel determinado porque nunca puede estar solo. Los estereotipos se modelan siempre en relación con el clasificador al que amplía. La metaclase se conecta con el estereotipo modelando una extensión (Extension).
Desde UML 2.4 la especificación establece escribir la etiqueta de un estereotipo con mayúscula inicial, como <<Type>>. Otras etiquetas, p. ej., para las propiedades en los extremos de las asociaciones, se escriben en minúsculas.
Se diferencian dos tipos de relación entre la (meta)clase y el estereotipo:
- La extensión requerida (isRequired = true) define que un estereotipo entra en relación con cada instancia de la metaclase en el diagrama de clases.
- La extensión no requerida (isRequired = false) permite conectar libremente instancias de la metaclase con un estereotipo. También puede borrarse el estereotipo. Aunque durante la ejecución una instancia solo puede conectarse una vez con un determinado estereotipo.
Para borrar un estereotipo, se borra el perfil que lo define de la sección de perfiles aplicados (appliedprofiles) en el paquete superior. Opcionalmente puede borrarse la instancia a la que amplía.
UML define algunos estereotipos de clase que amplían un diagrama de clases. Seis son considerados estándar, pero hay tres que, sin ser estándar, se usan mucho, y con los que puede implementarse el modelo “Model-View-Controller” (MVC) en UML. Son estos:
- Entidad (<>): el estereotipo Entity define a una clase o a un objeto. Cada instancia representa a una colección de datos, a menudo datos de sistema que se han de guardar durante mucho tiempo. La entidad asume el rol del modelo del patrón MVC. UML conoce este estereotipo, pero lo asigna por defecto a los diagramas de componentes. En la especificación no se representa a esta habitual notación. La entidad se modela como un círculo que descansa sobre una línea corta.
- Frontera (<>): la Frontera es un estereotipo para una clase o un objeto. Se corresponde aproximadamente con el elemento View del modelo MVC. La Frontera modela los límites de tu sistema, p. ej., una interfaz de usuario. Suele representarse gráficamente como un círculo de cuyo lado izquierdo sale una línea que acaba en una línea vertical.
- Control (<>): el elemento de Control representa el Controller en MVC. Las clases o los objetos con este estereotipo modelan elementos que determinan el comportamiento del sistema o los flujos de control. En el estándar UML el estereotipo <> asume tareas similares. La instancia de control se dibuja como un círculo con una flecha encima de la línea.
Los tres estereotipos pueden dibujarse como clases. En los rectángulos se escribe el nombre del estereotipo. Los modeladores aplican estas formas principalmente en diagramas de secuencia. Lee nuestro artículo sobre diagramas de secuencia con UML si quieres profundizar en los diagramas de entidad-frontera-control.
Los estereotipos estandarizados para diagramas de clases son:
- Foco (<>)
- Auxiliar (<>)
- Tipo (<>)
- Clase de implementación (<>)
- Metaclase (<>)
- Utilidad (<>)
Foco
La clase foco define la lógica de negocio fundamental o el flujo de control de las clases auxiliares. Estas apoyan a la clase foco que conecta a uno o más auxiliares. Define a la clase a la que ayuda de forma implícita iniciando una relación de dependencia (ver más adelante “La relación dirigida”). Si usa clases auxiliares, las define de forma explícita. El estándar UML recomienda este estereotipo para la fase de diseño en la que se representan los flujos de control entre los componentes o se determina la lógica de negocio básica.
La lógica de negocio, también llamada lógica de aplicación, describe la lógica de un sistema dedicado a la ejecución de requisitos de negocio reales diferenciándose, así, de la lógica que prescribe la ejecución técnica. En la programación orientada a objetos, la lógica de negocio generó el concepto del objeto de negocio, el cual modela procesos concretos y valores reales en un sistema de información.
Auxiliar
La clase auxiliar suele combinarse con la clase foco y asiste por lo general a clases con una posición significativa para el sistema. Para ello ejecuta flujos de control en un segundo plano y define lógicas subsidiarias. Si asiste a una clase foco, la definición es explícita; si hay una relación de dependencia, define a la clase a la que asiste de forma implícita.
Tipo
La clase tipo especifica una región para objetos de negocio y especifica los operadores de estos objetos. El estereotipo de tipo puede ostentar atributos y asociaciones, pero no describe la ejecución física del objeto.
Clase aplicación
Algunos lenguajes de programación (Java o C++) solo permiten una instancia por clase, pero con UML una instancia puede asignarse a varias clases. La clase aplicación lanza un puente entre estos dos mundos. Este estereotipo restringe a la clase UML, determinando que, bajo él, una instancia solo puede realizar a una clase. La clase aplicación puede implementar tipos diferentes. Para ejecutar con éxito un clasificador subordinado a ella ha de cumplir con dos condiciones: ha de suministrar todas las operaciones del clasificador y estas han de mostrar el comportamiento que se definió para el clasificador. Los atributos y asociaciones de carácter físico, sin embargo, no han de coincidir.
Metaclase
Como las formas de clase y metaclase no se diferencian, la etiqueta Metaclass señala que se trata del estereotipo Metaclase. Las instancias de esta clase son clases también. Con este estereotipo se trabaja a un nivel superior de abstracción.
Utilidad
La clase utilidad no posee instancias. Solo etiqueta a una colección de atributos y operaciones, que son siempre estáticos. Los atributos estáticos no cambian cuando se les llama. Las operaciones estáticas se aplican en entidades o tipos entidad. Si utilizas la clase utilidad, has de indicar ya al principio los correspondientes valores y operaciones porque ya no cambiarán. Para señalizar a estos elementos, se subrayan.
UML especifica algunos estereotipos estándar más para otros tipos de diagrama. Su ámbito de aplicación y su notación se encuentra en la especificación UML 2.5.1, capítulo 22: Standard profile, tabla 22.1 (pág. 680).
Interfaces
Las interfaces son clasificadores. Su notación se parece a la de las clases, aunque no son clases sino declaraciones, es decir, declaran un conjunto de funciones y obligaciones abiertas e interrelacionadas de forma lógica. Para ello utilizan un contrato. Si una instancia ejecuta la interfaz, ha de cumplir con el contrato. Aquí se habla entonces de que una instancia ofrece un servicio según contrato. En su rol de declaración, no configura instancias por sí misma.
En su lugar lo hace la clase, porque puede instanciar. Su instancia utiliza especificaciones de interfaces, para lo que ha de cumplir el contrato de la interfaz. Como contrapartida, utiliza la interfaz como escenario público. Un clasificador puede implementar varias interfaces y a la inversa, una interfaz puede servir a varios clasificadores. En el diagrama de clases UML las notaciones de interfaz y clase son similares: un cuadrado que puede seccionarse en tres partes opcionalmente.
Para mostrar que una clase utiliza una interfaz se utiliza la notación InterfaceRealization (que conocemos por los clasificadores de comportamiento). Esta representa a una interfaz suministrada (Provided Interface), una interfaz que ejecuta directamente a una instancia. Esto se aplica también a clases superiores como los componentes. Si la clase tiene un puerto público, es este el que proporciona la interfaz. Para dibujar una InterfaceRealization se utiliza un círculo que se une al clasificador por medio de una línea.
También están las interfaces requeridas (Required Interfaces), que visualizan una relación de dependencia (ver en “Relaciones”). Aquí un elemento necesita a otro elemento para ejecutar todo el potencial de sus funciones propias. En este caso un clasificador (o una de sus instancias) necesita una interfaz. La InterfaceUsage (uso de la interfaz) especifica qué exigencias se plantean a la interfaz. Para ello una línea une al clasificador con un medio círculo que simboliza a la interfaz. El nombre de la interfaz se escribe en ambos representantes debajo del círculo o el medio círculo.
Si una clase lega una interfaz a una clase inferior, se ha de modelar la conexión de la interfaz a la clase o instancia subordinada. La relación jerárquica se muestra con el acento circunflejo (^), p. ej., ^interfaz 1.
Si empleas la notación cuadrada de las interfaces, dibuja una línea entre los dos nodos. En los diagramas de clases, las líneas modelan las relaciones entre clases, instancias o componentes. UML prescribe diferentes líneas y flechas para funciones y relaciones diversas. En este caso, para unir a una clase con la interfaz requerida se utiliza una flecha discontinua con punta abierta. Añade la etiqueta <<use>> a la flecha. Para unir a una interfaz requerida con una clase se utiliza una flecha discontinua con punta cerrada, sin rellenar. La flecha apunta siempre en dirección a la interfaz.
Tipos datos
Los tipos datos asocian a un conjunto de objetos con sus operaciones utilizando rangos concretos de valores y agrupándolos con sus operaciones especiales. Los objetos pueden tener varios tipos. Sus valores abarcan desde los tipos primitivos a las enumeraciones de cierta longitud.
Los tipos datos son clasificadores y solo es posible identificar sus instancias a partir de su valor. Con los tipos datos se visualizan en los diagramas de clases UML tipos valor, tipos primitivos y tipos estructurados. Si copias una instancia tipo dato o modelas dos instancias del mismo tipo dato con el mismo valor, se consideran como instancias iguales.
Si el tipo dato posee atributos, UML lo clasifica como tipo dato estructurado. Sus instancias solo se consideran iguales si su estructura y los valores de sus atributos son iguales.
Los tipos primitivos no muestran estructuras subordinadas, sino que constituyen valores de datos atómicos. En los diagramas de clases también encuentran aplicación en restricciones. Más allá de la especificación UML, estos tipos ostentan una semántica compleja. En UML, sin embargo, no tienen identidad, por lo cual, en caso de tener el mismo valor, no pueden diferenciarse. Algunos de los tipos primitivos en UML son:
- Booleanos (variables booleanas)
- Íntegros
- UnlimitedNatural (cifra natural, ilimitada)
- Real (cifra real)
- String (secuencia de caracteres)
Los tipos primitivos se notan con la etiqueta <<primitive>> sobre el nombre del tipo dato.
La enumeración es un tipo dato. Representan el valor de la enumeración con un símbolo tipográfico. Como en la imagen de arriba, se trata sencillamente de un nombre que representa simbólicamente a un valor determinado. Este nombre lo elige el usuario. En la lista “clases de rosa” el nombre “rosa de té” representa al número de rosas de té que tiene una floristería. En el diagrama de clases se dibuja a este clasificador con el símbolo para la clase, un cuadrado. En la parte superior se incluye la etiqueta <<enumeration>>. Esta parte se separa del cuerpo en departamentos con líneas horizontales.
Como en otras clases, la enumeración reserva los campos superiores para atributos y operaciones. Si quedan vacíos, estas secciones se eliminan. En la parte inferior escribe los símbolos para la enumeración. En el caso de una tienda de flores, la enumeración se llamaría “clases de rosas” y en el cuerpo se escribe la lista: rosas de té, rosas Noisette, rosas gallica, rosas Bourbon, rosa majalis.
Relaciones
Los diagramas de clases representan relaciones entre elementos de sistema con el fin de que el observador vea qué componentes necesita el sistema y cómo influyen los unos en los otros. El elemento relación es una clase abstracta y representa a la idea de una relación entre componentes en el sistema. De este modo no posee una notación especial, pero sus manifestaciones muestran detalles específicos que las diferencian.
En UML las relaciones se entienden como líneas entre nodos, así que se modelan generalmente como líneas que pueden ofrecer variaciones (flechas).
La definición de las subclases de relación y las instancias ha cambiado de UML 1 a UML 2, en parte drásticamente. Originariamente había relaciones semánticas, estructurales y dirigidas. UML clasificaba tres relaciones (asociación, restricción y dependencia) entre las relaciones semánticas. En UML 2 las restricciones ya son elementos empaquetables, las asociaciones definen algunas fuentes como relación estructural y semántica. La dependencia se clasifica en las relaciones direccionales.
Queda esperar cómo se verá modificado el estándar en el futuro. Seguidamente explicamos los diagramas de clases según UML 2.5, que establece dos subclases para la metaclase relación: la relación de dirección y la asociación.
La asociación
La asociación es una relación que conecta tuplas. En informática, las tuplas son colecciones de datos ordenadas. Al contrario que en los conjuntos, aquí intervienen conexiones y secuencias lógicas. Por eso, no sería erróneo asignar también un componente estructural a la asociación que se sume al título oficial de relación semántica. La asociación es una conexión entre clasificadores. Los elementos de esta relación tienen una proximidad lógica o física. En función de la cantidad de miembros, la asociación se llama binaria (dos instancias), ternaria (tres instancias) o n-aria (a partir de cuatro instancias).
Los extremos de una asociación en los diagramas de clases UML conectan asociaciones con instancias. El extremo tiene un nombre que expresa el rol de la instancia en cada relación. Pensemos en un estudiante que graba varias versiones de un cortometraje para un seminario de cine. El rol del estudiante en relación con el film sería el de “creador”. El rol de la película sería “trabajo de seminario”. Estos dos nombres se escriben bajo la línea que los une, junto al símbolo de la instancia que describen. El extremo pertenece a la asociación misma o al clasificador. En el caso de tratarse de más de dos extremos, el rol pertenece a la asociación.
La flecha junto al nombre de la asociación en el diagrama de clases de arriba indica la dirección de la relación. En el diagrama inferior el punto en la instancia “Film” señaliza que el extremo “Seminar work” pertenece a la instancia “Film student”. Como el extremo “Creator” no tiene esta marca, pertenece a la asociación misma. La multiplicidad “1” muestra que existe una sola instancia “Film student”, mientras que la instancia “Film” tiene por lo menos tres manifestaciones.
La navegabilidad es una propiedad final (End Property) que muestra si puede accederse a una instancia en este final de la asociación desde el otro final de la asociación. Si la instancia B es accesible para instancia A, se dibuja una punta abierta de flecha en la línea de la asociación en dirección a instancia B exactamente en el símbolo de la instancia B. Si la instancia C no puede acceder a la instancia D, se dibuja una X en la línea en la instancia D. Si no quieres indicar navegabilidad, no se escribe nada en especial.
Hay dos variantes de la asociación: el enlace (link) y la agregación.
- El enlace es una instancia de la asociación. Dispone de al menos dos extremos con una multiplicidad cada uno. Este valor ha de ser una instancia del tipo datos de la terminación. En nuestro ejemplo un estudiante rueda tres películas mientras estudia. El valor para la instancia “estudiante” es “1”; para la instancia “Película”, “3”. La conexión se modela como línea continua entre los participantes. Al contrario que la asociación, el enlace conecta instancias, pero no clasificadores.
- La agregación es una asociación binaria: tiene siempre dos participantes. Al contrario que el enlace, la agregación no crea ninguna relación en el mismo nivel, sino que muestra relaciones entre una parte y el todo. La agregación se representa por una propiedad en el extremo de la asociación en forma de rombo junto a la instancia que representa el todo.
La subespecie composición (Composite Aggregation) describe la relación entre un conjunto de partes y una parte de este todo. Si el sistema elimina el todo (la composición o conjunto de partes) también destruye todas las partes, p. ej., si un árbol es el todo, una hoja es una parte, y si el árbol cae víctima de un incendio, este incendio también destruye a las hojas. Para representar a esta relación en un diagrama de clases se dibuja una línea continua entre las instancias y se modela un rombo negro en el lado de la composición (en nuestro ejemplo, la instancia “árbol”). A este lado se le llama también extremo de la agregación.
La segunda subespecie de la agregación es la agregación compartida (o agregación a secas). Esta relación asimétrica existe entre una propiedad (Property) y una instancia que representa a un conjunto de instancias. La relación debería ser directa porque si no una instancia composición podría interpretarse como parte de sí misma. Esto podría pasar si se modela la relación de dependencia de forma cíclica. La propiedad compartida puede pertenecer a varias composiciones. Al mismo tiempo, su instancia puede existir de forma independiente a la composición. Si el sistema borra a una composición (o a todas) la instancia parte puede seguir existiendo, por eso esta relación se considera débil en comparación con la composición.
La asociación presenta otra particularidad: la clase asociación, clase y relación al mismo tiempo. Esto hace que puedan asignarse atributos a la clase asociación en el diagrama de clases.
La relación de dirección
La relación de dirección es una clase abstracta que define relaciones entre un origen y un destino. Los extremos pueden presentar varios elementos. Como la asociación, la relación de dirección tampoco tiene una notación definida. Sus subclases configuran formas específicas que se basan en una línea desde el origen al objetivo. Las siguientes instancias caracterizan a esta relación:
- Generalización (Generalization)
- Dependencia (Dependency)
- Unión de plantillas (Template Binding)
- Incluir (Include): pertenece a la notación para diagramas de caso de uso
- Extender (Extend): pertenece a la notación para diagramas de caso de uso
La generalización es una relación binaria entre clases y va de una subclase a una superclase, es decir, de una clase concreta a una más general. La clase concreta (dalia) posee la generalización. Una flecha con punta cerrada, pero en blanco, señala un movimiento del origen al destino. El destino es la clase general (p. ej., las asteráceas).
La subclase especifica la clase general. Esto también significa que la subclase comparte algunas propiedades (internas y estructurales) con la superclase, normalmente los elementos fundamentales. A este estado se le conoce como herencia. Así, la clase dalia del ejemplo comparte con la superclase asteráceas la inflorescencia en forma de cesto. Una cualidad específica del género dalia son sus ocho pares de cromosomas (otras plantas tienen por lo general solo dos pares de cromosomas). Las diversas especies de dalia presentan por ende cualidades mucho más variadas.
A nivel coloquial, las generalizaciones también se denominan como relaciones “es un…”. Así, puede decirse “una dalia es una asterácea”.
De forma implícita, UML permite la herencia múltiple de modo que pueden modelarse varias subclases, que presentan superclases comunes y diferentes. Como alternativa, también existen varias capas de la generalización. Estas relaciones pueden representarse con la notación de flecha o anidando las subclases en sus superclases. Para ello se modelan todas las subclases pertenecientes en el cuerpo de la superclase.
El set de generalización (Generalization Set) puede ayudarte a mantener la vista general del diagrama de clases. Este set es un elemento empaquetable. En UML, los paquetes son contenedores para elementos mencionados que tienen semejanza semántica y podrían modificarse juntos. Un paquete es un espacio de nombres, pero no una clase. El set de generalización puede asociarse con un clasificador. Este recibe el nombre de Powertype.
El Powertype se modela como cadena en la línea de la generalización de esta forma: {[isCovering Property] , [isDisjoint Property]} : [Nombre del Powertype]. La propiedad isCovering describe si el set está completo. Los valores pueden ser complete (completos) o incomplete (incompletos). La propiedad isDisjoint declara si el clasificador tiene instancias en común. Los valores pueden ser disjoint (no se solapan) o overlapping (se solapan).
El estándar UML 2.5 da poca información sobre la herencia, pero es posible orientarse por las versiones anteriores: UML 2 aclara que las clases especializadas adoptan las propiedades y restricciones de sus superclases; UML 1.4 concretó que los atributos declarados en una subclase sobrescriben los atributos heredados.
La dependencia (Dependency) es una relación entre el “proveedor” y el “cliente” (supplier-client-relationship). Esta relación dirigida describe que un elemento depende de otro. Puede tratase también de un conjunto de elementos. El cliente necesita un elemento diferente para una especificación mayor o para ejecutar su tarea. Sin el proveedor el cliente carece de un componente estructural o semántico. Por eso es muy probable que los cambios en el proveedor tengan un efecto en el cliente. Según UML 2.5 la semántica siempre influye en el elemento mencionado, pero no en sus instancias. Las dependencias no solo desempeñan un rol en el diagrama de clases UML, sino también en otros diagramas de estructura como el de componentes o el de disposición.
La dependencia tiene tres subcategorías:
- Abstracción (Abstraction)
- Disposición (Deployment)
- Uso (Usage)
La abstracción conecta elementos de capas diferentes. También puede mostrar perspectivas diferentes. Los elementos mencionados en esta relación de dependencia representan al mismo concepto. Según el estándar UML el elemento más específico es el cliente, que depende del proveedor, el elemento más abstracto. El final de la flecha debería estar en la subclase y la punta en la superclase. Pero UML autoriza también una notación inversa. Si es más conveniente que el elemento abstracto depende de su subclase la punta de la flecha se dibuja en el elemento más específico.
La abstracción tiene dos subclases: la realización (Realization) y la manifestación (Manifestation).
La realización se ha mencionado ya en relación con las interfaces. La realización de interfaces (InterfaceRealization) es una especificación de la realización y describe una relación entre el clasificador y la interfaz. El clasificador utiliza la interfaz para ofrecer un servicio a su cliente. La interfaz ejecuta este servicio, pero para ello el clasificador ha de cumplir el contrato que fija la interfaz. La notación para interfaces dispuestas y requeridas se encuentra en el apartado “Interfaces”.
La substitución (Substitution) es otra relación que especifica la realización. Está compuesta por un clasificador substituto y un contrato substituto. El clasificador substituto satisface el contrato del otro clasificador. Durante la ejecución, las instancias del clasificador substituto substituyen a instancias potenciales del contrato substituto. A diferencia de la especialización, no hay semejanza estructural entre elementos de la substitución. En el diagrama de clases, la substitución se escribe como una unión de dependencia (línea discontinua con punta abierta) añadiendo la palabra clave <<substitute>> sobre la línea.
La manifestación, elemento del diagrama de despliegue en el que no nos extenderemos, describe a una relación entre un artefacto y uno o más elementos de modelado. UML define a los artefactos como clasificadores. Simbolizan instancias concretas y físicas como carpetas de archivo. La manifestación indica que un artefacto ejecuta a un elemento vinculado, pero, a la inversa, puede simbolizar que hay elementos implicados en la creación de un artefacto. Tienen la misma notación que las substituciones y se escribe como <<manifest>>.
La abstracción también define a algunos estereotipos. Estos se incluyen en los perfiles de UML, que se definen cada vez que una metaclase que ya existe se ha de ampliar para un proyecto. La clase estereotipo se utiliza siempre en combinación con la metaclase, porque un perfil solo puede modificar lo que ya existe o añadir terminología. Desde el estándar UML 2.4.1, los estereotipos se escriben con mayúscula inicial. Los estereotipos estándar para una abstracción son:
- Derivar (<<Derive>>): un elemento se deriva de otro elemento diferente que generalmente es del mismo tipo.
- Refinar (<<Refine>>): un elemento proporciona datos detallados de una clase que también existe en otro elemento. Estos dos elementos se encuentran en capas de abstracción diferentes. Por ejemplo, un modelo en un nivel ejecutivo podría refinar su clase “empleado” en relación con la clase “empleado” en la capa de diseño.
- Rastrear (<<Trace>>): diferentes modelos manifiestan aspectos diferentes de un sistema. Con métodos de rastreo (mapping o tracing) se localizan elementos que representan el mismo concepto en modelos diferentes, lo que permite entender los cambios en los elementos o en las instrucciones.
Con ayuda de estos estereotipos de abstracción puede rastrearse la relación entre cliente y proveedor. Este proceso puede tener lugar de forma unilateral o bilateral y formal o informalmente. El cliente y el proveedor se han de encontrar en diagramas diferentes, p. ej., en un diagrama de clases y en uno de casos de uso.
El despliegue muestra la relación entre un artefacto y su objetivo operativo. En un diagrama UML la línea de despliegue parte de uno o más artefactos hacia el objetivo (Deployment Target) y se identifica con la etiqueta <<deploy>>. Esta dependencia también puede aplicarse en el nivel de las instancias. Opcionalmente, puede modelarse el artefacto en el cuerpo del objetivo operativo bien dibujando el artefacto como símbolo o enumerando los artefactos desplegados. Esta dependencia es una parte de la notación para diagramas de despliegue.
El uso describe una relación en la cual el cliente necesita al proveedor para cumplir con todas sus tareas o ejecutar operaciones. Haciendo esto, el uso pone en práctica la dependencia general como instancia. Esta dependencia manifiesta algunas relaciones concretas:
- Usar (<<use>>): un elemento utiliza a otro elemento, aunque no está definido del todo cuáles son los participantes de esta relación ni cuál es su utilidad.
- Crear (<<create>>): un clasificador cliente o uno de sus elementos de comportamiento o estructura crea una o más instancias del clasificador proveedor.
- Llamar (<<call>>): una operación llama a otra operación. El objetivo puede ser cualquier operación en el entorno de la operación fuente, incluso de clasificadores superiores.
- Enviar (<<send>>): una operación es la fuente, esto es, el cliente. Su objetivo es una señal. La dependencia modela así que la operación envía la señal objetivo.
- Interfaz requerida (Required Interface ----C): la interfaz requerida no existe, al contrario que la desplegada, en el clasificador. Determina los servicios que necesita un clasificador para ejecutar sus funciones para sus clientes. La dependencia se da entre los clasificadores y las interfaces (ver apartado “Interfaces”).
Vincular plantillas (Template binding) es la última relación dirigida que encuentra aplicación en los diagramas de clases. Al crear un diagrama de clases, puede resultar útil elaborar plantillas para las clases. Estas plantillas constan de parámetros, que se incluyen en la firma de la plantilla. La firma especifica el conjunto ordenado de parámetros dentro de una plantilla. Si modelas clases que no han de ostentar propiedades individuales, el trabajo es más eficiente si se utilizan plantillas, pero si una clase ha de contener parámetros fijos, se utiliza el template binding. La relación se da entre un elemento conectado y la firma en una plantilla objetivo.
El elemento conectado es templateable, es decir, que puede convertirse en una plantilla o conectarse a otras plantillas. El elemento está conectado porque consta de una conexión a una plantilla. Esta unión describe la estructura del elemento al sustituir parámetros formales de la plantilla por parámetros de calidad.
El diagrama de clases es uno de los diagramas UML más populares porque representa estructuras de sistemas tanto de forma detallada como general. Como diagrama de estructuras, muestra un sistema en estado estático de modo que el observador obtiene una perspectiva general de los elementos imprescindibles de un sistema, pero también visualizan las relaciones entre los componentes de esta arquitectura. Con un diagrama de clases UML se modelan desde objetos reales a clases abstractas con perfiles ampliables en cualquier lenguaje de programación. Con ellos se facilita la comunicación entre departamentos especializados en la realización de un proyecto.