Editor de diagramas de clases Mermaid
Un diagrama de clases muestra tipos y cómo se relacionan: qué contiene a qué, qué hereda de qué, qué depende de qué. Sirve cuando lo importante es la forma del código — un modelo de dominio, una interfaz de extensión, un árbol de herencia. Si quieres mostrar qué ocurre en ejecución y no cómo encajan los tipos, usa un diagrama de secuencia.
Un modelo de dominio de pagos
Tres tipos de relación en un solo diagrama: composición para las partes que no sobreviven al todo, herencia para la jerarquía de medios de pago y una asociación normal con multiplicidad. Aquí el significado lo llevan casi todo las flechas; las cajas de clase son casi accesorias.
classDiagram
class Pedido {
+String referencia
+EstadoPedido estado
+Dinero total()
+void añadirLinea(Articulo a, int cantidad)
}
class LineaPedido {
+Articulo articulo
+int cantidad
+Dinero subtotal()
}
class MedioDePago {
<<abstract>>
+autorizar(Dinero importe) bool
}
class Tarjeta {
+String ultimos4
+autorizar(Dinero importe) bool
}
class Bizum {
+String telefono
+autorizar(Dinero importe) bool
}
class Transferencia {
+String iban
+autorizar(Dinero importe) bool
}
Pedido "1" *-- "1..*" LineaPedido : contiene
Pedido --> MedioDePago : se paga con
MedioDePago <|-- Tarjeta
MedioDePago <|-- Bizum
MedioDePago <|-- TransferenciaEjemplos resueltos
1. Una clase
`+` es público, `-` privado y `#` protegido. Un miembro con paréntesis se dibuja como método; sin ellos es un campo.
classDiagram
class Usuario {
+String correo
-String hashContraseña
+bool verificar(String candidata)
}2. Herencia e interfaces
`<|--` es herencia, y se lee «el de la derecha extiende al de la izquierda». La anotación `<<interface>>` es una etiqueta y no un comportamiento, pero es lo que hace legible el diagrama.
classDiagram
class Repositorio {
<<interface>>
+buscar(String id) Entidad
+guardar(Entidad e) void
}
class RepositorioPostgres {
-Conexion conexion
+buscar(String id) Entidad
+guardar(Entidad e) void
}
class RepositorioEnMemoria {
-Map almacen
+buscar(String id) Entidad
+guardar(Entidad e) void
}
Repositorio <|.. RepositorioPostgres
Repositorio <|.. RepositorioEnMemoria3. Composición frente a agregación
La diferencia es el tiempo de vida. El rombo relleno (`*--`) significa que la parte muere con el todo: borras la factura y sus líneas desaparecen. El rombo hueco (`o--`) significa que la parte sigue existiendo por su cuenta.
classDiagram
class Factura {
+String numero
}
class LineaFactura {
+String concepto
}
class Cliente {
+String nombre
}
Factura "1" *-- "1..*" LineaFactura : se compone de
Cliente "1" o-- "0..*" Factura : ha emitido4. Genéricos
Las virgulillas dan parámetros de tipo: `Repositorio~Usuario~`. También se pueden anidar, cosa que a veces hace falta y casi nunca es buena idea. Los acentos y la ñ funcionan igual dentro de un genérico.
classDiagram
class Repositorio~T~ {
+buscar(String id) T
+todos() List~T~
}
class Cache~K, V~ {
+obtener(K clave) V
+guardar(K clave, V valor) void
}
class RepositorioUsuarios {
+buscarPorCorreo(String correo) Usuario
}
Repositorio~Usuario~ <|-- RepositorioUsuarios5. Notas y dirección
`direction LR` dispone el diagrama de izquierda a derecha, que a un árbol de herencia le suele sentar mejor que la disposición por defecto. Una nota es el sitio correcto para la restricción que no cabe en una caja de clase.
classDiagram
direction LR
class AlmacenDeEventos {
+añadir(Evento e) void
+reproducir(String flujo) List~Evento~
}
class Instantanea {
+int version
+byte[] contenido
}
AlmacenDeEventos --> Instantanea : escribe cada 100 eventos
note for AlmacenDeEventos "Solo admite añadidos. Los eventos nunca se modifican ni se borran."Referencia de sintaxis del diagrama de clases
Las flechas de relación son lo que merece memorizarse: son lo que distingue un diagrama de clases de un dibujo de cajas y líneas, y se leen de derecha a izquierda de una forma que despista mucho al principio.
| Sintaxis | Significado |
|---|---|
| classDiagram | Abre el diagrama. Distingue mayúsculas. |
| class Nombre { ... } | Clase con miembros. La llave de cierre va en su propia línea. |
| +miembro | Público. |
| -miembro | Privado. |
| #miembro | Protegido. |
| +metodo(Tipo arg) TipoRetorno | Un método: los paréntesis son lo que lo convierten en método. |
| <<interface>> / <<abstract>> | Estereotipo, escrito como primera línea dentro de la clase. |
| A <|-- B | Herencia: B extiende a A. |
| A <|.. B | Realización: B implementa la interfaz A. |
| A *-- B | Composición: B no sobrevive a A. |
| A o-- B | Agregación: B puede existir sin A. |
| A --> B | Asociación con dirección. |
| A ..> B | Dependencia: A usa B pero no lo guarda. |
| A "1" --> "0..*" B : etiqueta | Multiplicidad en cada extremo más una etiqueta de relación. |
| class Repo~T~ | Parámetro de tipo genérico. |
| note for A "texto" | Nota asociada a una clase. |
| direction LR | Cambia la dirección de la disposición. |
Errores que rompen un diagrama de clases
Reproducidos con Mermaid 11.12.2. El diagrama de clases es de los más indulgentes de los seis tipos, así que varios de estos se dibujan tan tranquilos y te dan el dibujo equivocado.
Lo que ves
Parse error, termina en: got 'EOF_IN_STRUCT'
Por qué
Un cuerpo de clase abierto con `{` y nunca cerrado. Por una vez el nombre del token ayuda de verdad: significa que el fichero se acabó estando todavía dentro de una clase.
Solución
Cierra la llave en su propia línea.
classDiagram
class Pedido {
+String referenciaclassDiagram
class Pedido {
+String referencia
}Lo que ves
Parse error, termina en: got 'ANNOTATION_END'
Por qué
Una flecha de diagrama de secuencia usada en un diagrama de clases. Aquí `->>` no significa nada, y el analizador avanza lo bastante dentro de ella como para devolver un nombre de token desconcertante.
Solución
Usa una relación de clases: `-->` para asociación, `<|--` para herencia, `*--` para composición.
classDiagram
Pedido ->> ClienteclassDiagram
Pedido --> Cliente : pertenece aLo que ves
No diagram type detected matching given configuration
Por qué
Mayúsculas mal puestas en la palabra clave. `classdiagram` no es `classDiagram`.
Solución
La D en mayúscula.
classdiagram
class PedidoclassDiagram
class PedidoLo que ves
La flecha apunta al revés de lo que querías
Por qué
Las flechas de relación se leen desde la punta hacia atrás. `A <|-- B` significa que B hereda de A, no al contrario. Escrito al revés se dibuja igual: lo que pasa es que ahora afirma que tu clase base extiende a su propia subclase.
Solución
Léelo como «el extremo lejano extiende al extremo con punta». Pon el padre a la izquierda de `<|--`.
classDiagram
Tarjeta <|-- MedioDePagoclassDiagram
MedioDePago <|-- TarjetaLo que ves
Sale un campo donde esperabas un método
Por qué
Los paréntesis son lo único que distingue un método de un campo. `+guardar` es un campo llamado guardar; `+guardar()` es un método. Las dos formas son válidas, así que nada te avisa.
Solución
Añade los paréntesis, y detrás el tipo de retorno si quieres que se vea.
classDiagram
class Repo {
+guardar
+buscar
}classDiagram
class Repo {
+guardar(Entidad e) void
+buscar(String id) Entidad
}Lo que ves
Composición y agregación se parecen a simple vista y significan lo contrario
Por qué
`*--` y `o--` se diferencian en un carácter y codifican una diferencia semántica real: si la parte puede sobrevivir al todo. Usar la equivocada produce un diagrama técnicamente bien formado y factualmente falso sobre tu dominio.
Solución
Rombo relleno `*--` cuando borrar el padre borra al hijo. Hueco `o--` cuando no.
classDiagram
Pedido o-- LineaPedido : contieneclassDiagram
Pedido *-- LineaPedido : contieneNotas sobre el dibujado
Medido sobre el Mermaid 11.12.2 que usa este sitio.
Crece a lo alto más deprisa que ningún otro tipo de aquí
Medido con clases de dos miembros encadenadas por herencia: tres clases dan un viewBox de unos 176×548 y cuarenta clases dan 180×7726, es decir unos 194 píxeles de altura por clase, el crecimiento más pronunciado de los seis tipos del sitio. Un diagrama de cuarenta clases pasa de los siete mil píxeles de alto y es inservible como imagen única. `direction LR` ayuda, pero a partir de unas quince clases lo honesto es partir el diagrama por contextos.
El número de miembros apenas afecta al ancho
El ancho lo marca la firma de miembro más larga, no cuántos miembros hay. Una clase con veinte campos cortos no es más ancha que una con tres. Es decir: puedes ser generoso con los miembros y tacaño con las clases, que es justo lo contrario de lo que pide el instinto. En español las firmas salen más largas que en inglés, así que aquí el ancho lo suele fijar un único método con nombre descriptivo.
Los acentos y la ñ funcionan en todas partes
Comprobado: `hashContraseña`, `Artículo` o `añadirLinea` valen como nombres de clase y de miembro, y también dentro de un genérico. No hay que escribir el modelo sin tildes para que se dibuje. La única restricción real la impone la virgulilla, que es sintaxis.
Los genéricos usan virgulillas, y eso tiene consecuencias
`Repositorio~T~` existe porque los ángulos chocarían con el HTML de las etiquetas. También implica que una virgulilla literal en el nombre de una clase o de un miembro se leerá como el principio de un parámetro de tipo. Es raro, pero cuando pasa desconcierta de verdad.
Las etiquetas son HTML, así que la exportación a PNG redibuja
Las etiquetas de clase se dibujan dentro de un `<foreignObject>` del SVG, que los navegadores se niegan a rasterizar sobre un canvas. La exportación a PNG de este sitio fallaba antes en silencio y devolvía un fichero SVG; ahora redibuja primero el diagrama con etiquetas de texto SVG plano. El PNG sale correcto y a tamaño completo, con una tipografía mínimamente distinta de la de la pantalla.
Cuándo conviene otro diagrama
Si documentas una base de datos y no un sistema de tipos, usa un diagrama ER. La distinción importa: los diagramas de clases modelan comportamiento y herencia, que las tablas no tienen, y los ER modelan claves y cardinalidad como es debido, cosa que los de clases hacen a medias.
Si el diagrama son sobre todo cajas con `-->` entre ellas y sin miembros, lo que estás dibujando es una arquitectura, no un diagrama de clases. Un diagrama de flujo con subgrafos quedará mejor y afirmará menos cosas.
Y si la lista de clases sale generada del código, plantéate si el diagrama debería salir igual. Un diagrama de clases mantenido a mano de un código que cambia cada semana está desfasado en un mes, y un diagrama equivocado cuesta más caro que no tener ninguno.
Otros tipos de diagrama
Escrito por Dominik Malsch · Última actualización: