XML * XML-SCHEMA * XPATH * XSL * XSL-FO * SVG * XQUERY * XPROC * ANT * DIVERSES



Diverses / JavaScript / Objektorientiert programmieren mit JavaScript / Datenkapselung

Datenkapselung

Datenkapselung

➪ Leider gibt es in JavaScript keine Zugriffsmodifizierer wie private / protected / public. Felder, die mit prototype oder this. deklariert werden, stehen allgemein zur Verfügung (public). Um dennoch den Schutzmechanismus der Datenkapselung aufrecht zu erhalten, muss man sich anderer Verfahren bedienen. Es reicht definitiv nicht aus, die zu schützenden Felder mit var statt this / prototype zu definieren, da dieses Verfahren nicht instanzsicher ist.

Clojures sind ein möglicherweise umständliches, dafür aber probates Mittel, um das Problem der Datenkapselung zu lösen. Freilich kann es recht aufwendig werden, für mehrere geschützte Felder einer "Klasse" jeweils ein Clojure mit Getter und Setter anzulegen.

Eine Alternative liegt darin, die Datenkapselung für jedes geschützte Feld mit allen getter- und Setter-Methoden in einen separaten Typ auszulagern, der eine spezielle Clojure implementiert (z.B. myhiddeninteger). Dort kann das geschützte Feld einmalig gekapselt und via get und set verfügbar gemacht werden. Nebenbei kann man sich auf diese Weise die mühsame Schreibarbeit sparen, für jedes geschützte Feld jeweils ein getter und setter anzulegen. Im eigentlichen Property wird der Clojure-Typ instanziiert; damit kann Getter- bzw. Setter des Clojures gezielt aufgerufen werden.


var myhiddeninteger = function () {
  var verstecktesfeld;
  this.get = function () {
    return verstecktesfeld;
  };
  this.set = function (val) {        
    verstecktesfeld = isNaN(parseInt(val)) ? 1 : parseInt(val);    
  };
};
var hhh = new myhiddeninteger();
hhh.set("x95");
console.log("myhidden: " + hhh.get());
var Bruch = function () {  
  this.Zaehler = new myhiddeninteger();
  this.Nenner = new myhiddeninteger();
  /*fuer ueberladenen Konstruktor mit 2 Parametern*/
  if (arguments.length === 2) {
    this.Zaehler.set(arguments[0]);  
    this.Nenner.set(arguments[1]);
  }
  this.toString = function () {
    this.vorzeichenwechsel();
    if (this.Nenner.get() === 0) 
      return "Nenner ist 0, NICHT DEFINIERT";
    else if (this.Zaehler.get() === 0 || this.Nenner.get() === 1) 
      return this.Zaehler.get();
    else return "(" + this.Zaehler.get() + "/" + this.Nenner.get() + ")";
  };
  this.vorzeichenwechsel = function () {
    if (this.Nenner.get() < 0) {
      this.Zaehler.set(this.Zaehler.get() * (-1));
      this.Nenner.set(this.Nenner.get() * (-1));
    };
  };
  /* Deklariere addiere in der Function Bruch. 
   * Das aufrufende Objekt ruft die Methode addiere mit 2 Patemetern auf. 
   * Der Aufruf lautet 
    var cc = new Bruch();
    cc.addiere(aa, bb);
  */
  this.addiere = function(a, b){
    if ( (a instanceof Bruch) && (b instanceof Bruch)  ) {
      a.kuerzen();
      b.kuerzen();
      this.Zaehler.set(a.Zaehler.get() * b.Nenner.get() 
          + b.Zaehler.get() * a.Nenner.get());
      this.Nenner.set(a.Nenner.get() * b.Nenner.get());
      this.kuerzen();
    }      
  }
  /* Deklariere multipliziere in der function Bruch. 
   * Es wird ein neues Objekt der Klasse Bruch generiert. 
   * Der Aufruf lautet var dd = aa.multipliziere(a, b);*/
  this.multipliziere = function(b){
    var erg = null;
    if ( (this instanceof Bruch) && (b instanceof Bruch)  ) {
      this.kuerzen();
      b.kuerzen();
      erg = new Bruch();      
      erg.Zaehler.set(this.Zaehler.get() * b.Zaehler.get());
      erg.Nenner.set(this.Nenner.get() * b.Nenner.get());
      erg.kuerzen();
    }
    return erg;
  }
};
/*Deklariere kuerzen als prototype*/
Bruch.prototype.kuerzen = function () {
  var z = Math.abs(this.Zaehler.get());
  var n = Math.abs(this.Nenner.get());
  if (z > 0 && n > 0) {
    while (z !== n) {
      if (z > n) z = z - n;
      else n = n - z; 
    }
    this.Zaehler.set(this.Zaehler.get() / z);
    this.Nenner.set(this.Nenner.get() / z);
  }
};
/* Deklariere subtrahiere als Prototype. 
 * Es wird ein neues Objekt der Klasse Bruch generiert. 
 * Der Aufruf lautet var dd = aa.subtrahiere(bb);*/
Bruch.prototype.subtrahiere = function (b) {
  var erg = null;
  if ((b instanceof Bruch)) {
    b.kuerzen();
    this.kuerzen();
    erg = new Bruch();
    erg.Zaehler.set(this.Zaehler.get() * b.Nenner.get() 
        - b.Zaehler.get() * this.Nenner.get());
    erg.Nenner.set(this.Nenner.get() * b.Nenner.get());
    erg.kuerzen();
  }
  return erg;
};
/* Deklariere dividiere als Prototype. 
 * Das aufrufende Objekt ruft die Methode addiere mit 2 Patemetern auf. 
 * Der Aufruf lautet 
  var cc = new Bruch();
  cc.dividiere(aa, bb);
*/
Bruch.prototype.dividiere = function (a, b) {  
  if ( (a instanceof Bruch) && (b instanceof Bruch)  ) {
    a.kuerzen();
    b.kuerzen();    
    this.Zaehler.set(a.Zaehler.get() * b.Nenner.get());
    this.Nenner.set(a.Nenner.get() * b.Zaehler.get());
    this.kuerzen();
  }
};
// Aufruf uber den "Standardkonstruktor"
var aa = new Bruch();
// Initialisiere Werte über Set-Methoden
aa.Zaehler.set(-57);
aa.Nenner.set(-95);
//Aufruf uber den "Parametrisierten Konstruktor"
var bb = new Bruch(33, 55);
//Aufruf uber den "Standardkonstruktor"
var cc = new Bruch();
cc.addiere(aa, bb);
console.log(aa.toString() + " + " + bb.toString() + " = " + cc.toString());
// Hier generiert aa ein neues Objekt der Klasse Bruch
// und berechnet dessen Werte mit den Werten aus aa, kombiniert mit bb
var dd = aa.subtrahiere(bb);
console.log(aa.toString() + " - " + bb.toString() + " = " + dd.toString());
dd = aa.multipliziere(bb);
console.log(aa.toString() + " * " + bb.toString() + " = " + dd.toString());
cc.dividiere(aa, bb);
console.log(aa.toString() + " / " + bb.toString() + " = " + cc.toString());
console.log("\nREFLECTION fuer Objekt aa\n");
for (var p in aa) {
  if (aa.hasOwnProperty(p)) {    
    if (p === 'Zaehler' || p === 'Nenner') {
      console.log("OwnProperty: " + p + " Aktueller Wert: " + aa[p].get());}
    else 
      console.log("OwnProperty: " +p + "; Result: " + aa[p].call(aa, ""));
  }
  else console.log("NOT OwnProperty: " + p);
}

Das Ergebnis:


myhidden: 1
(3/5) + (3/5) = (6/5)
(3/5) - (3/5) = 0
(3/5) * (3/5) = (9/25)
(3/5) / (3/5) = 1
REFLECTION fuer Objekt aa
OwnProperty: Zaehler Aktueller Wert: 3
OwnProperty: Nenner Aktueller Wert: 5
OwnProperty: toString; Result: (3/5)
OwnProperty: vorzeichenwechsel; Result: undefined
OwnProperty: addiere; Result: undefined
OwnProperty: multipliziere; Result: null
NOT OwnProperty: kuerzen
NOT OwnProperty: subtrahiere
NOT OwnProperty: dividiere

wg / 6. September 2020



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.



V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/javascript3.html