Skip to content
IRC-Coding IRC-Coding
Class Relationships Association Aggregation Composition Inheritance

OOP Class Relationships: Association, Aggregation, Composition

Master OOP class relationships: association, aggregation, composition & inheritance with practical examples and UML diagrams.

S

schutzgeist

2 min read

OOP Class Relationships: Association, Aggregation, Composition & Inheritance

This article is a comprehensive explanation of class relationships in OOP – including association, aggregation, composition and inheritance with practical examples.

In a Nutshell

Class relationships describe how objects interact and work together to form complex systems. The four main relationship types are association, aggregation, composition, and inheritance.

Compact Technical Description

Class relationships define the way classes and their objects are connected to each other. They are fundamental to the structure of object-oriented systems.

Four main relationship types:

1. Association (has-a)

  • Description: Two classes are connected to each other
  • Lifecycle: Independent of each other
  • Example: Customer has Orders
  • UML: Simple line between classes

2. Aggregation (consists-of)

  • Description: “has-a” relationship, parts can exist independently
  • Lifecycle: Part can exist without the whole
  • Example: Car has Tires
  • UML: Line with empty diamond at the whole

3. Composition (is-part-of)

  • Description: “is-part-of” relationship, parts exist only with the whole
  • Lifecycle: Part cannot exist without the whole
  • Example: Car has Engine
  • UML: Line with filled diamond at the whole

4. Inheritance (is-a)

  • Description: “is-a” relationship, specialization
  • Lifecycle: Subclass inherits from superclass
  • Example: Car is a Vehicle
  • UML: Line with empty arrow to superclass

Exam-Relevant Key Points

  • Association: Simple relationship between classes
  • Aggregation: “has-a” relationship with independent parts
  • Composition: “is-part-of” relationship with dependent parts
  • Inheritance: “is-a” relationship with specialization
  • Multiplicities: 1, , 0..1, 1.., 0..*
  • UML Notation: Different arrows and diamond symbols
  • Lifecycle: Dependency of objects to each other
  • IHK-relevant: Important for software architecture and design

Core Components

  1. Association: Bidirectional or unidirectional relationship
  2. Aggregation: Weak “has-a” relationship
  3. Composition: Strong “is-part-of” relationship
  4. Inheritance: Specialization and reuse
  5. Multiplicity: Number of relationship instances
  6. Roles: Designation of the relationship role
  7. Navigability: Direction of the relationship
  8. Qualifiers: Additional information about the relationship

Practical Examples

1. Association (Customer - Order)

// Bidirectional association
public class Kunde {
    private String kundenId;
    private String name;
    private List<Bestellung> bestellungen = new ArrayList<>();
    
    public void addBestellung(Bestellung bestellung) {
        bestellungen.add(bestellung);
        bestellung.setKunde(this); // Back reference
    }
    
    public List<Bestellung> getBestellungen() {
        return new ArrayList<>(bestellungen);
    }
}

public class Bestellung {
    private String bestellId;
    private Date bestelldatum;
    private Kunde kunde; // Back reference to customer
    
    public void setKunde(Kunde kunde) {
        this.kunde = kunde;
    }
    
    public Kunde getKunde() {
        return kunde;
    }
}

// Usage
Kunde meier = new Kunde("1", "Meier");
Bestellung b1 = new Bestellung("B001", new Date());
Bestellung b2 = new Bestellung("B002", new Date());

meier.addBestellung(b1);
meier.addBestellung(b2);

2. Aggregation (Car - Tires)

// Aggregation: Car has tires, tires can exist without car
public class Auto {
    private String modell;
    private List<Reifen> reifen = new ArrayList<>();
    
    public Auto(String modell) {
        this.modell = modell;
    }
    
    public void addReifen(Reifen reifen) {
        if (reifen.size() < 4) {
            this.reifen.add(reifen);
        }
    }
    
    public void removeReifen(Reifen reifen) {
        this.reifen.remove(reifen);
        // Tire continues to exist and can be assigned to another car
    }
}

public class Reifen {
    private String hersteller;
    private int groesse;
    
    public Reifen(String hersteller, int groesse) {
        this.hersteller = hersteller;
        this.groesse = groesse;
    }
    
    // Tire can exist independently of the car
    public void montieren() {
        System.out.println("Tire is being mounted");
    }
}

// Usage
Auto golf = new Auto("Golf");
Reifen michelin1 = new Reifen("Michelin", 195);
Reifen michelin2 = new Reifen("Michelin", 195);

golf.addReifen(michelin1);
golf.addReifen(michelin2);

// Tires can be removed and reused
golf.removeReifen(michelin1);

3. Composition (Car - Engine)

// Composition: Engine exists only with car
public class Auto {
    private String modell;
    private Motor motor; // Engine cannot exist without car
    
    public Auto(String modell, int leistung) {
        this.modell = modell;
        this.motor = new Motor(leistung); // Engine is created internally
    }
    
    public void starten() {
        motor.starten();
        System.out.println(modell + " is starting");
    }
    
    public void ausschalten() {
        motor.ausschalten();
        System.out.println(modell + " is shutting down");
    }
    
    // Engine is destroyed with car
    protected void finalize() {
        // Engine is automatically cleaned up
    }
}

public class Motor {
    private int leistung;
    private boolean laeuft;
    
    // Private constructor - only car can create engine
    protected Motor(int leistung) {
        this.leistung = leistung;
        this.laeuft = false;
    }
    
    protected void starten() {
        this.laeuft = true;
        System.out.println("Engine with " + leistung + " hp is starting");
    }
    
    protected void ausschalten() {
        this.laeuft = false;
        System.out.println("Engine is shutting down");
    }
}

// Usage
Auto bmw = new Auto("BMW", 200);
bmw.starten(); // Engine is started internally
bmw.ausschalten();

