Card 04/ 08
From Class Diagram to Code in Python, Java and TypeScript
The same boxes and arrows, written three ways.
Each arrow in a class diagram has a usual form in code, and writing one diagram in three languages shows which parts are the notation and which are the language. This card takes a small order system with five of the six relationships and writes it in Python, Java and TypeScript, with each relationship's line highlighted.
The order system in three languages
from typing import Protocol
class Notifier(Protocol):
def send(self, text: str) -> None: ...
class EmailNotifier(Notifier):
def send(self, text: str) -> None:
print(f"email: {text}")
class OrderLine:
def __init__(self, name: str, price: float) -> None:
self.name = name
self.price = price
class Order:
def __init__(self) -> None:
self._lines: list[OrderLine] = []
def add_line(self, name: str, price: float) -> None:
self._lines.append(OrderLine(name, price))
def total(self) -> float:
return sum(line.price for line in self._lines)
class PriorityOrder(Order):
def total(self) -> float:
return super().total() + 5.0
class Checkout:
def __init__(self, notifier: Notifier) -> None:
self._notifier = notifier
def place(self, order: Order) -> None:
self._notifier.send(f"order placed, total {order.total():.2f}")
order = PriorityOrder()
order.add_line("book", 12.5)
order.add_line("pen", 2.5)
Checkout(EmailNotifier()).place(order)email: order placed, total 20.00import java.util.ArrayList;
import java.util.List;
public class UmlToCode {
public static void main(String[] args) {
Order order = new PriorityOrder();
order.addLine("book", 12.5);
order.addLine("pen", 2.5);
new Checkout(new EmailNotifier()).place(order);
}
}
interface Notifier {
void send(String text);
}
class EmailNotifier implements Notifier {
public void send(String text) {
System.out.println("email: " + text);
}
}
class OrderLine {
final String name;
final double price;
OrderLine(String name, double price) {
this.name = name;
this.price = price;
}
}
class Order {
private final List<OrderLine> lines = new ArrayList<>();
void addLine(String name, double price) {
lines.add(new OrderLine(name, price));
}
double total() {
return lines.stream().mapToDouble(line -> line.price).sum();
}
}
class PriorityOrder extends Order {
@Override
double total() {
return super.total() + 5.0;
}
}
class Checkout {
private final Notifier notifier;
Checkout(Notifier notifier) {
this.notifier = notifier;
}
void place(Order order) {
notifier.send(String.format("order placed, total %.2f", order.total()));
}
}email: order placed, total 20.00interface Notifier {
send(text: string): void;
}
class EmailNotifier implements Notifier {
send(text: string): void {
console.log(`email: ${text}`);
}
}
class OrderLine {
constructor(readonly name: string, readonly price: number) {}
}
class Order {
private readonly lines: OrderLine[] = [];
addLine(name: string, price: number): void {
this.lines.push(new OrderLine(name, price));
}
total(): number {
return this.lines.reduce((sum, line) => sum + line.price, 0);
}
}
class PriorityOrder extends Order {
total(): number {
return super.total() + 5.0;
}
}
class Checkout {
constructor(private readonly notifier: Notifier) {}
place(order: Order): void {
this.notifier.send(`order placed, total ${order.total().toFixed(2)}`);
}
}
const order = new PriorityOrder();
order.addLine("book", 12.5);
order.addLine("pen", 2.5);
new Checkout(new EmailNotifier()).place(order);email: order placed, total 20.00The highlighted lines are the arrows, in the same order in each language:
- Realisation is the implementing declaration:
class EmailNotifier(Notifier)in Python,implements Notifierin Java and TypeScript. - Composition is
Ordercreating eachOrderLineitself, insideadd_line. No other object ever holds a line, so the lines go when the order does. - Inheritance is
PriorityOrdernamingOrderas its parent and overridingtotal. - Association is the
notifierfield, set once in the constructor and kept. - Dependency is the
orderparameter ofplace.Checkoutuses the order for one call and keeps no reference to it.
The diagram does not say how a language spells privacy. Java and TypeScript enforce private; Python marks it with a leading underscore and trusts the reader. All three print the same line, because the structure is the same.
Aggregation is the one relationship missing. It would look like composition with one change: the parts arrive as parameters from outside instead of being created inside, so they can outlive the whole.
← → move through sections and cards