Realization
Realization is the odd one out on this page: every other relationship connects two
concrete classes, but realization connects a class to an interface. It's the
"implements" arrow - a Circle realizing a Shape, an Invoice realizing a Payable
- and it's worth a page of its own because it's the one relationship that's a binding contract rather than a casual link, and the one most often confused with its closest neighbour: plain old inheritance.
Definition: fulfilling a contract, not borrowing an implementation
A class realizes an interface by providing a concrete method body for every method the interface declares. The interface states what must exist; the class decides how. Nothing about the interface's (nonexistent) implementation gets inherited - there's nothing to inherit, since an interface has no method bodies and no state to begin with:
Invoice promised to have an amountDue() method that returns a double, and it wrote
every line of that method itself. Payable supplied the shape of the promise; Invoice
supplied all of the substance.
UML notation
Realization draws as a dashed line with a hollow (unfilled) triangle arrowhead pointing at the interface - the same triangle shape used for generalization (inheritance), but on a dashed line instead of a solid one. That's the entire visual difference, and it's exactly backwards from what people expect: the stronger-looking solid line is the weaker binding (see below), while the lighter-looking dashed line is the one that breaks compilation if you get it wrong.
One class can realize several interfaces at once - a SubscriptionPlan could just as
easily implement Payable alongside Invoice, each providing its own unrelated
amountDue() body, and the diagram would simply show two dashed arrows leaving two
different classes toward the same interface box.
Multiplicity - not applicable here either
Like dependency, realization isn't counting instances of anything - a class either realizes an interface or it doesn't, and that's a static, compile-time fact about the class's declaration, not a runtime count of connected objects. You won't see multiplicity written on a realization arrow for the same reason you won't see it on a generalization arrow: both describe a class's type, not a collection of related objects.
Directionality
Realization is always unidirectional, from the implementing class to the interface -
Invoice knows about Payable, but Payable has no idea Invoice exists, let alone
how many classes realize it. This mirrors generalization exactly: a subclass knows its
superclass, never the reverse.
Telling realization apart from generalization (extends)
This is the comparison that actually matters, because the two relationships look similar (both use a triangle arrowhead) and both often show up between a class and something more abstract above it. The test: does the subtype inherit any concrete implementation or state, or only an obligation to have certain methods?
- Generalization (extends):
Invoice extends BillingDocumentinheritsBillingDocument'sidfield and whatever concrete method bodiesBillingDocumentalready wrote (itsdescribe()default, if it has one). The subclass gets real, reusable code for free. - Realization (implements):
Invoice implements Payableinherits nothing but an obligation -Payablehas no fields and no method bodies to hand down.InvoicewritesamountDue()completely from scratch; the interface only guaranteed that a method with that name and signature would exist somewhere.
Put differently: generalization shares code down a solid line because the subclass is a specialization of its parent. Realization shares nothing but a promise down a dashed line because the implementing class behaves as the interface requires, without being any kind of specialization of it.
Telling realization apart from dependency
A class that merely takes an interface as a parameter type has a dependency on it,
not a realization - PriceEngine.apply(Payable item) depends on Payable without
promising to ever implement it. Realization is reserved specifically for the class on
the other side of that relationship: the one that wrote the method bodies. The
practical difference in stakes is real: drop a dependency and, at worst, you delete a
parameter and adjust a call site. Drop a method a realized interface requires and the
class does not compile - a dependency can be walked away from casually, a
realization cannot.
Worked example
total never mentions Invoice or SubscriptionPlan by name. Both classes realized
Payable independently, wrote completely different math inside amountDue(), and are
now interchangeable everywhere the interface is the declared type - which is the whole
reason to reach for realization over a shared abstract base class when the
implementations genuinely have nothing in common but that one method's signature.
Common mistakes
- Drawing a solid line for "implements." The line must be dashed - a solid triangle line is reserved for generalization, and mixing them up tells the reader the wrong story about how much code is actually shared.
- Using an abstract class purely to fake an interface, then treating it as
realization. If
BillingDocumenthad zero fields and zero method bodies - only abstract method signatures - it's functionally acting like an interface, and calling the relationship "generalization" instead of "realization" is a modeling choice that hides how little is actually being inherited. Prefer an actual interface when there's no state or default behavior to share. - Fulfilling the contract with a body that throws. A method that satisfies the
compiler with
throw new UnsupportedOperationException()technically realizes the interface, but breaks the promise realization is supposed to represent for any caller that trusts the interface's contract - a Liskov substitution violation wearing a realization's clothing.
Try it yourself: model a Comparable interface with one method,
compareTo(other): int, realized by a Money class that compares by amount. Then ask:
if Money also extended an abstract Currency base class for shared formatting logic,
which of the two relationships on that diagram would break compilation if you deleted
the method body, and which would just mean losing some free formatting code?
Check yourself
What UML notation distinguishes realization from generalization, given that both use a triangle arrowhead?