Beginner14 min readUML & Diagramminglive prototype

Relationship Notation

The lines between boxes carry as much meaning as the boxes. This is the decoder for the six connectors — association, dependency, aggregation, composition, generalization, realization — and how to pick the right one.

The idea

What it is

In a class diagram the boxes get all the attention, but the lines between them carry just as much meaning. A line tells you whether two classes barely know each other, share a part, or live and die together. Get the line wrong and you've described a different design. This lesson is a decoder for the six connector notations, lined up from loosest to tightest.

Think of relationships between people. An acquaintance you just know (association). Someone you borrow a tool from once (dependency). A club you belong to — it can disband and you carry on (aggregation). Your body and its organs — they don't survive without you (composition). Being a kind of something — a doctor is a person (generalization). And promising to do a job — you sign a contract to deliver (realization). Same idea, six strengths of tie.

The one sentence to remember

To identify any relationship, read just two things: the line style (solid or dashed) and the end shape (plain · open arrow · diamond ◇◆ · triangle ▷). Those two facts alone name all six.

Mechanics

How it works

Read two facts, name the line

Every connector is built from two choices. The line style is solid or dashed. The end shape is one of: nothing, an open arrowhead, a diamond (hollow ◇ or filled ◆), or a hollow triangle ▷. Decode those two and you've named the relationship. Here is the whole family on one card:

THE SIX CONNECTORS loosest → tightest 1 · Association A knows / uses B (a field) A B 2 · Dependency A uses B briefly (a parameter) A B 3 · Aggregation has-a; parts survive alone Whole Part 4 · Composition owns-a; parts die with whole Whole Part 5 · Generalization is-a (extends) Child Parent 6 · Realization implements a contract Class Iface
Read any connector by its line style (solid vs dashed) and its end shape (open arrow / hollow vs filled diamond / hollow triangle) — that pair alone names the relationship.

1 · Association — a plain solid line

The loosest structural tie. One class knows about and uses another, usually by holding a reference to it as a field. No ownership, no shared fate — just a lasting link.

  • Notation: a plain solid line, no end shape. An optional open arrow on one end shows navigability (which way you can reach the other), and small numbers at the ends show multiplicity (1, 0..1, *, 1..*).
  • Example: an Order keeps a reference to its Customer. Both exist independently; the order just knows its customer.
  • Code form: a stored field — class Order { customer: Customer }.

2 · Dependency — dashed line, open arrow

The most fleeting tie. Class A uses B only for a moment — B is passed in as a method parameter, created as a local variable, or returned. When the method ends, the link is gone.

  • Notation: a dashed line with an open (unfilled) arrowhead pointing at the class being used.
  • Example: placeOrder(gateway: PaymentGateway) takes a PaymentGateway just to charge once. Order doesn't keep it.
  • Code form: a method parameter, local variable, or return type — not a stored field.

3 · Aggregation — solid line, hollow ◇ diamond

A whole–part tie where the parts have an independent lifetime. The whole has the parts, but they were not created by it and survive without it. They may even be shared by several wholes.

  • Notation: a solid line with a hollow ◇ diamond sitting on the whole (the container).
  • Example: a Team ◇── Player. Disband the team and the players still exist — they can join another team.
  • Code form: a part passed in and stored — class Team { constructor(players: Player[]) {...} }. The team didn't make the players.

4 · Composition — solid line, filled ◆ diamond

The tightest whole–part tie. The whole owns the parts exclusively, and they share one lifetime: created with the whole, destroyed with it. No sharing.

  • Notation: a solid line with a filled ◆ diamond on the whole.
  • Example: a House ◆── Room. Demolish the house and the rooms are gone too; a room belongs to exactly one house.
  • Code form: the part created inside the whole — class House { rooms = [new Room()] }. Born and dying together.

5 · Generalization / Inheritance — solid line, hollow ▷ triangle

The "is-a" tie. A child class is a kind of its parent and reuses the parent's members. This is plain class-to-class inheritance.

  • Notation: a solid line with a hollow ▷ triangle pointing at the parent.
  • Example: SavingsAccount ──▷ Account. A savings account is an account.
  • Code form: class SavingsAccount extends Account.

6 · Realization / Implementation — dashed line, hollow ▷ triangle

The contract tie. A class promises to fulfil an interface — it provides all the methods the interface lists. It looks like inheritance but the line is dashed, because the class isn't a kind of the interface, it just keeps its promise.

  • Notation: a dashed line with a hollow ▷ triangle pointing at the interface.
  • Example: ArrayList ⇠▷ «interface» List. ArrayList implements List.
  • Code form: class ArrayList implements List.

Two memory tricks that decode everything

(a) Line style: dashed = a looser, temporary use or a contract (dependency, realization); solid = a stronger, structural tie (the other four). (b) Diamond: the diamond always sits on the whole, never the part. Hollow ◇ = parts survive (aggregation); filled ◆ = parts die with the whole (composition) — filled means a stronger, single-fate bond.

The two most-confused pairs

