Autor: HM_JDSZielgruppe: Sek I

Attribute, Kapselung, Setter und Getter

Das zugehoerige Arbeitsblatt ist als Mini-Projekt "Geometrische Figuren" aufgebaut. Die zentrale Aufgabe lautet dort: fehlende Setter und Getter ergaenzen und dadurch ein bereits vorbereitetes Klassenpaket vervollstaendigen. Dieses Kapitel macht aus dieser Aufgabenidee eine systematische OOP-Einheit.

Warum Kapselung unverzichtbar ist

Objekte sollen intern konsistent bleiben. Wenn Attribute beliebig von aussen veraendert werden koennen, treten schnell Fehler auf:

  • negative Laengen oder Radien
  • ungueltige Koordinaten
  • widerspruechliche Zustandskombinationen

Darum gilt als Standardregel:

  • Attribute moeglichst private
  • Zugriff ueber Methoden mit klarer Bedeutung
  • Pruefungen beim Setzen von Werten

Kapselung ist kein "Extra", sondern die Grundlage fuer robuste Objektmodelle.

Rolle von Attributen

Attribute speichern den Zustand eines Objekts. Im Figurenkontext sind typische Attribute:

  • Position (x, y)
  • Groessenwerte (radius, breite, hoehe)
  • Sichtbarkeit (sichtbar)
  • Farbe oder Linienstaerke

Wichtig ist die Frage: Welche dieser Daten duerfen direkt aenderbar sein, welche nur ueber kontrollierte Methoden?

Getter und Setter als Schnittstelle

Getter

Getter liefern intern gespeicherte Werte nach aussen.

public double getRadius() {
    return radius;
}

Setter

Setter schreiben Werte in Attribute, aber nur mit Gueltigkeitspruefung.

public void setRadius(double radius) {
    if (radius > 0) {
        this.radius = radius;
    }
}

Merksatz

Ein Setter ist nicht nur "Wert rein", sondern eine Fachregel: Welche Aenderungen sind erlaubt?

Beispielklasse im Figurenprojekt

public class Kreis {
    private int x;
    private int y;
    private double radius;
    private boolean sichtbar;

