IS-A, HAS-A and Object Lifetime

OOP · lesson 32 of 43 · 3 min read

Association, aggregation and composition: who owns whom, and what still exists when the owner is gone.

Open this lesson in the learning hub

Key points

  • IS-A is inheritance; HAS-A is a field. Most real models are almost all HAS-A with very little inheritance.
  • Composition: the whole creates and owns the part. Drop the order and its lines go with it, because nothing else held them.
  • Aggregation: the whole holds a part it did not create. Drop the order and the customer carries on existing.
  • Association: it simply uses another object, usually one handed to a method, and keeps no field for it at all.
  • Choose by lifetime: if the part cannot outlive the whole, build it inside; otherwise take it through the constructor.
  • Keep an owned collection private and never hand it back raw, or the ownership you just modelled leaks away.

Example

import java.util.ArrayList;
import java.util.List;

public class Main {

    record Customer(String name) { }

    interface Printer { String render(String who, int cents); }

    static final class Order {
        // COMPOSITION: the Order creates its lines and nobody else can hold them.
        private final List<Line> lines = new ArrayList<>();
        // AGGREGATION: the customer is passed in and outlives this order.
        private final Customer customer;

        Order(Customer customer) { this.customer = customer; }

        void add(String item, int cents) { lines.add(new Line(item, cents)); }

        int total() {
            int sum = 0;
            for (Line line : lines) sum += line.cents();
            return sum;
        }

        // ASSOCIATION: it uses a Printer for one call and keeps no field for it.
        String print(Printer printer) { return printer.render(customer.name(), total()); }

        record Line(String item, int cents) { }
    }

    public static void main(String[] args) {
        Customer ada = new Customer("Ada");

        Order order = new Order(ada);
        order.add("keyboard", 4500);
        order.add("cable", 900);

        System.out.println(order.print((who, cents) -> who + " owes " + cents + " cents"));

        // The order owns its lines: no caller can reach them or share them.
        // The customer is only referenced, so she outlives every order.
        System.out.println("customer still here: " + ada);
    }
}

Model the relationship by lifetime and ownership, not by what is quickest to type.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the OOP course, and every lesson in it is listed on the OOP contents page.