7. Das Geheimnisprinzip (D. Parnas)

Werbung
7. Das Geheimnisprinzip (D. Parnas)
•
•
•
•
•
In großen Softwaresystemen muss der globale
Namensraum nicht nur strukturiert sondern auch
eingeschränkt werden
Bezeichner, die in der Spezifikation eines ADTs
vorkommen, sollten öffentlich sein
Bezeichner die nur für die Implementierung der
Spezifikation notwendig sind, und die Implementierung
selber sollten für Klienten verborgen („geheim“) bleiben
Damit kann gesichert werden, dass Klienten die Daten
vom ADT ausschließlich durch die spezifizierten
Operationen zugreifen können
Eine einmal getestete Komponente kann durch einen
fehlerhaften externen Zugriff nicht zerstört werden
László Böszörményi
ESOP
Geheimnisprinzip - 1
Sichtbarkeit in Java (visibility modifiers)
•
public
– Von überall her zugreifbar
•
protected
– In der definierenden Klasse
– Im Paket, dem die definierende Klasse gehört
– In Unterklassen – siehe später – auch in anderen Paketen
•
default (kein modifier)
– In der definierenden Klasse
– Im Paket, dem die definierende Klasse gehört
– Annahme dahinter: Klassen eines Pakets sind „Freunde“
•
private
– Nur in der definierenden Klasse
– Eine ganze Klasse kann nur dann private sein, wenn sie in eine
andere Klasse eingeschachtelt ist
László Böszörményi
ESOP
Geheimnisprinzip - 2
Stack-Klasse mit Sichtbarkeit Einstellungen
public class Stack {
private int top = -1;
private Object[] info;
// Kann beliebige Objekte stapeln
// Der Stack-Zustand ist „versteckt“.
// Damit ist gesichert, dass ein Zugriff nur
// über die öffentlichen Methoden möglich ist
public Stack(int max) { info = new Object[max]; }
// Konstruktor
public boolean empty () {return top < 0;}
public void push (Object obj) { top++; info[top] = obj; }
public Object pop() { top--; return info[top + 1]; }
// Die Operationen
// sind alle
// öffentlich
} // Stack
László Böszörményi
ESOP
Geheimnisprinzip - 3
Gültigkeitsbereich von Bezeichnern –1.
•
•
•
Der Namensraum muss strukturiert werden
Bezeichner (Namen) die in einer Klasse deklariert
werden, sind in der ganzen Klasse gültig
Namen einer Klasse können in Methoden der Klasse
neu deklariert (redeklariert) werden
– Redeklarierte Namen überdecken in ihrem Gültigkeitsbereich
den ursprünglichen Namen
– Nachher kommt der alte Name wieder zu Geltung
•
•
Der Rumpf einer Methode ist ein Block
Ein Block ist eine Folge von Deklarationen für lokale
Variablen und von Anweisungen
– Ein Name in einem Block ist gültig ab seiner Deklaration bis
zum Ende des Blockes, wo er deklariert ist
– Blöcke können ineinander geschachtelt werden
– Eingeschachtelte Blöcke dürfen Namen der äußeren Blöcke
nicht redeklarieren
László Böszörményi
ESOP
Geheimnisprinzip - 4
Gültigkeitsbereich von Bezeichnern –2.
•
Die Parameter einer Methode gehören zum äußersten
Block der Methode
– Sie sind deshalb in der ganzen Methode gültig
– Sie sind wie lokale Variablen dieses Blocks
•
In einem Block müssen alle Bezeichner unterschiedlich
sein mit folgenden Ausnahmen
– Verschiedenartige Programmelemente (Klassen, Methoden,
sonstige Variablen) können gleich benannt werden – sollten
aber nicht!
– Methoden mit unterschiedlichen Parametertypen können gleich
benannt werden (overloading)
•
•
Klassen können ineinander geschachtelt werden
Namen sind für den Menschen da
– Deshalb sollten sie verständlich (aber auch nicht zu lang) sein!
László Böszörményi
ESOP
Geheimnisprinzip - 5
Bezeichner und Blöcke – ein krankes Beispiel
public class Euclid {
// Klasse und Methode heißen gleich (kein Konstruktor!)
static int Euclid (int a, int b) { // a und b sind redeklariert: lokal zu der Methode
int Euclid;
// lokale Variable heißt auch Euclid
while (a != b)
// a und b überdecken die äußeren a und b Namen
if (a > b) a = a - b; else b = b - a;
Euclid = a;
// (Variable Euclid ist sogar unnötig – return a; reicht aus)
return Euclid;
// Es ist schlechte Praxis den gleichen Namen
} // Euclid
// (egal wie schön) in dieser Weise mehrfach zu benützen!
static void main(String [] args) {
int result;
// result ist lokal zu der main Methode
a = GetPosInt(); b = GetPosInt(); // a und b sind im äußeren Block deklariert
result = Euclid(b, a);
// Nicht der Name, sondern die Position zählt
} // main
static int a, b;
} // Euclid
László Böszörményi
// a und b sind Namen der Klasse (Klassenvariablen),
// sie können auch vor ihrer Deklaration verwendet werden
ESOP
Geheimnisprinzip - 6
Hierarchie der Namenesräume
•
•
Namen einer Klasse sind für andere Klassen durch einen
qualifizierten Bezeichner erreichbar
Die qualifizierten Bezeichner haben die Form b1.b2.b3 ...
und bilden einen eindeutigen hierarchischen Namen
– Hierarchie geht von oben nach unten und von links nach rechts
– „Kinder des gleichen Vaters“ müssen unterschiedlich heißen
•
Statische Variablen und Methodennamen
werden durch den Klassennamen qualifiziert
–
Out.print bezeichnet:
Klasse Out → Klassenmethode print
•
x
Instanzvariablen werden durch
den Namen einer Objektinstanz
qualifiziert, wie: account1.check()
László Böszörményi
ESOP
z
y
x.z.y
z
x.z.z
...
z
x.y.z
y
y
x.y.y
Geheimnisprinzip - 7
Pakete (packages)
•
Klassen (und Schnittstellen) können zu Paketen
(packages) zusammengefasst werden
– Package-Anweisung am Anfang der Klassendatei
package Paketname
– Pakete können zur Benützung „importiert“ werden
import package.* – importiert alle Klassen des Pakets
import package.class; – importiert eine Klasse
import package; – letzte Komponente der Name genügt
– Paketnamen können in qualifizierten Namen stehen
java.lang.Integer.parseInt bedeutet:
Package java.lang → Klasse Integer → Methode parseInt
– Umgebungsvariable CLASSPATH
•
László Böszörményi
Muss (meistens) die Ordner mit Paketen enthalten
ESOP
Geheimnisprinzip - 8
Schnittstelle (interface)
•
•
Die öffentlichen und privaten Teile einer Klasse können
– und sollen – auch syntaktisch getrennt werden
Öffentliche Teile werden in eine Schnittstelle gestellt
– Konstante
– Abstrakte Methoden (dargestellt durch den Methodenkopf)
•
Die Rumpfteile der Methoden können durch Klassen
implementiert werden (implements)
– Eine Klasse kann mehrere Interfaces implementieren
– Ein Interface kann von mehreren Klassen implementiert
werden
•
•
Die Implementierung muss die Spezifikation erfüllen
Interfaces können nicht instanziert werden (mit new)
– Klienten legen Objekte der implementierenden Klasse an
– Sie müssen nur die Konstruktoren und die Schnittstelle kennen
•
Zusätzliche Eigenschaften von Java-interfaces später
László Böszörményi
ESOP
Geheimnisprinzip - 9
Interface für die Stack-Klasse
public interface Stack_I {
// Stack-Interface
public boolean empty ();
// Ergibt wahr, wenn der Stack leer ist
public void push (Object obj); // Legt ein Element auf den Stack
// empty (push (s, x)) = false;
// Vorbedingung: Muss noch Platz da sein
public Object pop();
// Gibt oberstes Element vom Stack zurück
// pop (push (s, x)) = (s, x)
// Vorbedingung: Stack darf nicht leer sein
} // Stack_I
• Die Stack-Implementierungen müssen diese Methoden realisieren
• Die Konstruktoren sind in den implementierenden Klassen zu finden
László Böszörményi
ESOP
Geheimnisprinzip - 10
Array-Implementierung vom Stack-Interface
public class StackArray implements Stack_I { // Implementiert Stack-Interface
protected int top = -1;
protected Object[] info;
// Stack-Zustand kann in Klassen des
// gleichen Pakets
// und in Subklassen zugegriffen werden
public StackArray (int max) { info = new Object[max]; } // Konstruktor
public boolean empty () {return top < 0;}
public void push (Object d) { top++; info[top] = d; }
public Object pop() { top--; return info[top + 1]; }
} // StackArray
László Böszörményi
ESOP
Geheimnisprinzip - 11
Implementierung mit Zusicherungen
public class StackArray implements Stack_I { // Implementiert Stack-Interface
protected int top = -1;
// Stack-Zustand kann nur im Paket
protected Object[] info;
// und in Subklassen zugegriffen werden
public StackArray (int max) { info = new Object[max]; } // Konstruktor
static final void Assert(boolean b) throws java.lang.Error {
) throw
java.lang.Error
("Falscher
Aufruf");
if ( !bif )( !b
throw
new new
java.lang.Error
("Falscher
Aufruf");
} // Assert;
public boolean empty () {return top < 0;}
public void push (Object obj) {
Assert(
Assert( top
top << info.length
info.length -- 11 );
);
top++;
info[top] = obj;
} // pusch
public Object pop() { Assert( !empty() ); top--; return info[top + 1]; }
} // StackArray
László Böszörményi
ESOP
Geheimnisprinzip - 12
Listen
•
•
•
•
•
•
•
•
Eine Liste verbindet eine Reihe von Knoten
Knoten können eingefügt und gelöscht werden
Die Knoten enthalten beliebige Informationen
Sie enthalten eine Referenz auf einen Nachbarknoten –
auf den „nächsten“ (next)
Das Ende der Liste ist ein Knoten mit next == null
Ein Ring ist eine Liste ohne Ende (die Knoten bilden
einen Kreis)
In doppelt verketteten Listen enthalten die Knoten je
eine Referenz auf beide Nachbarn
In sortierten Listen werden die Knoten nach einem
Ordnungskriterium eingefügt
– Z.B. nach einer Nummer, die als „Schlüssel“ dient
•
Weiteres über Listen siehe später
László Böszörményi
ESOP
Geheimnisprinzip - 13
Listen als Stack
•
Die einfachsten Listen sind als Stack organisiert
– Sowohl Einfügen als auch Löschen geschieht am Kopf (head)
– x zeigt auf das einzufügende Element
Löschen: head = head.next;
head
info
next
2.
x
info
next
info
next
info
next
null
1.
Einfügen: x.next = head; head = x;
info
next
László Böszörményi
ESOP
Geheimnisprinzip - 14
Listen-Implementierung vom Stack-Interface -1.
public class StackList implements Stack_I {
// Implementiert Stack-Interface mit Liste
protected class Node {
// Klasse Node definiert die Listenstruktur
Object info; Node next; // info ist ein belibiges Objekt, next zeigt auf
Node (Object i) {info = i; next = null; }
// das nächste Node-Objekt
} // Node
protected Node head;
// Kopf der Liste
StackList () { head = null; }
// Konstruktor
public boolean empty () {
return head == null;
} // empty
// Leer, wenn der Kopf auf nichts zeigt
László Böszörményi
ESOP
Geheimnisprinzip - 15
Listen-Implementierung vom Stack-Interface -2.
public void push (Object obj) { // Legt einen neuen Knoten vorne an
Node x = new Node(obj);
/* x zeigt auf den neuen Knoten (mit info als Inhalt) */
x.next = head;
// Einfügen
head = x;
} // push
public Object pop() {
Object x = head.info;
head = head.next;
return x;
} // pop
// Entfernt den Knoten am Kopf
// x zwischenspeichert das Info- Objekt
// Entfernen aus der Liste
// Info zurückgeben
} // StackList
László Böszörményi
ESOP
Geheimnisprinzip - 16
Benutzerklasse vom Stack-Interface
public class StackClient { // Methode StackFractions is polymorph (siehe später):
// sie funktioniert für alle Stack-Arten die die Schnittstelle Stack_I implementieren
static void StackFractions (Stack_I stack, int N, Fraction x) {
for (int i = 0; i < N; i++) { // „Pusht“ N Brüche x, x/2, x/4 . . . x/2N-1
stack.push(x);
x = Fraction.times(x, new Fraction(1, 2) );
} // for i
while ( !stack.empty() ) { // „Popt“ und zeigt alle Elemente am Stack
System.out.print( stack.pop() + " " ) ;
} // while stack not empty
System.out.println();
} // StackFractions
static void main(String [] args) { // Ruft StackFractions mit 2 verschiedenen Stacks
StackFractions(new StackArray(8), 8, new Fraction (3, 4));
StackFractions(new StackList(), 9, new Fraction (1, 2));
} // main
3/512 3/256 3/128 3/64 3/32 3/16 3/8 3/4
} // StackClient
1/512 1/256 1/128 1/64 1/32 1/16 1/8 1/4 1/2
László Böszörményi
ESOP
Geheimnisprinzip - 17
Eingabe/Ausgabe
•
Datei
– Benannte Sammlung von Daten, meistens persistent
•
Datenstrom
– Sequenz von Daten eines Typs (byte, int, etc.)
– Abbildung auf Tastatur, Bildschirm, Datei etc.
•
Die Klassen In und Out sind auch für Dateien verwendbar
–
open, close: zur Eröffnung bzw. Schließung einer Datei
–
done: zur Abfrage des Erfolgs einer E/A Operation
•
Objekte von Klassen, die das Interface Serializable
implementieren, werden automatisch serialisiert, und können
in dieser Form direkt in eine Datei geschrieben werden
•
Mehr über Persistenz der Daten in weiteren LVs
László Böszörményi
ESOP
Geheimnisprinzip - 18
Aus- und Eingabe eines Zahlenstroms
public class TestIO {
static final String FileName = "Vector";
// Name der Datei
static void main(String [] args) {
int [] v1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Out.open(FileName);
// Neue Datei zum Schreiben erzeugen
if (Out.done() ) {
// Wenn erfolgreich:
for (int i = 0; i < v1.length; i++) Out.println(v1[i]);
Out.close();
// Persistent: erst durch Schließen
0
} else { Out.println("File " + FileName + " cannot be created"); }
1
In.open(FileName);
// Eröffne vorhandene Datei
2
if (In.done()) {
// Wenn erfolgreich:
3
int i = In.readInt();
4
5
while (In.done()) {
// Solange Datei nicht endet:
6
Out.println(i); i = In.readInt(); // weiterlesen
7
} // while
8
In.close();
// Eingabedatei schließen
9
} else { Out.println("File " + FileName + " not found"); }
}
} // main, TestIO
László Böszörményi
ESOP
Geheimnisprinzip - 19
Programm liest eigenen Text – 1.
public class PrintSelf {
static final String FileName = "PrintSelf.java";
static void ReadFile1 (String fileName) {
In.open(FileName);
// Datei eröffnen
if (In.done()) {
// Wenn erfolgreich
char ch = In.read();
// Byteweise einlesen
while (In.done()) {
// Solange Datei nicht endet
Out.print(ch);
ch = In.read(); // weiterlesen
} // while
In.close();
// Eingabe schließen
} else { Out.println("File " + FileName + " not found"); }
} // ReadFile1
László Böszörményi
ESOP
Geheimnisprinzip - 20
Programm liest eigenen Text – 2.
static void ReadFile2 (String fileName) {
In.open(FileName);
// Datei eröffnen
if (In.done()) {
// Wenn erfolgreich
String s = In.readFile(); // Liest die ganze Datei!
Out.println(s);
// Gibt den ganzen String aus
In.close();
// Eingabe schließen
} else { Out.println("File " + FileName + " not found"); }
} // ReadFile2
static void main(String [] args) {
ReadFile1(FileName);
ReadFile2(FileName);
} // main
} // PrintSelf
László Böszörményi
// Gibt die Datei PrintSelf.java aus
// Gleiche Datei nochmals aus
ESOP
Geheimnisprinzip - 21
Kategorisierung von Klassen
•
Werkzeugkasten (toolbox) (z.B. Klasse Math)
– Bieten zusammengehörende statische Funktionen an
– Sie sind nicht instanzierbar
– Sie sind zustandslos
•
Module (Klasse mit der main Methode, oder In und Out)
– Haben (ausschließlich) statische Variablen und Methoden
– Sie sind nicht instanzierbar
– Sie haben einen einzigen (statischen) Zustandsraum
•
Klassen für Typbildung (ADTs) (z.B. die Klasse Fraction)
– Sie sind instanzierbar
– Jedes Objekt hat eigenen Zustandsraum (Instanzvariablen)
•
Mischungen sind eher zu vermeiden!
László Böszörményi
ESOP
Geheimnisprinzip - 22
Herunterladen