Objektorientierung in JavaScript/Datenkapselung, Vererbung, Polymorphie/Datenkapselung
Aus ProgrammingWiki
Wiki-Quelltext dieser Seite.
<language>Javascript</language>
<html>
<head>
<style>
p.dotted {border-style: dotted; padding: 10px;}
</style>
</head>
</html>
==Was ist Datenkapselung?==
Datenkapselung bedeutet, dass ein Objekt seine Attribute nach außen hin versteckt (information hiding) und sie so vor ungeregeltem Zugriff schützt. Es hat das alleinige Recht, auf seine Daten zuzugreifen und sie zu lesen oder zu ändern. Möchten andere Objekte Zugriff auf die Daten erhalten, müssen sie dies über definierte Schnittstellen tun.
[[Bild:Flogerlinghoff_Datenkapselung1.JPG]]
<p class=dotted>Durch Datenkapselung schützen Objekte ihre Daten vor dem Zugriff von außen. Sie stellen Schnittstellen bereit, durch die diese gelesen oder geändert werden können.</p>
In JavaScript kann auf Variablen, die im Konstruktor nicht mit dem Schlüsselwort ''this'' gekennzeichnet wurden, nicht von außen zugegriffen werden.
<code id="54jhin213jn1">
function Person(name) {
var name = name;
this.getPersonsName = function() {
return name;
}
}
</code>
<run id="54jhin213jn2">
var peter = new Person("Peter");
typeof(peter.name);
</run>
<run id="54jhin213jn3">
var Emma = new Person("Emma");
Emma.getPersonsName();
</run>
Methoden, die in der Konstruktorfunktion der Klasse liegen, haben die Möglichkeit, auf die privaten Variablen im Konstruktor zuzugreifen. Man nennt sie deshalb auch priviligierte Methoden.
Methoden, die über <tt>ClassName.prototype.method</tt> definiert werden, können das nicht.
<code id="5427190802042016">
function Haustier(name) {
var name = name;
}
Haustier.prototype.getHaustiersName = function() {
return this.name;
};
</code>
<run id="5426191002042016">
var urmel = new Haustier("Urmel");
urmel.getHaustiersName();
</run>
==Aufgaben==
Bei der Klasse ''Buch'' sollen die Attribute ''autor'' und ''seitenanzahl'' gekapselt werden. Der Zugriff soll über die Methoden ''getAutor'' und ''getSeitenanzahl'' möglich sein.
<code id="54uhiqwu891">
function Buch (titel, autor, verlag, seitenanzahl) {
...
}
</code>
<check>
var cleanCode = new Buch("Clean Code", "Uncle Bob", "mitp-Verlag", 480);
return (typeof cleanCode.seitenanzahl == "undefined" && typeof cleanCode.autor == "undefined" && cleanCode.getSeitenanzahl() == 480 && cleanCode.getAutor() == "Uncle Bob");
</check>
<run id="56fac5b8a63d7">
var cleanCode = new Buch("Clean Code", "Uncle Bob", "mitp-Verlag", 480);
</run>
Durch Datenkapselung kann erreicht werden, dass zwei Eigenschaften nur zusammen geändert werden dürfen.
Wenn die elektrische Kraft in einem Radialfeld gleich bleiben soll, aber eine der beiden Ladungen geändert wird, muss entweder der Abstand der Ladungen zueinander oder der Betrag der zweiten Ladung auch geändert werden (siehe [https://de.wikipedia.org/wiki/Coulombsches_Gesetz Coulombsches Gesetz]).
Implementiere die Methoden <tt>getQ1()</tt>, <tt>getQ2()/tt>, <tt>getR()/tt>, <tt>getF()</tt>, <tt>setQ1(newValue)</tt> und <tt>setQ2(newValue)</tt>. Wenn eine Ladung geändert wird, soll die andere automatisch angepasst werden, sodass der Betrag der Kraft gleich bleibt.
<code id="5427195102042016">
function Radialfeld(q1, q2, r) {
var q1 = q1;
var q2 = q2;
var r = r;
this.getQ1 = function() { return q1; };
this.getQ2 = function() { return q2; };
this.getR = function() { return r; };
this.getF = function() {
return (1 / (4*Math.PI*(8.854*Math.pow(10, -12)))) * ((this.getQ1() * this.getQ2()) / Math.pow(this.getR(), 2));
};
this.setQ1 = function(newV) {
q2 = this.getQ2() * this.getQ1() / newV;;
q1 = newV;
};
this.setQ2 = function(newV) {
q1 = this.getQ1() * this.getQ2() / newV;
q2 = newV;
};
}
</code>
Zur Berechnung der Kraft wird Math.PI verwendet. e0 ist mit 8.854*10^(-12) definiert.
<check>
Radialfeld rf = new Radialfeld(0.08, 0.02, 0.1);
var checkGetF = rf.getF() == (1 / (4*Math.PI*(8.854*Math.pow(10, -12)))) * ((rf.getQ1() * rf.getQ2()) / Math.pow(rf.getR, 2));
var oldF = rf.getF();
rf.setQ1(0.05);
var checkSetQ1 = this.getQ2 == 0.032;
rf.setQ2(0.04);
var checkSetQ2 = this.getQ1 == 0.04;
return checkGetF && checkSetQ1 && checkSetQ2;
</check>
<run id="5426200802042016">
Radialfeld rf = new Radialfeld(0.08, 0.02, 0.1);
rf.setQ1(0.05);
</run>
==Datenkapselung in UML==
In den meisten Programmiersprachen wird Datenkapselung durch ''Zugriffsmodifizierer'' umgesetzt. Die Sichtbarkeit von Elementen einer Klasse hängt von diesen ab.
Obwohl in JavaScript keine Zugriffsmodifizierer unterstützt werden, ist es sinnvoll, private und öffentliche Felder im UML-Diagramm zu unterscheiden.
In UML werden folgende Zugriffsmodifiziefer unterschieden:
*'''+ public''': Alle anderen Objekte können auf Elemente eines Objekts zugreifen.
*'''- private''': Nur das Objekt selbst kann auf seine Elemente zugreifen.
Diese beiden Modifizierer können auch mit JavaScript umgesetzt werden.
Desweiteren gibt es noch:
*'''# protected''': Das Objekt selbst und alle erbende Objekte können auf Attribute und Methoden zugreifen.
*'''~ package''': Objekte im gleichen ''Package'' haben Zugriff.