Editor de diagrama de classes Mermaid
Um diagrama de classes mostra tipos e como eles se relacionam: o que contém o quê, o que herda de quê, o que depende de quê. Use quando o assunto for o formato do código — um modelo de domínio, uma interface de extensão, uma árvore de herança. Se quiser mostrar o que acontece em tempo de execução em vez de como os tipos se encaixam, use um diagrama de sequência.
Um modelo de domínio de pagamentos
Três tipos de relação num diagrama só: composição para as partes que não sobrevivem ao todo, herança para a hierarquia de formas de pagamento e uma associação comum com multiplicidade. Aqui o significado está quase todo nas setas; as caixas de classe são quase acessórias.
classDiagram
class Pedido {
+String codigo
+StatusPedido status
+Dinheiro total()
+void adicionarItem(Produto p, int quantidade)
}
class ItemDoPedido {
+Produto produto
+int quantidade
+Dinheiro subtotal()
}
class FormaDePagamento {
<<abstract>>
+autorizar(Dinheiro valor) bool
}
class CartaoDeCredito {
+String ultimos4
+autorizar(Dinheiro valor) bool
}
class Pix {
+String chave
+autorizar(Dinheiro valor) bool
}
class Boleto {
+String linhaDigitavel
+autorizar(Dinheiro valor) bool
}
Pedido "1" *-- "1..*" ItemDoPedido : contém
Pedido --> FormaDePagamento : pago com
FormaDePagamento <|-- CartaoDeCredito
FormaDePagamento <|-- Pix
FormaDePagamento <|-- BoletoExemplos resolvidos
1. Uma classe
`+` é público, `-` é privado e `#` é protegido. Um membro com parênteses é desenhado como método; sem eles é um campo.
classDiagram
class Usuario {
+String email
-String hashDaSenha
+bool verificar(String candidata)
}2. Herança e interfaces
`<|--` é herança, lida como «o da direita estende o da esquerda». A anotação `<<interface>>` é um rótulo e não um comportamento, mas é ela que torna o diagrama legível.
classDiagram
class Repositorio {
<<interface>>
+buscar(String id) Entidade
+salvar(Entidade e) void
}
class RepositorioPostgres {
-Conexao conexao
+buscar(String id) Entidade
+salvar(Entidade e) void
}
class RepositorioEmMemoria {
-Map armazenamento
+buscar(String id) Entidade
+salvar(Entidade e) void
}
Repositorio <|.. RepositorioPostgres
Repositorio <|.. RepositorioEmMemoria3. Composição versus agregação
A diferença é o tempo de vida. O losango preenchido (`*--`) significa que a parte morre com o todo: apague a nota fiscal e os itens dela somem. O losango vazado (`o--`) significa que a parte continua existindo por conta própria.
classDiagram
class NotaFiscal {
+String numero
}
class ItemDaNota {
+String descricao
}
class Cliente {
+String razaoSocial
}
NotaFiscal "1" *-- "1..*" ItemDaNota : composta por
Cliente "1" o-- "0..*" NotaFiscal : emitiu4. Genéricos
Os tis dão parâmetros de tipo: `Repositorio~Usuario~`. Aninhar também funciona, o que às vezes é necessário e raramente é boa ideia. Acentos funcionam normalmente dentro de um genérico.
classDiagram
class Repositorio~T~ {
+buscar(String id) T
+todos() List~T~
}
class Cache~K, V~ {
+obter(K chave) V
+guardar(K chave, V valor) void
}
class RepositorioDeUsuarios {
+buscarPorEmail(String email) Usuario
}
Repositorio~Usuario~ <|-- RepositorioDeUsuarios5. Notas e direção
`direction LR` dispõe o diagrama da esquerda para a direita, o que costuma servir melhor a uma árvore de herança que o padrão. Uma nota é o lugar certo para a restrição que não cabe numa caixa de classe.
classDiagram
direction LR
class RepositorioDeEventos {
+anexar(Evento e) void
+reproduzir(String fluxo) List~Evento~
}
class Snapshot {
+int versao
+byte[] conteudo
}
RepositorioDeEventos --> Snapshot : grava a cada 100 eventos
note for RepositorioDeEventos "Somente anexação. Eventos nunca são alterados nem apagados."Referência de sintaxe do diagrama de classes
As setas de relação são a parte que vale decorar: são elas que separam um diagrama de classes de um desenho de caixas e linhas, e se leem da direita para a esquerda de um jeito que confunde por bastante tempo.
| Sintaxe | Significado |
|---|---|
| classDiagram | Abre o diagrama. Diferencia maiúsculas. |
| class Nome { ... } | Classe com membros. A chave de fechamento fica numa linha só dela. |
| +membro | Público. |
| -membro | Privado. |
| #membro | Protegido. |
| +metodo(Tipo arg) TipoRetorno | Um método — são os parênteses que o tornam um. |
| <<interface>> / <<abstract>> | Estereótipo, escrito na primeira linha dentro da classe. |
| A <|-- B | Herança: B estende A. |
| A <|.. B | Realização: B implementa a interface A. |
| A *-- B | Composição: B não sobrevive a A. |
| A o-- B | Agregação: B pode existir sem A. |
| A --> B | Associação com direção. |
| A ..> B | Dependência — A usa B mas não o guarda. |
| A "1" --> "0..*" B : rótulo | Multiplicidade em cada ponta mais um rótulo de relação. |
| class Repo~T~ | Parâmetro de tipo genérico. |
| note for A "texto" | Nota anexada a uma classe. |
| direction LR | Muda a direção do layout. |
Erros que quebram um diagrama de classes
Reproduzidos no Mermaid 11.12.2. O diagrama de classes é dos mais tolerantes entre os seis tipos daqui, então vários destes desenham tranquilamente e devolvem a imagem errada.
O que você vê
Parse error, terminando em: got 'EOF_IN_STRUCT'
Por quê
Um corpo de classe aberto com `{` e nunca fechado. Por uma vez o nome do token ajuda de verdade: significa que o arquivo terminou enquanto ainda estávamos dentro de uma classe.
Solução
Feche a chave numa linha só dela.
classDiagram
class Pedido {
+String codigoclassDiagram
class Pedido {
+String codigo
}O que você vê
Parse error, terminando em: got 'ANNOTATION_END'
Por quê
Uma seta de diagrama de sequência usada num diagrama de classes. `->>` não significa nada aqui, e o analisador entra o bastante nela para produzir um nome de token confuso.
Solução
Use uma relação de classes: `-->` para associação, `<|--` para herança, `*--` para composição.
classDiagram
Pedido ->> ClienteclassDiagram
Pedido --> Cliente : pertence aO que você vê
No diagram type detected matching given configuration
Por quê
Maiúsculas erradas na palavra-chave. `classdiagram` não é `classDiagram`.
Solução
D maiúsculo.
classdiagram
class PedidoclassDiagram
class PedidoO que você vê
A seta aponta para o lado contrário do que você queria
Por quê
As setas de relação se leem da ponta para trás. `A <|-- B` significa que B herda de A, não o contrário. Escrita ao contrário ela desenha do mesmo jeito: só que agora afirma que sua classe base estende a própria subclasse.
Solução
Leia como «a ponta distante estende a ponta com a seta». Ponha o pai à esquerda de `<|--`.
classDiagram
CartaoDeCredito <|-- FormaDePagamentoclassDiagram
FormaDePagamento <|-- CartaoDeCreditoO que você vê
Aparece um campo onde você esperava um método
Por quê
Os parênteses são a única coisa que distingue um método de um campo. `+salvar` é um campo chamado salvar; `+salvar()` é um método. Os dois são válidos, então nada avisa.
Solução
Acrescente os parênteses e, depois deles, o tipo de retorno se quiser vê-lo.
classDiagram
class Repo {
+salvar
+buscar
}classDiagram
class Repo {
+salvar(Entidade e) void
+buscar(String id) Entidade
}O que você vê
Composição e agregação parecem iguais de relance e significam o oposto
Por quê
`*--` e `o--` diferem em um caractere e codificam uma diferença semântica real: se a parte pode sobreviver ao todo. Usar o errado produz um diagrama tecnicamente bem formado e factualmente falso sobre o seu domínio.
Solução
Losango preenchido `*--` quando apagar o pai apaga o filho. Vazado `o--` quando não.
classDiagram
Pedido o-- ItemDoPedido : contémclassDiagram
Pedido *-- ItemDoPedido : contémNotas sobre a renderização
Medido no Mermaid 11.12.2 que este site usa.
Cresce em altura mais rápido que qualquer outro tipo daqui
Medido com classes de dois membros encadeadas por herança: três classes dão um viewBox de aproximadamente 176×548 e quarenta classes dão 180×7726, ou seja, cerca de 194 pixels de altura por classe, o crescimento mais íngreme dos seis tipos do site. Um diagrama de quarenta classes passa dos sete mil pixels de altura e é inservível como imagem única. `direction LR` ajuda, mas depois de umas quinze classes a solução honesta é dividir o diagrama por contexto.
A quantidade de membros quase não afeta a largura
A largura é ditada pela assinatura de membro mais longa, não por quantos membros existem. Uma classe com vinte campos curtos não é mais larga que uma com três. Ou seja: pode ser generoso com membros e mesquinho com classes, o oposto do que o instinto pede. Em português as assinaturas saem mais longas que em inglês, então a largura costuma ser decidida por um único método de nome descritivo.
Acentos, til e cedilha funcionam em toda parte
Verificado: `código`, `hashDaSenha` e `ItemDoPedido` funcionam como nomes de classe e de membro, e os acentos passam também dentro de um genérico. Não é preciso tirar os acentos do modelo para ele desenhar. A única restrição real vem do til usado como sintaxe de genérico.
Genéricos usam tis, e isso tem consequência
`Repositorio~T~` existe porque os sinais de menor e maior colidiriam com o HTML dos rótulos. Também implica que um til literal num nome de classe ou de membro será lido como o começo de um parâmetro de tipo. É raro, mas genuinamente confuso quando acontece.
Os rótulos são HTML, então a exportação para PNG redesenha
Os rótulos de classe são desenhados dentro de um `<foreignObject>` do SVG, que os navegadores se recusam a rasterizar num canvas. A exportação para PNG deste site falhava em silêncio e devolvia um arquivo SVG; agora ela redesenha antes o diagrama com rótulos em texto SVG simples. O PNG sai correto e em tamanho cheio, com uma tipografia muito levemente diferente da tela.
Quando usar outro diagrama
Se você está documentando um banco de dados e não um sistema de tipos, use um diagrama ER. A distinção importa: diagramas de classes modelam comportamento e herança, que tabelas não têm, e diagramas ER modelam chaves e cardinalidade direito, o que os de classes disfarçam.
Se o diagrama é basicamente caixas com `-->` entre elas e sem membros, o que você está desenhando é uma arquitetura, não um diagrama de classes. Um fluxograma com subgrafos fica melhor e afirma menos.
E se a lista de classes é gerada a partir do código, considere se o diagrama também não deveria ser. Um diagrama de classes mantido à mão para uma base que muda toda semana está errado em um mês, e um diagrama errado custa mais caro que diagrama nenhum.
Outros tipos de diagrama
Escrito por Dominik Malsch · Última atualização: