Ausblick: Entwurfsmuster (Design Pattern)

Werbung
Ausblick:
Entwurfsmuster (Design Pattern)
12.1 Entwurfsmuster (Design Pattern)
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12.1 Entwurfsmuster (Design Pattern)
12-1
Entwurfsmuster (Design Pattern)
• Als Entwurfsmuster bezeichnet man einen wohl überlegten Vorschlag für den
Entwurf eines objektorientierten Programmierproblems. Es beschreibt in
rezeptartiger Weise das Zusammenwirken von Klassen, Objekten und Methoden.
Entwurfsmuster identifizieren Programmierprobleme und geben den
Software-Entwürfen charakterisierende Namen.
• Entwurfsmuster stellen wie Algorithmen oder Datenstrukturen vordefinierte
Lösungen für konkrete Programmierprobleme dar, allerdings auf einer höheren
Ebene. In der Regel können Entwurfsmuster nicht in allen Details übernommen
werden, sondern müssen an das jeweilige Problem angepasst werden.
• Entwurfsmuster sind eine der wichtigsten Entwicklungen der objektorientierten
Programmierung der letzten zwanzig Jahre.
12.1 Entwurfsmuster (Design Pattern)
12-2
Entwurfsmuster
Beispiele für Entwurfsmuster sind:
• Singleton
• Immutable
• Observer
• Composite
• Interface
• Factory
• Iterator
• Delegate
• Visitor
Wir erläutern die Idee jetzt an drei einfachen Beispielen.
12.1 Entwurfsmuster (Design Pattern)
12-3
Das Entwurfsmuster „Singleton“
• Ein Singleton ist eine Klasse, von der nur ein einziges Objekt erstellt werden darf.
• Sie stellt eine Zugriffsmöglichkeit auf dieses Objekt zur Verfügung und instanziiert
es beim ersten Zugriff.
• Es gibt viele Beispiele für Singletons. Hier seien nur der Fenstermanager oder die
Symboltabelle eines Compilers genannt.
12.1 Entwurfsmuster (Design Pattern)
12-4
Das Entwurfsmuster „Singleton“
Merkmale der folgenden Implementierung sind:
• Sie besitzt ein statisches Attribut ihres eigenen Typs, in dem die einzige Instanz
gespeichert wird.
• Mithilfe der statischen Methode getInstance() kann auf die Instanz zugegriffen
werden.
• Die Klasse enthält einen privaten parameterlosen Konstruktor. So wird verhindert,
dass andere Klassen den new-Operator anwenden und weitere Instanzen erzeugen.
12.1 Entwurfsmuster (Design Pattern)
12-5
Das Entwurfsmuster „Singleton“
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
12.1 Entwurfsmuster (Design Pattern)
12-6
Das Entwurfsmuster „Singleton“
// Singleton s1 = new Singleton();
gibt Fehler
Singleton s2 = Singleton.getInstance(); // new wird aufgerufen
Singleton s3 = Singleton.getInstance(); // new wird nicht aufgerufen
12.1 Entwurfsmuster (Design Pattern)
12-7
Das Entwurfsmuster „Immutable“
• Als immutable (unveränderlich) werden Objekte bezeichnet, die nach ihrer
Instanziierung nicht mehr verändert werden können.
• Unveränderliche Objekte können gefahrlos mehrfach referenziert werden und
erfordern im Multithreading keinen Synchronisationsaufwand.
12.1 Entwurfsmuster (Design Pattern)
12-8
Das Entwurfsmuster „Immutable“
Merkmale der folgenden Implementierung sind:
• Alle Attribute sind privat.
• Schreibende Zugriffe finden nur in einem Konstruktor oder in Initalisierern statt.
• Lesende Zugriffe sind verboten, wenn das Attribut ein veränderliches Objekt oder
ein Array ist.
• Werden veränderliche Objekte oder Arrays an einen Konstruktor übergeben, so
müssen sie geklont werden, bevor sie einer Attributvariablen zugewiesen werden.
12.1 Entwurfsmuster (Design Pattern)
12-9
Das Entwurfsmuster „Immutable“
public class Immutable {
private int
value1;
private String[] value2;
public Immutable(int value1, String[] value2) {
this.value1 = value1;
this.value2 = (String[]) value2.clone();
}
12.1 Entwurfsmuster (Design Pattern)
12-10
public int getValue1() {
return value1;
}
public String getValue2(int index) {
return value2[index];
}
}
12.1 Entwurfsmuster (Design Pattern)
12-11
Das Entwurfsmuster „Immutable“
• Durch Ableitung könnte ein unveränderliches Objekt wieder veränderlich werden.
Zwar ist es der abgeleiteten Klasse nicht möglich, die privaten Attribute zu
überschreiben, sie könnte aber eigene Attribute einführen, die veränderbar sind.
• Erforderlichenfalls muss die Klasse als final deklariert werden.
12.1 Entwurfsmuster (Design Pattern)
12-12
Das Entwurfsmuster „Observer“
• Das Observer-Pattern beschreibt die Idee, bestimmte Objekte auf Veränderungen
ihres Zustands zu überwachen.
• Die überwachten Objekte, die sog. Observables, informieren die ihnen bekannt
gemachten Observer von den Veränderungen.
• Auf diese Weise werden die Veränderungen der Daten und die daraus
resultierenden Aktionen entkoppelt.
• Das Observer-Pattern ist eines der in Java am häufigsten benutzten
Entwurfsmuster, zum Beispiel als „Listener“.
12.1 Entwurfsmuster (Design Pattern)
12-13
Das Entwurfsmuster „Observer“
• Die zugrunde liegende Idee ist die Verwendung einer Klasse Observable, deren
Objekte überwacht werden sollen. Diese Klasse enthält (mindestens)
◦ ein privates Observer-Attribut sowie
◦ Methoden zum Hinzufügen und Löschen von Observern.
• Außerdem gibt es die Klasse Observer,
◦ in deren Konstruktor, die Anmeldung beim zu beobachtenden Objekt erfolgt
sowie
◦ eine Update-Methode, in der die Reaktion auf die Veränderung spezifiziert wird.
• Wir erläutern jetzt dieses Entwurfsmuster an einem einfachen Beispiel mit nur
einem Beobachter. Beobachtet werden Objekte der Klasse Name auf
Veränderungen des Attributs String name.
12.1 Entwurfsmuster (Design Pattern)
12-14
Das Entwurfsmuster „Observer“
public class Name {
private String name;
private Observer observer; // bei mehreren Beobachtern: Vector
public void setObserver(Observer observer) { this.observer = observer; }
public void deleteObserver(Observer observer) { this.observer = null; }
public void setName(String name) {
this.name = name;
if (observer != null)
observer.update(this);
}
public String getName() { return name; }
}
12.1 Entwurfsmuster (Design Pattern)
12-15
Das Entwurfsmuster „Observer“
public class Observer {
private Name[] namen;
public Observer() {
namen = new Name[10];
for (int i = 0; i < namen.length; i++) {
namen[i] = new Name();
namen[i].setObserver(this);
}}
public void update(Name n) {
int index = 0;
while (n != namen[index]) index++;
System.out.println("Name Nr. " + index + " wurde geändert.");
System.out.println("Neuer Name: " + namen[index].getName());
}
public Name getName(int i) { return namen[i]; }
}
12.1 Entwurfsmuster (Design Pattern)
12-16
Das Entwurfsmuster „Observer“
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Observer obs = new Observer();
for (int i = 0; i < 5; i++) {
Scanner sc = new Scanner(System.in);
int index = (int) (Math.random() * 10);
System.out.print("Name: ");
obs.getName(index).setName(sc.next());
}
}
}
12.1 Entwurfsmuster (Design Pattern)
12-17
Ausblick:
Programmierparadigmen und -sprachen und Veranstaltungen
12.1 Entwurfsmuster (Design Pattern)
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-18
Wiederholung: Paradigmen zur Algorithmenbeschreibung
In einem objektorientierten Algorithmus werden Datenstrukturen und Methoden zu
einer Klasse zusammengefasst. Von jeder Klasse können Objekte gemäß der
Datenstruktur erstellt und über die Methoden manipuliert werden.
In einem imperativen Algorithmus gibt es Variable, die verschiedene Werte annehmen
können. Die Menge aller Variablen und ihrer Werte sowie der Programmzähler
beschreiben den Zustand zu einem bestimmten Zeitpunkt. Ein Algorithmus bewirkt
eine Zustandstransformation.
Ein Algorithmus heißt funktional, wenn die zugrunde liegende Berechnungsvorschrift
mittels einer Sammlung von Funktionen definiert wird. Die Funktionsdefinitionen
dürfen insbesondere Rekursionen und Funktionen höherer Ordnung enthalten.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-19
Algorithmus von Euklid
Der folgende, in einer imperativen Programmiersprache formulierte
Algorithmus von Euklid
berechnet den größten gemeinsamen Teiler der Zahlen x , y ∈ N mit x ≥ 0 und y > 0:
a := x;
b := y;
while b
do r :=
a :=
b :=
od
# 0
a mod b;
b;
r
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-20
Algorithmus von Euklid
Variable
r
a
b
z2
–
36
52
z5
36
52
36
z8
16
36
16
z11
4
16
4
z14
0
4
0
ggT(36, 52) = 4
Durchlaufene Zustände:
z0, z1, z2, ... , z14
Zustandstransformation:
z0 7−→ z14
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-21
Imperatives Programmieren
• In einem imperativen Programm gibt es Variable, die Werte speichern können. Die
Variablen und ihre Werte legen den Zustand des Programms fest. Der Zustand
ändert sich mit dem Ablauf des Programms.
• Die Wertzuweisung gestattet es, den Zustand zu verändern.
• ◦ Mit einer Sequenz können Anweisungen nacheinander ausgeführt werden.
◦ Die Selektion erlaubt die Auswahl zwischen Anweisungen.
◦ Anweisungen können mit der Iteration wiederholt werden.
• ◦ Eingabe-Anweisungen ermöglichen es, den Zustand von außen zu beeinflussen.
◦ Ausgabe-Anweisungen erstellen einen Ausdruck des Zustands (oder eines Teils
davon).
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-22
Imperatives Programmieren
• Prozeduren: Abstraktionen von Anweisungen
• Funktionen: Abstraktionen von Ausdrücken
• Datentypen:
◦ Primitive Datentypen:
boolean, char, int, real
◦ Zusammengesetzte Datentypen:
enumeration, array, record, pointer
◦ Typdeklarationen: Abstraktionen von Datentypen
Typsysteme können unabhängig von Paradigmen und Sprachen definiert und
untersucht werden.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-23
Imperatives Programmieren
• Weitere Kontrollstrukturen
• Module
• Ausnahmebehandlung
• Parallelverarbeitung
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-24
Algorithmus von Euklid
• imperative/iterative Formulierung:
while b #
do r :=
a :=
b :=
od
0
a mod b;
b;
r
• funktionale/rekursive Formulierung:
(
a
b=0
ggT(a,b) =
ggT(b, a mod b) b =
6 0
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-25
Algorithmus von Euklid
(Scheme, funktional)
(define (ggT a b)
(if (= b 0)
a
(ggT b (remainder a b))))
(ggt 36 52)
> 4
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-26
Funktionales Programmieren
• Ein funktionaler Algorithmus formuliert die Berechnungsvorschrift durch eine
Menge von Funktionen.
• Die Funktionen können wechselseitig-rekursiv oder auch
• von höherer Ordnung (Funktionale) sein.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-27
Funktionen höherer Ordnung
(define (inc n) (+ n 1))
(define (square x) (* x x))
(define (cube x) (* x x x))
(define (sum f a next b)
(if (> a b)
0
(+ (f a)
(sum f (next a) next b))))
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-28
(define (sum-square a b)
(sum square a inc b))
(define (sum-cube a b)
(sum cube a inc b))
> (sum-square 1 4)
30
// 30 = 1+4+9+16
> (sum-cube 1 4)
100
// 100 = 1+8+27+64
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-29
Deduktive Algorithmen
• Ein deduktiver (logischer) Algorithmus führt Berechnungen durch, indem er aus
Fakten und Regeln weitere Fakten, sogenannte Anfragen (Ziele), beweist.
• Fakten:
P
• Regeln:
P if Q1 and Q2 and ... and Qk
Regeln dieser Form werden auch Horn-Klauseln genannt. Fakten können als Regeln
mit k = 0 gesehen werden.
• Die folgenden Beispiele wurden in der deduktiven Programmiersprache Prolog
geschrieben.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-30
Beispiel: Eingabe der Fakten und Regeln
vater(johann,heinrich).
vater(johann,thomas).
vater(heinrich,carla).
vater(thomas,erika).
vater(thomas,klaus).
vater(thomas,golo).
vater(thomas,monika).
vater(thomas,elisabeth).
vater(thomas,michael).
verheiratet(johann,julia).
verheiratet(heinrich,maria).
verheiratet(thomas,katia).
mutter(X,Y) :- vater(Z,Y), verheiratet(Z,X).
geschwister(X,Y) :- vater(Z,X), vater(Z,Y), X \= Y.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-31
Beispiel: Eingabe der Anfragen
Nachdem das Programm eingelesen wurde, können Anfragen gestellt werden, die von
einer Interferenzmaschine, zum Beispiel einem Prolog-Interpreter, beantwortet werden.
Anfragen werden nach der Eingabeaufforderung | ?- gestellt:
| ?- geschwister(thomas, heinrich).
true ? ;
no
| ?- geschwister(thomas, golo).
no
Die Ausgabe true bedeutet, dass die Anfrage positiv beantwortet wurde, das heißt,
dass Thomas und Heinrich Geschwister sind. Nach einem Fragezeichen erwartet der
Interpreter Anweisungen, wie fortzufahren ist. Ein Semikolon ist die Aufforderung,
nach weiteren Lösungen zu suchen.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-32
Beispiel: Eingabe der Anfragen
Falls eine Anfrage eine Variable enthält, werden alle Belegungen für die Variablen
ermittelt, die die Aussage wahr werden lassen. Wenn wir die Geschwister von Golo
suchen, stellen wir die folgende Anfrage.
| ?- geschwister(X,golo).
X = erika ? ;
X = klaus ? ;
X = monika ? ;
X = elisabeth ? ;
X = michael ? ;
no
Erika, Klaus, Monika, Elisabeth und Michael sind also die Geschwister von Golo.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-33
Beispiel: Eingabe der Anfragen
Eine Anfrage kann mehr als eine Variable enthalten. Durch
| ?- geschwister(X,Y).
werden insgesamt 32 Geschwisterpaare ermittelt, da Paare wegen der Symmetrie der
Relation doppelt ausgegeben werden.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-34
Algorithmus von Euklid
(Prolog, deduktiv)
ggt(A,0,A).
ggt(A,B,Z) :- U is A mod B, ggt(B,U,Z).
| ?- ggt(36,52,Z).
Z = 4 ?
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-35
Funktionen und Relationen
• Eine Funktion f : X −→ Y ordnet jedem Element der Menge X
(Definitionsbereich) genau ein Element der Menge Y (Wertebereich) zu:
x 7−→ f (x )
• Eine Relation R ⊆ X × Y besteht aus Paaren (x , y ) ∈ X × Y . Dabei kann es zu
einem x ∈ X mehrere Elemente y ∈ Y mit
(x , y ) ∈ R
geben.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-36
Deduktives Programmieren
• Deduktives Programmieren beschäftigt sich mit Relationen und nicht mit
Funktionen.
• Fakten und Regeln können als Eingabe von Relationen bzw. als
Konstruktionsvorschriften für Relationen angesehen werden.
• Anfragen überprüfen, ob Paare in einer bestimmten Relation stehen oder ermitteln
solche Paare:
◦ Eine Anfrage der Form P(x , y ) überprüft, ob x und y bezüglich P in Relation
stehen.
◦ Die Anfrage P(X , y ) berechnet alle x mit (x , y ) ∈ P.
◦ Anfragen der Form P(X , Y ) führen zur Ausgabe aller Paare (x , y ) mit
(x , y ) ∈ P.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-37
Deklaratives Programmieren
• In deklarativen Programmiersprachen wird aus einer nach bestimmten Regeln
gebildeten mathematischen Formulierung eines Problems automatisch ein
Programm erzeugt.
• Die formale Problembeschreibung kann z. B. auf der Prädikatenlogik (logische
Programmiersprachen) oder dem λ-Kalkül (funktionale Programmiersprachen)
basieren.
• Deklarative Programmiersprachen haben sich vom Konzept der ausführenden
Maschine gelöst.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-38
Entwicklung der Programmiersprachen
.
.
2000
C#
1995
Programmiersprachen in der
Informatikausbildung
JAVA
SCHEME (standard)
1990
• Algol
OCCAM
C++
1985
CSP
ADA
1980
SMALLTALK80
MODULA−2
1975 C
SCHEME
PROLOG
PASCAL
1970
ALGOL68
• Algol68
• Modula-2
LOGO
SIMULA
• Scheme
1965 PL/I
BASIC
1960
1955
COBOL
ALGOL
LISP
FORTRAN
• Java
.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-39
Programmiersprachen
• Imperative Programmiersprachen:
Cobol, Fortran, PL/I, Basic, Algol, Algol68, Pascal, Modula-2, C, Ada.
• Funktionale Programmiersprachen:
Lisp, Scheme, ML, Haskell, Scala. Die Sprache Scala ist eine Erweiterung von Java.
• Objektorientierte Programmiersprachen:
C++, Eiffel, Smalltalk, Java, C#, Oberon.
• Logische Programmiersprachen:
Prolog.
• Hybride Sprachen: z. B. Java, C++, Scala.
• Skriptsprachen, Spezialsprachen
• prozedurales, deklaratives Vorgehen
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-40
Programmierveranstaltungen
• Imperative und objektorientierte Programmierung
◦ Programmieren I
◦ Programmieren II
(Java, 1. Sem.)
(Java und kleiner Blick auf C, JavaScript, 2. Sem.)
• Software Engineering
◦ Software Engineering I (UML, 3. Sem.)
◦ Software-Entwicklungspraktikum
(UML, die Programmiersprache legt das betreuende Institut fest, 4. Sem.)
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-41
Programmierveranstaltungen (Wahlpflicht)
• Übergeordnete Sichtweise, funktionale Programmierung
◦ Programmieren f. Fortgeschrittene (zurzeit: Haskell)
• Logisches Paradigma, weitere Logiken
◦ Logik in der Informatik (Prolog, Master)
• Bedeutung und Umsetzung von Programmiersprachen
◦ Semantik von Programmiersprachen (Master)
◦ Compiler I, II, Praktikum (Master)
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-42
Programmierlabor im Sommersemester 2015
• Das Programmierlabor findet in diesem Semester vom
29. bis zum 31. Juli, vom 03. bis zum 05. August und am 10. und 12. August 2015
statt.
• Wann und wie Sie sich anmelden können, sage ich Ihnen nächste Woche.
12.2 Programmierparadigmen und -sprachen und Veranstaltungen
12-43
Herunterladen