// Engine cannot be created independently:
// Motor motor = new Motor(150); // Error: Constructor is protected

4. Inheritance (Vehicle - Car)

// Superclass
public abstract class Fahrzeug {
    protected String marke;
    protected int baujahr;
    protected int aktuelleGeschwindigkeit = 0;
    
    public Fahrzeug(String marke, int baujahr) {
        this.marke = marke;
        this.baujahr = baujahr;
    }
    
    // Common methods
    public void beschleunigen(int kmh) {
        this.aktuelleGeschwindigkeit += kmh;
        System.out.println(marke + " accelerates to " + aktuelleGeschwindigkeit + " km/h");
    }
    
    public void bremsen(int kmh) {
        if (aktuelleGeschwindigkeit >= kmh) {
            this.aktuelleGeschwindigkeit -= kmh;
            System.out.println(marke + " brakes to " + aktuelleGeschwindigkeit + " km/h");
        }
    }
    
    // Abstract method - must be implemented by subclasses
    public abstract void hupen();
    
    // Concrete method - can be overridden
    public void anzeigen() {
        System.out.println("Vehicle: " + marke + ", Year: " + baujahr + 
                          ", Speed: " + aktuelleGeschwindigkeit + " km/h");
    }
}

// Subclass
public class Auto extends Fahrzeug {
    private int anzahlTueren;
    private boolean klimaanlage;
    
    public Auto(String marke, int baujahr, int anzahlTueren) {
        super(marke, baujahr); // Call superclass constructor
        this.anzahlTueren = anzahlTueren;
        this.klimaanlage = false;
    }
    
    // Implementation of abstract method
    @Override
    public void hupen() {
        System.out.println("Car honks: Honk Honk!");
    }
    
    // Additional method only for car
    public void klimaanlageEin() {
        klimaanlage = true;
        System.out.println("Air conditioning turned on");
    }
    
    // Override superclass method
    @Override
    public void anzeigen() {
        super.anzeigen(); // Call superclass method
        System.out.println("  Type: Car, Doors: " + anzahlTueren + 
                          ", Air conditioning: " + (klimaanlage ? "on" : "off"));
    }
}

// Further subclass
public class Motorrad extends Fahrzeug {
    private boolean hatSeitenwagen;
    
    public Motorrad(String marke, int baujahr, boolean hatSeitenwagen) {
        super(marke, baujahr);
        this.hatSeitenwagen = hatSeitenwagen;
    }
    
    @Override
    public void hupen() {
        System.out.println("Motorcycle honks: Beep Beep!");
    }
    
    public void wheelie() {
        System.out.println("Motorcycle does a wheelie!");
    }
    
    @Override
    public void anzeigen() {
        super.anzeigen();
        System.out.println("  Type: Motorcycle, Sidecar: " + 
                          (hatSeitenwagen ? "yes" : "no"));
    }
}

// Usage
Fahrzeug golf = new Auto("Volkswagen", 2023, 5);
Fahrzeug harley = new Motorrad("Harley-Davidson", 2022, false);

golf.hupen();      // Car honks: Honk Honk!
harley.hupen();   // Motorcycle honks: Beep Beep!

golf.beschleunigen(50);
harley.beschleunigen(80);

golf.anzeigen();
harley.anzeigen();

// Downcasting for specific methods
if (golf instanceof Auto) {
    Auto autoGolf = (Auto) golf;
    autoGolf.klimaanlageEin();
}

if (harley instanceof Motorrad) {
    Motorrad motorradHarley = (Motorrad) harley;
    motorradHarley.wheelie();
}

UML Notation for Relationships

Association

Kunde 1..* --* Bestellung

Aggregation

Auto 1 --* Reifen

Composition

Auto 1 --* Motor

Inheritance

Fahrzeug <|-- Auto
Fahrzeug <|-- Motorrad

Multiplicities

SymbolMeaningExample
1Exactly one1 Motor
0..1Zero or one0..1 Führerschein
*Zero or more* Reifen
1..*At least one1..* Türen
2..4Between 2 and 42..4 Räder

Decision Aid for Relationship Types

When to use which relationship?

Use association when:

  • Two classes interact but there is no dependency
  • Relationship is temporary or optional
  • Objects exist independently of each other

Use aggregation when:

  • “has-a” relationship exists
  • Parts can exist without the whole
  • Parts can be shared between different wholes

Use composition when:

  • “is-part-of” relationship exists
  • Parts exist only with the whole
  • Lifecycle of the part is bound to the whole

Use inheritance when:

  • “is-a” relationship exists
  • Subclass is a special form of the superclass
  • Code reuse and polymorphism are desired

Advantages and Disadvantages

Advantages of class relationships

  • Structure: Clear system architecture
  • Reusability: Shared functionality
  • Flexibility: Easy to extend
  • Comprehensibility: Real world is mapped
  • Maintainability: Targeted changes possible

Disadvantages

  • Complexity: Many relationships can become confusing
  • Coupling: Strong dependencies can cause problems
  • Performance: Too many object connections can be slow
  • Testability: Complex relationships are hard to test

Common Exam Questions

  1. What is the difference between aggregation and composition? Aggregation: Parts can exist independently, composition: Parts exist only with the whole.

  2. Explain the multiplicity 1..*! At least one, any number of objects can be connected.

  3. When do you use inheritance instead of composition? When an “is-a” relationship exists and code reuse is desired.

  4. What does bidirectional association mean? Both classes know each other and can access one another.

Most Important Sources

  1. https://de.wikipedia.org/wiki/Assoziation_(UML)
  2. https://refactoring.guru/design-patterns/composition-over-inheritance
  3. https://www.uml-diagrams.org/class-diagram-relationships.html
Back to Blog
Share:

Related Posts