Getter & Setter im Detail
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 33 von 110.
Getter und Setter werden in Kombination mit privaten Feldern zu mächtigen Werkzeugen für die Kapselung. Sie ermöglichen es Ihnen, eine saubere öffentliche Schnittstelle bereitzustellen, während Sie die volle Kontrolle darüber behalten, wie auf Daten zugegriffen wird und wie diese geändert werden.
Ein gängiges Muster besteht darin, ein privates Feld mit einem öffentlichen Getter und einem Setter zu kombinieren, der eine Validierung beinhaltet:
class Temperature {
double _celsius = 0;
double get celsius => _celsius;
set celsius(double value) {
if (value < -273.15) {
_celsius = -273.15; // Absolute zero minimum
} else {
_celsius = value;
}
}
}Setter können Geschäftsregeln erzwingen und so sicherstellen, dass Ihr Objekt niemals in einen ungültigen Zustand gerät.
Sie können auch berechnete Getter erstellen, die Werte aus privaten Daten ableiten:
class Rectangle {
double _width;
double _height;
Rectangle(this._width, this._height);
double get area => _width * _height; // Berechnet
double get perimeter => 2 * (_width + _height);
double get width => _width;
set width(double value) {
if (value > 0) _width = value;
}
}Manchmal möchten Sie einen schreibgeschützten Zugriff. Geben Sie einfach einen Getter ohne einen Setter an:
class Order {
final DateTime _createdAt = DateTime.now();
DateTime get createdAt => _createdAt; // Schreibgeschützt
}Dieses Muster ermöglicht externem Code Einblick in die Daten, während gleichzeitig jegliche Modifikationen verhindert werden – das private Feld in Kombination mit einem reinen Getter erzeugt einen echten schreibgeschützten Zugriff.
Aufgabe
EinfachLassen Sie uns ein Produktinventarsystem erstellen, das die Leistungsfähigkeit von Gettern und Settern zur Steuerung des Datenzugriffs demonstriert. Sie werden eine Klasse erstellen, die ihre internen Daten schützt und gleichzeitig berechnete Eigenschaften und Validierungen bereitstellt.
Sie werden Ihren Code in zwei Dateien organisieren:
product.dart: Definieren Sie eine KlasseProduct, die das Inventar mit ordnungsgemäßer Kapselung verwaltet. Ihr Produkt sollte Folgendes haben:- Einen öffentlichen
String name - Einen privaten
double _price - Einen privaten
int _quantity - Einen Konstruktor, der alle drei Werte entgegennimmt
- Einen Getter
price, der den privaten Preis zurückgibt - Einen Setter
price, der nur Werte größer als0akzeptiert (ungültige Werte ignorieren) - Einen Getter
quantity, der die private Menge zurückgibt - Einen Setter
quantity, der nur Werte von0oder größer akzeptiert (negative Werte ignorieren) - Einen berechneten Getter
totalValue, der_price * _quantityzurückgibt - Einen berechneten Getter
isInStock, dertruezurückgibt, wenn die Menge größer als0ist - Einen schreibgeschützten Getter
sku, der eine einfache SKU generiert, indem er die ersten 3 Zeichen des Namens in Großbuchstaben gefolgt von der Menge zurückgibt (z. B.LAP25für "Laptop" mit der Menge 25) - Eine Methode
displayProduct(), die die Produktdetails anzeigt
- Einen öffentlichen
main.dart: Importieren Sie Ihre Produktklasse und demonstrieren Sie, wie Getter und Setter den Zugriff steuern:- Erstellen Sie ein Produkt namens
'Laptop'mit dem Preis999.99und der Menge25 - Rufen Sie
displayProduct()auf - Geben Sie
In stock: [isInStock]aus - Geben Sie
SKU: [sku]aus - Versuchen Sie, den Preis auf
-50.0zu setzen (sollte ignoriert werden) - Setzen Sie den Preis auf
899.99(gültige Änderung) - Versuchen Sie, die Menge auf
-10zu setzen (sollte ignoriert werden) - Setzen Sie die Menge auf
0(gültige Änderung) - Rufen Sie
displayProduct()auf - Geben Sie
In stock: [isInStock]aus - Geben Sie
SKU: [sku]aus
- Erstellen Sie ein Produkt namens
Die Methode displayProduct() sollte in diesem Format drucken:
--- Product Info ---
Name: [name]
Price: $[price]
Quantity: [quantity]
Total Value: $[totalValue]Erwartete Ausgabe:
--- Product Info ---
Name: Laptop
Price: $999.99
Quantity: 25
Total Value: $24999.75
In stock: true
SKU: LAP25
--- Product Info ---
Name: Laptop
Price: $899.99
Quantity: 0
Total Value: $0.0
In stock: false
SKU: LAP0Spickzettel
Getter und Setter bieten in Kombination mit privaten Feldern Kapselung und Kontrolle über den Datenzugriff.
Privates Feld mit Getter und Setter
class Temperature {
double _celsius = 0;
double get celsius => _celsius;
set celsius(double value) {
if (value < -273.15) {
_celsius = -273.15;
} else {
_celsius = value;
}
}
}Berechnete Getter
Getter können Werte aus privaten Daten ableiten:
class Rectangle {
double _width;
double _height;
Rectangle(this._width, this._height);
double get area => _width * _height;
double get perimeter => 2 * (_width + _height);
double get width => _width;
set width(double value) {
if (value > 0) _width = value;
}
}Schreibgeschützter Zugriff
Stellen Sie einen Getter ohne Setter für schreibgeschützte Eigenschaften bereit:
class Order {
final DateTime _createdAt = DateTime.now();
DateTime get createdAt => _createdAt;
}Probier es selbst
import 'product.dart';
void main() {
// TODO: Erstelle ein Produkt namens 'Laptop' mit dem Preis 999.99 und der Menge 25
// TODO: Rufe displayProduct() auf
// TODO: Drucke "In stock: [isInStock]"
// TODO: Drucke "SKU: [sku]"
// TODO: Versuche, den Preis auf -50.0 zu setzen (sollte ignoriert werden)
// TODO: Setze den Preis auf 899.99 (gültige Änderung)
// TODO: Versuche, die Menge auf -10 zu setzen (sollte ignoriert werden)
// TODO: Setze die Menge auf 0 (gültige Änderung)
// TODO: Rufe displayProduct() auf
// TODO: Drucke "In stock: [isInStock]"
// TODO: Drucke "SKU: [sku]"
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor