Kolekce a asociace (1:N, M:N)

Proč to potřebuji?

Většina reálných vztahů mezi objekty má kardinalitu vyšší než 1:1. Kolekce jsou nezbytným nástrojem pro implementaci vztahů 1:N a M:N, které najdete prakticky v každé aplikaci.

Teorie

Vztah 1:N se implementuje tak, že strana „1" drží kolekci (typicky List) odkazů na stranu „N". Vztah M:N vyžaduje kolekci na obou stranách, nebo pomocnou třídu (vazební entita).

Agregace: objekt je přidáván zvenčí (předán jako parametr). Kompozice: objekt je vytvářen uvnitř vlastníka.

Příklady

// === 1:N – Kurz má mnoho studentů ===
public class Kurz {
    private String nazev;
    private List<Student> studenti = new ArrayList<>();

    public Kurz(String nazev) {
        this.nazev = nazev;
    }

    public void zapisStudenta(Student s) {
        if (!studenti.contains(s)) {
            studenti.add(s);
        }
    }

    public void odhlasStudenta(Student s) {
        studenti.remove(s);
    }

    public List<Student> getStudenti() {
        return Collections.unmodifiableList(studenti); // ochrana
    }
}

// === M:N – Student může mít více kurzů, kurz více studentů ===
public class Student {
    private String jmeno;
    private List<Kurz> kurzy = new ArrayList<>();

    public Student(String jmeno) {
        this.jmeno = jmeno;
    }

    public void zapisDoKurzu(Kurz k) {
        if (!kurzy.contains(k)) {
            kurzy.add(k);
            k.zapisStudenta(this); // obousměrná vazba
        }
    }
}

// === Kompozice – Objednávka vlastní své položky ===
public class Objednavka {
    private List<Polozka> polozky = new ArrayList<>();

    // Položka se VYTVÁŘÍ uvnitř – kompozice
    public void pridejPolozku(String nazev, int pocet) {
        polozky.add(new Polozka(nazev, pocet));
    }

    // Vnitřní třída – zdůrazňuje vlastnictví
    private static class Polozka {
        String nazev;
        int pocet;
        Polozka(String nazev, int pocet) {
            this.nazev = nazev;
            this.pocet = pocet;
        }
    }
}

Shrnutí

Klíčové body

  • 1:N → List<T> na straně „1"
  • M:N → kolekce na obou stranách + synchronizace obou směrů
  • Agregace = objekt přijat zvenčí, Kompozice = vytvořen uvnitř
  • Collections.unmodifiableList() chrání interní kolekci