Dart Kurs Weiter zu Komposition

Lektion 16 - Getter & Setter

Daten kontrolliert lesen und schreiben

Getter und Setter sehen beim Verwenden aus wie normale Attribute. Im Hintergrund sind es aber spezielle Methoden. Dadurch kannst du Werte berechnen, schuetzen, validieren und nach aussen sauber anbieten.

1. Warum braucht man Getter und Setter?

Ohne Kontrolle koennte jeder Code von aussen Werte direkt veraendern. Das ist oft gefaehrlich: Ein Alter koennte negativ werden, ein Kontostand unlogisch, ein Name leer. Getter und Setter helfen, die Regeln einer Klasse an einer Stelle zu halten.

ProblemLoesung mit Getter/Setter
Wert soll nur gelesen werdenGetter ohne Setter
Wert soll beim Setzen geprueft werdenSetter mit Validierung
Wert ist berechnetGetter berechnet aus anderen Attributen
Interne Daten sollen geschuetzt seinPrivates Feld mit Unterstrich

2. Getter: Wert lesen

Ein Getter gibt einen Wert zurueck. Er wird ohne Klammern verwendet, obwohl im Hintergrund Code ausgefuehrt wird.

class Rectangle {
  final double width;
  final double height;

  Rectangle(this.width, this.height);

  double get area => width * height;
}

final rect = Rectangle(4, 5);
print(rect.area); // 20

area wird nicht gespeichert, sondern aus width und height berechnet.

3. Setter: Wert schreiben

Ein Setter wird beim Zuweisen genutzt. Dadurch kannst du pruefen, ob ein neuer Wert erlaubt ist.

class Temperature {
  double _celsius = 0;

  double get celsius => _celsius;

  set celsius(double value) {
    if (value < -273.15) {
      return;
    }

    _celsius = value;
  }
}

temperature.celsius = -300 sieht aus wie eine normale Zuweisung, ruft aber den Setter auf.

4. Private Felder mit Unterstrich

In Dart werden Namen mit Unterstrich am Anfang privat fuer die aktuelle Library. Dadurch sagst du: Dieses Feld ist intern. Von aussen soll man nicht direkt daran herumspielen.

class BankAccount {
  double _balance = 0;

  double get balance => _balance;

  void deposit(double amount) {
    if (amount > 0) {
      _balance += amount;
    }
  }
}
_balance

Internes Feld. Es soll nicht direkt von aussen veraendert werden.

balance

Getter. Von aussen kann der Kontostand gelesen werden.

deposit

Methode. Veraendert den Kontostand nur bei gueltigem Betrag.

5. Getter vs. Methode

Beide koennen Werte zurueckgeben. Der Unterschied liegt in der Bedeutung beim Lesen: Ein Getter fuehlt sich wie eine Eigenschaft an. Eine Methode fuehlt sich wie eine Aktion oder aufwendigere Berechnung an.

GetterMethode
person.fullNameEigenschaftsartig, einfach lesbar
cart.totalKann berechnet sein, wirkt aber wie Zustand
cart.calculateTotal()Klingt nach aktiver Berechnung
account.deposit(50)Aktion, veraendert Zustand

Faustregel: Nutze Getter fuer einfache Werte ohne Seiteneffekt. Nutze Methoden fuer Aktionen, komplexe Abläufe oder Veraenderungen.

6. Beispiel: Person mit fullName

Ein voller Name muss nicht extra gespeichert werden. Er kann aus Vorname und Nachname berechnet werden.

class Person {
  final String firstName;
  final String lastName;

  Person(this.firstName, this.lastName);

  String get fullName => '$firstName $lastName';
}

final person = Person('Jutta', 'Jenssen');
print(person.fullName);

Vorteil: Wenn sich die Basisdaten aendern wuerden, waere fullName automatisch passend berechnet.

7. Beispiel: Counter mit geschuetztem Wert

Ein Counter soll nicht einfach auf unsinnige Werte gesetzt werden. Der interne Wert wird privat, nach aussen gibt es Getter und kontrollierte Methoden.

class Counter {
  int _value = 0;

  int get value => _value;

  set value(int newValue) {
    if (newValue < 0) {
      return;
    }

    _value = newValue;
  }

  void increase() {
    _value++;
  }
}

In vielen Faellen ist eine Methode wie increase() klarer als ein Setter, weil sie eine Aktion beschreibt.

8. Setter mit Fehlermeldung oder still ignorieren?

Ein Setter kann ungueltige Werte ignorieren, korrigieren oder einen Fehler werfen. Welche Variante sinnvoll ist, haengt vom Ziel ab.

Ignorieren

set age(int value) {
  if (value < 0) return;
  _age = value;
}

Fehler werfen

set age(int value) {
  if (value < 0) {
    throw ArgumentError('Alter ungueltig');
  }
  _age = value;
}

Beim Lernen reicht oft Ignorieren oder eine klare Methode. In echten Projekten ist ein ausdruecklicher Fehler manchmal besser.

9. Flutter-Bezug

In Flutter nutzt du Getter oft fuer berechnete UI-Werte. So bleibt die build-Methode lesbarer.

class CounterState {
  final int value;

  CounterState(this.value);

  bool get isEven => value % 2 == 0;

  String get label {
    return isEven ? 'Gerade Zahl' : 'Ungerade Zahl';
  }
}

Im Widget kannst du dann state.label oder state.isEven verwenden, statt dieselbe Logik mehrfach in der UI zu schreiben.

10. Code-Planung

Aufgabe: Plane eine Klasse Score. Der Wert darf nicht negativ sein. Aus dem Wert soll berechnet werden, ob die Aufgabe bestanden wurde.

Erstelle Klasse Score
Setze internes Feld _points auf 0

Wenn points gelesen wird:
  Gib _points zurueck

Wenn points gesetzt wird:
  Wenn neuer Wert kleiner als 0 ist:
    Speichere nichts
  Sonst:
    Speichere neuen Wert in _points

Wenn passed gelesen wird:
  Wenn _points groesser oder gleich 6 ist:
    Gib true zurueck
  Sonst:
    Gib false zurueck
  1. Implementiere Score mit privatem Feld _points.
  2. Baue Getter points und Setter points.
  3. Baue Getter passed.
  4. Teste Werte -1, 0, 5, 6 und 10.

11. Uebungen

  1. Erstelle Klasse Person mit Getter fullName.
  2. Erstelle Klasse Counter mit privatem Wert _value und Getter value.
  3. Baue einen Setter, der negative Counter-Werte verhindert.
  4. Erstelle Klasse Rectangle mit Getter area und perimeter.
  5. Erklaere, wann ein Getter besser ist als eine Methode.
  6. Erklaere, warum private Felder die Klasse sicherer machen.
Weiter zu Komposition & Methoden