Warum keine Setter-Methode in meinem Beispiel notwendig ist – und wie unveränderliche Modelle eine Alternative sein können

Die Wahl der richtigen Datenstruktur in einer Software ist entscheidend für Wartbarkeit, Stabilität und Lesbarkeit des Codes. Gerade in Dart oder Flutter taucht oft die Frage auf: Brauche ich wirklich Setter-Methoden für mein Modell, oder gibt es Alternativen?

In diesem Beitrag schauen wir uns an, warum Setter in deinem Beispiel nicht zwingend notwendig sind und wie ein unveränderliches Modell als Alternative funktioniert.


Warum keine Setter-Methode notwendig ist

Direkter Zugriff auf die Datenstruktur

Im Code greifen wir direkt auf eine Map in einem Modell zu, um eine Antwort zu speichern:

_questionnaire?.answers[question] = answer;

Die answers-Map ist Teil des Questionnaire-Modells und wurde als final deklariert:

final Map<String, String> answers;

Wichtig zu verstehen: final bedeutet in Dart nicht, dass der Inhalt der Map unveränderlich ist. Es sagt lediglich, dass die Referenz auf die Map nicht geändert werden kann – die Inhalte (Keys und Values) dürfen aber modifiziert werden.

Das ermöglicht dir, direkt Einträge in der Map zu verändern, ohne eine Setter-Methode zu definieren. Das spart Aufwand und Code, solange:

  • Du keine zusätzlichen Regeln oder Logik bei der Modifikation benötigst.
  • Der Zugriff auf die Daten nur in kontrollierten Kontexten (z. B. innerhalb eines Providers) geschieht.

Wann direkter Zugriff ausreicht

Ein direkter Zugriff wie in deinem Beispiel funktioniert problemlos, wenn:

  • Dein Modell intern gut gekapselt ist, z. B. über einen Provider.
  • Es keine komplexe Logik gibt, die du bei Änderungen durchsetzen musst.
  • Die Datenstruktur leicht verständlich und flexibel sein soll.

In kleinen bis mittelgrossen Projekten oder für einfache Modelle reicht dieser Ansatz oft völlig aus.


Die Grenzen direkter Änderungen

Direkte Änderungen an einer Map oder anderen Datenstrukturen können in grossen Projekten oder bei komplexen Datenmodellen problematisch werden:

  • Schwierige Fehlersuche: Wenn Daten an mehreren Stellen geändert werden können, wird es schwer, die Ursache für fehlerhafte Zustände zu finden.
  • Fehlende Kontrolle: Du kannst keine Validierungen oder Logik erzwingen, bevor Daten geändert werden.
  • Unerwartete Seiteneffekte: Unkontrollierte Änderungen an einem Objekt könnten andere Teile der Anwendung beeinflussen.

Hier kommen unveränderliche Modelle ins Spiel.


Was sind unveränderliche Modelle – und warum sind sie nützlich?

Grundidee unveränderlicher Modelle

Unveränderliche Modelle (immutable models) funktionieren nach einem einfachen Prinzip: Einmal erstellt, bleibt das Objekt unverändert. Änderungen am Zustand erzeugen eine neue Instanz des Objekts.

Beispiel für ein unveränderliches Questionnaire-Modell:

class Questionnaire {
  final String id;
  final Map<String, String> answers;

  Questionnaire(this.id, Map<String, String> answers)
      : answers = Map.unmodifiable(answers);

  Questionnaire copyWith({String? id, Map<String, String>? answers}) {
    return Questionnaire(
      id ?? this.id,
      answers ?? this.answers,
    );
  }
}

In diesem Ansatz:

  • Ist die answers-Map unveränderlich dank Map.unmodifiable.
  • Änderungen passieren nur durch die Methode copyWith, die ein neues Objekt mit aktualisierten Daten erstellt.

Wie sieht das in der Praxis aus?

Angenommen, du möchtest eine neue Antwort hinzufügen. Statt direkt die Map zu ändern, erzeugst du eine neue Instanz:

final updatedQuestionnaire = questionnaire.copyWith(
  answers: {...questionnaire.answers, 'question2': 'answer2'},
);

Das Original bleibt unverändert, und updatedQuestionnaire enthält die neuen Daten.


Vorteile unveränderlicher Modelle

1. Sicherheit und Vorhersehbarkeit

Da der Zustand eines Objekts nicht mehr verändert wird, kannst du sicher sein, dass sich ein einmal erstelltes Objekt nicht unvorhergesehen ändert. Das hilft enorm bei der Fehlersuche und macht die Anwendung stabiler.

2. Perfekt für State-Management

State-Management-Lösungen wie Provider, Bloc, oder Redux arbeiten hervorragend mit unveränderlichen Modellen. Sie setzen darauf, dass Änderungen durch das Erzeugen eines neuen Zustands repräsentiert werden.

3. Verbesserte Debugging-Erfahrung

Mit unveränderlichen Modellen kannst du leichter den Zustand deines Programms nachvollziehen, da du genau weisst, wann und wo ein neues Objekt erstellt wurde.


Wann solltest du welchen Ansatz verwenden?

Direkter Zugriff und mutable Modelle

  • Geeignet für: Kleine Projekte, schnelle Prototypen oder interne Datenstrukturen ohne komplexe Änderungslogik.
  • Vorteile: Weniger Code, einfache Implementierung.
  • Nachteile: Potenzial für unkontrollierte Änderungen und schwer nachvollziehbare Bugs.

Unveränderliche Modelle

  • Geeignet für: Mittlere bis grose Projekte, Anwendungen mit komplexen Datenmodellen, Multi-Threading oder modernen State-Management-Lösungen.
  • Vorteile: Stabilität, Wartbarkeit, bessere Kontrolle.
  • Nachteile: Mehraufwand bei der Implementierung, minimaler Performance-Overhead.

Fazit

Ob du dich für direkten Zugriff oder ein unveränderliches Modell entscheidest, hängt von den Anforderungen deines Projekts ab.

  • Für einfache Szenarien: Der direkte Zugriff auf Maps ist völlig legitim und spart dir Code und Komplexität.
  • Für langfristige Projekte: Unveränderliche Modelle bieten dir Kontrolle, Sicherheit und Flexibilität, die besonders bei wachsender Codebasis wichtig werden.

Comments

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert