Datenkapselung

thor_norsk

Bekanntes Mitglied
Guten Tag,

ich habe folgende Aufgabe erhalten und bin mir nicht sicher, ob ich die Aufgabe richtig gelöst habe?

Aufgabe: Sie haben folgende Klassenvereinbarungen in getrennten Quelltextdateien:

[CODE lang="java" title="Datenkapselung"]package tiere;

public class Katze {

private int gewicht;
private int farbe;
private int groesse;
}

package tiere;

public class Elternkatze extends Katze {

private int kinderzahl;
}[/CODE]

Die Klasse Elternkatze soll auf die Instanzvariable gewicht der Klasse Katze zugreifen können.
Welche Möglichkeiten kennen Sie, diesen Zugriff zu ermöglichen? Bewerten Sie diese Möglichkeiten bitte auch.
Achten Sie dabei auf die Datenkapselung.
Ein Tipp: Sie sollten mindestens drei verschiedene Varianten nennen können. Zwei hängen direkt mit der Vereinbarung der Instanzvariablen zusammen, die dritte dagegen nicht.

Meine Lösungsvorschläge:
Mit dem Zugriff, verstehe ich sowohl gewicht setzen, und abfragen?


1 Möglichkeit ) private weg lassen, allerdings verletze ich die Regeln der Datenkapselung?
2 Möglichkeit ) Mit 2 Methoden erweitern die auf public gesetzt sind ?
3 Möglichkeit ) Öffentlicher Kostruktor, zum beispiel:
// öffentlicher Konstruktor
public Katze (int gewicht) {
setGewicht(gewicht);
}
// die Methode ist als private deklariert!
private void setGewicht(int gewicht) {
this.gewicht = gewicht;
}

4 Möglichkeit) Habe ich mir gedacht, ersetzte private durch public, aber ich denke ist nicht Sinn und Zweck der Aufgabe oder ?
 
M

Mart

Gast
1 Möglichkeit ) private weg lassen, allerdings verletze ich die Regeln der Datenkapselung?
wenn du private weg lässt und nichts davor stehen hast hast du die Package sichtbarkeit die beiden klassen sind in demselben package... muss abgewogen werden ob es erlaubt ist dass jeder im package in der katze rum wurschteln darf
2 Möglichkeit ) Mit 2 Methoden erweitern die auf public gesetzt sind ?
public bringt dir hier gar nichts, da es die datenkapselung komplett zerstört, weil du dann noch mehr sichtbarkeit als wie mit package sichtbarkeit hergibst
3 Möglichkeit ) Öffentlicher Kostruktor, zum beispiel:
nein

was wäre mit

PROTECTED ... du bist in vererbung unterwegs
=> protected getter vllt sogar
=> kinderanzahl passt dann auf private da die Katze
Java:
protected final int getGewicht(){

return this.gewicht;

}
somit hat die eltern katze zugang aufs lesen des gewichts aber keine Schreibe Rechte => problematik des gewchts ist nur in der Katze klasse nicht in der Vererbungs klasse
so hättest du minimale Rechte fürs gewicht meines erachtens
minimales Recht kann man *als gute datenkapselung* interpretieren... stell ich mal so in den Raum
 

thor_norsk

Bekanntes Mitglied
So wie du beschrieben hast, habe ich nur Lesezugriff ? Ich dachte ich muss auch Schreibzugriff ermöglichen? Weil unter Zugriffsrecht verstehe ich Lese und Schreibzugriff.
 

temi

Top Contributor
Zwei hängen direkt mit der Vereinbarung der Instanzvariablen zusammen
Das wäre vermutlich package private (deine 1. Möglichkeit) und protected.

Ein öffentlicher Getter wäre noch in Ordnung, bei Settern bin ich generell eher vorsichtig. Der Objektzustand sollte sich normalerweise über fachliche Methoden ändern. Im Fall des Gewichts der Katze, wäre das dann etwas wie fresse().
 

Oneixee5

Top Contributor
Als Kapselung oder Datenkapselung bezeichnet man den kontrollierten Zugriff auf Methoden bzw. Attribute von Klassen. Klassen können den internen Zustand anderer Klassen nicht in unerwarteter Weise lesen oder ändern. Es gibt demnach für die Aufgabe folgende Lösungsmöglichkeiten:
1 Möglichkeit ) private weg lassen, allerdings verletze ich die Regeln der Datenkapselung? - Ist richtig und: Nein, du willst den Zugriff ermöglichen oder einschränken, du gibst also die Regeln vor, du definierst die Regel.
2 Möglichkeit ) Mit 2 Methoden erweitern die auf public gesetzt sind ? - Ist vollkommen richtig
3 Möglichkeit ) Öffentlicher Kostruktor - ist falsch: bei 1 beziehst du dich auf die Standard-Sichbarkeit, das ist aber nicht die einzige Möglichkeit. Beziehe dich besser auf das Schlüsselwort protected.
 
M

Mart

Gast
So wie du beschrieben hast, habe ich nur Lesezugriff ? Ich dachte ich muss auch Schreibzugriff ermöglichen? Weil unter Zugriffsrecht verstehe ich Lese und Schreibzugriff.
datenkapselung = schutz der daten

wenn jeder lesen und schreiben kann weist du dann noch ob der datensatz richtig ist? ;)

deswegen minimale rechte, wenn du schreibne MUSST schreibt man einen setter ansonsten nicht ... ende aus...

falls du schreibe und lese zugriff hast kannst gleich das attribut auf public setzen ...... weil du es dann eh nicht mehr weis was überhaupt los ist ..nett gesagt

get und set methode zu haben macht schon sinnn aber setter sollte man mit bedacht einsetzen
 

thor_norsk

Bekanntes Mitglied
1) Gefällt mir nicht, weil in der Aufgabestellung darauf hingewiesen wird, man solle auf Datenkapselung achten! Einfach private weg lassen
funktioniert zwar aber Datenkapselung ist hin oder ?
2) Sage ich danke!
3) mit protected hätte ich selber darauf kommen müssen, sage ich nochmals danke!

Gibt es eine andere Möglichkeit ?
 

temi

Top Contributor
Gefällt mir nicht, weil in der Aufgabestellung darauf hingewiesen wird, man solle auf Datenkapselung achten! Einfach private weg lassen
funktioniert zwar aber Datenkapselung ist hin oder ?
Es kann durchaus gewollt und sinnvoll sein, dass Klassen im selben Package Zugriff haben dürfen. Das ist situationsbedingt. Die Kapselung ist schlechter als bei private, aber besser als bei public.
 

temi

Top Contributor
OK. Ich denke private weg lassen wäre richtig , da in der Aufgabestellung darauf hingewiesen wird!
Du sollst die Möglichkeiten ja auch bewerten. Insofern können sie ja wohl nicht alle gleichwertig sein.

EDIT: Darum kann man hier gerne auch weniger sinnvolle Möglichkeiten erwähnen und entsprechend (vor allem hinsichtlich der Kapselung) bewerten.
 
Zuletzt bearbeitet:

Robert Zenz

Top Contributor
1 Möglichkeit ) private weg lassen, allerdings verletze ich die Regeln der Datenkapselung?
package-private ist der Teufel wenn es um API-Design geht! Es ist so einfach damit Konstellationen zu machen welche weder erweiterbar noch verwendbar sind, dass ist furchtbar. Vergiss am besten dass es das gibt. protected waere dann die Sichtbarkeit der Wahl.

Also, es gibt die klassische Java-Klasse, wo alle Felder einfach nur private sind, aber ich sehe keinen bis wenige Nachteile darin die Felder einfach protected zu machen. Der Vorteil hier ist das ableitende Klassen tatsaechliche die Moeglichkeit haben die Klasse sinnvoll zu erweitern. Der Nachteil ist, dass jemand eventuell deinen internen Zustand vergiftet, und dann bei dir im Bug-Tracker aufschlaegt mit einer dummen Frage (sehen wir's ein, das passiert nie).

protected bedeutet auch das Zugriff aus dem selben Package moeglich ist...vergiss das einfach, das ist nur praktisch fuer Unit-Tests. Ist fuer den eigentlichen Anwendungsfall genauso schlecht wie package-private.

2 Möglichkeit ) Mit 2 Methoden erweitern die auf public gesetzt sind ?
Ja, klassisches Zugriffsbeispiel:

Java:
public class Example {
    private int value = 0;
   
    public Example() {
        super();
    }
    
    public int getValue() {
        return value;
    }
    
    public void setValue(int value) {
        this.value = value;
    }
}

Hierbei ist zu beachten dass man nun ueber den Setter bestimmte Werte bestimmen (und auch mit Fehler quittieren) kann, also wenn du zum Beispiel einen Wertebereich durchsetzen willst. Nach aussen kann eine ableitende Klasse deine Getter/Setter aber immer noch ueberschreiben, und damit auch deinen internen Zustand vergiften wenn du diese Methoden verwendest. Sagen wir mal:

Java:
public class Example {
    private int value = 0;
   
    public Example() {
        super();
    }
    
    public int getValue() {
        return value;
    }
    
    public void setValue(int value) {
        verifyValueIsInRangeOrThrow(value);
       
        this.value = value;
    }

    public int performOperation() {
        return somethingSomethingWithValue(getValue());
    }
}

Wenn sich jetzt eine Klasse ableitet und diese dann getValue() ueberschreibt, wird deine Operation den Wert verwenden welche diese ausliefert:

Java:
public class ExtendedExample {
    public ExtendedExample() {
        super();
    }
    
    @Override
    public int getValue() {
        return valueTotallyOutsideAcceptableRange;
    }
}

Damit kann man dann immer noch deinen internen Zustand zu einem gewissen Grad vergiften. Auch sind die Getter/Setter public, was eventuell nicht gewuenscht ist.

Als Alternative dazu kannst du die Getter/Setter protected machen, um nur ableitenden Klassen Zugriff zu erlauben, zum Beispiel wenn du den Wert nur zum Zugriff und nicht zum aendern nach aussen fuehren willst:

Java:
public class Example {
    private int value = 0;
   
    public Example() {
        super();
    }
    
    public int getValue() {
        return value;
    }
    
    protected void setValue(int value) {
        verifyValueIsInRangeOrThrow(value);
       
        this.value = value;
    }
}

Damit koennen nun sich ableitende Klassen einen neuen Wert wuenschen, aber sie koennen immer noch die Methoden ueberschreiben. Wenn du jetzt wirklich gezielten und kontrollierten Zugriff erlauben willst, machst du die Getter/Setter am besten final:

Java:
public class Example {
    private int value = 0;
   
    public Example() {
        super();
    }
    
    public final int getValue() {
        return value;
    }
    
    protected final void setValue(int value) {
        verifyValueIsInRangeOrThrow(value);
       
        this.value = value;
    }
}

Damit hast du nun kontrollierten Zugriff, und kannst immer genau sagen dass der Wert welche zurueckgegeben oder verwendet wird, innerhalb des von dir gewuenschten Bereiches liegt. Gleichzeitig koennen ableitende Klassen auch den Zustand setzen, was bei nur einer private nicht moeglich waere.

3 Möglichkeit ) Öffentlicher Kostruktor, zum beispiel:
Ja, wenn sich die Werte nie wieder im Laufe des Lebens der Instanz aendern sollen, akzeptabel. Man muss aber aufpassen dass dann die Konstruktoren nicht dann zwanzig Variablen uebernimmt, dann muss man sich was neues ueberlegen.

In diesem Beispiel weniger, aber auch hier kann man eine Kombination aus public und protected Konstruktoren machen um ableitenden Klassen die Chance zu geben den Wert zu bestimmen:

Java:
public class Example {
    private int value = 0;
   
    public Example() {
        this(DEFAULT_VALUE);
    }
    
    protected Example(int value) {
        super();

        verifyValueIsInRangeOrThrow(value);
        
         this.value = value;
    }
}

In deinem Fall wuerde aber ein public Konstruktor welche alle Werte uebernimmt (und validiert) zielfuehrend wenn ich das richtig sehe.

4 Möglichkeit) Habe ich mir gedacht, ersetzte private durch public, aber ich denke ist nicht Sinn und Zweck der Aufgabe oder ?
Es ist eine Moeglichkeit, und es kann Sinn machen, aber es ist denke ich nicht im Sinne der Aufgabe, ja.

Also Klassen wie zum Beispiel:

Java:
public class Example {
    public int value = 0;
   
    public Example() {
        super();
    }
}

Koennen Sinn machen, aber ziemlich immer ist es besser den Zugriff auf die eine oder andere Art zu kontrollieren, wie du ja bereits festgestellt hast. Der Vorteil daran Methoden (Getter/Setter) zu stellen, ist der dass du Logik nachruesten kannst ohne dass die verwender der API etwas aendern muessen. Die rufen weiterhin die Getter/Setter auf, und du machst darin einfach Dinge, zum Beispiel validieren oder veraendern des Werts.
 

thor_norsk

Bekanntes Mitglied
Zuerst möchte ich mich bedanken. Wir haben bis jetzt nur Sichtbarkeit (public, private, protected) besprochen und die Erweiterung mit den Methoden. Ich werde lieber keine Experimente machen und halte mich lieber am Lehrplan.
 

thor_norsk

Bekanntes Mitglied
Also : Ich habe nochmal nachgelesen, ich könnte wenn ich euch richtig verstanden habe, als 4 Möglichkeit ,,package'' für Attribut wählen?
z.B. public class Katze {
package int gewicht;

......

}

Da Beide Klassen sind in gleichem Paket befinden wäre möglich?
 

Neue Themen


Oben