Skip to main content

One-to-many relationship using collections

Short answer

A one-to-many association is represented on the ‘one’ side with a collection (List, Set, Map) of references to the ‘many’ side. Generic classes (e.g., List<Employee>) provide compile-time type safety, avoid casting, and dynamic sizing. Use List for ordered, Set for unique, Map for key lookup; keep bidirectional consistency and return unmodifiable views.

During object oriented implementation of design class diagram you may encounter one-to-many relationships between classes. With the help of collection and generic classes, explain how you can represent these relationships in object oriented programming.

A one-to-many association in a class diagram (for example, one Department has many Employees) cannot be stored in a single reference. The "one" side must hold a collection of references to the "many" side.

 +------------+ 1       * +----------+
 | Department |-----------| Employee |
 +------------+           +----------+
 Department has List<Employee>

Collections and generics

  • The Java Collections Framework (List, ArrayList, Set, HashSet, Map) and its C# counterparts (List<T>, Dictionary<K,V>) provide dynamic containers that grow as needed (unlike fixed-size arrays).
  • Generic classes (List<Employee>) fix the element type at compile time, so no casting is needed and wrong types are rejected by the compiler (type safety).
  • Choice: use List if order matters or duplicates are allowed, Set if elements must be unique, and Map<K,V> if lookup by key (e.g. by employee id) is needed.

Implementation

import java.util.*;

class Employee {
    private String name;
    private Department dept;          // optional back reference (many-to-1)
    public Employee(String name) { this.name = name; }
    public String getName() { return name; }
    void setDept(Department d) { dept = d; }
}

class Department {
    private String name;
    private List<Employee> employees = new ArrayList<>();   // 1 -> *
    public Department(String name) { this.name = name; }

    public void addEmployee(Employee e) {
        employees.add(e);
        e.setDept(this);               // keep both ends consistent
    }
    public void removeEmployee(Employee e) {
        if (employees.remove(e)) e.setDept(null);
    }
    public List<Employee> getEmployees() {
        return Collections.unmodifiableList(employees);  // protect internals
    }
}

Points:

  • The collection is created in the constructor or field initialiser (multiplicity 0..* allows an empty list).
  • For 1..*, the constructor should require at least one element.
  • Maintain both ends if the association is bidirectional.
  • Return an unmodifiable view or a copy to preserve encapsulation.
  • For a bounded multiplicity such as 0..30, check the size in add... and throw an exception when it would exceed the limit.

✓ Answer checked by Claude Opus 5.5 (high effort)

All Object Oriented Analysis and Design chapter 4 questions →