Apuntes DAM
Tema 6 de 7ED · 1º DAM/DAW

Entornos de Desarrollo

Diagramas UML

Diagramas de clases y de comportamiento (casos de uso, secuencia, actividad, estados) con herramientas específicas.

50 min lecturaIntermedioRevisado el

Diagramas UML

Cuando un arquitecto diseña un edificio no empieza directamente con los ladrillos — primero elabora planos. Esos planos son un lenguaje visual estandarizado que cualquier arquitecto del mundo puede leer e interpretar sin ambigüedad. En el desarrollo de software ocurre exactamente lo mismo: antes (y durante) la implementación, los desarrolladores necesitan un lenguaje gráfico común para comunicar la estructura y el comportamiento de un sistema. Ese lenguaje es UML.

UML (Unified Modeling Language, Lenguaje Unificado de Modelado) es un estándar internacional mantenido por el Object Management Group (OMG). No es un lenguaje de programación — no se ejecuta. Es un lenguaje de modelado: una notación gráfica para representar sistemas de software de forma abstracta, independientemente del lenguaje de programación en que vayan a implementarse.

UML define catorce tipos de diagramas, organizados en dos grandes familias. Los diagramas estructurales muestran la organización estática del sistema — qué clases existen, qué atributos y métodos tienen, cómo se relacionan entre sí. Los diagramas de comportamiento muestran la dinámica del sistema — cómo fluye la información, en qué orden se ejecutan las operaciones, qué estados puede tener un objeto. En esta unidad estudiaremos los más usados en la práctica profesional.

UML e ingeniería inversa

Los entornos de desarrollo modernos como IntelliJ IDEA y Eclipse pueden tanto generar código Java a partir de un diagrama UML (ingeniería directa) como generar diagramas UML a partir de código Java existente (ingeniería inversa). Esta bidireccionalidad hace de UML una herramienta viva, no solo documentación estática.


Diagrama de clases

El diagrama de clases es el diagrama UML más importante y el que más se usa en la práctica. Representa la estructura estática de un sistema orientado a objetos: las clases que lo componen, sus atributos y métodos, y las relaciones que existen entre ellas. Es el plano del sistema — la vista de "qué hay y cómo está organizado".

Un diagrama de clases bien elaborado permite a cualquier desarrollador del equipo entender la arquitectura del sistema sin necesidad de leer miles de líneas de código. También sirve como base de discusión en reuniones de diseño, como documentación de la API interna y como guía para la implementación.

Notación de una clase

En UML, una clase se representa como un rectángulo dividido en tres compartimentos. El superior contiene el nombre de la clase (en negrita, centrado). El central contiene los atributos (campos). El inferior contiene los métodos (operaciones). Delante de cada elemento se indica su visibilidad con un símbolo:+ público,- privado,# protegido,~ de paquete.

Cliente
- id: Long
- nombre: String
- email: String
- activo: boolean
+ getNombre(): String
+ setNombre(n: String): void
+ isActivo(): boolean
+ desactivar(): void
«abstract»
Forma
- color: String
+ calcularArea(): double
+ calcularPerimetro(): double
+ getColor(): String
«interface»
Comparable<T>
(sin atributos)
+ compareTo(o: T): int
Leyenda:  - privado  + público  # protegido  cursiva = abstracto  subrayado = estático

Relaciones entre clases

Las relaciones entre clases son la parte más rica y expresiva de los diagramas de clases. Cada tipo de relación tiene una semántica precisa y se representa con un tipo de línea y flecha diferente. Conocerlas y aplicarlas correctamente es la clave para leer e interpretar diagramas de software real.

RelaciónSímbolo UMLSignificadoEjemplo Java
Herencia──────▷ (flecha hueca)Una clase extiende otra. Es una relación 'es un tipo de'.class Circulo extends Forma
Realización- - - - -▷ (flecha hueca discontinua)Una clase implementa una interfaz.class ArrayList implements List
Asociación───────→ (flecha sólida)Una clase conoce a otra. Puede tener nombre y multiplicidad.class Pedido { Cliente cliente; }
Agregación◇────── (rombo hueco)'Tiene un'. Las partes pueden existir sin el todo.class Departamento { List<Empleado> empleados; }
Composición◆────── (rombo relleno)Las partes no pueden existir sin el todo. Relación fuerte.class Pedido { List<LineaPedido> lineas; }
Dependencia- - - - → (flecha discontinua)Una clase usa otra puntualmente (como parámetro o variable local).void procesar(Servicio s) { s.ejecutar(); }

Multiplicidad

La multiplicidad indica cuántos objetos de cada clase pueden participar en una asociación. Se escribe en ambos extremos de la línea de asociación. Su correcta lectura es fundamental para entender las reglas de negocio del sistema.

