Objektorientierte Programmierung Proseminar Programmiersysteme 31.03.2004 Lehrstuhl für Programmiersysteme Prof. Gert Smolka Vortragender: Philipp Brendel Tutor: Andreas Rossberg Gliederung • Konzepte objektorientierter Programmierung (OOP) • Java • Smalltalk • Diskussion Konzepte der OOP - Objektbegriff - • Erste OOP: Simula 67 – entwickelt am Norwegian Computing Center um 1960 – dient zur Programmierung ereignisbasierter Simulationen – erfordet Datenstruktur zur Repräsentation unterschiedlicher „Ereignisse“ Konzepte der OOP - Objektbegriff • Ein Objekt vereint Daten und Prozeduren, die auf diesen Daten operieren, in einem Wert • Eigenschaften, die den meisten klassenbasierten objektorientierten Programmiersprachen gemein sind: – Enkapsulierung – Vererbung – dynamische Bindung – Subtyping Konzepte der OOP - Ein Beispiel in ML - • Implementierung eines Zählers mit Prozeduren zur Abfrage (get) und Erhöhung (inc) • Realisierung durch Prozedur newCounter : unit -> counter zur Erzeugung neuer Objekte des Typs counter Konzepte der OOP - Ein Beispiel in ML type counter = { get:unit -> int, inc:unit -> unit } fun newCounter () val n in { get inc } end = let = ref 0 = fn () => !n, = fn () => n := !n + 1 > newCounter = fn : unit -> counter Konzepte der OOP - Ein Beispiel in ML Enkapsulierung: • Verbergung der Referenz n, die den Zählerstand enthält • Zugriff auf Zählerstand nur durch offengelegte Prozeduren: > > > > val c = newCounter () val c = {...} : counter val i = #get(c) () val i = 0 : int #inc(c) () val it = () : unit val j = #get(c) () val j = 1 : int Konzepte der OOP - Ein Beispiel in ML • Erweiterung des Zählers um eine Reset-Prozedur: type reset_counter = { get:unit -> int, inc:unit -> unit, reset:unit -> unit } fun newResetCounter () = let val n = ref 0 in { get = fn () => !n, inc = fn () => n := !n + 1, reset = fn () => n := 0 } end Konzepte der OOP - Ein Beispiel in ML • Subtyping: Werte vom Typ reset_counter sind gültige Argumente für Prozeduren, die Werte vom Typ counter erwarten (in idealisiertem ML-Dialekt). • Dynamische Bindung: Der in einer solchen Prozedur ausgeführte Code hängt von der Implementierung des Arguments ab. > > > > fun f (c:counter) = #inc(c) () ; #get(c) () val f = fn : counter -> int val (c, c‘) = (newCounter (), newResetCounter()) val c = {...} : counter val c‘ = {...} : reset_counter f c val it = 1 : int f c‘ val it = 1 : int Konzepte der OOP - Subtyping • Ein Typ σ ist ein Subtyp eines Typs τ (σ ≤ τ), wenn in jedem Kontext, der einen Wert des Typs τ erwartet, ein Wert des Typs σ verwendet werden kann • Subtyping definiert eine Relation ≤ Typ Typ, die folgende Eigenschaften aufweist: – Reflexivität – Transitivität – Antisymmetrie Die Subtypingrelation ist also eine Teilordnung. Konzepte der OOP - Subtyping • Erweiterung des Typsystems mit Typrelation R um eine Subsumtionsregel, die Subtyping ermöglicht: (, t , ) R ( t , ) R Konzepte der OOP - Subtyping Regeln für Subtyping von Records: i {1,...,n} : i i { 1..., n } { 1... n } { 1 ... n 1} { 1 n } Regel für Subtyping von Prozeduren: ' ' ' ' Java • Entwickelt von SUN Microsystems um 1990 Designziele: – Offenheit: Klassen werden nach Bedarf zur Laufzeit geladen (dynamisches Linking), Objekttypen können zur Laufzeit im- und exportiert werden – Portabilität: Programme werden zu Bytecode kompiliert und laufen auf einer virtuellen Maschine – Sicherheit: Mechanismen zur Verhinderung von Sicherheitsverletzungen sind Bestandteil von Java Java • Java ist klassenbasiert: Schemata, die die Implementierung von Objekten definieren, heißen Klassen • Klassen definieren Prozeduren (Methoden) und Daten (Felder oder Instanzvariablen) Java • jedes Objekt ist eine Instanz einer Klasse • instanzerzeugende Prozeduren heißen Konstruktoren • Enkapsulierung erfolgt durch Zugriffsmodifizierer (public, private, protected und package), die für jede Methode und jedes Feld wählbar sind Java • Vererbung: Jede Klasse erbt von genau von einer Oberklasse, deren Code sie weiterverwenden oder spezialisieren kann • Die Subtypingrelation ist durch die Vererbungshierarchie gegeben: ein Objekt wird als Instanz aller seiner Oberklassen betrachtet (Nominelles Subtyping im Gegensatz zum strukturellen Subtyping des ML-Beispiels) Java - Codebeispiel Definition einer Zählerklasse in Java: class Counter extends Object { private int n; public Counter() { n = 0; } public int get() { return n; } public void inc() { n = n + 1; } } Verwendung der Klasse: Counter c = new Counter(); int i = c.get(); c.inc(); int j = c.get(); Am Ende des Beispiels hat i den Wert 0 und j den Wert 1. Smalltalk • entwickelt von Xerox PARC in den 1970er Jahren • Designziele: – simples Konzept – Flexibilität – Betriebssystem des DYNABOOK – von „Nichtprogrammierern“ verwendbar Smalltalk • äußerst einfaches und elegantes Konzept: „Alles ist ein Objekt“ • Programme werden ausgeführt, indem sogenannte Nachrichten an Objekte geschickt werden, die diese behandeln • äußerst einfache Syntax Smalltalk • Komplexität durch umfangreiche Klassenbibliothek • Beispiel für konsequente Einhaltung der Objektmetapher: – Klassen sind Objekte, Instantiierung durch Senden einer Nachricht an Klassenobjekt – Klassen werden durch Senden einer Nachricht an ein Metaclass-Objekt erzeugt Smalltalk • Enkapsulierung ist fest vorgegeben: Methoden sind öffentlich, Instanzvariablen sind geschützt • Dynamische Typisierung • Objekte haben die Möglichkeit, individuell auf unbekannte Nachrichten zu reagieren, indem sie die Nachricht doesNotUnderstand implementieren Smalltalk - Codebeispiel Definition einer Zählerklasse in Smalltalk: Object subclass: #Counter instanceVariableNames: 'n' initialise (n = nil) ifTrue: [n 0] inc self initialise. n (n + 1) get self initialise. n Smalltalk - Codebeispiel Verwendung der Klasse: c Counter new. i c get. c inc. j c get. Am Ende des Beispiels hat i den Wert 0 und j den Wert 1. Diskussion - Interessante Aspekte objektorientierter Programmierung - • Objektmetapher erleichtert Enkapsulierung • Zerlegung von Problemen ist in OOP „natürlich“ • Wiederverwendbarkeit von Code in verschiedenen Szenarien Diskussion - Probleme der OOP • Mehrfachvererbung: – Was geschieht, wenn dieselbe Methode von mehreren Oberklassen geerbt werden soll? – Wie geht man vor, wenn zweimal von derselben Klasse geerbt wird? • „Inheritance is not subtyping“: Subklassen sind oft keine Subtypen, Beispiel: – Klasse Point2D besitzt Methode boolean equal (Point2D q) – Klasse Point3D erbt von Point2D und implementiert boolean equal (Point3D q) Point3D ist kein Subtyp von Point2D Diskussion • Binary-Methods-Problem: Im Gegensatz zu prozeduraler Programmierung fällt der Objektzugriff bei OOP einseitig aus: Point.add(Point q) { return new Point (this.x + q.x, this.y + q.y); } Literatur • John C. Mitchell: Concepts in Programming Languages. Cambridge University Press 2003 • Kim Bruce, Luca Cardelli, Giuseppe Castagna, Hopkins Objects Group, Gary T. Leavens, Benjamin Pierce: On Binary Methods, Theory And Practice of Object Systems. • Richard P. Gabriel, Objects Have Failed, OOPSLA Debate 2002 • William Cook, Walter Hill, Peter Canning, Inheritance Is Not Subtyping. Principles of Programming Languages (POPL) 1990