Aggregation ◇ vs composition ◆: both are has-a; ask “if I destroy the whole, do the parts die?” — yes ⇒ composition (filled), no ⇒ aggregation (hollow). Dependency vs association: both mean uses; ask “does the class keep a reference?” — a stored field is association (solid line); a one-off parameter or local is dependency (dashed arrow).

Interactive prototype

See it. Build it. Break it.

A sandboxed, hands-on simulation — no setup, no install. Play with it as you read.

About this simulation

A decoder quiz. You read a plain-English statement — “A House is made of Rooms; demolish the house and the rooms go too.” — then click which of the six notations matches, each drawn as a tiny picture of its real line and end-shape. One fixed-height panel flips to ✓ or ✗ and explains why (filled diamond = parts die with the whole). Next › walks you through six statements covering all six relationships, with a running score. Nothing scrolls away or grows the page.

Hands-on

Try these yourself

Open the prototype above, predict what happens, then verify.

try 01

Decode by the two facts

Open the prototype and read the first statement before clicking. For each notation choice, name its two facts out loud — “solid line, filled diamond” or “dashed line, open arrow.” Pick the one whose two facts match the meaning. The verdict panel confirms whether your decode was right.

try 02

Nail the diamond pair

Find the two diamond statements — the House/Rooms one and the Team/Players one. Both are "has-a", so the only question is shared fate. Ask “if the whole is destroyed, do the parts die?” House → yes → composition ◆. Team → no → aggregation ◇. Getting this back-to-back burns in the difference.

try 03

Tell dashed from solid

Compare the SavingsAccount is a BankAccount statement with the ArrayList implements List one. Both use a triangle ▷ — but one is solid (generalization, real inheritance) and one is dashed (realization, a contract). Pick wrong on purpose once to read why the dashes change the meaning.

In practice

When to use it — and what trips people up

When this notation earns its keep

Any time you draw or read a class diagram, the connectors are how you record intent. They also settle real arguments in design and code review — “does the order own the customer, or just reference it?” is a question about which line to draw. And in interviews, picking the right connector shows you understand ownership and lifetime, not just class names.

Where it pays off

Use it whenever you sketch or read a class diagram; to settle code-review arguments about ownership and lifetime; and in interviews, where getting aggregation ◇ vs composition ◆ right is a classic question that quietly separates beginners from people who think in terms of object lifetimes.

What it gives you

  • A precise, shared vocabulary — one line communicates ownership, lifetime, and direction at a glance.
  • Forces the right design question early: who owns what, and for how long?
  • Maps cleanly to code — a field, a parameter, extends, implements each have a known line.
  • Decodable from just two facts (line style + end shape), so it's quick to read once learned.

Common mistakes

  • People routinely confuse aggregation and composition — the two diamonds look almost identical.
  • Aggregation vs composition is sometimes genuinely debatable; reasonable engineers disagree on lifetimes.
  • Dashed-vs-solid and diamond-end details are easy to get backwards until practised.
  • Over-precise connectors can imply more certainty about a design than you actually have.

Reference

Code & further reading

A minimal reference implementation and pointers worth bookmarking.

// All six relationships in one file. The comment on each shows the notation.
interface PaymentGateway { charge(amount: number): void; } // an interface to implement

// 5. Generalization (is-a): solid line, hollow ▷ triangle  →  extends
class Account { protected balance = 0; }
class SavingsAccount extends Account { rate = 0.04; }

// 6. Realization (implements a contract): DASHED line, hollow ▷ triangle  →  implements
class StripeGateway implements PaymentGateway {
  charge(amount: number): void { /* ... */ }
}

class Customer { name = ""; }
class Player { name = ""; }
class Room { constructor(public name: string) {} }

class Order {
  // 1. Association (knows-a): solid line — a STORED field reference
  customer: Customer;
  constructor(customer: Customer) { this.customer = customer; }

  // 2. Dependency (uses briefly): dashed line, open arrow — a PARAMETER, not stored
  placeOrder(gateway: PaymentGateway): void { gateway.charge(100); }
}

class Team {
  // 3. Aggregation (has-a, parts survive): hollow ◇ — players PASSED IN and stored
  constructor(public players: Player[]) {}
}

class House {
  // 4. Composition (owns-a, parts die with whole): filled ◆ — rooms MADE inside
  private rooms: Room[] = [new Room("kitchen"), new Room("bath")];
}

References & further reading

5 sources

Knowledge check

Did it land?

Quick questions, answers revealed on submit. Sign in to save your best score.

question 01 / 05

A House is composed of Rooms; if the house is demolished, its rooms cease to exist. Which notation models this?

question 02 / 05

A Team has Players, but if the team disbands the players still exist and can join another team. Which notation fits?

question 03 / 05

ArrayList implements the List interface. Which notation is correct — and how does it differ from SavingsAccount extends Account?

question 04 / 05

placeOrder(gateway: PaymentGateway) takes a PaymentGateway as a parameter, uses it to charge once, and never stores it. Which line?

question 05 / 05

You only know two facts about a connector: the line is DASHED and the end is an OPEN ARROWHEAD (no diamond, no triangle). Which relationship is it?

0/5 answered