Geheimnisprinzip
In der Zusatzaufgabe der letzten Lektion hast du macheProbefahrt gegen negative Werte abgesichert. Die Frage war: Reicht das?
Der Angriff
Betrachte die Klasse AutoOffen. Ihre Attribute sind public statt private.
Sage voraus, was das Hauptprogramm ausgibt. Beurteile danach, ob die Absicherung in macheProbefahrt überhaupt etwas nützt.
Auflösung
VW, 84000 km, 7500.0 Euro
VW, 84000 km, 7500.0 Euro
VW, 12000 km, 7500.0 Euro
Die Prüfung in macheProbefahrt funktioniert – die Probefahrt mit -20000 wird ignoriert.
Und sie nützt trotzdem nichts. Denn wagen.kilometerstand = 12000; schreibt direkt in das Attribut und umgeht die Methode vollständig. Die Regel „der Kilometerstand darf nur steigen“ steht zwar im Programm, ist aber nicht durchsetzbar.
Die Lösung: private
Das Geheimnisprinzip (auch: Datenkapselung) besagt: Ein Objekt verbirgt seine Attribute nach außen. Zugriff gibt es nur über Methoden, die das Objekt selbst anbietet.
Damit kann das Objekt jede Änderung an seinen Daten prüfen – und sicherstellen, dass es niemals in einen unsinnigen Zustand gerät.
Die Schlüsselwörter private und public heißen Zugriffsmodifikatoren.
| Sichtbarkeit | Zeichen im Diagramm | bedeutet |
|---|---|---|
private |
- |
nur innerhalb der eigenen Klasse sichtbar |
public |
+ |
von überall sichtbar |
Faustregel: Attribute sind private. Methoden, die andere benutzen sollen, sind public.
Entferne im Hauptprogramm die beiden Schrägstriche vor wagen.kilometerstand = 12000; und lies die Fehlermeldung.
Beurteile: Ist es ein Vorteil oder ein Nachteil, dass dieser Fehler jetzt schon beim Übersetzen auffällt und nicht erst beim Ausführen?
Auflösung
Ein klarer Vorteil. Ein Übersetzungsfehler wird immer gefunden – ein Laufzeitfehler nur, wenn der betroffene Programmweg zufällig getestet wird.
Je mehr Fehler die Sprache schon beim Übersetzen abfängt, desto weniger können sich im laufenden System verstecken.
Getter und Setter
- Eine Getter-Methode liefert einen Attributwert nach außen:
getKilometerstand(). - Eine Setter-Methode ändert einen Attributwert – und prüft dabei:
setPreis(double pPreis).
Ein Setter ist kein Ersatz für public. Der Unterschied ist, dass der Setter die Änderung kontrollieren kann:
public void setPreis(double pPreis) {
if (pPreis >= 0) {
preis = pPreis;
}
}
Und nicht jedes Attribut braucht beides. Für den Kilometerstand gibt es bewusst nur einen Getter – geändert wird er ausschließlich durch macheProbefahrt.
Aufgabe 1: Bankkonto
Ein Bankkonto ist das Musterbeispiel für das Geheimnisprinzip: Niemand darf den Kontostand einfach überschreiben.
Setze die Klasse so um, dass alle Tests grün werden. Achte besonders auf die Regeln:
- Einzahlen geht nur mit positiven Beträgen.
- Auszahlen geht nur mit der richtigen PIN und nur, wenn genug Geld da ist.
- Der Kontostand darf nie negativ werden.
- Die PIN wird niemals nach außen gegeben.
Tipp 1: Die PIN vergleichen
pPin und pin sind Zeichenketten. Also pPin.equals(pin) – nicht pPin == pin.
Tipp 2: Drei Bedingungen
Für eine erfolgreiche Auszahlung müssen alle drei Bedingungen gleichzeitig gelten. Verknüpfe sie mit &&.
Tipp 3: Warum gibt hebeAb einen Wahrheitswert zurück?
Damit das aufrufende Programm erfährt, ob es geklappt hat. Eine void-Methode könnte höchstens etwas ausgeben – und wäre damit für ein Programm ohne Konsole nutzlos.
Aufgabe 2: Beurteilen
Eine Mitschülerin schlägt vor, die Klasse Bankkonto um diese Methode zu ergänzen:
public void setKontostand(double pNeuerStand) {
kontostand = pNeuerStand;
}
Sie begründet das damit, dass man sonst bei der Kontoeröffnung kein Startguthaben eintragen kann.
a) Beurteile den Vorschlag.
b) Schlage eine Lösung vor, die ihr Problem löst, ohne die Kapselung aufzugeben.
Auflösung
a) Der Vorschlag hebt die Kapselung vollständig auf. Mit setKontostand kann jeder den Kontostand auf jeden beliebigen Wert setzen – alle Prüfungen in zahleEin und hebeAb sind damit wertlos. Es ist genau der Zustand, den wir am Anfang der Lektion abgeschafft haben.
b) Zwei saubere Wege:
- Einen zweiten Konstruktor ergänzen, der ein Startguthaben entgegennimmt. Das Guthaben wird dann genau einmal gesetzt, bei der Erzeugung, und kann geprüft werden.
- Nach der Erzeugung einfach
zahleEin(startguthaben)aufrufen. Das ist sachlich sogar richtiger – eine Kontoeröffnung mit Guthaben ist eine Einzahlung.
Zusatzaufgabe
Nimm deine eigene Klasse aus der letzten Lektion noch einmal vor.
a) Prüfe: Sind alle Attribute private?
b) Gibt es Attribute, die von außen gar nicht sichtbar sein müssen? Streiche deren Getter.
c) Gibt es Regeln über die Werte, die dein Objekt einhalten sollte – etwa „der Akkustand liegt zwischen 0 und 100“? Setze sie in den Methoden durch und schreibe Tests dafür.