Class diagrams
A class diagram is UML: classes drawn as boxes with attribute and method compartments, joined by typed relations. It suits a data model, a type hierarchy or the implementations of an interface. The class spec reference lists every field and its allowed values.
Classes and members
Section titled “Classes and members”A class has an id, a label, and optionally attributes and methods. Each member has a
visibility of + (public), - (private), # (protected) or ~ (package), and its text.
A method may be static, drawn underlined, or abstract, drawn in italics. A stereotype
adds a line such as «interface» above the name, and type_params adds <T> to it.
{ "type": "class", "direction": "RIGHT", "classes": [ { "id": "repository", "label": "Repository", "stereotype": "interface", "type_params": ["T"], "methods": [ {"visibility": "+", "text": "find(id: string): T", "abstract": true}, {"visibility": "+", "text": "save(item: T)", "abstract": true} ] }, { "id": "orders", "label": "OrderStore", "attributes": [ {"visibility": "+", "text": "name: string"}, {"visibility": "-", "text": "cache: Map"}, {"visibility": "#", "text": "limit: int"}, {"visibility": "~", "text": "version: int"} ], "methods": [ {"visibility": "+", "text": "find(id: string): Order"}, {"visibility": "+", "text": "open(): OrderStore", "static": true} ] } ], "relations": [ {"id": "orders-repository", "from": "orders", "to": "repository", "kind": "realization"} ]}

┌────────────────────────────┐
│ OrderStore │
┌──────────────────────────┐ ├────────────────────────────┤
│ «interface» │ │ + name: string │
│ Repository<T> │ │ - cache: Map │
├──────────────────────────┤◁╌╌╌│ # limit: int │
│ + find(id: string): T * │ │ ~ version: int │
│ + save(item: T) * │ ├────────────────────────────┤
└──────────────────────────┘ │ + find(id: string): Order │
│ + open(): OrderStore $ │
└────────────────────────────┘
Text art has no underline or italics, so it marks a static member with a $ suffix and an
abstract one with *, as in the art above.
Show only the members the reader needs. check reports god-class above 15 members, and
overlong-member for a member line over 40 characters, which widens the box.
Relations and how to choose
Section titled “Relations and how to choose”There are six kinds of relation. Pick by what the two classes mean to each other:
| Kind | Use it for | Drawn as |
|---|---|---|
inheritance |
a subtype of a supertype | a hollow triangle at the supertype |
realization |
a class implementing an interface | a dashed line, hollow triangle at the interface |
composition |
owned parts: the part cannot outlive the whole | a filled diamond at the whole |
aggregation |
shared parts: the part exists on its own | a hollow diamond at the whole |
dependency |
uses: a parameter, a call | a dashed line with an arrowhead |
association |
anything else (the default) | a plain line |
{ "type": "class", "direction": "RIGHT", "legend": true, "legend_labels": {"inheritance": "is a"}, "classes": [ {"id": "animal", "label": "Animal"}, {"id": "dog", "label": "Dog"}, {"id": "pet", "label": "Pet", "stereotype": "interface"}, {"id": "owner", "label": "Owner"}, {"id": "kennel", "label": "Kennel"}, {"id": "collar", "label": "Collar"}, {"id": "vet", "label": "Vet"} ], "relations": [ {"id": "dog-animal", "from": "dog", "to": "animal", "kind": "inheritance"}, {"id": "dog-pet", "from": "dog", "to": "pet", "kind": "realization"}, { "id": "kennel-dog", "from": "kennel", "to": "dog", "kind": "aggregation", "from_card": "1", "to_card": "*" }, { "id": "dog-collar", "from": "dog", "to": "collar", "kind": "composition", "from_card": "1", "to_card": "1" }, {"id": "vet-kennel", "from": "vet", "to": "kennel", "kind": "dependency"}, { "id": "owner-vet", "from": "owner", "to": "vet", "kind": "association", "from_card": "1", "to_card": "*" } ]}

┌────────┐
│ Animal │◁────────┐
└────────┘ │
│
│
┌──────────────┐ │ ┌──────┐
│ «interface» │ └──│ Dog │ 1 ┌────────┐
│ Pet │◁╌╌╌╌╌│ │◆───│ Collar │
└──────────────┘ ┌──│ │ 1 └────────┘
│ └──────┘
│ *
┌────────┐ * ┌──────┐ ┌────────┐ │
│ Owner │────│ Vet │╌╌╌►│ Kennel │◇────────┘
└────────┘ 1 └──────┘ └────────┘ 1
◇── aggregation
─── association
◆── composition
╌╌► dependency
◁── is a
◁╌╌ realization
When two classes could be joined by more than one kind, choose the one with the strongest
ownership that is true, and leave association for relations that fit none of the others.
Which end is from
Section titled “Which end is from”For inheritance and realization, from is the subtype (or the implementing class) and to
is the supertype or interface: dog-animal above reads “Dog inherits from Animal”. The engine
lays the supertype out first and draws the hollow triangle at its end. For the other kinds the
adornment sits at the from end of a composition or aggregation: from is the whole.
directed
Section titled “directed”directed puts an arrowhead at to. It is on by default for dependency and off for
association, and you may set it on an association to draw an arrowhead at to. It
is not allowed on the four adorned kinds (inheritance, realization, aggregation,
composition), whose adornment already says it.
Cardinalities
Section titled “Cardinalities”from_card and to_card are free text placed beside the wire ends: 1, *, 0..*. Use
them where multiplicity is the point, such as the 1 to * between Kennel and Dog.
Give every relation an id, as you would a flow edge, so that diago diff and
render -previous can match relations across versions.
Packages
Section titled “Packages”A package groups related classes in a labelled frame. It follows the same rules as a flow
group, under the key packages: nesting up to 3 levels and an
optional color. A package of one class only adds a frame, so give it at least 2.
{ "type": "class", "direction": "DOWN", "classes": [ {"id": "order", "label": "Order", "attributes": [{"visibility": "-", "text": "id: string"}]}, {"id": "line", "label": "OrderLine"}, { "id": "invoice", "label": "Invoice", "attributes": [{"visibility": "-", "text": "total: Money"}] }, {"id": "payment", "label": "Payment"} ], "relations": [ { "id": "order-line", "from": "order", "to": "line", "kind": "composition", "from_card": "1", "to_card": "*" }, { "id": "invoice-order", "from": "invoice", "to": "order", "kind": "association", "label": "bills" }, { "id": "invoice-payment", "from": "invoice", "to": "payment", "kind": "aggregation", "from_card": "1", "to_card": "*" } ], "packages": [ {"id": "sales", "label": "Sales", "contains": ["order", "line"]}, {"id": "billing", "label": "Billing", "color": "gray", "contains": ["invoice", "payment"]} ]}

┌─ Billing ─────────────────┐
│ │
│ ┌────────────────┐ │
│ │ Invoice │ │
│ ├────────────────┤ │
│ │ - total: Money │ │
│ └────────────────┘ │
│ │ ◇ 1 │
│ │ │ │
│ │ └────┐ │
│ │ │ * │
│ │ ┌──────────┐ │
│ │ │ Payment │ │
│ bills │ └──────────┘ │
└───────┼───────────────────┘
│
│
│
┌─ Sales ──┼─────────┐
│ │ │
│ ┌──────────────┐ │
│ │ Order │ │
│ ├──────────────┤ │
│ │ - id: string │ │
│ └──────────────┘ │
│ ◆ 1 │
│ │ │
│ │ * │
│ ┌────────────┐ │
│ │ OrderLine │ │
│ └────────────┘ │
└────────────────────┘
Use a package for a boundary that means something to the reader, and keep its label to one short word in text art, since a long one widens the frame.
The legend
Section titled “The legend”"legend": true adds one row per relation kind present, which helps once 3 or more kinds
appear and the reader may not know the notation. legend_labels overrides a row’s text: the
relations diagram above renames the inheritance row to is a. An empty value hides a row. In
text art the legend is printed under the diagram, as above.
For every field and value, see the class spec reference.