Encapsulation

Say

Aktives Mitglied
Hallo zusammen,

Diesen Begriff höre ich ständig. Geht es hier vor allem um die Getter und Setter Methoden, damit niemand die Variablen von aussen verändern kann?
 

M.L.

Top Contributor
Weiterhin sind Methoden eine Ansammlung elementarer Schlüsselwörter oder Befehle. Das Beispiel aus der Wikipedia (zwecks Demo) absichtlich modifiziert:
Java:
import java.math.BigDecimal;

public class Employee {
private BigDecimal salary = new BigDecimal(50000.02);
    
   // public BigDecimal getSalary() {
   //     return this.salary;
   // }

public BigDecimal bekomm_abd() {
    System.out.println("Huhu...");
    return this.salary;
    //System.out.println("Anweisung");  <-- unreachable code
}
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Employee e = new Employee();
        //BigDecimal sal = e.getSalary();
       BigDecimal sal = e.bekomm_abd();
        System.out.println(sal);
    }

}
Ausgabe:
Huhu...
50000.0199999999967985786497592926025390625
 

KonradN

Super-Moderator
Mitarbeiter
Kalselung ist einfach das, was schon in der Feuerzangenbowle vorkommt: "Wat is ne Dampfmaschin?"

Es interessiert die Außenwelt einfach nicht, was in der Dampfmaschine abgeht. Es interessiert nur die Schnittstelle. Daher ist die Dampfmaschine in der Feuerzangenbowle eine große schwarze Kiste - die aber ein Interface nach außen hat: Zwei Löcher: In das eine Loch geht der Dampf rein und aus dem anderen Loch kommt er wieder heraus.

Wichtig wird das, denn dadurch, dass die Außenwelt nicht weiss, was in der Dampfmaschine ist, kann man da beliebig etwas verändern. Und das komplett: Die "Dampfmaschine" hat dann evtl. einen Elektormotor und so und die beiden Löcher sind nur noch mit einem Rohr verbunden (falls da jemand doch mal Dampf rein schicken will).

Und damit haben wir auch schon den Bewegungsgrund: Du willst hier saubere Abhängigkeiten haben! Wenn Du eine Instanzvariable direkten Zugriff hast, dann ist das ein Implementierungsdetail, das nicht mehr verändert werden kann.

Kleines Beispiel: Du hast eine Liste implementiert und damit Du immer die Größe hast, hast Du die als Variable abgelegt. Und auf diese Variable wird dann direkt zugegriffen.
Jetzt kannst Du dieses Detail nicht mehr verändern!

Wenn Du das aber nur mit einer Methode machst, dann hast Du die Möglichkeit, das jederzeit zu ändern. Du musst ja keine Instanzvariable zurück geben sondern Du kannst da irgendwas berechnen oder so.
 

temi

Top Contributor
Hallo zusammen,

Diesen Begriff höre ich ständig. Geht es hier vor allem um die Getter und Setter Methoden, damit niemand die Variablen von aussen verändern kann?
Die Grundregel lautet ungefähr: Eine Klasse sollte so viele ihrer internen Details (Daten) verbergen wie möglich und nur öffentlich machen, was unbedingt notwendig ist.

Ein
Hintergrund ist, dass die Daten intern völlig anders verwaltet werden können, als durch die öffentliche Schnittstelle bekannt ist. Und die interne Organisation kann jederzeit geändert werden, ohne dass der Benutzer der Klasse davon etwas mitkriegt. Die öffentliche Schnittstelle ist ja unverändert. Hätte der Benutzer der Klasse Zugriff auf interne Details und würde diese auch verwenden, dann wäre sein Code nicht mehr funktionsfähig, sobald intern daran etwas geändert würde.

Getter und Setter sind ein Weg dazu, wobei Setter, meiner Ansicht nach, deutlich sparsamer verwendet werden sollten. Man möchte den internen Zustand von Instanzen in der Regel durch fachliche Methoden verändern und nicht direkt. Und wie darüber schon erläutert, kann es sein, dass das Datenformat von Getter/Setter vom internen Format abweichen. Das hängt von der Gestaltung der öffentlichen Schnittstelle ab, die es dem Benutzer leicht machen soll, mit der Klasse zu arbeiten und das möglichst ohne Fehler machen zu können.

Hier kommt übrigens deine Frage zu Kopierkonstruktor und zum Nutzen dessen wieder ins Spiel. Nehmen wir eine "gut" gekapselte Klasse:
Java:
public class Foo {
 
    private List<String> values;
 
    public Foo(List<String> values) {
        this.values = values;
    }
 
    public List<String> getValues() {
        return values;
    }
}
Sieht alles ganz prima aus. Die Liste ist privat, kann über den Konstruktor initialisiert werden und es gibt nur lesenden Zugriff über den Getter. Blöderweise ist die Liste ein Referenztyp. Die Verwendung des Getters gibt also eine Referenz auf die intern verwendete List zurück.
Java:
ArrayList<String> list = new ArrayList<>();
list.add("Eins");
list.add("Zwei");
list.add("Drei");

Foo foo = new Foo(list);

List<String> returnedList = foo.getValues(); // liefert Referenz auf die interne Liste

returnedList.clear(); // leert die Liste in foo
Das muss vom Benutzer der Klasse nicht einmal böswillig geschehen sein. Er war in der Annahme, dass es sicher ist, die zurück gegebene Liste zu ändern. Das lässt sich verbessern.
Java:
    public List<String> getValues() {
        return new ArrayList<>(values); // erzeugt eine Kopie der internen Liste
    }

Blöderweise wird auch dem Konstruktor eine Referenz auf eine Liste übergeben.
Java:
ArrayList<String> list = new ArrayList<>();
list.add("Eins");
list.add("Zwei");
list.add("Drei");

Foo foo = new Foo(list); // übernimmt eine Referenz auf die Liste

list.clear(); // löscht auch den Inhalt der internen Liste von foo

Aber auch dass lässt sich verbessern:
Java:
    public Foo(List<String> values) {
        this.values = new ArrayList<>(values); // erzeugt eine defensive Kopie der übergebenen Liste
    }
 
Zuletzt bearbeitet:

Neumi5694

Top Contributor
Gerade in Java selbst wurden die Prinzipien der Kapselung oft ignoriert. All zu oft gibt es direkten Zugriff auf die Variablen (Klassisches Beispiel: Punkte und Abmessungen).
Jetzt würde man es klarerweise besser wissen und machen, aber dann würden all die Programme nicht mehr laufen, welche auf diese Variablen zugreifen.
 

Neue Themen


Oben