NotaciónSignificadoEjemplo de negocio
1Exactamente unoUn pedido tiene exactamente un cliente
0..1Cero o uno (opcional)Un empleado puede tener o no un coche de empresa
* ó 0..*Cero o másUn cliente puede tener ningún pedido o muchos
1..*Uno o más (al menos uno)Un pedido tiene al menos una línea de pedido
2..5Entre dos y cincoUn equipo tiene entre 2 y 5 miembros
3Exactamente tresUn triángulo tiene exactamente tres vértices

Diagrama de clases completo: sistema de pedidos

A continuación se muestra un diagrama de clases de un sistema de gestión de pedidos, con las principales relaciones y multiplicidades. Lee el diagrama de arriba abajo y de izquierda a derecha: un Cliente realiza uno o más Pedidos, cada Pedido tiene una o más LíneaDePedido, y cada LíneaDePedido referencia a un Producto del catálogo.

Cliente
- id: Long
- nombre: String
- email: String
- esVIP: boolean
+ realizarPedido(): Pedido
+ getPedidos(): List
1
realiza
→
0..*
Pedido
- id: Long
- fecha: LocalDate
- estado: EstadoPedido
+ calcularTotal(): double
+ confirmar(): void
+ cancelar(): void
1
◆
contiene (composición)
1..*
LíneaDePedido
- cantidad: int
- precioUnitario: double
+ getSubtotal(): double
*
referencia
→
1
Producto
- referencia: String
- nombre: String
- precio: double
- stock: int
+ hayStock(n: int): boolean
+ reducirStock(n: int): void

Del diagrama de clases al código Java

Los IDEs permiten generar código Java a partir de un diagrama de clases y, en sentido inverso, generar el diagrama a partir del código existente (ingeniería inversa). El siguiente ejemplo muestra cómo el diagrama anterior se traduce directamente a código:

Código Java generado a partir del diagrama de clases
1// ── Enum para el estado del pedido ──────────────────────────────────
2public enum EstadoPedido {
3    PENDIENTE, CONFIRMADO, ENVIADO, ENTREGADO, CANCELADO
4}
5
6// ── Producto ─────────────────────────────────────────────────────────
7public class Producto {
8    private String referencia;
9    private String nombre;
10    private double precio;
11    private int    stock;
12
13    public boolean hayStock(int cantidadNecesaria) {
14        return stock >= cantidadNecesaria;
15    }
16
17    public void reducirStock(int cantidad) {
18        if (!hayStock(cantidad)) throw new StockInsuficienteException(referencia, cantidad);
19        this.stock -= cantidad;
20    }
21    // getters y setters omitidos por brevedad
22}
23
24// ── LíneaDePedido: composición → no existe sin su Pedido ─────────────
25public class LineaDePedido {
26    private int     cantidad;
27    private double  precioUnitario;
28    private Producto producto;       // asociación → referencia a Producto
29
30    public LineaDePedido(Producto producto, int cantidad) {
31        this.producto       = producto;
32        this.cantidad       = cantidad;
33        this.precioUnitario = producto.getPrecio();
34    }
35
36    public double getSubtotal() {
37        return cantidad * precioUnitario;
38    }
39}
40
41// ── Pedido ───────────────────────────────────────────────────────────
42public class Pedido {
43    private Long                id;
44    private LocalDate           fecha;
45    private EstadoPedido        estado;
46    // Composición: las líneas no pueden existir sin el pedido
47    private List<LineaDePedido> lineas = new ArrayList<>();
48
49    public double calcularTotal() {
50        return lineas.stream()
51                     .mapToDouble(LineaDePedido::getSubtotal)
52                     .sum();
53    }
54
55    public void confirmar() {
56        if (lineas.isEmpty()) throw new PedidoVacioException();
57        this.estado = EstadoPedido.CONFIRMADO;
58    }
59
60    public void addLinea(LineaDePedido linea) { lineas.add(linea); }
61}
62
63// ── Cliente ──────────────────────────────────────────────────────────
64public class Cliente {
65    private Long          id;
66    private String        nombre;
67    private String        email;
68    private boolean       esVIP;
69    // Asociación: 1 cliente tiene 0..* pedidos
70    private List<Pedido>  pedidos = new ArrayList<>();
71
72    public Pedido realizarPedido() {
73        Pedido nuevoPedido = new Pedido();
74        pedidos.add(nuevoPedido);
75        return nuevoPedido;
76    }
77
78    public List<Pedido> getPedidos() {
79        return Collections.unmodifiableList(pedidos);
80    }
81}


Diagramas de comportamiento

Mientras que el diagrama de clases muestra la estructura estática del sistema, los diagramas de comportamientomuestran su dinámica: cómo fluye la información, en qué orden se ejecutan las operaciones, qué eventos ocurren y en qué estados puede encontrarse el sistema. UML define varios tipos de diagramas de comportamiento; estudiaremos los cuatro más usados.

Diagrama de casos de uso

El diagrama de casos de uso es el más cercano al usuario. Muestra qué puede hacer el sistema (casos de uso) y quién lo usa (actores). No describe cómo se hace — eso es responsabilidad de otros diagramas. Su propósito es capturar y comunicar los requisitos funcionales del sistema de forma comprensible para personas no técnicas: clientes, usuarios finales, gerentes.

Los elementos básicos son el actor (figura de un hombre de palitos — representa un usuario u otro sistema externo), el caso de uso (óvalo con el nombre de la funcionalidad) y las relaciones: asociación simple entre actor y caso de uso,«include» (el caso A siempre invoca al caso B), y «extend» (el caso B puede extender opcionalmente al caso A).

Casos de uso — Tienda online

Cliente
Sistema Tienda Online
Buscar producto
Añadir al carrito
Realizar pedido
«include» Autenticarse
Autenticarse
Pagar con PayPal
«extend» Realizar pedido
Ver historial
«include» Autenticarse
Administrador
(gestionar catálogo,
ver informes...)

Diagrama de secuencia

El diagrama de secuencia muestra cómo los objetos interactúan entre sí a lo largo del tiempo para completar un caso de uso concreto. El tiempo fluye de arriba hacia abajo. Cada objeto tiene una línea de vida (línea vertical discontinua). Las interacciones son mensajes (flechas horizontales entre líneas de vida). Es el diagrama más útil para entender el flujo detallado de una operación compleja.

Diagrama de secuencia — Realizar pedido

🧑 Usuario
🖥️ ControladorPedidos
📦 ServicioPedidos
🗄️ RepositorioPedidos
▶
confirmarPedido(pedidoId)
▶
procesarPedido(pedidoId)
▶
buscarPedido(pedidoId)
▶
pedido: Pedido
▶
actualizarEstado(CONFIRMADO)
▶
OK
▶
mostrarConfirmacion()
─── llamada síncrona- - - respuesta / retorno

Diagrama de actividad

El diagrama de actividad es el equivalente UML de los diagramas de flujo. Muestra el flujo de control de un proceso o algoritmo: qué actividades se realizan, en qué orden, cuándo hay decisiones y bifurcaciones, y cuándo hay actividades paralelas. Es muy útil para modelar procesos de negocio y algoritmos complejos.

Los elementos básicos son: nodo inicial (círculo relleno negro), actividad (rectángulo con esquinas redondeadas), decisión (rombo, con la condición entre corchetes en cada rama), bifurcación/unión (barra horizontal — separa o une flujos paralelos) y nodo final (círculo relleno negro con borde).

Diagrama de actividad — Proceso de compra online

Buscar producto
Añadir al carrito
¿Seguir
comprando?
[Sí][No]
Buscar más
productos
(↑ volver)
Ir al
checkout
Introducir
datos de envío
Pagar
Confirmar
pedido

Diagrama de estados

El diagrama de estados (también llamado diagrama de máquina de estados) modela el ciclo de vida de un objeto concreto: los distintos estados en los que puede encontrarse y las transiciones que lo llevan de un estado a otro. Cada transición se etiqueta con el evento que la desencadena y, opcionalmente, con una condición de guarda (entre corchetes) y una acción (tras la barra).

Diagrama de estados — Pedido

→
PENDIENTE
confirmar()
→
CONFIRMADO
preparar()
→
PREPARANDO
enviar()
→
ENVIADO
entregar()
→
ENTREGADO
→
Transición especial: desde cualquier estado → CANCELADO con evento cancelar()


Herramientas para crear diagramas UML

Existen dos grandes enfoques para crear diagramas UML: las herramientas gráficas (en las que arrastras y sueltas elementos con el ratón) y las herramientas textuales (en las que el diagrama se describe en un lenguaje específico y se renderiza automáticamente). Cada enfoque tiene sus ventajas.

HerramientaTipoVentajasUso recomendado
draw.io / diagrams.netGráfica (web, gratuita)Sencilla, sin instalación, exporta PNG/SVG/XML, integrada en Confluence/NotionDiagramas de presentación, casos de uso, diagramas de flujo
PlantUMLTextual (open source)Diagrama como código, versión controlada con Git, automatable en CIDiagramas técnicos que evolucionan con el código
MermaidTextual (web)Integrada en GitHub, GitLab, Notion y Markdown. Muy sencilla de usarDiagramas en README, documentación técnica en repos
StarUMLGráfica (de escritorio)Potente, soporta todos los tipos UML, ingeniería inversa JavaProyectos grandes que necesitan todas las características UML
IntelliJ IDEAIntegrada en el IDEGenera diagramas a partir del código Java existente (ingeniería inversa)Documentar código existente, explorar arquitectura
LucidchartGráfica (web, SaaS)Colaboración en tiempo real, plantillas profesionalesEquipos que trabajan en la nube, diagramas colaborativos