    public Kreis(int x, int y, double radius) {
        this.x = x;
        this.y = y;
        setRadius(radius);
        sichtbar = true;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public double getRadius() {
        return radius;
    }

    public boolean isSichtbar() {
        return sichtbar;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setRadius(double radius) {
        if (radius > 0) {
            this.radius = radius;
        }
    }

    public void setSichtbar(boolean sichtbar) {
        this.sichtbar = sichtbar;
    }
}

Dieses Muster passt direkt zur Blattaufgabe "fehlende Setter und Getter ergaenzen".

Was im Mini-Projekt typischerweise fehlt

Beim Vervollstaendigen eines halbfertigen Projekts fehlen oft genau diese Punkte:

  1. Getter fuer einzelne Attribute
  2. Setter mit Gueltigkeitspruefung
  3. einheitliche Namenskonvention (get..., set..., is...)
  4. saubere Verwendung von this bei Namensgleichheit

Beispiel:

public void setX(int x) {
    this.x = x;
}

Ohne this wuerde der Parameter x sich selbst zugewiesen werden.

Setter brauchen Fachregeln, nicht nur Syntax

Ein guter Setter prueft, ob die Aenderung fachlich erlaubt ist.

Kreisradius

  • erlaubt: radius > 0
  • nicht erlaubt: radius <= 0

Rechteckgroesse

  • erlaubt: breite > 0 && hoehe > 0
  • optional: Obergrenzen, falls Zeichenflaeche begrenzt ist

Sichtbarkeit

  • oft nur direktes Setzen von true/false
  • alternativ domaenennahe Methoden: anzeigen(), verbergen()

Damit wird der Code sprechender als mit einem generischen Setter.

Wann ein Attribut keinen Setter haben sollte

Nicht jedes Attribut sollte aenderbar sein.

Beispiele:

  • Erzeugungszeitpunkt
  • eindeutige ID
  • intern berechneter Cache

In solchen Faellen:

  • Getter ja
  • Setter nein

Das reduziert unbeabsichtigte Seiteneffekte.

Zusammenspiel mit Konstruktoren

Im Arbeitsblattkontext ist es sinnvoll, Konstruktoren und Setter zu verbinden:

  • Konstruktor setzt Anfangszustand
  • Setter erzwingen dieselben Regeln auch spaeter

Muster:

public Rechteck(int breite, int hoehe) {
    setBreite(breite);
    setHoehe(hoehe);
}

So steht die Validierung nur an einer Stelle und wird nicht dupliziert.

Teststrategie fuer das Blattprojekt

Fuer jede ergaenzte Klasse sollten mindestens diese Tests laufen:

  1. gueltige Werte setzen
  2. ungueltige Werte setzen
  3. Ruecklesen per Getter
  4. Kombination mehrerer Aenderungen
  5. Randfaelle (0, negative Werte, sehr grosse Werte)

Beispieltestidee:

  • setRadius(10) -> getRadius() ist 10
  • setRadius(-3) -> Wert bleibt unveraendert

Typische Fehler im Kapitel

  1. Attribute public lassen Dann kann niemand Regeln erzwingen.
  2. Setter ohne Pruefung Objekte werden inkonsistent.
  3. this vergessen Namenskonflikte fuehren zu wirkungslosen Settern.
  4. Automatisch fuer alles Setter erzeugen Das oeffnet mehr Schnittstellen als noetig.
  5. Berechnete Werte speichern statt ableiten Besser oft: bei Bedarf berechnen (getFlaeche()).

Erweiterte Aufgaben zur Vertiefung

  1. Ergaenze in allen Figurenklassen fehlende Getter und Setter.
  2. Fuehre fuer alle Groessenattribute die Regel "nur > 0" ein.
  3. Ersetze setSichtbar(boolean) durch anzeigen() und verbergen().
  4. Implementiere verschiebe(int dx, int dy) ueber x und y.
  5. Schreibe eine kurze Dokumentation, welche Attribute absichtlich keinen Setter bekommen.

Verbindung zu den naechsten Kapiteln

Dieses Kapitel bereitet direkt vor auf:

  • Konstruktoren und Ueberladen
  • Sichtbarkeit (private/protected/public)
  • Vererbung in Figurenhierarchien

Wer Kapselung sauber umsetzt, hat spaeter deutlich weniger Probleme mit Vererbungsdesign und Nebenwirkungen.

Fazit

Die Aussage des Arbeitsblatts bleibt der Kern:

  • Fehlende Setter und Getter nachtragen ist nicht nur Fleissarbeit.
  • Es ist der Schritt von "Code existiert" zu "Klassen sind robust modelliert".
  • Gute Kapselung sorgt dafuer, dass Objekte nur gueltige Zustaende annehmen.

Mini-Projekt: Geometrische Figuren

Abbildung 1

Die Kapitelvorlage nutzt ein Figurenprojekt mit Klassen wie Kreis und Quadrat. Ziel ist, fehlende Setter/Getter zu ergaenzen und dabei konsistente Zustaende zu sichern.

Invarianten explizit dokumentieren

Zu jeder Klasse im Figurenprojekt sollte eine kurze Invariantenliste gehoeren. Beispiel Kreis:

  1. radius > 0
  2. x und y sind ganzzahlige Koordinaten
  3. Sichtbarkeit ist stets definiert (true oder false)

Diese Liste ist mehr als Doku. Sie bestimmt direkt, welche Pruefungen in Konstruktoren und Settern noetig sind.

Konstruktor und Setter konsistent halten

Ein haeufiger Fehler: Konstruktor prueft Werte, Setter aber nicht (oder umgekehrt). Das fuehrt zu inkonsistentem Verhalten.

Regel:

  • Alle Wege, die den Zustand aendern, muessen dieselben Regeln durchsetzen.

Muster:

public Kreis(int x, int y, double radius) {
    this.x = x;
    this.y = y;
    setRadius(radius);
}

So wird die Validierungslogik nur an einer Stelle gepflegt.

Getter als Fachschnittstelle statt Rohdatenexport

Getter muessen nicht immer nur Feldwerte durchreichen. Sie koennen auch fachliche Ableitungen liefern.

Beispiel:

public double getFlaeche() {
    return Math.PI * radius * radius;
}

Vorteile:

  • keine redundante Speicherung abgeleiteter Werte
  • immer konsistente Berechnung auf Basis des aktuellen Zustands

Wann Setzen verweigert werden sollte

Das Blatt fordert das Ergaenzen fehlender Setter. Bei Vertiefung ist wichtig: Manche Setzversuche sollen bewusst scheitern.

Moegliche Strategien:

  1. still ignorieren
  2. boolean fuer Erfolg/Fehlschlag zurueckgeben
  3. IllegalArgumentException werfen

Fuer den Unterricht ist boolean oft gut nachvollziehbar, fuer groessere Systeme sind Exceptions oft klarer.

Kapselung und Testbarkeit

Kapselung verbessert nicht nur Sicherheit, sondern auch Tests:

  • durch Getter kann Zustand gezielt geprueft werden
  • durch validierende Setter lassen sich Fehlfaelle reproduzierbar testen

Testbeispiel:

  1. setRadius(5) -> Erfolg
  2. setRadius(-2) -> Misserfolg
  3. getRadius() bleibt 5

Das ist ein klarer Nachweis, dass die Klasse Invarianten schuetzt.

Vermeidung von "anemischen" Klassen

Ein Risiko bei vielen Settern/Gettern: Klassen werden zu reinen Datensaecken ohne Verhalten.

Gegenmassnahme:

  • wichtige Fachaktionen als Methoden modellieren
  • nicht nur setX, sondern z. B. verschiebe(dx, dy)
  • nicht nur setSichtbar, sondern anzeigen() und verbergen()

So bleibt das Objektmodell fachlich ausdrucksstark.

Beispiel: Rechteck mit konsistenten Regeln

public class Rechteck {
    private double breite;
    private double hoehe;

    public Rechteck(double breite, double hoehe) {
        setBreite(breite);
        setHoehe(hoehe);
    }

    public double getBreite() {
        return breite;
    }

    public double getHoehe() {
        return hoehe;
    }

    public boolean setBreite(double breite) {
        if (breite <= 0) return false;
        this.breite = breite;
        return true;
    }

    public boolean setHoehe(double hoehe) {
        if (hoehe <= 0) return false;
        this.hoehe = hoehe;
        return true;
    }

    public double getFlaeche() {
        return breite * hoehe;
    }
}

Dieses Muster zeigt die Kombination aus Kapselung, Validierung und fachlicher Methode.

Namenskonventionen im Kapitel

  1. getX fuer Werte
  2. isSichtbar fuer booleans
  3. setX fuer gezielte Aenderungen
  4. fachliche Verben fuer Aktionen (verschiebe, skaliere, zeichne)

Konsequente Namensgebung erhoeht Lesbarkeit und erleichtert Teamarbeit.

Uebungspaket zur Vertiefung

  1. Ergaenze in allen Figurenklassen Invarianten als Kommentarblock.
  2. Vereinheitliche alle Setter auf dieselbe Fehlerstrategie.
  3. Fuege zu jeder Klasse mindestens eine fachliche Methode ohne Setter-Charakter hinzu.
  4. Implementiere kopiere() oder Copy-Konstruktor fuer eine Figur.
  5. Schreibe fuer jede Klasse drei Tests:
    • gueltiger Zustand
    • ungueltiger Zustand
    • Zustand nach mehreren Aenderungen

Debug-Checkliste fuer Zustandsfehler

  1. Welcher Setter/Konstruktor hat den Zustand zuletzt geaendert?
  2. Wurde this korrekt verwendet?
  3. Wird ein ungueltiger Wert still akzeptiert?
  4. Sind alle Felder nach Konstruktion initialisiert?
  5. Gibt es abgeleitete Werte, die veralten koennen?

Diese Fragen loesen einen grossen Teil typischer OOP-I-Probleme.

Bewertungsdimensionen fuer das Mini-Projekt

  1. Korrekte Sichtbarkeit (private statt offener Felder)
  2. Vollstaendige Getter/Setter gemaess Aufgabenstellung
  3. Gueltigkeitspruefungen bei kritischen Attributen
  4. Konsistente Namensgebung
  5. Nachvollziehbare Tests

Zusammenfassung der Vertiefung

Die Arbeitsblattaufgabe "fehlende Setter/Getter ergaenzen" wird erst dann wirklich stark, wenn sie mit Invarianten, Fehlerstrategie und Testdisziplin verbunden wird. Genau dadurch wird aus einem formalen OOP-Schritt ein belastbares Klassendesign.

Abschlussprojekt zur Kapselung

Baue eine Klasse Schuelerprofil mit Attributen fuer Name, Klasse, Notendurchschnitt und Aktivstatus.

Regeln:

  1. Name darf nicht leer sein.
  2. Notendurchschnitt muss zwischen 1.0 und 6.0 liegen.
  3. Aktivstatus wird nur ueber fachliche Methoden geaendert (aktivieren, deaktivieren).

Aufgabe:

  • implementiere sinnvolle Getter
  • setze nur dort Setter ein, wo fachlich noetig
  • begruende kurz, welche Felder bewusst keinen Setter erhalten

Diese Aufgabe prueft, ob Kapselung als Designprinzip verstanden wurde und nicht nur als Syntaxmuster.

Pruefungsnahe Kurzfragen

  1. Was ist eine Invariante, und wo wird sie im Code abgesichert?
  2. Warum ist this in manchen Settern notwendig?
  3. Wann ist ein Getter sinnvoll, wann nicht?
  4. Nenne ein Attribut, das bewusst keinen Setter haben sollte, und begruende dies.

Diese Fragen pruefen, ob Kapselung als Entwurfsprinzip verstanden wurde.

Kurze Transferfrage

Nenne ein Attribut aus einem eigenen Projekt, das bisher direkt gesetzt wird, und formuliere eine fachliche Methode, die dieses Setzen kapselt (z. B. erhoehePunktestand, setzeStatusAktiv). Begruende kurz, welche Fehler dadurch verhindert werden.