PlantUML: diagramas como código

PlantUML es una herramienta especialmente interesante porque permite describir los diagramas en texto plano y genera automáticamente la imagen. Al estar en texto, los diagramas se pueden guardar en Git junto al código, se puede ver la evolución del diagrama en el historial, y se pueden generar automáticamente en el pipeline de CI.

diagrama-clases.puml — Diagrama de clases en PlantUML
1@startuml
2
3' Diagrama de clases — Sistema de pedidos
4skinparam classAttributeIconSize 0
5
6class Cliente {
7    - id: Long
8    - nombre: String
9    - email: String
10    - esVIP: boolean
11    + realizarPedido(): Pedido
12    + getPedidos(): List<Pedido>
13}
14
15class Pedido {
16    - id: Long
17    - fecha: LocalDate
18    - estado: EstadoPedido
19    + calcularTotal(): double
20    + confirmar(): void
21    + cancelar(): void
22}
23
24class LineaDePedido {
25    - cantidad: int
26    - precioUnitario: double
27    + getSubtotal(): double
28}
29
30class Producto {
31    - referencia: String
32    - nombre: String
33    - precio: double
34    - stock: int
35    + hayStock(n: int): boolean
36    + reducirStock(n: int): void
37}
38
39enum EstadoPedido {
40    PENDIENTE
41    CONFIRMADO
42    ENVIADO
43    ENTREGADO
44    CANCELADO
45}
46
47' Relaciones
48Cliente "1" --> "0..*" Pedido : realiza
49Pedido "1" *-- "1..*" LineaDePedido : contiene
50LineaDePedido "*" --> "1" Producto : referencia
51Pedido --> EstadoPedido
52
53@enduml
secuencia.puml — Diagrama de secuencia en PlantUML
1@startuml
2
3actor       Usuario
4participant "ControladorPedidos" as Ctrl
5participant "ServicioPedidos"    as Svc
6database    "RepositorioPedidos" as Repo
7
8Usuario -> Ctrl : confirmarPedido(pedidoId)
9activate Ctrl
10
11Ctrl -> Svc : procesarPedido(pedidoId)
12activate Svc
13
14Svc -> Repo : buscarPedido(pedidoId)
15activate Repo
16Repo --> Svc : pedido: Pedido
17deactivate Repo
18
19Svc -> Repo : actualizarEstado(CONFIRMADO)
20Repo --> Svc : OK
21
22Svc --> Ctrl : OK
23deactivate Svc
24
25Ctrl --> Usuario : mostrarConfirmacion()
26deactivate Ctrl
27
28@enduml

Ingeniería inversa en IntelliJ IDEA

IntelliJ IDEA puede generar automáticamente un diagrama UML a partir de código Java existente: haz clic derecho sobre una clase o paquete → Diagrams → Show Diagram. El diagrama es interactivo: puedes expandir clases, filtrar relaciones y navegar hasta el código fuente haciendo doble clic en cualquier elemento.


Resumen de la unidad

Diagrama de clases

  • ✓Representación estática: clases, atributos, métodos y relaciones
  • ✓Visibilidad: + público, - privado, # protegido
  • ✓Relaciones: herencia, realización, asociación, agregación, composición
  • ✓Multiplicidad: 1, 0..1, *, 1..*, n..m

Diagramas de comportamiento

  • ✓Casos de uso: actores, funcionalidades, «include» y «extend»
  • ✓Secuencia: objetos, líneas de vida, mensajes y retornos
  • ✓Actividad: flujo de control, decisiones, paralelismo
  • ✓Estados: estados, transiciones, eventos y condiciones de guarda

Herramientas UML

  • ✓draw.io / Mermaid: diagramas rápidos y colaborativos
  • ✓PlantUML: diagramas como código, versionables con Git
  • ✓StarUML: herramienta completa para todos los tipos UML
  • ✓IntelliJ IDEA: ingeniería inversa desde código Java

UML en el flujo de desarrollo

  • ✓Ingeniería directa: del diagrama al código Java (generación)
  • ✓Ingeniería inversa: del código Java al diagrama (documentación)
  • ✓Diagramas como documentación viva junto al código fuente
  • ✓Integración en pipelines de CI para generar documentación automática

¿Has encontrado un error, algo desactualizado o una explicación que no se entiende? Avísanos y lo corregimos.

¿Has terminado este tema?

Crea una cuenta gratis para guardar qué temas has terminado, subir de nivel y ganar medallas.

Guardar mi progreso