Objekttechnologie Reihenherausgeber Martin Schader, Mannheim
Springer
Berlin Heidelberg New York Barcelona Budapest Hongkong London Mailand Paris Santa Clara Singapur Tokio
Objekttechnologie
Martin Schader und Michael Rundshagen Objektorientierte Systemanalyse 2. Auflage IX, 241 Seiten. 1996 Martin Schader und Stefan Kuhlins Programmieren in C++ 4. Auflage XI, 386 Seiten. 1997 Martin Schader Objektorientierte Datenbanken Die C++-Anbindung des ODMG-Standards X, 219 Seiten, 1997
Gunther Vinek
Objektorientierte Softwareentwicklung mit Smalltalk Mit 88 Abbildungen und 2 Tabellen
,
Springer
Prof. Dr. Gunther Vinek Universitat Wien Institut fUr Angewandte Informatik und lnformationssysteme RathausstraBe 19/4 A-lOlO Wien Osterreich
ISBN 3-540-62558-5 Springer-Verlag Berlin Heidelberg New York Die Deuuche Bibliothek - CIP-E.inheits~ufn.hme Vinek, Gunther: Objektorientierte Sofiwu"ntwidiung mit Smalltalk: mit 2 TI~Ueni Gunther Vinek. - I. Auf!. - Berlin; Heidel~rg; New York; Barcelona: Budapest; Hongkong: London; Mailand; Paris: Santa Clan: Singapur; Tokio: Springer, 1997 (Objektt«bnologie) ISBN J -54D.fi2SSS-5 Diesel Werk iSI IUbeberreclnlich geschUtzl. Die d.dlUcb bq:rUndeten Rechle, inlbesondere die der Obersetzung. des Nachdrucks, des VOrlags, der Entnahme von Ab· bildungen und Ta~l1en, der Funksendung, der Mikroverfilmung ode. der Vervieltalligung auf anderen Wegen und de. Spekherung in Dalennrarbeitungslnlagen, blei~n, IUch bei nur lwzugswein r Verwertung, vor~haIten . Eine Vervieltaltigung diues Werm oder VOn Teilen diese. Werkes ist l uch im EinzelfaIl nur in den Grenzen der ge.setzJicben Bestimmungen des Urheberr...:;hugesetzes der Bundesrepublik IXutschland vom !J. September 1965 in der ;eweib gellenden Fauung zullssig. Sic ilt grund.ltdicb vcrgUtunglpflicbtig. Zuwiderhandlungen unterliegen den StnJbe$limmungcn del Urheberrecbtsgesetzes. C Springer-Verlag Berlin Heidelberg 1991
Die Wicdergabe von Gebrauchsnamen, Handclsnamen, Warenbczeichnungen IUW. in dicscm Wcrk berechligl aucb obne belondere Kennze:ichnung nidI! zu der Annabme, dall soleh. Namen im Sinne de. Warenzeich en- und Ma.kenscbutz-Gesetzgcbung ais frei tu betrachten wiren und daber von jcdermann benutt\ werden dilrften. SPIN 10S6!JIII
42/2202-5 4 3 2 I 0 - Gcdruckt auf slu.efreiem Papi.r
Vorwort Objektorientierung ist das dominierende Paradigm a der Informationsverarbeitung in diesem Jahrzehnt. Die Vorstellung, daB Objekte mit individuellem Zustand und einem fUr ihre Art charakteristischen Verhalten miteinander kommunizieren, urn Teile einer gemeinsamen Aufgabe autonom erfUllen, pragt nicht nur die Denkweise bei der Analyse von realen Geschiiftsvorgangen und bei der Entwicklung von Anwendungssystemen, sondern bildet auch die Basis der Betrachtung vieler Bereiche des sozialen und okonomischen Lebens. Smalltalk ist eines der besten Werkzeuge zur Realisierung objektorientierter Software. Es ist weit mehr als nur eine objektorientierte Programmiersprache, es bietet eine offene und erweiterbare Arbeitsumgebung mit integrierten Werkzeugen und einer umfassenden Klassenbibliothek, wodurch dem Anwendungsentwickler viele technische Detailarbeit abgenommen wird, sodaB er sich auf das Wesentliche einer Applikation konzentrieren kann. Wenige einfache Konzepte und ihre konsequente Realisierung bilden die Grundlage fUr die Produktivitat eines Smailtalk-Systems. Es gibt viele Biicher iiber Smalltalk, welche entweder eine griindliche EinfUhrung in alle Aspekte der Sprache und der Entwicklungsumgebung bieten sowie Technik und Stil des Programmierens im Detail behandeln oder sich speziellen Bereichen widmen, wie etwa der Vorgangsweise und den Werkzeugen zur Gestaltung von Benutzerschnittsteilen. Das vorliegende Buch befaBt sich ebenfalls und in erster Linie mit Smalltalk. Es erhebt weder den Anspruch, aile Aspekte der Objektorientierung zu behandeln, noch den ProzeB der Softwareentwicklung darzustellen, wohl aber den Bezug zu diesen Themen aus der Sicht von Smalltalk herzustellen. Es ist das Ziel diese Buches, einerseits die Konzepte und Mechanismen von Smalltalk selbst zu prasentieren und andererseits aufzuzeigen, wie diese eingesetzt werden konnen, urn die in der Analyse- und Entwurfsphase erstellten Strukturen in Small talk zu realisieren. Dariiber hinaus so11 deutlich gemacht werden, daB diese Konzepte allen Phasen der Systementwicklung zugrundegelegt werden konnen, sodaB ein durchgangiger Weg vom konzeptuellen Modell zum fertigen Programm entsteht. Die Auswahl der Themen ist so getroffen, daB Strukturen und Mechanismen in den Vordergrund geriickt werden, wobei manche, fUr die Entwicklung praktisch einsetzbarer Software wesentliche Bereiche, beispielsweise Fehlermanagement, Realisierung von Benutzerschnittstellen, Anbindung an Datenbanken oder Entwicklung verteilter Systeme, nur erwahnt oder ganz auBer acht gelassen wurden. Neben der Prasentation von grundlegenden Konzepten und Basisklassen werden auch abgeleitete Konzepte und Metastrukturen
VI
Vorwort
behandelt, urn dadurch einen Hinweis auf die Flexibilitat eines SmalltalkSystems zu geben. Einige aufeinander aufbauende Fallbeispiele sollen den Zusammenhang zwischen konzeptionellen Modellen und ihrer Realisierung in Small talk zeigen und einen Eindruck von der inkrementellen und iterativen Anwendungsentwicklung bieten. Das Buch richtet sich an Praktiker, denen es die Charakteristika und Einsatzmoglichkeiten von Small talk vermitteln und damit auch eine Unterstiitzung fUr Entscheidungen uber den Einsatz von objektorientierten Methoden im allgemeinen und von Smalltalk im besonderen bieten soli. Es richtet sich ebenso an Studenten, insbesonders der Wirtschaftsinformatik und Informatik, und an ihre Lehrer, die sich mit objektorientierter Modellierung und Realisierung von Anwendungssystemen befassen. Es wird dabei vorausgesetzt, daB die Leserinnen und Leser Grundkenntnisse in objektorientierten Techniken, in der Vorgangsweise des Entwurfes von Anwendungen und auch Erfahrungen mit einer Programmiersprache besitzen. Die Prasentation der behandelten Themen beruht auch auf Erfahrungen, die der Autor in Smalltalk-Kursen sowohl an der Universitat als aueh in der Wirtsehaft sammeln konnte. Die fall weise angefiigten und teilweise mit L6sungen versehenen Aufgaben sollen nieht nur Anregungen fUr selbstandiges Arbeiten geben, sondern aueh auf Situationen hinweisen, die in der Praxis oft AnlaB fur Fragen sind. Siimtliche Programme und Beispiele dieses Buehes sind mit Hilfe der Entwieklungsumgebung VisualWorks\Smalltalk® und teilweise mit ObjeetStore® entworfen. t Diese Version von Smalltalk steht in direkter Naehfolge des urspriingliehen Smalltalk-80 und beruht in wesentliehen Teilen auf der von A. Goldberg und D. Robson [17] besehriebenen Implementation. Es ist unvermeidlieh, daB systemnahe Beispiele dieses Buehes fUr diese Smalltalk-Implementation speziflSeh sind. Mein Dank riehtet sich an jene Person en, die zum Entstehen dieses Buehes beigetragen haben. Ich danke meinem Kollegen, Herrn Univ. Doz. Dr. Martin Hitz fUr viele wertvolle Anregungen und fUr das kritisehe Lesen des Manuskriptes. Ich danke auch den Mitarbeitern des Springer-Verlages, insbesonders Herrn Dr. Werner A. Muller, der viel Verstandnis dafur aufgebracht hat, daB ein solches V orhaben viel mehr Zeit in Anspruch nimmt, als man urspriinglich dafiir vorsieht. Einen betrachtlichen Teil dieser Zeit habe ieh meiner Familie und meinen Freunden vorenthalten. Fur die aufgebrachte Geduld und Einsieht gilt mein Dank im besonderen Malle meiner Frau Hannelore und meiner Toehter Elisabeth. Wien, im Dezember 1996
G. Vinek
t VisualWorks\Smalltalk® ist ein eingetragenes Warenzeichen von ParcPlace-Digitalk Inc., ObjectStore® ist ein eingetragenes Warenzenzeichen von Object Design, Inc. (001).
Inha Itsverzeichnis
1
Smalltalk: Konzepte, Stmkturen nnd Mechanismen ................................. l 1.1 1.2 1.3
Das Wesen von Smalltalk .................................................................. 1 Objekte und ihre Namen ................................................................... 2 Der konzeptionelle Objektraum ........................................................ 6 1.3.1 Ebenen des konzeptionellen Objektraumes .......................... 7 1.3.2 Der konzeptionelle Objektraum zwischen Realitiit und technischer Reprasentation ............................................ 11 1.3.3 Grenzen des Objektraumes ................................................... 12 1.4 Klassen und ihre Auspragungen ..................................................... 13 1.5 Klassenhierarchie und Strukturvererbung...................................... 15 1.6 Klassenhierarchie und Verhaltensvererbung ................................. 18 1.6.1 Methodensuche ...................................................................... 19 1.6.2 Die Konstanten "self' und "super" ....................................... 21 1.7 Die Erreichbarkeit von Objekten .................................................... 22 1.7.1 Der Horizont von Objekten ................................................... 22 1.7.2 Die Sichtbarkeit von Objektnamen ...................................... 23 1.8 Das Verhalten von Objekten ........................................................... 26 1.8.1 Der dynamische Horizont von Methoden ........................... 26 1.8.2 Mechanismus der Botschaftsiibermittlung .......................... 28 1.9 Der Lebenszyklus von Objekten ..................................................... 30 1.10 Die Architektur des Smalltalk-Systems .......................................... 31 1.10.1 Der physische Objektraum .................................................... 31 1.10.2 Die Komponenten des Smalltalk-Systems ........................... 32 1.11 Blicke in eine tiefere Systemebene ................................................. 33 1.11.1 Klassen und Metaklassen ...................................................... 34 1.11.2 System- und Poolverzeichnisse ............................................. 36 1.12 Realisierung der Konzepte 38 1.12.1 Variablenverzeichnisse .......................................................... 38 1.12.2 Klassen und Variablenverzeichnisse .................................... 39 1.12.3 Die Vererbungsbeziehung ..................................................... 41 1.12.4 Die Instanzierungsbeziehung zwischen einer Klasse und ihren Auspragungen ...................................................... .46 1.12.5 Metaklassen ............................................................................ 48
VIII 2
Inhaltsverzeichnis SmalltaIk: Elemente der Sprache ............................................................ 51
2.1 2.2
2.3
2.4
2.5
2.6 3
Methoden .......................................................................................... 51 Ausdriicke ......................................................................................... 56 2.2.1 Literale .................................................................................... 57 2.2.2 Konstante ................................................................................ 63 2.2.3 Variable ................................................................................... 64 2.2.4 Zuweisungen .......................................................................... 65 2.2.5 Botschaftsausdriicke ............................................................... 67 Blocke ................................................................................................ 74 2.3.1 Die Syntax von Blocken ........................................................ 75 2.3.2 Die Klasse BlockClosure ....................................................... 77 2.3.3 Primlirrnethoden .................................................................... 80 Kontrollstrukturen ........................................................................... 82 2.4.1 Die Klassen False und True .................................................. 83 2.4.2 Enumerationsmethoden ........................................................ 85 Weiterftihrende Bemerkungen 90 2.5.1 Binare Selektoren ................................................................... 90 2.5.2 Indirekte Botschaftsiibermittlung ......................................... 91 2.5.3 Blocke und "Lexical Scoping" ............................................... 93 2.5.4 Benennung von Variablen ..................................................... 97 Aufgaben ........................................................................................... 99
Ein erster Einsatz von SmailtaIk ............................................................ 103 3.1 3.2 3.3
Beispiel: einfache Zahlwerke ......................................................... 103 Beispiel: Zahlwerke mit Datum .................................................... 111 Beispiel: Erweiterte Zahlwerke ..................................................... 115 3.3.1 Zahlwerke mit zweitem Register ........................................ 115 3.3.2 Die Klassenhierarchie der Zahlwerke ................................ 118 3.3.3 Zusammengesetzte Zahlwerke ........................................... 121 3.4 Visualisierung von Zahlwerken ..................................................... 124 3.5 Aufgaben ......................................................................................... 129
4
Objektsammlungen ................................................................................ 131 4.1 4.2
Die Hierarchie der Kollektionen ................................................... 132 Generelle Methoden von Kollektionen ....................................... 133 4.2.1 Kardinalitat und Kapazitat .................................................. 134 4.2.2 Einftigen und Entfemen von Elementen ........................... 135 4.2.3 Enumeration ......................................................................... 136 4.3 Objekte mit indizierten Instanzvariablen ..................................... 142 4.3.1 Variable Klassen ................................................................... 143 4.3.2 Das Basisprotokoll variabler Klassen ................................. 146
Inhaltsverzeichnis 4.4
Einige wichtige Behiilterklassen .................................................... 147 4.4.1 Die abstrakte Klasse SequenceableCollection ................... 149 4.4.2 Die Klasse Array ................................................................... 150 4.4.3 Die Klasse ByteString .......................................................... 151 4.4.4 Die Klasse OrderedCollection ............................................. 152 4.4.5 Die Klasse SortedCollection ............................................... 159 4.4.6 Die Klasse Set. ...................................................................... 162 4.4.7 Die Klasse Dictionary .......................................................... 164 4.5 Sammelbehalter mit variabler Kapazitat ...................................... 166 4.6 Aufgaben ......................................................................................... 170
5
Mengen und Relationen ......................................................................... 175 5.1 5.2
Mengenoperationen ....................................................................... 175 Relationen ....................................................................................... 177 5.2.1 Die Klasse Relation .............................................................. 178 5.2.2 Die Selektion von Relationen ............................................. 181 5.2.3 Die Projektion von Relationen .......................................... .. 184 5.2.4 Der Verbund von Relationen .............................................. 185 5.3 Mehrfach polymorphe Methoden ................................................. 188 5.4 Aufgaben ......................................................................................... 192
6
Objektstmkturen .................................................................................... 197 6.1 Elementare Zuordnungsmethoden ............................................... 198 6.2 Attributzuordnungen ..................................................................... 199 6.3 Objektkopien ................................................................................... 204 6.3.1 Seichte Kopien ...................................................................... 207 6.3.2 Tiefe Kopien ......................................................................... 208 6.4 Eigenschaften von Objektzuordnungen ....................................... 211 6.5 Multiplizitat einer Zuordnung ....................................................... 212 6.6 Mehrfache Attributzuordnungen .................................................. 215 6.7 Varietlit einer Zuordnung ...............................................~ .............. 219 6.8 Heterogenitat einer Zuordnung .................................................... 225 6.9 Organisation von Mehrfachzuordnungen .................................... 228 6.9.1 Mengen von Partnerobjekten .............................................. 229 6.9.2 Anordnungen von Partnerobjekten .................................... 229 6.9.3 Verzeichnisse von Partnerobjekten .................................... 230 6.10 Indirekte Objektzuordnungen ....................................................... 231 6.11 Gekoppelte Objektzuordnungen ......................................~ ............ 234 6.12 Dynamische Einschrankungen ...................................................... 238 6.12.1 Initialisierung einer Zuordnung .......................................... 239
IX
x
Inhaltsverzeichnis 6.12.2 MutabiliHit einer Objektzuordnung .................................... 239 6.12.3 Flexibilitat einer Objektzuordnung .................................... 241 6.13 Untersuchung von Struktureigenschaften 243 6.14 Aufgaben ......................................................................................... 246
7
Verwaltung von Metainformationen fiber Objektstrokturen ................. 247 7.1 7.2
Beispiel: Studienwesen .................................................................. 247 Die Klasse AssociableObject .. ..................................................... 249 7.2.1 Die Struktur der Klasse AssociableObject ......................... 250 7.2.2 Die Metainformation einer Klasse ..................................... 252 7.2.3 Das Modellverzeichnis der Klassen .................................... 254 7.2.4 Das Beziehungsverzeichnis der Instanzen ......................... 257 7.3 Anwendung: Studienwesen ........................................................... 262 7.4 Aufgaben ................ ..... .................................................................... 266
8
Fallstudie: Geld .•..•.•...•.•..•.•.•..•.....•.••.•...•..•..•.•.••.•.•.•••.••...•..•..••...•..•..••..•. 269 8.1 Geldobjekte .................... ................................................................. 269 8.2 Klassenhierarchie: Magnitude ....................................................... 271 8.3 Die Klasse Money .......................................................................... 274 8.4 Aufgaben ........................................... .......................... .................... 280
9
Fallstudie: Konten .................................................................................. 281 9.1 9.2
10
Konten ............................................................................................. 281 Eine Hierarchie von Kontoklassen ............................................... 283 9.2.1 Die abstrakten Klassen Konto und Vollkonto .................. 283 9.2.2 Kontoumsatze ................................................ ........... ........... 287 9.2.3 Kontobewegungen ............................................................... 287 9.2.4 Einige konkrete Kontoklassen ............................................ 289 9.2.5 Beispiele fUr den Einsatz von Konten ................................ 290
Fallstudie: Banken.................................................................................. 293 10.1 10.2 10.3 10.4
Die Realitiit des Bankbetriebes ..................................................... 294 Strukturmodell eines Bankbetriebes ............................................ 295 Bankkunden .................................................................................... 297 Banken ... .......................................................................................... 299 10.4.1 Das Strukturmodell einer Bank .......................................... 299 10.4.2 Grundlegende Methoden einer Bank ................................. 301 10.4.3 Geschaftsfall: Anlegen eines Kunden ................................ 303 10.4.4 Registrieren und Zuordnen von Konten ............................ 306 10.4.5 Geschaftsfall: Eroffnen von Konten ................................... 308 10.4.6 Geschiiftsfall: Buchung auf einem Konto .......................... 310
Inhaltsverzeichnis 10.4.7 Geschaftsfall: Kontoiiberweisungen ................................... 312 10.4.8 Inforrnationen iiber Kunden ............................................... 314 10.4.9 Aufgaben ............................................................................... 315 11
Fallstudie: Bankwesen ............................................................................ 319 11.1 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9
12
Die Realitat des Bankwesens ......................................................... 319 Ein Modell des Bankwesens .......................................................... 320 Ein Blick in den konzeptionellen Objektraum ............................. 321 Zentralregister ................................................................................. 322 Erzeugen des Bankenservice ......................................................... 325 Bankregistrierungen ....................................................................... 330 Registrierte Banken ........................................................................ 331 Geschaftsfall: Registrierung einer Bank ....................................... 332 Aufgaben ......................................................................................... 335
Fallstudie: Zablungsverkehr zwischen Banken ..................................•... 337 12.1 12.2 12.3 12.4
Ein erweitertes Modell des Bankwesens ...................................... 338 Erweiterung der Klasse Bankenservice ......................................... 340 Kontoinforrnationen ....................................................................... 342 Bankauftrage ............................ ....................................................... 343 12.4.1 Inlandsiiberweisungen ......................................................... 344 12.4.2 Der Lebenszyklus einer Inlandsiiberweisung .................... 345 12.5 Erweiterung der Klasse Bank ........................................................ 349 12.6 Bearbeitung von Bankauftragen .................................................... 350
13
Persistenz von Objekten ......................................................................... 355 13.1 13.2 13.3 13.4
Kodierung von Objekten durch Ausdriicke ................................. 357 Kodierung von Objekten durch literale Felder ............................ 360 Das Binary Object Streaming Service ........................................... 362 Kodierung von Objekten durch Tupel relationaler Datenbanken ................................................................................... 364 13.5 Objektraumerweiterung durch objektorientierte Datenbanken ................................................................................... 365 13.6 Aufgaben ......................................................................................... 378
14
Erweiterte Konzepte und Mechanismen ................................................ 379 14.1 Kommunikationsmechanismen .................................................... 380 14.1.1 Gezielte Kommunikation zwischen Objekten ................... 381 14.1.2 Ungezielte Kommunikation zwischen Objekten: der Abhangigkeitsmechanismus ......................................... 381
XI
XII
Inhaltsverzeichnis 14.2 Selektive Kommunikation ..................... ........................................ 395 14.2.1 Feststellen des Senders einer Methode ............................. 396 14.2.2 Geschiitzte Register ............................................................. 397 14.3 Objekte mit dynamisch wechselnden Eigenschaften .................. 401 14.3.1 Objektmutation ............................ ........................................ 402 14.3.2 Objektdekoration .................................................................. 406
15
Literaturverzeichnis ................................................................................ 415
16
Programmverzeichnis ............................................................................. 419
17
Abbildungsverzeichnis ............................................................................ 427
18
Klassen- und Methodenverzeichnis ....................................................... 429
19
Index ....................................................................................................... 435
1 Smalltalk: Konzepte, Strukturen und Mechanismen
1.1
Das Wesen von Smalltalk
Was ist Small talk? Eine objektorientierte Programmiersprache wie andere auch? Eine Arbeitsumgebung fur die Entwicklung objektorientierter Software? Ein Vorratssystem zur Verwaltung und Bereitstellung wiederverwendbarer und modiflzierbarer Softwarekomponenten? Ein Werkzeug fUr die konzeptionelle Modellierung? Oder ein Hilfsmittel fUr die Gestaltung von Benutzerschnittstellen? Smalltalk ist ein System, das viele dieser Funktionen in sich vereint und doch nicht direkt mit den erwahnten Werkzeugen einzeln vergleichbar ist. Es stellt auf der Basis weniger und einfacher Konzepte die Funktionen solcher Werkzeuge bereit und zwar in einer einheitlichen und integrierten Form derart, daB kein Unterschied zwischen Werkzeug und Produkt besteht. Aile Komponenten der Entwicklungsumgebung wie etwa Editoren, Browser, Mentis aber auch Parser und Kompiler stehen als vorgefertigte, direkt oder modiflziert wiederverwendbare Elemente fUr neue Softwareprodukte zur VerfUgung. Smalltalk ist somit ein offenes System, das auf vieifliltige Weise erweiterbar und an spezielle Anforderungen adaptierbar ist. "Smalltalk is a vision" ist im Vorwort des ersten und grundlegenden Werkes tiber Smalltalk [17] zu lesen. Die damalige Vision der interaktiven Arbeit mit einem Computer mit Hilfe einer graphischen Benutzerschnittstelle und des Einsatzes dec Fenstertechnik ist inzwischen zur Realitat geworden. Die Vorstellung, Software als Simulationsmodell einer realen Welt zu sehen, die nicht ktinstlich durch Trennung in Daten und Funktionen denaturiert wurde, ist erst in letzter Zeit daran, den Charakter einer Vision zu verlieren. Small talk ist durch eine ausschlieBliche und rigorose Umsetzung des objektorientierten Paradigmas gekennzeichnet: es gibt nichts anderes als
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
2
1 Smalltalk: Konzepte, Strukturen und Meehanismen
Objekte! Es gibt also im besonderen keine Daten und daher aueh keine isolierten Prozeduren, die aufzurufen und mit Daten zu versorgen waren. Es gibt somit aueh keine Datenbestande und Programmbibliotheken im herkommlichen Sinne. Smalltalk verwaltet eine Menge von miteinander kommunizierenden autonomen Objekten. Diese haben einen individuellen Zustand und reagieren auf Anforderungen anderer Objekte in vorgegebener Weise, wobei sie zur ErfUIlung ihrer Aufgaben auf Dienste ihnen bekannter Objekte zUrUekgreifen konnen. Manehe Objekte sind einfaeh aufgebaut, andere sind komplex und aus mehreren Komponentenobjekten zusammengesetzt. Manehe Objekte sind mit der Gabe ausgestattet, auf Stimuli von auBen zu reagieren, andere wiederum haben die Fahigkeit, neue Objekte mit vorgegebenen Verhaltensmustern zu erzeugen. Anwendungssoftware in Smalltalk zu erstellen, heiBt letztlieh Vorsorge zu treffen, daB Objekte erzeugt und am Leben gehalten werden konnen, die den realen Objekten des Anwendungsgebietes in Struktur und Verhalten entsprechen und die untereinander in einer Weise kommunizieren, daB dadureh die Dynamik des Anwendungsgebietes reflektiert wird. Die Tatsaehe, daB in Smalltalk jegliehe Funktionalitat als Folge von Interaktionen zwischen koexistierenden Objekten zu sehen ist, bildet einerseits die Basis fUr die Maehtigkeit des Systems, sie ist aber andererseits aueh die Ursaehe daftir, daB ein betraehtlieher Anfangsaufwand fUr das Kennenlernen und Einarbeiten notwendig ist. So ist es nieht leieht moglieh, einzelne Themen wie etwa den syntaktisehen Autbau der Spraehe, die Klassenhierarehie mit ihren fUr die Systemfunktion wesentliehen Basisklassen oder die Arbeitsumgebung mit ihren Werkzeugen getrennt voneinander in linearer Abfolge darzustellen, ohne dabei wesentliehe Zusammenhange zu untersehlagen. Aus diesem Grunde wird einer ganzheitliehen Sieht Vorrang gegeben, aueh wenn es dabei unvermeidlieh ist, Begriffe zu verwenden, die erst an einer spateren Stelle behandelt werden. Die starke Betonung des Begriffes "Objektraum" als konzeptioneller Ort allen Gesehehens und seine graphisehe Veransehauliehung mogen dazu beitragen, eine Hilfe fUr das Verstandnis von Strukturen und Vorgangen zu geben und die Zusammenhange nieht aus den Augen zu verlieren.
1.2
Objekte und ihre Namen
Objekte sind von ihrer Umwelt abgegrenzte und mit einer eindeutigen Identitat versehene Entitaten, die einen individuellen, veranderbaren Zustand besitzen und ein vorgegebenes Verhalten aufweisen.
1.2 Objekte und ihre Namen
3
Objekte werden tiber Objektnamen angesprochen. Namen sind (innnerhalb ihres Kontextes) eindeutige Bezeichner fUr Objekte. Jedes Objekt kann gleichzeitig mehrere Namen haben, jeder Name hingegen ist stets genau an ein Objekt gebunden. Ausdrucksweisen der Art "ein Name bezeichnet, benennt oder referenziert ein Objekt", "ein Name ist mit einem Objekt belegt" oder "ein Objekt tragt einen Namen" bedeuten, daB zwischen dem Namen und dem Objekt eine aufrechte Bindung besteht. Die Bindung eines Objektes an (mindestens einen) Namen ist auch eine Voraussetzung fUr seine Existenz. Werden aBe Namensbindungen eines Objektes gelost, so ist das Objekt nicht mehr ansprechenbar und hat seine Existenzberechtigung verloren. Das Errichten der Bindung zwischen einem Namen und einem Objekt wird Zuweisung (des Objektes an den Namen) genannt. Den meisten Namen konnen zeitlich hintereinander verschiedene Objekte zugewiesen werden, aus diesem Grunde werden solche Namen auch als Variable bezeichnet. In einigen Sonderfallen ist die Bindung von Namen an Objekte vorgegeben und unabanderlich, sodaB die Namen die Bedeutung von Konstanten haben. In Abbildung 1-1 sind Objekte, Objektnamen und ihre Beziehung graphisch veranschaulicht. Objekte werden durch Rechtecke (hier mit abgerundeten Ecken) symbolisiert, die graue Schattierung weist darauf hin, daB sie abgekapselt und von auBen nicht einsehbar sind. Die Beschriftung im oberen Tell der Objektsymbole gibt einen Hinweis auf die Art der Objekte, im unteren Tell kann eine Angabe gemacht werden, welche das Objekt in seinem aktueBen Zustand in Form einer Zeichenkette charakterisiert. Beispielsweise kann das in Abbildung 1-1 mit dem Namen breite bezeichnete Objekt in schriftlicher Form durch 12 charakterisiert werden, die Angabe einObjekt weist darauf hin, daB es ist von einer nicht naher spezifizierten Art ist.
Abbildung 1-1
Objekte und Namen
4
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Namen sind durch Kreise symbolisiert, die mit einem Bezeichner versehen sind. Ein von einem Namen zu einem Objekt weisender Pfeil zeigt die Bindung zwischen dem Namen und dem Objekt an. Man erkennt aus Abbildung 1-1, daB die N amen t ecke und spitze Synonyme sind, also beide dasselbe Objekt bezeichnen. Weiterhin erkennt man, daB es fUr das Objekt breite offensichtlich einen anderen Namen gibt, der aber hier nicht sichtbar ist. Wurde ausgehend von der in Abbildung 1-1 gezeigten Situation die Zuweisung spitze := breite ausgefUhrt, so wurde spitze nunmehr jenes Objekt ben ennen, das auch von breite referenziert wird. Es sei bereits an dieser Stelle darauf hingewiesen, daB Namen obne Einschrlinkung mit beliebigen Objekte verb un den werden k6nnen. Es gibt insbesonders keine M6glichkeit, bei der Vereinbarung eines Namens festzulegen, daB dieser Name nur Objekte einer bestimmten Art referenzieren darf. In Smalltalk sind Variable nicht statisch typisiert.
ecke
Abbildung 1-2
Die innere Struktur eines Objektes
Objekte sind im allgemeinen selbst wieder aus Komponentenobjekten aufgebaut. In Abbildung 1-2 ist das mit ecke (und gleichzeitig auch mit spitze) bezeichnete Objekt ge6ffnet, sodaB sein Aufbau inspiziert werden kann. Es enthlilt zwei Namen x und y, uber die es mit zwei anderen Objekten in Beziehung steht, welche seinen Zustand reprlisentieren. Diese nur objektintern sichtbaren Namen k6nnen durch Zuweisung an wechselnde Objekte gebunden werden, sie werden deshalb als Zustandsvariable oder Instanzvariable bezeichnet. Anzahl und Namen der Instanzvariablen bilden die fur aIle Objekte einer Art gleiche Struktur, die Belegung der Instanzvariablen mit Objekten charakterisiert den jeweiligen, fUr jedes Objekt individueIlen Zustand. t Es wird in dec Foige nicht zwischen Namen und Bezeichnem unterschieden.
1.2 Objekte und ihre Namen
5
Die Instanzkonstante self (sie wird manehmal aueh als "Pseudovariable" bezeiehnet) stellt einen Namen dar, dureh den sich ein Objekt selbst referenzieren kann. Wlihrend die Instanzvariablen bei der Festlegung der Struktur einer Objektart vereinbart werden miissen, steht die Konstante self ohne explizite Vereinbarung zur VerfUgung. Dureh die Belegung einer Instanzvariablen mit einem Objekt wird eine Beziehung zwischen zwei Objekten etabliert, die auf unterschiedliche Art interpretiert werden kann. Beispielswelse kann die in Abbildung 1-2 gezeigte Situation interpretiert werden als "das Objekt ecke wird durch die in Beziehung gesetzten Objekte namens x und y beschrieben", "es ist ein komplexes, aus den Objekten x und y zusammengesetztes Objekt", oder "es enthlilt diese Objekte" oder auch nur "es hat diese Objekte zugeordnet". Welcher dieser Interpretationen in einem speziellen Fall der Vorzug zu geben ist, hlingt von den Objekten der Realitlit ab, die durch Smalltalk-Objekte modelliert werden. Die in der Abbildung gewlihlten Namen sowie die Besehriftung der Objekte legen nahe, daB das geoffnete Objekt einen zweidimensionalen Punkt darstellt, der durch die kartesischen Koordinaten x und y gegeben ist. Die Instanzvariablen referenzieren selbst wieder Objekte, die offensichtlich so aufgebaut sind, daB ihr Zustand den Wert von ganzen Zahlen reprlisentiert. Selbst einfache "Zahlenwerte" werden in Smalltalk durch Objekte dargestellt - es gibt in Smalltalk niehts anderes als Objekte! Das Verhalten von Objekten liuBert sich dadureh, daB fUr jedes Objekt eine Menge von Botscha/ten (Nachrichten) gegeben ist, die es versteht und auf die es in festgelegter Weise reagieren kann. Die Reaktion auf eine empfangene Botsehaft besteht in jedem Fall darin, daB das Objekt dem Sender der Botschft als Ergebnis seiner Aktivitlit ein Riickgabeobjekt iibermittelt. Zur DurchfUhrung dieser Aktivitlit kann das Objekt auf Dienste anderer Objekte oder aueh auf eigene Dienste zurUckgreifen, die in gleicher Weise durch Ubersendung einer Botschaft aktiviert werden. Die Wirkung der durch eine Botschaft stirnulierten Aktivitlit besteht somit auBer in der Festlegung oder Erzeugung des RUckgabeobjektes auch in Seiteneffekten in Form von Zustandslinderungen des Objektes selbst oder eines der anderen angesproehenen Objekte. Urn in der graphischen Darstellung von Objekten explizit darauf hinzuweisen, daB ein Objekt eine bestimmte Botschaft versteht, wird an der Kontur des Objektsymbols ein kleines Rechteck angefUgt, das an ein "Bedienelement" zur Aktivierung einer Aktion erinnern soIl, seine Beschriftung gibt den Namen der Botschaft an. In Abbildung 1-2 ist angezeigt, daB das Objekt namens ecke (unter anderen) auf die Botschaften x und theta reagieren kann. FUr Smalltalk-Objekte gilt prinzipiell, daB sie uneingesehrlinkt alle Dienste der jeweils sichtbaren Objekte in Anspruch nehmen konnen, ihr gesamtes Verhaltensprotokoll ist offentlich.
6
1.3
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Der konzeptionelle Objektraum
Mit dem Konzept einer Gemeinschaft miteinander kommunizierender Objekte ist eng der Begriff eines Objektraumes verbunden. Ein Objektraum kann als Substrat betrachtet werden, das die Grundlage fUr die Existenz der Objekte und fUr die Entfaltung ihrer Aktivitaten bildet. In Analogie zu einem biologischen System kann der Objektraum als Lebensraum und Nahrboden fUr die Objektpopulation angesehen werden. Je nach der Art der betrachteten Objekte konnen unterschiedliche Arten von Objektraumen angenommen werden. Betrachtet man im Rahmen der Softwarentwicklung die realen Objekte eines Anwendungsgebietes, so liegt der Vorstellung ein realer Objektraum zugrunde, der einen fUr die Applikation relevanten Ausschnitt aus der Realitiit darstellt. Betrachtet man hingegen die in einem Computer agierenden Softwareartefakte als Objekte, so liegt dieser Vorstellung ein technischer oder physischer Objektraum zugrunde, der durch Speichermedien realisiert wird. Zwischen diesen Extremen liegt die Vorstellung eines konzeptionellen Objektraumes, der als Denkschema fUr das Verstandnis der Strukur und des Verhaltens von abstrakten Objekten dient. Der Begriff des konzeptionellen Objektraumes wird eingefUhrt, urn die Erklarung des Autbaues von Objekten, die Veranschaulichung von Zusammenhiingen zwischen Objekten und die Erlauterung von Kommunikationsvorgangen zu erleichtern. Er dient als Vorstellungshilfe beim Entwurf eines objektorientierten Systems und als Verstandnisbasis fUr die Erkliirung seines Verhaltens. Die Entwicklung von Software mit Small talk kann unter der impliziten Annahme eines konzeptionellen Objektraumes gesehen werden, der den Charakteristika von Small talk entspricht. Die in diesem Objektraum betrachteten Objekte sind prinzipiell Smalltalk-Objekte, das heiBt, ihre Struktur, ihr Verhalten, ihre gegenseitigen Beziehungen und ihr Zusammenwirken ist in Smalltalk beschreib bar. Ein Blick in diesen Objektraum zeigt immer einen Ausschnitt des Zustandes einer laufenden Applikation, die im Rahmen einer inkrementellen und iterativen Entwicklung moglicherweise noch unvollstiindig und vorlaufig ist. Die graphische Darstellung von Objektkonstellationen soli Zusammenhange in den Vordergrund riicken, die auch in der direkten Arbeit mit dem SmalltalkSystem erzeugt und mit Hilfe von Smalltalk-Werkzeugen untersucht werden konnen. In diesem Sinne werden im konzeptionellen Objektraum nicht Entwiirfe formuliert, die spater in einem getrennten Vorgang in Programme umgesetzt werden, es handelt sich dabei vielmehr urn die visuelle Darstellung von Strukturen und Zustiinden, die durch eine konkrete Software erzeugt werden konnen.
1.3 Der konzeptionelle Objektraum
1.3.1
7
Ebenen des konzeptionellen Objektraumes
Objektzustlinde und Kommunikationsvorglinge zwischen Objekten konnen mit unterschiedlicher Auflosung betrachtet werden. So kann ein komplexes Objekt einmal als Ganzes gesehen werden, ein anderes Mal ist sein innerer Aufbau von Interesse. Entsprechend dem Detaillierungsgrad der Betrachtung kann von man mehrere Ebenen des konzeptionellen Objektraum sprechen. Als Beispiel sei auf eine Applikation aus dem Bereich einer Bank gewahlt. In Abbildung 1-3 wird das Augenmerk auf einen Ausschnitt des Objektraumes gelegt, der ein Objekt der Art Bank und zwei Objekte der Art Kunde enthlHt. Aus der DarstelIung ist zu entnehmen, daB innerhalb des Bankobjektes Referenzen auf zwei Kundenobjekte bestehen, die somit der Bank zugeordnet und von dieser aus erreichbar sind. Wegen des geringen Detaillierungsgrades ist allerdings nicht zu erkennen, durch welche Namen die Kundenobjekte innerhalb der Bank bezeichnet werden.
Abbildung 1-3
Konzeptioneller Objektraum auf Anwendungsebene
Die gewlihlte Betrachtung des konzeptionellen Objektraumes (KOR) zeigt nur Objekte des Anwendungsgebietes und solche Beziehungen zwischen ihnen, die fUr die Anwendungslogik von Bedeutung sind. Es wird die Tatsache in den Vordergrund gertickt, daB die "X-Bank" die Kunden "Kunde 17" und "Kunde 23" hat und diese daher ansprechen kann, verborgen wird jedoch die interne Struktur, die fUr die Zuordnung und das gezielte Ansprechen der Kunden realisiert sein muB. Diese Betrachtungsebene solI als Anwendungsebene oder Geschii/tsebene bezeichnet werden. Eine Momentaufnahme des konzeptionellen Objektraumes kann nur Information tiber die Objektstruktur liefem, nicht aber tiber das Objektverhalten. Da die Struktur im Laufe der Applikation Verlinderungen unterworfen wird, muB zumindest angenommen werden, daB die beteiligten Objekte die Flihig-
8
1 Smalltalk: Konzepte, Strukturen und Mechanismen
keit haben, strukturelle Beziehungen einzugehen, abzuiindern und wieder aufzulOsen. Das im Beispiel erwiihnte Bankobjekt muB also zumindest Methoden zur Verftigung haben, die es erlauben, neue Kunden aufzunehmen und bestehende Kunden zu entfernen, wobei eventuelle Einschriinkungen zu beriicksichtigen sind. Methoden, die dazu geeignet sind, die auf der Geschiiftsebene des konzeptionellen Objektraumes relevanten Strukturen zu verwalten, werden in der Folge als Geschii/tsmethoden bezeichntet.
elne8ank
KOR 8aslsebene
Abbildung 1-4
1-------------------1
Konzeptioneller Objektraum auf Arbeitsebene
Ein genauerer Einblick in die Realisierung der Bank-Kunden-Beziehung ist in Abbildung 1-4 gegeben. Man erkennt, daB das Bankobjekt tiber seine Instanzvariable kunden ein Kundenverzeichnis enthiilt, in welches die einzelnen Kunden eingtragen sind. Das Verzeichnis ist ein Objekt von der in SmalItalk bekannten Art Dictionary. Ein solches Verzeichnis hat die Fiihigkeit, ein anderes Objekt (im Beispiel einen Kunden) tiber einem eindeutigen Schltissel (im Beispiel eine ganze Zahl) in sich einzuordnen und unter diesem Schliissel wieder erreichbar zu machen. Beim Zuordnen eines neuen Bankkunden zu einer Bank muB dieser mit einer noch nicht verge ben en Kundennummer in dieses Kundenverzeichnis eingetragen werden. Die fUr das EinfUgen, Loschen und Auffinden von Verzeichniseintriigen notwendigen Methoden sind Verzeichnissen der Art Dictionary bekannt, die auf Anwendungsebene zu erstellenden Methoden konnen auf diese zuriickgreifen. Die hier angesprochene Betrachtungsebene solI als Arbeitsebene bezeichnet, weil auf dieser Ebene normalerweise der Einstieg in Smalltalk erfolgt. Eine noch detailliertere Betrachtung gibt auch einen Einblick in den Aufbau des Verzeichnisses selbst. Aus Abbildung 1-5 ist zu ersehen, daB ein Verzeichnis auf einer Menge beruht, deren Elemente Zuordnungsobjekte der Art Association sind. Jedes Assoziationsobjekt besteht aus einem Schltisselobjekt (im Beispiel eine ganzzahlige Kundennummer) und aus einem Wert (im Bei-
1.3 Der konzeptionelle Objektraum
9
spiel ein Kundenobjekt), welche durch die Instanzvariablen key und value gehalten werden. Die Zusammenfassung der Zuordnungselemente als eine Art Menge ist dureh das gestriehelt umrandete Symbol mit der Besehriftung aSet angedeutet. Dieses Symbol steht nieht fUr ein eigenstandiges Objekt, sondern fUr eine noeh verborgene Struktur des Verzeiehnisses.
aDictionary
eineBank
kunden
KOR Basisebene
Abbildung 1-5
1-------------------....1
Konzeptioneller Objektraum auf Basisebene (1)
Urn einen Einblick in diese, in Abbildung 1-5 noch verborgene, Struktur zu erhalten, bedarf es eines weiteren und tieferen Inspektionsvorganges, der sehlieBlieh die in Abbildung 1-5 dargestellte Objektkonstellation ergibt. Man erkennt, daB in diesem Fall das Verzeiehnis drei tiber Indizes anspreehbare Instanzvariable enthalt, von denen zwei die erwahnten Assoziationsobjekte referenzieren, wahrend die Instanzvariable mit dem Index 3 auf das Objekt nil weist. Ftir das Verstandnis dieser Situation, die in gleicher Weise bei einem laufenden Smalltalk-System mit Hilfe eines Inspektors beobaehtet werden kann, bedarf es einer Erlauterung. Das SmalltaIk-System stellt fUr die Realisierung von Behaltern Objekte mit einer bei ihrer Erzeugung vorgebbaren Anzahl von Instanzvariablen bereit, die nieht dureh Namen, sondern dureh Indizes identiflZiert werden. Wie an einer spateren Stelle noeh genauer gezeigt wird, bedienen sieh Verzeiehnisse ebenso wie Mengen dieser Moglichkeit und
10
1 Smalltalk: Konzepte, Strukturen und Mechanismen
verwalten das Feld der mit Indizes bezeichneten Instanzvariablen durch ein Hash-Verfahren. Die im Beispiel gezeigte Menge besteht aus zwei Elementen, die in einer Hash-Tabelle mit drei TabeIlenpHitzen eingetragen sind. Nichtbesetzte Tabellenpllitze (Instanzvariable) verweisen auf nil, das in Smalltalk ebenfalls den Charakter eines Objektes hat.
aDlctionary
3
Kunden
KOR System ,............................................ ..........
Abbildung 1-6
~.~~ . ~--.~-.~~~~~~
..
..
~~ ~~~~--~ .~..•.. .. ~ . ~
..• .......••..•..................... .}
Konzeptioneller Objektraum auf Basisebene (2)
In Abbildung 1-5 sind aIle Objekte, welche an der Realisierung der Beziehung einer Bank zu ihren Kunden letztendlich beteiligt sind, in "atomarer" Form gezeigt, lediglich die Geschiiftsobjekte der Arten Bank und Kunde sind nicht im Detail dargestellt. Die hier angesprochene Ebene soIl als Basisebene oder Systemebene bezeichnet werden, weil sie den Objektraum in einem so hohen Detaillierungsgrad zeigt, daB die Basis der yom Smalltalk-System gebotenen Funktionalitiit erkennbar ist. Die erwiihnten Ebenen des konzeptionellen Objektraumes konnen nicht eindeutig und allgemeingiiltig festgelegt werden, sie charakterisieren vielmehr eine geordnete Folge von Sichten fUr die Betrachtung der Objektpopulation, die bei der Softwareentwicklung durchschritten werden. Wesentlich ist, daB ausgehend von einer Ebene die Struktur und das Verhalten der Objekte der niichsthoheren Ebene durch Abstraktion sowie der niichsttieferen Ebene
1.3 Der konzeptionelle Objektraum
11
durch Verfeinerung erhalten werden. Wesentlich ist auch, daB bei einer im Smalltalk-System laufenden Applikation aIle Ebenen koexistent und operabel sind, mit anderen Worten, aIle Zustande und Verhaltensweisen von Objekten und damit die von diesen gebildeten Strukturen konnen auf jeder Ebene durch konkrete Software erzeugt und beeinfluBt sowie mit entsprechenden Werkzeugen direkt beobachtet werden. Beim Erlernen von Small talk erfolgt der Einstieg zumeist auf einer Ebene, die hier als Arbeitsebene bezeichnet ist. Auf dieser Ebene geht man davon aus, daB ein Objektraum vorliegt, der bereits zahlreiche Objekte enthiilt, welche wichtige Bausteine fUr die Applikationsentwicklung bilden. Die allgemein empfundene Schwierigkeit beim ersten Arbeiten mit Small talk besteht nicht im Verstandnis der Konzepte und Mechanismen, sondern im Gewinnen eines Uberblickes tiber vorhandene Objekte, die entweder direkt oder nach geringfUgiger Adaption wiederverwendet werden konnen. Durch das intensive Arbeiten mit Smalltalk erhiilt man einen tieferen Einblick in systemnahere Ebenen, die es erlauben, die Grundfunktionalitat von Small talk zu erweitern und auch an eigene Bedtirfnisse anzupassen. Das Smalltalk-System ist (mit Ausnahme des in der virtuellen Maschine integrierten grundlegenden Systemverhaltens) in Smalltalk geschrieben, der gesamte Quellcode liegt zur Einsicht offen. Fragen nach der Art der Realisierung von Objektverhalten konnen somit durch Betrachtung auf einer tieferen Ebene in Smalltalk selbst beantwortet werden. Bei der Erstellung von Applikationen werden auf hoheren Ebenen ebenfalls Objektarten konstruiert, die Bausteine fUr die Applikationsentwicklung bilden. Es muB ein besonderes Ziel der objektorientierten Softwareentwicklung sein, Applikationsobjekte so zu entwerfen, daB ihre Wiederverwendbarkeit in moglichst vielen Fallen gewahrleistet ist.
1.3.2
Der konzeptionelle Objektraum zwischen Realitiit und technischer Reprasentation
Viele der in einer hoheren Ebene des konzeptionellen Objektraumes erscheinenden Geschaftsobjekte sind direkte Abbilder realer Objekte aus dem jeweiligen Anwendungsbereich. Ihre Struktur und ihr Verhalten ist das Ergebnis einer Analyse der Realitiit und eines darauf aufbauenden Entwurfes. Sie werden im Rahmen der Applikationsentwicklung durch zusatzliche Applikationsobjekte erganzt, beispielsweise durch KontroIlobjekte und Schnittstellenobjekte, die im allgemeinen eine untersttitzende Funktion haben und nicht direkt aus der Realitat abgeleitet werden konnen. AIle diese Objekte sind schlieBlich aus elementaren Basisobjekten zusammengesetzt, die im techni-
12
1 Smalltalk: Konzepte, Strukturen und Mechanismen
schen Objektraum eine direkte Reprasentation besitzen. In diesem Sinne entsprechen Objekten der realen Welt Artefakte im technischen Objektraum, die jene Eigenschaften widerspiegeln, die fUr die jeweilige Applikation als wesentlich betrachtet werden. Der konzeptionelle Objektraum hat dabei die Funktion eines Mittlers zwischen Realitat und deren technischer Reprasentation: er dient als gedankliches Hilfsmittel zur Darstellung eines Realitatsausschnittes, die sich auf die fUr die Anwendung wesentlichen Phanomene beschrankt, ohne auf die technischen Einzelheiten Rticksicht zu nehmen.
Abbildung 1-7
Der Zusammenhang zwischen Objektraumen
Der Zusammenhang zwischen dem realen, dem konzeptionellen und dem technischen Objektraum und den darin befindlichen Objekten ist in Abbildung 1-7 veranschaulicht.
1.3.3
Grenzen des Objektraumes
Die Existenz eines Objektes ist mit seinem Aufenthalt in einem Objektraum untrennbar verbunden. Es ist fUr ein Objekt unmoglich, seinen Objektraum zu verlassen, ohne daB das gleichzeitig die Vernichtung seiner Identitat und damit seiner Existenz bedeutet. Daraus folgt auch, daB nie ein Objekt als solches in einen Objektraum eingebracht werden kann. Die Grenze des Objektraumes ist fUr Objekte prinzipiell undurchliissig.
1.4 Klassen und ihre Ausprligungen
GescMftsobjekte
Abbildnng 1-8
13
Schnittstelienobjekte
Geschlifts- und Schnittstellenobjekte
1m allgemeinen ist es auch fUr Objekte nicht moglich, in Wechselwirkung mit der AuBenwelt zu treten. Manche Objekte jedoch haben die besondere Eigenschaft, eine Art Informationskanal in die AuBenwelt zu besitzen, sie konnen dadurch Informationen in eine oder auch beide Richtungen austauschen. In Abbildung 1-8 sind solche an Geschliftsobjekte (domain objects) gekoppelte Schnittstellenobjekte (interface objects) gezeigt, sie sind durch eine Verbindung zum Rand des konzeptionellen Objektraumes symbolisiert.
1.4
Klassen und ihre Auspragungen
Nachdem bereits Einiges tiber Eigenschaften von Objekten sowie tiber ihren Lebensraum gesagt wurde, stellt sich die Frage, auf welche Weise Objekte erzeugt werden konnen und wodurch ihre Eigenschaften festgelegt werden. Diese Funktionen werden in klassenbasierten Systemen von Klassen erfUllt. Klassen sind in Smalltalk vollwertige Objekte, die sich von anderen Objekten durch ihre Flihigkeit unterscheiden, Objekte erzeugen zu konnen. Klassen sind Mutterobjekte, die einerseits eine Schablone in sich tragen, welche die Struktur der zu erzeugenden Objekte beschreibt und andererseits die Methoden verwalten, die deren Verhalten bestimmen. Die von einer Klasse erzeu&ten Objekte werden als Auspragungen oder auch als Instanzen der Klasse Tbezeichnet. Ein Klassenobjekt hat alle Eigenschaften eines "normalen" Objektes, nlimlich eine durch seine Instanzvariablen festgelegte Struktur, einen durch deren
14
1 Smalltalk: Konzepte, Strukturen und Mechanismen
jeweilige Belegung gegebenen Zustand und ein Verhalten, das sich durch die von ihm verstandenen Botschaften und die zugeh6rigen Methoden auBert. Abbildung 1-9 zeigt eine Klasse namens A1 (in Smalltalk werden Klassennamen mit groBen Anfangsbuchstaben geschrieben), fUr welche die Instanzvariablen ex und ey definiert sind und welche zumindest die Botschaften new und em 1 versteht. Entsprechend ihrer Bedeutung werden Instanzvariable eines Klassenobjektes auch Klasseninstanzvariable (class instance variables) genannt, sie sind von Klassenvariablen (class variables) woW zu unterscheiden. Die Schablone der in Abbildung 1-9 gezeigten Klasse A1 legt fest, daB jede Auspragung dieser Klasse genau drei Instanzvariable mit den Namen x, y und z tragt, sie stellt weiterhin Methoden (Programmcode) fur die Botschaften m1 und m2 bereit, die somit von den Instanzen der Klasse A1 verstanden werden. 1m Unterschied zu der bisherigen gr6beren Betrachtung zeigt sich dabei auch, daB nicht die Auspragungen einer Klasse selbst den Methodencode in sich tragen, sondern daB dieser von der Klasse fUr alle ihre Instanzen bereitgestellt wird.
011 012
lA\
'" 01"-1
T
cxO
CyO Klaua
instance class
f; \-
Curl
... • • • • •
<
:> 1
• • • •• • • Auspragung •
!nstanzierungsbezienung
Abbildung 1-9
t
Klassen und ihre Auspragungen (Instanzen)
1m Englischen wird die Auspriigung einer Klasse als instance of a class bezeichnet. In Foige einer unkritischen Ubersetzung des englischen Begriffes instance hat sich auch in der deutschen Fachliteratur der Ausdruck "Instanz" eingebiirgert.
1.5 Klassenhierarchie und Strukturvererbung
15
Jede Klasse reagiert auf die Botschaft new mit der Erzeugung einer Auspragung, die als Ruckgabeobjekt dem Sender der Botschaft zur Verfugung gestellt wird. Dieser Erzeugungsvorgang wird auch Instanzierung genannt. In der rechten Ralfte der Abbildung ist ein Objekt (einA1) gezeigt, welches Auspragung dieser Klasse ist. Man beachte, daB die lnstanzvariablen von einA 1 genau der Schablone entsprechen, daB aber zusatzlich zu den in der Schablone vorgegebenen Methoden offensichtlich noch andere Botschaften verstanden werden. Die Beziehung zwischen einem Klassenobjekt und einer seiner Auspragungen wird als Instanzierungsbeziehung bezeichnet und im konzeptionellen Objektraum in Ubereinstimmung mit der der OMT-Notation [33] durch einen zum Klassenobjekt hinweisenden punktierten Pfeil veranschaulicht. Klassenobjekte selbst werden durch Rechtecke mit scharfen Ecken symbolisiert. 1m unteren Teil von Abbildung 1-9 ist auf eine allgemeine Eigenschaft der lnstanzierungsbeziehung hingewiesen. Die MultiplizitatsangabeTdruckt aus, daB jedes Objekt Auspragung genau einer (1) Klasse ist, jede Klasse hingegen kann beliebig viele (O .. n) Auspragungen haben. Der Doppelpfeil gibt einen Rinweis auf die Navigationsmoglichkeiten, er besagt, daB jedes Objekt seine Klasse und jede Klasse die Menge ihrer Auspragungen aufkurzem Wege feststellen kann. Diese allgemeine Beziehungseigenschaft kann fUr manche Klassen we iter eingeschrlinkt sein. So gibt es beispielsweise Klassen, die nur genau eine Auspragung besitzen (durfen), sie werden als Singleton-Klassen [16] bezeichnet. Einen wichtigen Sonderfall bilden Klassen, von denen uberhaupt keine Auspragungen erzeugt werden sollen, ihre Existenzberechtigung liegt in der Bereitstellung von Struktur und Methoden fUr ihre Unterklassen. Solche Klassen werden als abstrakte Klassen bezeichnet, sie vererben ihren Unterklassen allgemeine Konzepte, die jedoch noch konkretisiert werden mussen, um Objekte mit vollstandiger Funktionalitat erzeugen zu konnen. 1m Unterschied zu den abstrakten Klassen stehen konkrete Klassen, deren lnstanzen sinnvolle Objekte darstellen.
1.5
Klassenhierarchie und Strukturvererbung
Klassen beschreiben die Struktur und das Verhalten ihrer Auspragungen, aIle Auspragungen einer Klasse sind daher in diesen Eigenschaften gleich und in dies em Sinne von gleicher Art.
t
1m Unterschied zur OMT-Notation wird die Multiplizitatsangabe bier an den Anfang der Verbindungslinie geschrieben.
16
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Bei der systematischen Untersuchung realer Objekte faGt man solche mit jeweils gleichen relevanten Charakteristika zu einer Gruppe zusammen. Weiterhin versucht man, diese Gruppen untereinander in Beziehung zu setzen, so daB man zu Klassifikationshierarchien kommt, wie beispielsweise in der Botanik, wo man von Klassen, Unterklassen, Ordnungen, Gattungen und Arten spricht. Auf ahnliche Weise werden Klassen in einem objektorientierten System zueinander in Beziehung gesetzt. Besitzen aile Auspragungen einer Klasse A1 dieselben Eigenschaften wie Auspragungen einer Klasse A und zusatzlich noch weitere Eigenschaften, so kann man sie als speziellere Objekte betrachten, die Klasse A1 ist dann eine Unterklasse der Klasse A. Bei der Definition von A1 als direkte Unterklasse von A wird davon ausgegangen, daB aile Eigenschaften von A geerbt werden, so daB nur noch die zusatzlichen Eigenschaften (und eventuell auch Veranderungen der geerbten Eigenschaften) fUr die Klasse A1 festzulegen sind.
Abbildung 1-10 Ausschnitt aus der Klassenhierarchie von Smalltalk In Smalltalk ist einfache Vererbung realisiert, das bedeutet, daB jede Klasse nur eine direkte Oberklasse (direkte Superklasse) besitzt, sie kann aber beliebig viele direkte Unterklassen (Subklassen) haben. Die mit dieser Einschrankung gebildete Klassenhierarchie entspricht einer Baumstruktur. An der Wurzel der Klassenhierarchie steht die Klasse Object, die selbst keine Superklasse besitztt.
1.5 Klassenhierarchie und Strukturvererbung
17
Jede Klasse erbt somit von allen ihren Oberklassen, also von allen jenen Klassen, die auf dem Vererbungspfad von der Klasse selbst bis zur Wurzelklasse Object liegen. In Abbildung 1-10 ist ein sehr kleiner Ausschnitt aus der Klassenhierarchie von Smalltalk gezeigt. Man erkennt, daB die Klassen Boolean und Collection direkte Unterklassen von Object sind und daB diese Klassen selbst wieder die Wurzeln von Teilhierarchien bilden. Beispielsweise bildet die Klasse Collection die Wurzel einer Teilhierarchie, die aus tiber 80 Klassen besteht, von denen viele abstrakte Klassen sind. Die Boolean-Teilhierarchie hingegen besteht nur aus der abstrakten Klasse Boolean und deren Unterklassen False und True, deren jeweils einzige Ausprligungen die Objekte false und true sind. Da die Strukturvererbung (Vererbung der Instanzvariablen) und die Verhaltensvererbung (Vererbung der Methoden) nach unterschiedlichen Mechanismen erfolgt, werden diese auch getrennt behandelt.
new
new
cmx
cm1
Superklasse
O.. n
<----:>
'I
Subklasse
Vererbungsbeziehung
Abbildung 1-11 Strukturvererbung zwischen Klassen t Es ist moglich, auch andere Klassen ohne Oberldasse zu definieren, so daB mehr als eine Klassenhierarchie vorliegen kann. In der Folge wird nur die Klassenhierarchie betrachtet, deren Wurzel die Klasse Object ist.
18
1 Smalltalk: Konzepte, Strukturen und Mechanismen
In Abbildung 1-11 sind zwei Klassenobjekte A und A1 gezeigt, die in direkter Vererbungsbeziehung stehen. Die Klasse A1 ist eine direkte Unterklasse der Klasse A, welche umgekehrt direkte Oberklasse der Klasse A1 ist. Diese Beziehung ist fUr die Struktur der Instanzen der Klasse A1 von besonderer Bedeutung. Die Strukturschablone der Oberklasse wird in die direkte Unterklasse ubertragen t und dort durch spezieIle Elemente erweitert. In dem gezeigten Beispiel ist angedeutet, daB die fUr Auspragungen der Klasse A definierte Instanzvariable x automatisch auch in Auspragungen der Klasse A1 vorkommt, diese besitzen jedoch zusatzlich noch die in ihrer eigenen Klasse definierten Instanzvariablen y und z. Dieses Konzept wird als Strukturvererbung bezeichnet. Auspragungen der Unterklasse besitzen somit die Struktur von Auspragungen der Oberklasse, diese kann noch durch zusatzliche Elemente erweitert sein. In diesem Sinne sind aIle Auspragungen einer Klasse NutznieBer der Erbschaft ihrer Klasse, sie sind "spezieIIere" Objekte als die Instanzen ihrer Oberklassen, weil sie noch zusatzliche Merkmale (an Instanzvariable gebundene Objekte) tragen. Fur die Strukturvererbung gibt es in SmaIItalk keine M6glichkeit, eine Enterbung festzulegen oder eine Erbschaft zu verweigern, es werden alle Instanzvariablen der Oberklasse in die Unterklasse ubernommen. Will man die in Abbildung 1-11 gezeigte Klasse A1 erzeugen, so muB man sie als Unterklasse der bereits existierenden Klasse A positionieren und (fUr ihre Auspragungen) die Instanzvariablen y und z festIegen. Sendet man dieser Klasse nun die Instanzerzeugungsbotschaft new, so Iiefert diese ein Objekt mit den drei Instanzvariablen x, y und z. Programm 1-2 zeigt den SmaIItalk-Code, der ausgefUhrt werden muB, urn die Klassen A und A1 einzurichten.
1.6
Klassenhierarchie und Verhaltensvererbung
Ein Objekt behalt wah rend seiner gesamten Lebenszeit jene Struktur bei, die ihm bei seiner Erzeuguqg durch die in der Klasse enthaItene Strukturschablone aufgepragt wurde TT, die Belegung seiner Instanzvariablen steIIen den jeweiligen individueIIen und privaten Objektzustand dar. t Es handelt sieh hier urn eine konzeptionelle Sieht, das bedeutet nieht, daB auf teehniseher Ebene ein Kopiervorgang stattfmdet.
tt Wird die Struktursehablone einer bereits existierenden Klasse dureh Redefinition der Klasse abgeandert, so wird diese allen im Objektraum existierenden Auspragungen dieser Klasse aufgepragt. Von dieser Mogliehkeit sollte jedoch nur dann Gebrauch gemacht werden, wenn man sieh alIer Konsequenzen bewuBt ist!
1.6 Klassenhierarchie und Verhaltensvererbung
19
Anders ist die Situation beim Verhalten, das keine individuelle Eigenschaft eines Objektes ist. Ein Objekt kann nicht autonom entscheiden, wie es auf eine Botschaft reagieren soH, es ist vielmehr darauf angewiesen, seine Verhaltensvorschrift in anderen Objekten, namlich in seiner Klasse und eventuell deren Oberklassen zu suchen. Ein Objekt teilt die Methoden, die sein Verhalten festiegen, mit allen anderen Auspragungen seiner Klasse. Klassenobjekte enthalten ein Methodenverzeichnis, in dem die in der Klasse (flir ihre Auspragungen) festgelegten Instanzmethoden eingetragen sind. Das Methodenverzeichnis ist so aufgebaut, daB unter jedem vereinbarten Methodennamen die entsprechende Methode, also der auszuflihrende Programmcode, aufgefunden werden kann.
1.6.1
Methodensuche
Wenn einem Objekt eine Botschaft iibersandt wird, so muB dieses erst feststellen, ob es die Moglichkeit hat, auf diese Nachricht zu reagieren und wenn ja, auf welche Weise dies zu geschehen hat. Zu diesem Zwecke beginnt das Objekt im Methodenverzeichnis seiner Klasse nach dem N amen der empfangenen Botschaft zu suchen, wenn es diesen und damit den zugehorigen Programmcode gefunden hat, wird die Methode aktiviert und ausgeflihrt. 1st die Suche erfolglos, so wird als niichstes das Methodenverzeichnis der unmittelbaren Oberklasse durchsucht, dies wird so lange fortgesetzt, bis die Suche entweder erfolgreich ist oder abgebrochen werden muB, weil der Suchvorgang bereits in der Klasse Object angelangt ist, die als Wurzel der Klassenhierarchie keine Oberklasse mehr besitzt. In letzterem Fall der erfolglosen Methodensuche wird ein Signal gesetzt, welches veranlaBt, daB eine fest vorgegebene "Ersatzbotschaft" (doesNotUnderstand: aMessage) an den Empfanger der nicht gefundenen Botschaft gesandt wird. Es ist sichergestellt, daB diese Ersatzbotschaft in der Klasse Object eingerichtet ist und daher auf jeden Fall verstanden wird. Bei einem Smalltalk-System, das zur Programmentwicklung konfiguriert ist, veranlaBt die Ersatzbotschaft im Normalfall eine Benachrichtigung, welche die Moglichkeit des direkten Einstieges in Analysewerkzeuge (Debugger und Inspektoren) gibt. Bei einem Smalltalk-System einer ausgelieferten Applikation (bei der dieser Fall eigentlich nicht vorkommen sollte), ist eine andere Reaktionsweise vorzusehen. In Abbildung 1-12 ist die Methodensuche an Hand eines Beispieles demonstriert. Hier ist eine Klasse A1 sowie ihre unmittelbare Oberklasse A sowie je eine Auspriigung dieser Klassen gezeigt. Wird beispielsweise dem Objekt einA1 die Botschaft m1 gesandt, so wird nach einer Methode mit diesem Namen in der zugehOrigen Klasse A1 gesucht
20
1 Smalltalk: Konzepte, Strukturen und Mechanismen
und ein entsprechender Eintrag im Methodenverzeichnis gefunden. Man beachte, daB der moglicherweise im Programmcode der Methode m1 vorkommende Name self erstjetzt an das Objekt einA1 gebunden werden kann! Wird die Botschaft m1 an einA gesandt, so fuhrt dies zu einer erfolglosen Suche, es sei denn, eine Methode mit entsprechendem Namen ist in einer in der Hierarchie hOheren Oberklasse defmiert.
m1
_ __ _ m2 "","",_ _ _ m5
Abbildung 1-12 Methodensuche in der Klassenhierarchie
Die Suche nach einer Methode m2 fUhrt sowohl fUr einA 1 als auch fUr einA zum Erfolg, es handelt sich allerdings urn zwei unterschiedliche Methoden. Empfangt eine Auspragung der Klasse A1 die Botschaft m2, so findet sie die entsprechende Methode in ihrer eigenen Klasse, sodaB keine Notwendigkeit mehr besteht, in der Oberklasse die Suche fortzusetzen. Die in der Klasse A definierte Methode m2 wiirde auf die Unterklasse A 1 vererbt werden, jedoch ist in der Klasse A1 eine gleichnamige Methode eingerichtet, wodurch
1.6 Klassenhierarchie und Verhaltensvererbung
21
die geerbte Methode nicht zum Zuge kommt. Diese Situation wird auch als Redefinition einer Methode in einer Unterklasse bezeicbntet. Empfangt das Objekt einA 1 die Botschaft m5, so wird zwar in der eigenen Klasse A1 keine Methode mit diesem Namen gefunden, wohl aber in der Oberklasse A. Klassen sind in Smalltalk vollwertige Objekte, denen durch entsprechende Botschaften neue Methoden hinzugeftigt oder bestehende Methoden entfemt werden konnen, wodurch es moglich wird, daB existierende Instanzen wahrend ihrer Lebenszeit ihr Verhalten andem. Wird beispielsweise wahrend der Lebenszeit des Objektes einA 1 eine Methode namens m5 in die Klasse A 1 eingefUgt, so wird einA 1 ab nun diese Methode als Reaktion auf die Botschaft m5 aktivieren, und nicht mehr die gleichnamige Methode der Oberklasse A. Der beschriebene Vorgang, namlich die Auswahl einer Methode zum Zwecke der Reaktion auf eine Botschaft, wird als Methodenbindung bezeichnet. Erfolgt das Binden der Methoden, wie in Smalltalk, erst zur Laufzeit nach dem Empfang einer Botschaft, so wird dies als spates Binden (late binding, delayed binding) oder dynamisches Binden (dynamic binding) bezeichnet. [7], [10], [11], [12], [15], [23], [30]
1.6.2
Die Konstanten "self" und "super"
Es wurde bereits darauf hingewiesen, daB sich jedes Objekt iiber den Namen self selbst referenziert, sodaB es dem Objekt moglich ist, innerhalb einer selbst
aktivierten Methode an sich selbst eine Botschaft zu richten. Da Auspragungen einer Klasse Spezialisierungen von Auspragungen ihrer Oberklassen sind, wird es oft sinnvoll sein, fUr ahnliche Aufgaben gleichnamige Methoden zu schreiben, wobei die Methode in der Unterklasse das Gleiche erledigt wie die Methode in der Oberklasse und zusatzlich noch Aufgaben wahmimmt, die der groBeren Spezialisierung entsprechen. Wiirde man eine Methode derart verfassen, daB das ausfUhrende Objekt an sich selbst eine gleichnamige Botschaft sendet, so wiirde dies zu einer unendlichen Rekursion ftihren, weil beim Suchvorgang immer dieselbe Methode gefunden und ausgeftihrt wird und es keine Chance gibt, den Code der Oberklasse zu aktivieren. Zur Bewaltigung solcher Falle dient die Objektkonstante super. Diese bezeichnet in gleicher Weise wie self das jeweilige Objekt selbst, sie bewirkt jedoch, daB fUr eine an das durch super (statt durch self) benannte Objekt gesandte Botschaft ihre Methode nicht in der Klasse des Objektes, sondem in seiner unmittelbaren Superklasse zu suchen begonnen wird. Die Namen self und super bezeichnen immer dasselbe Objekt, namlich den Empfanger der aktivierten Methode, sie sind also Synonyme, die sich nur durch die Startklasse fUr die Methodensuche unterscheiden.
22
1 SmaIlta1k: Konzepte, Strukturen und Meehanismen
Weitere Untersehiede, die in der syntatktisehen Verwendung dieser Namen liegen, werden im Zusammenhang mit der Spraehe Smalltalk in einem spateren Kapitel erlautert. Die Mogliehkeit, die Startklasse fUr die Methodensuehe zu beeinflussen, besteht nur fUr Botsehaften, die ein Objekt an sieh selbst sendet. Es ist nieht m6glieh, einem Objekt "von Au Ben" eine Botsehaft zu tibermitteln und dabei EinfluB auf die Methodensuehe zu nehmen.
1.7
Die Erreichbarkeit von Objekten
Ein Objekt kann nur dann mit einem anderen Objekt kommunizieren, wenn es dieses andere Objekt kennt und daher anspreehen kann. Die Kommunikation selbst erfolgt dureh Ubermittlung einer Botsehaft an das angesproehene Objekt, was nur im Rahmen einer Aktivitat des Senders selbst moglieh ist, also wlihrend der AusfUhrung einer Methode. Die Spreehweise "ein Objekt kennt ein anderes Objekt oder es kann dieses erreiehen" bedeutet daher, daB ein Objekt in seinen Methoden dem anderen Objekt Botsehaften senden kann. Es bestehen prinzipiell zwei M6gliehkeiten, ein Objekt als Empfanger einer Botsehaft zu lokalisieren.
1. Der Empfanger ist dem Sender unmittelbar bekannt, well mindestens einer seiner Name fur den Sender siehtbar ist. 2. Der Empflinger ist dem Sender zwar nieht unmittelbar bekannt, er kann aber dureh Senden einer Botsehaft an ein unmittelbar bekanntes Objekt ermittelt werden. 1m ersten Fall ist das Objekt direkt erreiehbar, im zweiten Fall bedarf es einer Navigation im Objektraum, urn zu dem gewtinsehten Objekt zu gelangen. In jedem Fall jedoeh ist der Ausgangspunkt ein Objekt mit einem fUr den Sender siehtbaren Namen. Der Begriff der Sichtbarkeit von Namen ist daher von wesentlieher Bedeutung.
1.7.1
Der Horizont von Objekten
Innerhalb der Methoden eines Objektes ist eine Menge von Objektnamen siehtbar, sodaB die an diese Namen gebundenen Objekte anspreehbar sind. Diese Menge der tiber Namen direkt anspreehbaren Objekte solI als Horizont des Objektes bezeiehnet werden.
1.7 Die Erreichbarkeit von Objekten
23
Soferne diese Namen nicht als Konstante unabiinderlich mit Objekten verbun den sind, konnen ihnen andere Objekte zugewiesen werden, wodurch sich der Horizont des Objektes iindern kann. Viele Namen liegen gleichzeitig im Sichtbarkeitsbereich mehrerer Objekte, es kann somit durch die DurchfUhrung der Methode eines Objektes der Horizont mehrerer Objekte veriindert werden. Da das Verhalten eines Objektes auch von seinem Horizont abhangt, ist dadurch ein Mechanismus fUr Objektwechselwirkungen gegeben. Die Menge der innerhalb einer Methode sichtbaren Objektnamen besteht einerseits aus statischen Namen, das sind solche, die auBerhalb der Methode vereinbart und somit fUr alle Methoden dieses Objektes (und teilweise auch anderer Objekte) sichtbar sind und andererseits aus dynamischen Namen, deren Giiltigkeit nur innerhalb einer aktivierten Methode gegeben ist. Dementsprechend kann man auch zwischen einem statischen Horizont eines Objektes und einem dynamischen Horizont einer aktivierten Methode eines Objektes unterscheiden. Wie in der Folge noch gezeigt wird, erweitert sich der statische Horizont in einer aktivierten Methode zu einem dynamischen Horizont, zu dem auch jene Objekte gehOren, die durch methodenlokale Namen referenziert werden. Die Mengen der durch statische und durch dynamische Namen bezeichneten Objekte sind im allgemeinen nicht disjunkt, da ein Objekt durch mehrere Namen bezeichnet werden kann.
1.7.2
Die Sichtbarkeit von Objektnamen
In Abbildung 1-13 ist veranschaulicht, welche Gruppen von (statischen) Objektnamen aus der Warte eines Objektes (genauer: aller Methoden eines Objektes) permanent sichtbar sind. Nach ihrem Sichtbarkeitsbereich konnen folgende Gruppen von Namen unterschieden werden. 1. Innerhalb eines Objektes sichtbare Namen Ein Objekt kann sich in seinen Methoden selbst durch die Objektkonstante self und alle seine Komponenten iiber seine Instanzvariablen ansprechen. Das Objekt selbst und seine Komponenten gehOren daher zu seinem Horizont. t Dieser Teil des Horizontes ist vollkommen privat, er kann durch andere Objekte weder eingesehen noch verandert werden.
t Man beachte, daB gleich bezeichnete Instanzvariable in verschiedenen Objekten verschiedenen Namen entsprechen.
24
1 Smalltalk: Konzepte, Strukturen und Mechanismen
2. Fur "verwandte" Objekte sichtbare Namen Fur eine Klasse konnen Klassenvariable defmiert werden, diese sind fur die Klasse selbst, fur alle ihre Unterklassen sowie fur alle Auspriigungen dieser Klassen sichtbar. Diese durch Subklassenbeziehung mit der defmierenden Klasse in Verwandtschaft stehenden Klassen sowie die mit diesen Klassen durch Instanzierungsbeziehungen verwandten Objekte haben somit einen Tell ihres Horizontes gemeinsam, sie konnen diesen veriindem und dadurch eine gegenseitige Wechselwirkung ausuben.
3. Fur frei wiihlbare Gruppen von Objekten sichtbare Namen Weiterhin konnen Variable (pool variables) in Variablenverzeichnissen (Pools) zusammengefaBt werden, die mehreren Klassen zugeordnet werden konnen. Diese Namen sind allen Klassen sichtbar, denen sie zugeordnet sind sowie allen Auspriigungen dieser Klassen. 1m Unterschied zu Klassenvariablen werden Poo/variable nicht automatisch den Unterklassen und deren Auspriigungen sichtbar gemacht, t es ist jedoch moglich, den Variablenpool einer Unterklasse explizit zuzuordnen. 4. Global sichtbare Namen SchlieBlich sind Namen mit globaler Sichtbarkeit (globale Variable) vorgesehen, die von ihnen referenzierten Objekte gehoren zum Horizont jedes im Objektraum existierenden Objektes. Die von jedem Objekt mogliche Zuweisung eines anderen Objektes an eine globale Variable beeinfluBt den Horizont aller Objekte, ihre Wirkung kann daher von groBer Tragweite sein. Zu dieser Gruppe gehoren auch die konstanten Namen fUr im Objektraum a-priori existierende und dort permanent verankerte Objekte, die durch ihren unveriinderbaren Zustand charakterisiert sind. Es sind dies die Objekte, die als Auspriigungen der Klasse Smalllnteger die unmittelbar im Speicher darstellbaren ganzen Zahlen repriisentieren sowie die Instanzen der Klasse Character. Diese Objektett bilden einen unveranderbaren Teil des Horizontes jedes Objektes. Weiterhin sind zu dieser Gruppe die auf besondere Weise verwalteten Namen nil, true und false zu ziihlen. Der spezielle Name Smalltalk bezeichnet ein Systemverzeichnis, welches alle globalen Variablen und die fur diese gultigen Objektbindungen enthiilt. Die wichtigsten globalen Objekte sind (neben den bereits erwiihnten) die Klassen und die Variablenpools.
t tt
Dies gilt fUr VisualWorks erst ab Version 2.5. Der Zustand dieser Objekte wird im technischen Objektraum durch ihren Objektzeiger reprasentiert, sie beanspruchen dariiber hinaus keinen Speicherplatz.
25
1. 7 Die Erreichbarkeit von Objekten
Private Variable
elnes ObJektes
Gem eiossme Variable mehrerer Objekte
I ,
o
'\ dss $wstem~ 'I verzelchnis
A
BO
/
! mit g!obaien Variablen
: SystemKoostante
•
statische Nam
Abbildung 1-13 Sichtbarkeit von statischen Objektnamen In Abbildung 1-13 ist das Objekt einA stellvertretend fUr irgendein Objekte hervorgehoben und mit Namen jener Objekte verbunden, die zu seinem statischen Horizont gehOren. Zusatzlich ist veranschaulicht, daB die Systemkonstante Smalltalk das Systemverzeichnis aller globalen Objekte referenziert, wozu die Klasse A und der gezeigte Variablenpool zahlt. Der Klassenpool ist kein globales Objekt, erwird durch eine Instanzvariable seiner Klasse gehalten. Die Abbildung zeigt in ihrem unteren Teil, daB zwischen einer Klasse und ihrem Klassenpool sowie zwischen einer Klasse und ihren Variablenpools explizite Beziehungen bestehen, diese werden an einer spateren Stelle noch
26
1 Smalltalk: Konzepte, Strukturen und Mechanismen
genauer betrachtet. Aus den angeftihrten MuItiplizitiitsangaben ist zu erkennen, daB jeder Klasse genau ein eigener Klassenpool zugeordnet ist. Weiterhin sieht man, daB eine Klasse beliebig viele Variablenpools (shared pools) zugeordnet haben kann und daB umgekehrt jedes Variablenverzeichnis seine Variablen beliebig vielen Klassen (und deren Instanzen) verftigbar machen kann. Variablenverzeichnisse konnen auch leer sein. Zuslitzlich zu den hier angeftihrten Namen gibt es noch temporlir wlihrend der Aktivierung einer Methode sichtbare Namen, dazu zlihlen die methodenlokalen Namen (einschlieBlich der Methodenparameter) und der Name thisContext. Diese Namen mussen so gewlihlt werden, daB sie nicht mit auch auBerhalb einer Methode vereinbarten Namen in Konflikt stehen. Die durch diese Namen referenzierten Objekte werden bei der Erlliuterung des dynamisch erweiterten Horizontes von Objekten diskutiert.
1.8
Das Verhalten von Objekten
Das Verhalten eines Objektes wird von den von ihm verstandenen Botschaften und den hinter diesen Botschaften stehenden Methoden bestimmt. Eine aktivierte Methode erftillt ihre Aufgaben im allgemeinen dadurch, daB sie ihrerseits an andere Objekte Botschaften sendet, deren Ergebnisse in Form von Ruckgabeobjekten zur Kenntnis nimmt, urn schlieBlich selbst ein Ruckgabeobjektjenem Objekt zu senden, von dem aus sie aktiviert wurde. Die Wirkung einer Methode besteht dabei nicht nur in der Uberrnittlung eines Ruckgabeobjektes (dieses wird in vie len Fiillen sogar ignoriert), sondern auch in Seiteneffekten, etwa in der Verlinderung der Zustlinde von Objekten, die bei der Methodendurchftihrung angesprochen wurden.
1.8.1
Der dynamische Horizont von Methoden
Bei der Aktivierung einer Methode wird der statische Horizont des Objektes urn jene Objekte erweitert, die durch die methodenlokalen Namen referenziert werden. In Abbildung 1-14 ist jene Situation veranschaulicht, die eingetreten ist, wenn ein Objekt eine Botschaft empfangen und eine entsprechende Methode aktiviert hat. Die Methode m2 ist nun an den Methodennamen (Selektor) m2 gebunden und in den Kontext des Empfangers gesetzt, was grafisch dadurch ausgedruckt ist, daB das Methodensymbol innerhalb des Objektes erscheint.
27
1.8 Das Verhalten von Objekten
Das an das Methodensymbol gekoppeltes Achteck soIl einen Einblick in die aktivierte Methode geben, es zeigt hier, daB die temporliren Variablen und die Konstante thisContext sichtbar sind.
Argumente
temportlra Variable
'Pseuoovarlab!e'
m2
dynamische Namen
Abbildung 1-14 Sichtbarkeit von dynamischen Objektnamen Die Parameternamen werden bei der Aktivierung der Methode an die iibergebenen aktuellen Parameterobjekte gebunden, weshalb sie in der Grank an den Positionen der formalen Parameter des Selektors eingefUgt sind. Parameter haben die Funktion von Konstanten, da es nicht zulassig ist, diese Namen innerhalb der Methode durch Zuweisung mit Objekten zu verbinden. Lokale Variable sind innerhalb einer Methode erkllirt, sie werden unmittelbat nach der Aktivierung der Methode an das Objekt nil gebunden. Die Konstante thisContext bezeichnet eine Instanz der Klasse MethodContext, welche die temporaren Variablen (Parameter und lokale Variable) verwaltet und den fUr die AusfUhrung der Methode benotigten Exekutionsstack zur VerfUgung steHt. Bei der Arbeit mit Smalltalk auf der Arbeitsebene oder auf einer hoheren Ebene kommt man mit dem Methodenkontext nicht explizit in Beriihrung. In der Abbildung ist auch die Konstante self hervorgehoben, um anzudeuten, daB diese erst im Zustand der Aktivierung an den Empfanger gebunden ist und dadurch eine konkrete Bedeutung edangt. Insgesamt enthalt der dynamische Horizont einer Methode aIle jene Objekte, die durch alle wahrend der Methodenausftihrung sichtbaren Namen angesprochen werden konnen, also aHe Objekte des statischen Horizontes und zusatzlich die eben erwahnten Objekte.
28
1 Smalltalk: Konzepte, Strukturen und Mechanismen
1.8.2 Mechanismus der Botschaftsubermittlung Der laufende ProzeB der Abarbeitung einer Methode besteht aus einer Folge von Botschaftsiibermittlungen an Objekte aus dem jeweiligen Objekthorizont. In Abbildung 1-15 ist die Situation beim Senden einer Botschaft skizziert. Das Objekt einA ist der Empfanger einer Botschaft m2, fUr die eine Methode aufgefunden und aktiviert wurde. Dieses Objekt ist eben bei der AusfUhrung dieser Methode und ist dem (in der Abbildung nicht gezeigten) Sender noch ein Riickgabeobjekt als Antwort schuldig. Ein in der Abbildung herausgehobener Schritt dieser Methode besteht im Senden der Botschaft do:with: an das Objekt mit Namen x (einEtwas), wobei entsprechend der Methodensignatur dem EmpHinger noch zwei Parameterobjekte zu benennen sind, welche im gezeigten Beispiel die Namen a1 und a2 tragen.
Sender
Botschaft
................••......•.......••..•...•. _~_~ .. ~~ •...•.. _
ROckgabeobj£lld
Empfanger
..• .................................................................................•...• ~~_ _ __ _----1
Abbildung 1-15 Strukturdiagramm einer Botschaftsiibermittlung Das Objekt einEtwas hat offensichtlich eine der empfangenen Botschaft entsprechende Methode (do:with:) gefunden, aktiviert und bereits ein Riickgabeobjekt festgestellt sowie dieses dem Sender einA als Ergebnis sichtbar gemacht. Aus der Warte der yom Objekt einA aktivierten Methode m2 wurde der Ausdruck x do: a1 with : a2 evaluiert und kann als Name fUr das Riickgabeobjekt aufgefaBt werden. In der aktivierten Methode (m2) des Objektes einA kann der nlichste Schritt durchgefUhrt werden, welcher eine Aktion der folgenden Art sein kann:.
29
1.8 Das Verhalten von Objekten
1. Das Riickgabeobjekt wird durch Zuweisung an eine Variable gebunden und dadurch in den Objekthorizont von einA eingefiigt, der dadurch moglicherweise vergroBert wird. a) Die Zuweisung an eine lokale Variable ermoglicht es, das Riickgabeobjekt fur einen spateren Gebrauch innerhalb der laufenden Methode verfiigbar zu haben. b) Die Zuweisung an eine Instanzvariable bedeutet eine Zustandsanderung des Objektes einA. c) Die Zuweisung an eine gemeinsame Variable verandert auch den statischen Horizont anderer Objekte. 2. Dem Riickgabeobjekt wird unmittelbar eine Botschaft gesandt, ansonsten wird es "vergessen". 3. Das Riickgabeobjekt wird unmittelbar als Parameter einer weiteren Botschaft verwendet, ansonsten wird es "vergessen". 4. Das erhaltene Riickgabeobjekt wird als Riickgabeobjekt der laufenden Methode an deren Sender weitergereicht. 5. Das Riickgabeobjekt wird iiberhaupt ignoriert, der Sinn der eben beendeten Botschaftsiibermittlung lag dann nur in deren SeitenetTekten.
einA
einEtwas
ts ... . . - . . . . . . . P3
Zeit
Abbildung 1-16 ProzeBdiagramm einer Botschaftsiibermittlung Wahrend in Abbildung 1-15 der strukturelle Aspekt der Kommunikation zwischen zwei Objekten betont wird, stellt die Darstellungsform in Abbildung 1-16 den Aspekt des zeitlichen Ablaufes des Kommunikationsprozesses in den Vordergrund. Das Objekt einA empflingt zur Zeit tl von einem hier nicht gezeigten Sender die Botschaft m2 und aktiviert die entsprechende Methode. Wahrend der Ausfiihrung dieser Methode wird zur Zeit t2 die (mit den entsprechenden Parametern versehene) Botschaft do:with: an das Objekt ein-
30
1 Smalltalk: Konzepte, Strukturen und Meehanismen
Etwas gesandt, welches zur Zeit t3 als Ergebnis ein Riiekgabeobjekt iiberrnittelt. SehlieBlieh beendet das Objekt einA naeh weiteren, hier nieht gezeigten Sehritten seine aktivierte Methode und meldet zur Zeit 4 das Ergebnis seinem Sender. Die Aktionsfolge Ph P2, P3 bildet einen Teil des laufenden Prozesses.
1.9
Der Lebenszyklus von Objekten
Die Existenz eines Objektes im Objektraum beginnt mit seiner Erzeugung durch Instanzierung einer Klasse. Unmittelbar naeh der Erzeugung eines Objektes steht dieses jener aktiven Methode zur Verfiigung, welehe den Erzeugungsvorgang veranlaBt hat. In dieser Phase ist das neue Objekt nicht an einen Namen gebunden, es kann jedoeh "transient" als Riickgabeobjekt oder als Parameter einer Methode weitergereieht werden oder auch selbst als Empflinger einer Botschaft aktiv werden. Erst durch die Bindung des Objektes an einen Namen wird sichergestellt, daB es iiber eine llingere Zeit "permanent" bleibt und angesprochen werden kann. Die Existenz eines Objektes ist so lange sichergestellt, solange es von anderen, ebenfalls gesichert existierenden Objekten im Objektraum referenziert wird. Es ist keine Moglichkeit vorgesehen, ein Objekt explizit aus dem Objektraum zu entfernen, ein nieht mehr ansprechbares Objekt wird jedoch durch einen automatisch ablaufenden "Objektraum-ReinigungsprozeB" entsorgt. Der technische Lebenszyklus ist somit durch die Erzeugung eines Objektes und dessen automatischer Entfernung aus dem Objektraum gekennzeichnet. Die bereits friiher erwahnten a-priori-Objekte haben eine permanente Existenz und unterliegen nieht dem technischen Lebenszyklus. Wahrend ihrer Lebenszeit durchlaufen Objekte einen Applikationslebenszyklus, der besonders im Falle von Gesehaftsobjekten oft dadurch explizit gemacht wird, daB Objekte ausdriicklich festgelegte Zustande nur in vorgegebenen Reihenfolgen durchlaufen diirfen. Ein neu erzeugtes Objektes liegt in einem "Rohzustand" vor, das heiBt, seine Instanzvariablen sind alle mit dem Objekt nil belegt. In vielen Fallen erfolgt unmittelbar nach der Erzeugung der neuen Auspragung eine Initialisienmg der Instanzvariablen und damit der Autbau eines komplexen Objektes. Die Initialisierung eines Objektes bildet den ersten Sehritt seines Applikationslebenszyklus. Es kann jedoeh aueh sinnvoll sein, eine Instanzvariable erst dann mit einem Objekt zu belegen, wenn dieses benotigt wird, ein Vorgehen, das als verzogerte Initialisierung (lazy initialization) bezeichnet wird.
1.10 Die Architektur des Smalltalk-Systems
31
1.10 Die Architektur des Smalltalk-Systems 1.10.1 Der physische Objektraum Wie aus den vorangehenden Abschnitten deutlich wird, ist es fUr das Verstandnis von Smalltalk ausreichend, einen konzeptionellen Objektraum als Ort allen Geschehens anzunehmen, in welchem Objekte existieren und ihre Aktivitaten entfalten konnen. Die tatsachliche Realisierung in einem Computer erfolgt in einem physischen oder technischen Objektraum (TOR), der fUr ein laufendes SmalltalkSystem in einem Teil des Speichers verwaltet wird. Dieser Objektraum ist implementationsabhangig und bildet die Basis fUr die Arbeit der virtuellen Maschine. Eine zentrale Aufgabe des Smalltalk-Systems liegt in der Verwaltung des physischen Objektraumes. Dazu gehort einerseits sicherzustellen, daB alle ansprechbaren Objekte ihrer Funktionalitat entwickeln konnen, ohne sich dabei zu behindem oder zu blockieren. Dazu gehOrt aber auch, Sorge zu tragen, daB nicht mehr ansprechbare Objekte aus dem Objektraum entfemt werden, sodaB Platz flir neue Objekte zur Verfligung steht. Bei der Realisierung des technischen Objektraumes stehen Fragen der Reprasentation von Objekten im Speicher und ihrer Positionierung im AdreBraum im Vordergrund. Wlihrend fUr konzeptionelle Fragen die Feststellung ausreichend ist, daB ein Objekt im Objektraum existiert und tiber seine N amen angesprochen werden kann, ist es im technischen Objektraum von Bedeutung, wo es sich befindet und wie es aufgefunden werden kann. Das Verstandnis der Vorgange im technischen Objektraum ist fUr die Arbeit mit Small talk nur selten erforderlich, doch moge ein oberfllichlicher Blick einen Eindruck davon vermitteln, was in einem Smalltalk-System im Verborgenen geschieht. Abbildung 1-17 gibt zu erkennen, daB der physische Objektraum in mehrere Segmente gegliedert ist. Die Segmente NewSpace, LargeSpace und PermSpace haben eine fest vorgegebene GroBe, der technische Objektraum kann jedoch durch dynamische A1lokation zuslitzlicher Speicherbereiche der Art OldSpace flexibel den Bedtirfnissen angepaBt werden. Objekte werden in NewSpace erzeugt und verbringen dort die Anfangsphase ihres Lebens, handelt es sich jedoch urn sehr groBe Objekte, werden sie im Bereich LargeSpace untergebracht. NewSpace ist selbst in einen "Geburtsbereich" und zwei "Uberlebensbereiche" unterteilt. Viele Objekte, wie etwa solche, die innerhalb einer Methode erzeugt und dort nur an eine temporlire Variable gebunden werden, haben eine so kurze Lebensdauer, daB
32
1 Smalltalk: Konzepte, Strukturen und Mechanismen
sie keine Gelegenheit haben, den Geburtsbereich zu verlassen. Wenn der Platz im Geburtsbereich knapp wird, werden die altesten in ibm befmdlichen Objekte in einen Uberlebensbereich fUr junge Objekte transferiert und erst dann, wenn sie eine weitere Zeit tiberleben, in einen Old Space-Bereich tibersiedelt. Innerhalb von NewSpace erfolgt eine regelmaBige Umlagerung zwischen den beiden Uberlebensbereichen, wobei Objekte, die bereits ihre Existenz verloren haben, schnell eliminiert werden kannen. Diese Vorgangsweise beruht auf der Erfahrung, daB die Verteilung der Objektlebenszeiten Haufungen bei sehr kurzen und bei langen Lebenszeiten aufweisen. Die Widmung eigener Bereiche fUr Objekte in verschiedenen Lebensstadien ermaglicht eine effektive Speicherverwaltung durch einen mehrstufigen Mechanismus fUr die Elimination toter Objekte (Speicherbereinigung).
Abbildung 1-17 Der technische Objektraum (VisuaIWorks)
1.10.2 Die Komponenten des Smalltalk-Systems Abbildung 1-18 zeigt schematisch den Aufbau eines Smalltalk-Systems und das zusammenwirken seiner Komponenten. Eine zentrale Komponente bildet die virtuelle Maschine (VM), welche den Objektraum verwaltet und die Ablaufe in diesem steuert. Aus einer konzeptionell en Sicht bildet sie den Lebensmotor des Systems, sie stellt dem Benutzer die Funktionalitat des Systems inklusive des Quellcodes siimtlicher Methoden zur VerfUgung.
33
1.11 Blicke in eine tiefere Systemebene
Die virtualle Maschine llidt bei ihrem Start ein Image-File (*.im), das einem "eingefrorenen" Objektraum entspricht, umgekehrt kann yom jeweiligen Zustand des aktiven Objektraumes ein "SchnappschuB" in Form eines ImageFiles erzeigt werden. Wlihrend der aktiven Phase des Objektraumes vorgenommene Systemlinderungen, insbesonders Quellcode neu erstellter Methoden, werden in Verlinderungs-Files (*.changes) abgelegt, die eine Erglinzung des Quellcode-Files (*.sources) darstellen.
Window
Manager
Hardware
Abbildung 1-18 Schematischer Aufbau des Smalltalk-Systems Ein Vorteil dieser Systemarchitektur liegt in der Portabilitlit des SmalltalkSystems. Die in der Abbildung grau hinteriegten Komponenten k6nnen auf jeder Hardware-Betriebssystem-Plattform direkt eingesetzt werden, auf der eine virtuelle Smalltalk-Maschine verftigbar ist.
1.11
Blicke in eine tiefere Systemebene
Es ist unvermeidlich, daB bei der Erkllirung der in diesem Kapitel vorgestellten Konzepte und Mechanismen Fragen offen bleiben, die nur auf einer systemnliheren Ebene beantwortet werden k6nnen. Aus diesem Grund werde einige ausgewlihlte Themen einer detaillierteren Betrachtung unterzogen. Dies solI auch als Beispiel daftir dienen, daB bei der Arbeit mit Smalltalk auf einer tieferen Ebene Kenntnisse gewonnen werden k6nnen, die nicht nur zu einem besseren Verstlindnis beitragen, sondem auch M6glichkeiten aufzeigen, die auf Applikationsebene von Nutzen sein k6nnen.
34
1 Smalltalk: Konzepte, Strukturen und Mechanismen
1.11.1 Klassen und Metaklassen Wenn jedes Objekt Auspdigung genau einer Klasse ist und Klassen vollwertige Objekte sind, stellt sich unmittelbar die Frage nach der Klasse einer Klasse. In gleicher Weise, wie die Struktur und das Verhalten von Nichtklassenobjekten durch ihre Klassen vorgegeben ist, ist die Struktur und das Verhalten eines Klassenobjektes durch seine Metaklasse bestimmt, die eine Art Klasse 2. Ordnung darstellt. Es ist sichergestellt, daB eine Metaklasse jeweils nur eine einzige Auspragung haben kann.
new em"!
Metaklssse
.....
«
«
«
«
«
«
«
«
•
«
«
••
Klassl')
Instanzierungsbezlehung
Abbildung 1-19 Klassen und ihre Metaklassen In Abbildung 1-19 ist gezeigt, daB die Metaklasse eine Schablone der Struktur ihrer Auspragung, also der Klasse, tragt und daB sie weiterhin Methoden bereitstellt, die von dieser ausgeflihrt werden konnen. Da die (einzige) Auspragung einer Metaklasse ein Klassenobjekt ist, handelt es sich dabei um Klasseninstanzvariable und Klassenmethoden. Ein Vergleich von Abbildung 1-19 mit Abbildung 1-9 verdeutlicht die Analogie zwischen den gezeigten Instanzierungsbeziehungen. In Abbildung 1-9 ist durch die Angabe instance/class darauf hinge wiesen, daB der entsprechende Schalter im Klassenbrowser beim Erstellen von Methoden den Focus zwischen der Schablone in der Klasse und der Schablone in der Metaklasse umschaltet.
1.11 Blicke in eine tiefere Systemebene
35
Die Existenz von Metaklassenobjekten erlaubt es, jeder Klasse ein individuelles Verhalten zu geben. Klassenmethoden dienen hauptsachlich dazu, Instanzen zu erzeugen, spezielle Initialisierungen von Instanzvariablen durchzufiihren und den Zugriff auf Klasseninstanzvariable anderen Objekten zu ermoglichen. Auf der Basis der bisherigen Betrachtung kann man feststeIlen, daB in Small talk drei Abstufungen von Objekten existieren:
1. Stufe der "normalen" Objekte "Normale" Objekte sind Auspragungen von Klassen, sie besitzen eine von ihrer Klasse vorgegebene Struktur (Instanzvariable), sie konnen Methoden (lnstanzmethoden) ausfiihren, die in ihrer Klasse oder in einer Oberklasse verfiigbar gehalten werden. Diese Objekte werden von ihrer Klasse erzeugt, sie konnen selbst keine anderen Objekte erzeugen. 2. Stufe der Klassenobjekte Klassenobjekte sind Auspragungen ihrer Metaklassen, sie besitzen eine von ihrer Metaklasse vorgegebene Struktur (Klasseninstanzvariable), sie konnen Methoden (Klassenmethoden) ausfiihren, die in ihrer Metaklasse oder in einer deren Oberklassen verftigbar gehalten werden. Klassenobjekte werden von ihrer Metaklasse erzeugt, sie haben selbst die Flihigkeit, beliebig viele "normale" Objekte erzeugen. 3. Stufe der Metaklassenobjekte Metaklassenobjekte erzeugen jeweils genau ein Klassenobjekt nach der in ihnen enthaltenen Strukturschablone und stellen fiir dieses Methoden bereit. Metaklassen sind in Smalltalk ebenfalls Objekte, es stellt sich somit in konsequenter FortfUhrung des Prinzipes der Klassenzugehorigkeit von Objekten die Frage nach der Klasse einer Metaklasse, also nach einer Meta-Meta-Klasse. Um dieser unendlichen Regression zu entkommen, ist in Smalltalk die Entscheidung getroffen worden, die Implementation des Systems derart vorzunehmen, daB aIle Metaklassen Auspriigungen einer einzigen Klasse MetaClass sind, die selbst wieder die einzige Auspragung der Klasse Metaclass class ist. In diesem Sinne ist Smalltalk als ein System mit runf Objektabstufungen zu sehen. Bei der Verwendung von Smalltalk auf der Arbeitsebene oder einer hoheren Applikationsebene bleibt dem Benutzer die Existenz der Metaklassen weitgehend verborgen. Implementationsarbeiten auf diesen Ebenen bestehen aus dem Einfiigen neuer Klassen in die bestehende Klassenhierarchie, dem
36
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Festlegen ihrer Strukturschablone und dem Einbringen von Klassen- und Instanzmethoden in die entsprechenden Methodenverzeichnisse. Erst beim Eintauchen in eine tiefere Systemebene werden die Metaklassen sichtbar. Dabei erkennt man etwa, daB das Erzeugen einer neuen Klasse bereits ein komplexer Vorgang ist: in einem ersten Schritt wird eine neue Metaklasse als Instanz von Metaclass class erzeugt und in die entsprechende Stelle der Metaklassen-»Schattenhierarchie" eingeftigt, erst dann kann die Metaklasse veranlaBt werden, die neue Klasse zu erzeugen und in der Klassenhierarchie zu positionieren. Das Protokoll der Metaklassen sowie auch die Funktionalitat weiterer Systemklassen (beispielsweise der Klassen ClassDescription, Behavior) verleiht Smalltalk jene Flexibilitat, die es erlaubt, durch nMetaprogrammierung" Klassen und ihre Methoden auch zur Laufzeit einer Applikation zu verandem.
1.11.2 System- und Poolverzeichnisse Wie bereits aus Abbildung 1-13 erkennbar ist, stellt Smalltalk nur eine kleine Zabl von globalen Konstanten zur Verftigung, nlimlich nil, true und false, weiterhin die Namen der a-priori-Objekte und den Namen Smalltalk, der fest mit einem zentralen Systemverzeichnis verbunden ist.
Das Systemverzeichnis Smalltalk Der Name Smalltalk referenziert die einzige Auspragung der Klasse SystemDictionary. Wie in jedem Verzeichnis sind auch im Verzeichnis Smalltalk Assoziationsobjekte enthalten, die ein im Verzeichnis eindeutiges Schltisselobjekt mit einem zugeordneten Objekt verbinden. Das Systemverzeichnis hat die Eigenschaft, die der Klasse Symbol angehorenden Schltisselobjekte als Namen der mit ihnen assoziierten Objekte global und direkt verftigbar zu machen. Bei jeder Vereinbarung einer globalen Variablen wird ein entsprechender Eintrag in das Systemverzeichnis Smalltalk vorgenommen, umgekehrt werden glob ale Variable durch Entfemen aus diesem Verzeichnis geloscht. Die meisten globalen Namen bezeichnen die jeweils vorliegenden Klassenobjekte. In Abbildung 1-20 ist veranschaulicht, daB die als Beispiel verwendete Klasse A in das Systemverzeichnis eingetragen ist, sie kann global durch ihren Namen A angesprochen werden, sodaB es nicht notwendig ist, sie tiber das Dictionary-Protokoll durch Evaluation des Ausdruckes Smalltalk at: #A zu lokalisieren.
37
1.11 Blicke in eine tiefere Systemebene
Klasse Klasse
1 --:->:> 1
~.~--------- classPool
O.. n
sharedPool
Abbildung 1-20 Organisation von Variablenverzeichnissen
Variablenverzeichnisse Analog zur Eintragung der globalen Variablen in das Systemverzeichnis werden gemeinsame Variable (shared variables) in Variablenverzeichnisse (Instanzen der Klasse PoolDictionary) eingetragen und den Methoden der am Variablenpool teilhabenden Objekten verfUgbar gemacht. Die Namen der Variablenverzeichnisse (sharedPools) sind selbst globale Variable und als solche im Systemverzeichnis Smalltalk eingetragen. Diese Situation ist in Abbildung 1-20 dargestellt. Aus den in der Abbildung angegebenen Eigenschaften t fUr die Beziehungen zwischen Klassen und Variablenverzeichnissen geht hervor, daB jede t Diese Eigenschaften werden bei einer "ordnungsgemaBen" Nutzung des Systems eingehalten, sie konnen aber durch systemnahe Methoden umgangen werden!
38
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Klasse genau ein Verzeichnis fur die Klassenvariablen zugeordnet haben muG, welches nicht gleichzeitig mehreren Klassen zugeordnet sein darf. Falls fUr eine Klasse keine Klassenvariablen definiert sind, bleibt dieses Verzeichnis leer. Demgegentiber kann eine Klasse beliebig viele Variablenverzeichnisse besitzen, von den en jedes beliebig vielen Klassen zugeordnet sein kann, wodurch die gemeinsame Nutzung der Variablen ermoglicht wird.
1.12
Realisierung der Konzepte
Ftir das Beherrschen von Small talk ist es nicht nur wichtig, die zugrundeliegenden Konzepte, Strukturen und Mechanismen zu verstehen, sondern auch ihre Realisierung im Objektraum und die Moglichkeiten ihrer Nutzung in Smalltalk-Methoden zu kennen. Aus diesem Grunde werden im vorliegenden Abschnitt die wichtigsten Strukturen, die bereits an Hand von einfachen Beispielen allgemein gezeigt wurden, konkret im Smalltalk-System erzeugt und ihre Eigenschaften untersucht. Ftir das Verstiindnis der folgenden Beispiele werden grundlegende Kenntnisse von Sprachkonstruktionen und von Teilen der Klassenhierarchie ebenso vorausgesetzt wie eine Vorstellung tiber den Umgang mit Smalltalk-Werkzeugen. Da diese Themen erst in spiiteren Kapiteln genauer behandelt werden, wird dem zum ersten Mal mit Small talk befaBten Leser empfohlen, erst nach der Lekttire der Kapitel 2 und 4 zu diesem Abschnitt zuriickzukehren.
1.12.1 Variablenverzeichnisse Ais Vorbereitung fUr die folgenden Beispiele werden in Programm 1-1 unter Punkt (1) zwei Variablenverzeichnisse als Auspriigungen der Klasse PoolDictionary angelegt und in das Systemverzeichnis Smalltalk derart eingetragen, daB sie durch die Symbole #PD1 und #PD2 identiflziert werden und damit dieglobalen Namen PD1 und PD2 tragen. Aus Punkt (2) ist zu ersehen, daB die Variable PD1 existiert und ein noch lee res Verzeichnis referenziert. Die Evaluation der unter Punkt (3) angefUhrten Ausdrticke tragen in jedes der beiden Variablenverzeichnisse je eine Variable ein. Beispielsweise enthiilt das tiber den Namen PD1 erreichbare Variablenverzeichnis eine Variable namens P1, welche an die Zeichenkette 'Version 1.0' gebunden ist. Diese Variable steht den Klassen- und Instanzmethoden jener Klassen zur VerfUgung, die an dem Variablenpool PD1 teilhaben. Analoges gilt fUr den Varia-
39
1.12 Realisierung der Konzepte
blenpool P02. Man beachte, daB ein Variablenname in einem Variablenverzeichnis durch ein Symbol repdisentiert wird.
Workspace "(1) Anlegen von zwei Variablenverzeichnissen." Smalltalk at: #POl put: PoolOictionary new; at: #P02 put: PoolOictionary new
"(2) Zugriff auf die globale Variable POt" POl
<printlt> PoolDictionary()
"(3) Eintragen von je einer Variablen in die Pool-Verzeichnisse." POl at: #Pl put: 'Version 1.0'. P02 at: #Pa put: 10 Programm 1-1
Globale Variable und Variablenverzeichnisse
1.12.2 Klassen und Variablenverzeichnisse Erzeugen von Klassen Durch Evaluation des in Programm 1-2 unter Punkt (1) gezeigten Ausdruckes wird die Klasse A als Subklasse von Object eingerichtet. In ihrer Strukturschablone ist die Variable x vermerkt, sodaB jede Auspragung dieser Klasse eine Instanzvariable x enthiilt. AuBerdem werden dieser Klasse zwei Klassenvariable Cl und Cn zugeordnet und ihr die Variablenverzeichnisse POl und P02 zuganglich gemacht. 1m Objektraum ist dadurch die bereits in Abbildung 1-20 gezeigte Struktur erzeugt worden. Auf ahnliche Weise wird unter Punkt (2) die Klasse A1 mit den Instanzvariablen y und z als Subklasse von A erzeugt. In der Strukturschablone dieser Klasse sind somit insgesamt drei Instanzvariable vorgerichtet, namlich die aus der Oberklasse A geerbte Variable x und die in der Klasse selbst festgelgten Variablen y und z. Punkt (2a) zeigt die Festlegung der Klasseninstanzvariablen cl und c2, sie werden in der Strukturschablone der Metaklasse A1 class vorgemerkt und daher in der Klasse A1 als Auspragung dieser Metaklasse erzeugt. Die dadurch erreichte Situation im Objektraum entspricht jener von Abbildung 1-11, allerdings sind die dort vermerkten Methoden erst einzurichten.
40
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Bei der Einrichtung von Klassen mit Hilfe des Klassenbrowsers werden fUr die in Programm 1-2 gezeigten Methoden Vorlagen geboten, die entsprechend editiert werden mussen.
Workspace "(1) Einrichten der Klasse A." Object subclass: :fI:A instanceVariableNames: 'x ' classVariableNames: 'C1 Cn ' poolDictionaries: 'PD1 PD2 ' category: 'Demo.
<dolt>
"(2) Einrichten der Klasse At" A subclass: :fI:A1 instanceVariableNames: 'y z ' classVariableNames: .. poolDictionaries: .. category: 'Demo'.
<dolt>
"(2a) Festlegen von Klasseninstanzvariablen fUr die Klasse At" A1 class instanceVariableNames: 'c1 c2'
Programm 1-2
<dolt>
Erzeugen von Klassen
Die Beziehung zwischen Klassen und Variablenverzeichnissen Workspace "(1) Feststellen des Verzeichnisses mit den Klassenvariablen der Klasse A."
<printlt>
A classPool
PoolDictionary «VariableBinding key: #C1) (VariableBinding key: :fI:Cn) ) "(2) Feststellen aller Verzeichnisse mit Poolvariablen der Klasse A." A 1 sharedPools
<printlt>
Set ( PoolDictionary «VariableBinding key: #Pa» Pool Dictionary «VariableBinding key: :fI:P1) Programm 1-3
Variablenverzeichnisse einer Klasse
»
1.12 Realisierung der Konzepte
41
Programm 1-3 zeigt, wie die einer Klasse zugeordneten Variablenverzeichnisse festgestellt werden konnen. Man erkennt an den Ergebnissen, daB im Objektraum die in Abbildung 1-20 gezeigte Struktur vorliegt. Es gibt keine M6glichkeit, fUr ein gegebenenes Variablenverzeichnis auf direktem Wege festzustellen, welchen Klassen es zugeordnet ist. Die Methoden fUr das HinzufUgen und Entfernen von Variablenverzeichnissen werden von der Klasse Class auf alle Klassen vererbt.
1.12.3 Die Vererbungsbeziehung Mit der Erzeugung einer Klasse durch die in Programm 1-2 angegebene Methode und ihre EinfUgung in die Klassenhierarchie wird gleichzeitig auch die Vererbungsbeziehung zu ihrer unmittelbaren Superklasse (und dadurch auch zu allen Oberklassen) eingerichtet. Workspace
"(1) Feststellen der Vererbungsbeziehungen der Klasse A." A superclass A subclasses
<print/t> Object <print/t> #(A1)
"(2) Feststellen der Vererbungsbeziehungen der Klasse A1." A 1 superclass A 1 allSuperclasses A 1 subclasses
Programm 1-4
<print/t> A <print/t> OrderedColiection (A Object) <print/t> #0
Vererbungsbeziehungen zwischen Klassen
Programm 1-4 zeigt Methoden, mit deren Hilfe entiang der Vererbungspfade in der Klassenhierarchie navigiert werden kann. Wird die Botschaft superclass an eine Klasse gesandt, dann erhiilt man die direkte Superklasse, die Botschaft allSuperclasses liefert als Ergebnis die Anordnung der Superklassen auf dem Vererbungspfad bis zur Wurzel der Klassenhierarchie. Eine analoge Namenskonvention ist fUr die Botschaften zum Aufsuchen von Subklassen eingehalten. Eine Klasse anwortet auf die Botschaft subclasses mit einer Sammlung aller direkten Subklassen und auf die Botschaft allSubclasses mit allen Klassen, die von der Empflingerklasse direkt oder indirekt erben. Die Evaluation der unter Punkt (2) gezeigten Ausdriicke ergibt, daB die Klasse A1 die direkte Superklasse A besitzt und insgesamt von den Klassen A und Object (in dieser Reihenfolge) erbt, sie hat selbst keine Subklassen.
42
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Die Klasse Behavior stellt allen Klassen jene Methoden bereit, die zur Positionierung in der Klassenhierarchie und zum Verfolgen der Vererbungspfade notwendig sind.
Strukturschablonen und Strukturvererbung Programm 1-5 zeigt eine Moglichkeit, die Strukturschablone einer Klasse zu untersuchen, wobei nur benannte, nicht aber indizierte Instanzvariable beriicksichtigt werden.
Workspace A instVarNames A 1 instVarNames A 1 alllnstVarNames
Programm 1-5
<printlt> #('x') <printlt> #('y' 'z') <printlt> OrderedCollection ('x' 'y' 'z')
Strukturschablone einer Klasse
Die Ergebnisse der Auswertung der Ausdriicke zeigen, daB in der Klasse A1 die Instanzvariablen y und z defmiert sind, daB aber die Strukturschablone auch die von der Oberklasse A geerbte Instanzvariable x enthlilt. Diese Tatsache wurde bereits in Abbildung 1-11 veranschaulicht. Die Strukturschablone einer Klasse wird durch Methoden eingerichtet (und moglicherweise auch verlindert), die in den Klassen Class und ClassDescription festgelegt sind.
Methodenverzeichnisse und Verhaltensvererbung Urn die Verhaltensvererbung an Hand der eingerichteten Beispielklassen A und A1 untersuchen zu konnen, ist es notwendig, diesen Klassen einige Methoden zuzuordnen. In Programm 1-6 ist gezeigt, daB diesen Klassen Methoden mit genau jenen Selektoren zugeordnet sind, die bereits in Abbildung 1-12 angegeben und zur Erlliuterung der Verhaltensvererbung herangezogen wurden. Diese Darstellung zeigt eine Auflistung von Methoden samt ihrer Zuordnung zu einer Klasse und ihrer Einordnung in eine Methodenkategorie in folgender Form. Nach einer Uberschrift, die auf die Klasse und die Methodenkategorie hinweist, folgen im allgemeinen mehrere Methoden, die jeweils mit einem (durch Fettdruck hervorgehobenen) Selektor beginnen und mit dem Smalltalk-Code der Methode fortgesetzt werden. Es handelt sich dabei jedoch nicht urn Smalltalk-Ausdriicke, durch deren Evaluation Methoden kompiliert und in die Methodenverzeichnisse eingetragen werden!
1.12 Realisierung der Konzepte
43
Beispielsweise bedeutet die mit (1) markierte Zeite, daB der Klasse A eine Methode mit dem Selektor m2 zugeordnet ist, deren Wirkung durch den Smalltalk-Ausdruck I\thisContext printString beschrieben ist. Diese Methode ist in die Methodenkategorie demo eingereiht. Die darauffolgende Zeile beginnt wieder mit einem Selektor (m5) und beschreibt eine andere Methode, die derselben Klasse und derselben Kategorie zugeordnet ist, wobei es ein Sonderfall ist, daB be ide Methoden den gleichen Smalltalk-Code aufweisen. A methodsFor: 'demo' m2 I\thisContext printString m5
(1)
I\thisContext printString
A1 methodsFor: 'demo'
m1
I\thisContext printString
m2
1\
super m2, , dann: " thisContext printString
(1) Die Methode Context»printString liefert eine Zeichenkette mit dem Namen
der Klasse des Empfangers, in Klammern den Namen der Klasse, in welcher die Methode gefunden wurde, falls diese nicht mit der Empfangerklasse iibereinstimmt und nach den Zeichen» den Namen der aktivierten Methode.
Programm 1-6
Auflistung von Methoden
Fiir die Untersuchung der Methodenverzeichnisse geniigt es festzuhalten, daB Methoden mit den Selektoren m2 und m5 in das Methodenverzeichnis der Klasse A eingtragen und Methoden mit Namen m1 und m2 der Klasse A1 zugeordnet sind. Es ist vorHiufig unerheblich, was diese Methoden bewirken. Das Methodenverzeichnis einer Klasse (eine Ausprligung der Klasse MethodDictionary) enthlilt aile dieser Klasse zugeordneten Methoden, die unter den innerhalb der Klasse eindeutigen Selektoren (Ausprligungen der Klasse Symbol) abgelegt sind. Programm 1-7 zeigt einige Ausdriicke, durch welche die Methodenverzeichnisse der Klassen A und A1 iiberpriift werden. Unter Punkt (1) ist gezeigt, daB durch die an eine Klasse gesandte Botschaft includesSelector: festgestellt werden kann, ob unter dem als Argument vorgegebenen Selektor eine Eintragung im Methodenverzeichnis voriiegt. 1m Unterschied dazu kann durch die Botschaft canUnderstand: festgestellt werden, ob die Ausprligungen der Klasse auf den vorgegebenen Selektor iiberhaupt reagieren, das heiBt, ob unter diesem Selektor eine Methode in irgendeinem Methodenverzeichnis auf dem Vererbungspfad gefunden wird. Aus einem Vergleich der Ergebnisse unter den Punkten (1) und (2) ist beispielsweise zu erkennen, daB die Klasse A1 zwar keine Methode mit dem Selektor
44
1 Smalltalk: Konzepte, Strukturen und Mechanismen
#m5 zugeordnet hat, jedoch eine solche erbt. Man beachte, daB die Namen von Methoden (Selektoren) im Methodenverzeichnis durch Symbole reprasentiert werden. Die unter unter Punkt (3) angegebenen Ausdriicke zeigen, wie die Menge aller Selektoren der einer Klasse zugeordneten Methoden festgestellt werden kann, ebenso die Menge alIer von den Instanzen einer Klasse akzeptierten Selektoren.
Workspace
"(1) Feststellen einer Eintragung im Methodenverzeichnis." A 1 includesSelector: #m 1 A 1 includesSelector: #m5
<printlt> true <printlt> false
"(2) Feststellen, ob ein Selektor auf dem Vererbungspfad aufgefunden wird." A canUnderstand: #m1 A1 canUnderstand: #m5 A1 canUnderstand: #m1
<printlt> false <printlt> true <printlt> true
"(3) Feststellen der Menge der akzeptierten Selektoren." A 1 selectors A 1 allSelectors
Programm 1-7
<printlt> IdentitySet (#m1 #m2) <printlt> Set (... #m1 #m2 #mS ...)
Methodenverzeichnisse
Metaprogrammierung Es wurde bereits darauf hingewiesen, daB Klassen in Smalltalk vollwertige, das heiBt im Objektraum existierende und wahrend ihrer Lebenszeit durch Botschaften ansprechbare Objekte sind. Ihr Zustand und ihre Beziehungen zu anderen Objekten sind daher nicht ein fur aIle Mal festgelegt, sondem jederzeit durch Methoden beeinfluBbar. Beispielsweise ist es moglich, eine Klasse in der Klassenhierarchie zu repositionieren (Klassenmigration), ihre Strukturschablone durch HinzufUgen oder Entfemen von Instanzvariablen zu modifizieren (Klassenmutation) oder ihre Methodenverzeichnisse durch Eintragen oder Loschen von Methoden zu verandem. Solche Moglichkeiten bilden die Grundlage fUr die besondere Flexibilitat des Smalltalk-Systems, ihre unkritische Anwendung kann jedoch zu schwerwiegenden Problemen fUhren, da sie sich auch auf jene Auspragungen auswirken, die bereits vor der Anderung ihrer Klasse im Objektraum existierten. Aus dies em Grunde werden Vorgange dieser Art nieht in den Vordergrund geriickt, jedoch solI an Hand eines Beispieles einen Eindruck von den Mogliehkeiten geboten werden.
45
1.12 Realisierung der Konzepte
In Programm 1-8 wird gezeigt, wie eine bereits festgelegte und in das Methodenverzeichnis einer Klasse eingetragene Methode durch andere Methoden verandert werden kann. Ausgangspunkt ist die Methode A1»m2, die in Programm 1-6 gezeigt ist und deren Quellcode durch den in Programm 1-8 unter Punkt (1) gezeigten Ausdruck als Zeichenkette erhalten wird. Unter Punkt (2) wird diese Zeichenkette kopiert, wobei jedoch die Teilkette 'super m2, II dann: ", , durch eine leere Zeichenkette ersetzt, also aus der urspriinglichen Zeichenkette entfernt wird. Diese neue Zeichenkette ist derart aufgebaut, daB sie einem syntaktisch giiltigen Methoden-Ausdruck entspricht, der kompiliert und der Klasse Al an Stelle der urspriinglichen Methode zugeordnet wird. Jede Ausprligunmg der Klasse A1, die ab nun die Botschaft m2 empflingt, reagiert nicht mehr nach der urspriinglichen, sondern nach der modifizierten Methode. Workspace
"(1) Feststellen des Quellcodes der urspriinglichen Methode." A 1 sourceCodeAt: #m2 <print/t> 'm2 Asuper m2, II dann: ", thisContext printString'
"(2) Manipulation und Kompilation einer Methode."
I code category I
code := A1 sourceCodeAt: #m2. category := A1 whichCategorylncludesSelector: #m2. code := code copyReplaceAII: 'super m2, II dann: ", 'with: " . A 1 compile: code classified: category <dolt>
(1)
"(3) Feststellen des Quellcodes der veranderten Methode." A 1 sourceCodeAt: #m2 <printlt> 'm2 AthisContext printString' (1) Man beachte, daB innerhalb der Literaldarstellung einer Zeichenkette das Zeichen ,,'" (einfaches Hochkomma) verdoppelt wird.
Programm 1-8
Modifikation von Methoden durch Botschaften
Diese Vorgangsweise ist eigentlich nichts Besonderes, sie wird wlihrend der Entwicklung einer Methode wiederholt angewendet : eine Small talk Methode wird durch Editieren und anschlieBendes Rekompilieren des Quellcodes abgelindert und in das Methodenverzeichnis der Klasse wieder eingetra-
46
1 Smalltalk: Konzepte, Strukturen und Mechanismen
gen. Die Mlichtigkeit ergibt sieh aber daraus, daB dies nieht auBerhalb des Objektraumes gesehieht, sondern einem Vorgang im Objektraum entsprieht, der sieh dureh niehts von anderen Vorglingen unterseheidet, die im Rahmen einer Applikation im Objektraum ablaufen. Auf dieser Grundlage konnen beispielsweise Methoden einer bestehenden Applikation derart abgelindert werden, daB sie nieht nur ihre urspriingliehen Aufgaben erftillen, sondern zuslitzlieh bei jeder Aktivierung den Empfanger und die Argumente protokollieren. In einem Reverse Engineering-Vorgang konnen dureh dies en »LausehangrifI" erhaltene Beobehtungen dazu dienen, Informationen tiber die der Applikation zugrundeliegenden Modellvorgaben abzuleiten [37].
1.12.4 Die Instanzierungsbeziehung zwischen einer Klasse und ihren Auspragungen Instanzieren einer Klasse Jede Klasse versteht auf dem Wege der Verhaltensvererbung die Botsehaft new (basicNew) und reagiert darauf mit der Erzeugung einer neuen Ausprligung, die als Riiekgabeobjekt der Methode geliefert wird. Workspace
"G1, G2 und G3 werden als globale Variable festgelegt" Smalltalk at: #G1 put: nil; at: #G2 put: nil; at: G3 put: nil <dolt>
"Instanzieren der Klasse A." G1 :=Anew. G2 :=A1 new. G3 := A1 new
Programm 1-9
<dolt>
Instanzieren einer Klasse
In Programm 1-9 werden vorerst drei globale Variable dureh Eintragen ihrer Namen samt deren Bindung an das Objekt nil in das Systemverzeiehnis Smalltalk festgelegt. In einem zweiten Sehritt werden diesen Variablen neu erzeugte Instanzen der Klassen A und A1 zugeordnet, die somit fUr die folgenden Beispiele zur VerfUgung stehen.
47
1.12 Realisierung der Konzepte
Die Instanzierungsbeziehung Bei der Erzeugung einer Auspragung wird implizit die Instanzierungsbeziehung zwischen der Klasse und dieser Auspragung errichtet, auf deren Eigenschaften bereits in Abbildung 1-9 hingewiesen wurde 1m Unterschied zu den anderen erwahnten Beziehungen ist die Instanzierungsbeziehung nicht durch eine Objektzuordnung iiber Instanzvariable realisiert, sie entspricht vielmehr einer inneren Eigenschaft des Objektraumes, die nur von der virtuellen Maschine direkt genutzt werden kann. Aus diesem Grunde kann die Instanzierungsbeziehung auch nicht auf Programmebene durch Methoden beeinfluBt werden. Die Beziehung zwischen einem Objekt und seiner Klasse ist unabanderbar und unauflosbar, das heiBt, ein Objekt ist wahrend seiner gesamten Lebenszeit untrennbar mit seiner Klasse verbunden. Einige Methoden zum Uberpriifen der Klassenzugehorigkeit von Objekten und zur Bestimmung der Menge ihrer Instanzen (Klassenextension) sind aus den in Programm 1-10 gezeigten Beispielen zu entnehmen. Diese Methoden sind entweder in der virtu ellen Maschine direkt verankerte Basismethoden oder greifen auf solche zurUck. Workspace "Navigation zwischen Klasse und ihren Auspragungen."
G1 class G2 class
<printlt> A <printlt> A1
"Feststellen der Klassenextension und ihrer Kardinalitiil"
A1 alllnstances A1 instanceCount
<printlt> #(an A1 an A1) <printlt> 2
"OberprOfen der KlassenzugehOrigkeil"
G2 isMemberOf: A G2 isKindOf: A
<printlt> false <printlt> true
Programm 1-10 Instanzierungsbeziehung zwischen Instanz und Klasse
Methodensuche und dynamisches Binden In Programm 1-11 sind einige Ausdriicke zusammengestellt, deren Evaluation direkt den Vorgang der Methodensuche erkennen laBt und damit den Mechanismus der Verhaltensvererbung veranschaulicht. Zum Verstandnis der gezeigten Ergebnisse ist es notwendig, auf die Bedeutung der bereits in Programm 1-6 gezeigten Methoden hinzuweisen. Jede dieser Methoden enthiilt
48
1 Smalltalk: Konzepte, Strukturen und Mechanismen
den Ausdruck thisContext printString, der eine Zeichenket1e mit folgendem Autbau liefert: Name der Klasse des Empfangers, in Klammern folgt der Name jener Klasse, in der die Methode gefunden wurde, falls diese nicht mit der Empflingerklasse iibereinstimmt und schlieBlich durch zwei spitze Klammern abgetrennt die empfangene Botschaft, also den Namen (Selektor) der ausgeftihrten Methode. Die in Programm 1-6 zusammengefaBten Methoden reagieren also selektiv auf den jeweiligen Methodenkontext, woraus sich auch erkHirt, daB es in diesem Spezialfall notwendig ist, Methoden mit fast gleichem Code unter mehreren Namen und in mehreren Klassen zu vereinbaren. Workspace
"Ausfiihren einiger Methoden." G1 m1 G2 m1
G1 m2 G2 m2 G1 mS G2mS
<printlt> <printlt> <printlt> <printlt> <printlt> <printlt>
Message not understood: #m 1
'A1»m1'
'A»m2' 'A1(A»>m2 dann: A1»m2' 'A»m5' 'A1(A»>m5'
Programm 1-11 Methodensuche und dynamisches Binden Man erkennt aus den Beispielen, daB die von der globalen Variablen G1 referenzierte Auspragung der Klasse A (siehe Programm 1-9) die Botschaft m1 nieht versteht, wohl aber die in ihrer eigenen Klasse festgelegten Methoden m2 und mS ausftihren kann. Die an die globale Variable G2 gebundene Instanz der Klasse A1 versteht aile an sie gesandten Botschaften und findet die Methoden m1 und m2 in ihrer eigenen Klasse, die Methode mS jedoch in ihrer Superklasse A. Die Methode A1»m2 spricht zuerst durch den Ausdruck super m2 explizit eine auf dem Vererbungspfad oberhalb der eigenen Klasse befindliche Methode an und evaluiert erst dann den Ausdruck thisContext printString. Diesen Sachverhalt gibt auch die Zeichenkette zu erkennen, die als Ergebnis der Evaluation des Ausdruckes G1 m2 erhalten wird.
1.12.5 Metaklassen Da eine Metaklasse nur genau einmal instanziert wird, erfolgt sowohl das Festlegen der Metaklasse als auch ihre Instanzierung "unbemerkt" bei der Einrichtung einer neuen Klasse durch die in Programm 1-2 gezeigte Methode. Es ist
49
1.12 Realisierung der Konzepte
daher nicht notig, das Einrichten von Metaklassen und ihre Instanzierung gesondert zu betrachten.
Instanzierungsbeziehung zwischen Metaklasse und Klasse Ein Vergleich der in den Programmen 1-10 und 1-12 gezeigten Ergebnisse macht deutlich, daB die Instanzierungsbeziehung zwischen einer Metaklasse und ihrer Auspragung mit den gleichen Methoden untersucht werden kann wie die Instanzierungsbeziehung zwischen einer Klasse und ihren Instanzent. Der erste in Programm 1-12 angegebene Ausdruck und das Ergebnis seiner Evaluation bedarf einer kurzen Erlauterung. Durch A1 class wird die Klasse A1 aufgefordert, ihre Klasse zu nennen. Ais Ergebnis der Evaluation erhalt man die Metaklasse, deren Druckdarstellung ebenfalls A1 class lautet, der Text A1 class kommt also in zwei verschiedenen Bedeutungen vor. Workspace "Navigation zwischen Metaklasse und Klasse."
A1 class A1 class alllnstances
<printlt> A1 class <printlt> #(A1)
"Oberpriifen der KlassenzugehOrigkeil"
A1 isMemberOf: A class A1 isKindOf: A class
<printlt> false <print/t> true
"Strukturschablone der Metaklasse."
A1 class instVarNames
<print/t> #('c1' 'c2')
Programm 1-12 Instanzierungsbeziehung zwischen Klasse und Metaklasse Die letzte Zelle von Programm 1-12 zeigt, daB in der Strukturschablone der Metaklasse A1 class die Variablen c1 und c2 vorgerichtet sind, also die Klasseninstanzvariablen der Klasse A1.
Vererbungsbeziehung zwischen Metaklassen Programm 1-13 macht deutlich, daB zwischen den Metaklassen der Klassen A und A1 die gleiche Hierarchie besteht wie zwischen A und A1 selbst. Die t 1m Unterschied zur Instanzierungsbeziehung zwischen Klassen und ihren Instanzen tragt jede Metaklasse eine Instanzvariable, welche ihre Auspragung referenziert.
50
1 Smalltalk: Konzepte, Strukturen und Mechanismen
Metaklassenhierarchie ist analog der Klassenhierarchie aufgebaut. Wahrend jedoch die Klasse A1 nur die Oberklassen A und Object besitzt, liegen auf dem Vererbungspfad der Metaklasse A1 class neben den Metaklassen A class und Object class noch die Klassen Class, ClassDescription, Behavior und auch Object. Diese Anomalie in der Klassenhierarchie wird hier nicht weiter diskutiert, sie gibt jedoch eine Erklarung daftir, daB die Funktionalitat von Klassen teilweise von den Klassen Class, ClassDescription und Behavior geerbt wird. Workspace
"Feststellen der Vererbungsbeziehungen." A class subclasses <printlt> IdentHySet (A1 class) A 1 class superclass <printlt> A class A 1 class aliSuperclasses <printlt> OrderedColiection (A class Object class Class ClassDescription Behavior Object)
Programm 1-13 Vererbungsbeziehung zwischen Metaklassen
2
Smalltalk: Elemente der Sprache
In dies em Kapitel wird ein Uberblick tiber die Sprache Smalltalkund die mit ihr eng verbundenen Klassen BlockClosure, False und True gegeben. Eine grundlegende Darstellung von Smalltalk geben A. Goldberg und D. Robson [17]. Implementationsspezifische Details der diesem Buch zugrundeliegenden Smalltalk-Version konnen dem Handbuch von VisuaIWorks\SmalltaIk® [42] entnommen werden. Detaillierte Beschreibungen der Sprache, der Klassenhierarchie und der Programmierumgebung mit vielen Beispielen bieten unter anderen W .R. Lalonde und 1.R. Pugh [25] und M.e. Bticker et.a!. [9]. Die Bemtihungen um eine Standardisierung der Sprache und eines zentralen Teiles der Klassenhierarchie werden aus dem vorHiufigen, im RevisionsprozeB befindlichen Dokument X3120 Working Draft of ANSI SmaIltalk Standard [46] ersichtlich.
2.1
Methoden
Methoden sind Programme, die festlegen, wie ein Objekt auf eine Botschaft reagiert, sie beschreiben daher charakteristische VerhaItensaspekte von Objekten. Methoden sind in einer Klasse verankert und konnen von deren Auspragungen (sowie auf dem Wege der Verhaltensvererbung auch von Auspragungen der Unterklassen) ausgefiihrt werden. Die Aktivierung einer Methode erfolgt im jeweiligen Kontext des Empfangers, wodurch erst die im Programm angesprochenen Instanzvariablen und der den Empfanger selbst bezeichnende Name self konkrete Bedeutung erlangen. Methoden konnen erst dann formuliert und in das System eingebracht werden, wenn die Klassen, denen sie zugeordnet werden sollen, festgelegt und bereits in der Klassenhierarchie positioniert sind. Wird eine Klasse aus dem System entfernt, so werden damit auch aile zugehorigen Methoden geloscht.
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
52
2 Smalltalk: Elemente der Sprache
Die strenge Anbindung von Methoden an Klassen ist die Voraussetzung daftir, daB Methoden mit gleichen Namen in verschiedenen Klassen vorkommen kannen. Welche der Methoden mit gleichen (iiberladenen) Methodennamen im konkreten Fall zur Ausftihrung gelangt, kann erst zur Laufzeit in Abhiingigkeit der KlassenzugehOrigkeit des Empfangerobjektes festgestellt werden, da wegen des Fehlens einer statischen Typisierung von Variablen dies nicht fruher maglich ist. Die Tatsache, daB eine Methode einer Klasse zugeordnet ist, kann aufverschiedene Weise ausgedruckt werden. Bei der detaillierten Angabe des Codes einer Methode, wie sie etwa in Programm 2-1 gegeben ist, t wird die Zuordnung zu einer Klasse und weiterhin zu einer Methodenkategorie dieser Klasse durch eine Angabe folgender Form verdeutlicht: methodsFor: <Methodenkategorie>
In einem erkIarenden Text eingebettet, bedeutet die Ausdrucksweise Collection»isEmpty, daB eine der Klasse Collection zugeordnete Methode isEmpty gemeint ist. Eine iihnliche Schreibweise dient auch zur Angabe der Tatsache, daB eine Instanz einer bestimmten Klasse eine Methode aktiviert hat, was bei der Beschreibung von Prozessen und fUr die Analyse von Programmabliiufen in einem Debugger von Bedeutung ist. Dabei ist zu beriicksichtigen, daB eine Methode nicht nur von Auspriigungen "ihrer" Klasse ausgeftihrt werden kann, sondern durch den Mechanismus der Verhaltensvererbung auch von Auspriigungen der Unterklassen. Durch die Schreibweise Set(Collection»>isEmpty wird ausgedriickt, daB einer Menge (Instanz der Klasse Set) die der Klasse Collection zugeordnete Methode isEmpty aktiviert hat. Bei der praktischen Arbeit mit dem Smalltalk-System wird Programmcode fast ausschliel3lich in einem Klassenbrowser editiert, wobei das Erzeugen von Methoden nur maglich ist, wenn die Zuordnung zu einer Klasse und zu einer Methodenkategorie eingestellt ist. Methoden bestehen in ihrem syntaktischen Aufbau aus einem Deklarationsteil (message pattern), einer optionalen Vereinbarung von temporiiren Variablen (temporaries) und einem Anweisungsteil (statements). Der Deklarationsteil ist aus dem Methodennamen (method selector) und der entsprechenden Anzahl von Argumentnamen zusammengesetzt; er wird auch a1s Signatur der Methode bezeichnet. Der Anweisungsteil wird aus einer Folge von Ausdrucken gebildet, die voneinander durch einen Punkt abgetrennt sind. Jeder Ausdruck beschreibt ein Objekt, das auch als Wert des Ausdruckes bezeichnet wird. Manche Ausdrucke beschreiben zusiitzlich Aktionen, durch welche der Zustand von Objek-
t
Programme (Method en), die nicht selbst erstellt wurden, sondem bereits in der Klassenhierarchie vorliegen und einen Bestandteil des Systems bilden, werden unter der Uberschrift "KlassenBrowser" dargestellt.
53
2.1 Methoden
ten verlindert werden kann. Die verschiedenen Arten von Ausdriicken werden in den folgenden Abschnitten erliiutert. Innerhalb eines Methodentextes konnen an beliebigen Stellen Kommentare eingeftigt werden, sie werden durch Zeichenketten dargestellt, die zwischen hochgestellten Anftihrungszeichen gesetzt sind. Das Layout der schriftlichen Darstellung des Quellcodes von Methoden dient nur der besseren Lesbarkeit, ist jedoch ohne syntaktische Bedeutung. KlassenBrowser Collection methodsFor: 'testing'
(1)
isEmpty
"Priifen, ob der Empfanger leer ist" 1\
self size = 0
Collection class methodsFor: 'instance creation'
(2)
with: anObject
"Erzeugen eines Sammelobjektes, das anObject als Element enthalt"
I newCollection I
newCollection := self new. newCollection add: anObject. 1\ newCollection
(1) Durch diese Angabe wird festgelegt, daB die folgenden Methoden der Klasse Collection zugeordnet und dort in die Methodenkategorie testing eingeordnet sind. Die Methode Collection>>isEmpty wird von Auspriigungen (einer Unterklasse) von Collection verstanden und ist somit eine Instanzmethode. (2) Die auf diese Angabe folgenden Methoden sind der Klasse Collection class zugeordnet, also der Collection-Metaklasse. Die Instanzierungsmethode Collection clasS>>With: ist somit eine Klassenmethode.
Programm 2-1
Zuordnung von Methoden zu Klassen
Bei der Ausftihrung einer Methode werden die in ihrem Anweisungsteil enthaltenen Ausdriicke in vorgegebener Reihenfolge evaluiert, wobei den erreichbaren (im dynamischen Horizont befmdlichen) Objekten Botschaften gesandt werden konnen. SchlieBlich wird die Ausftihrung mit der Obermittlung eines Riickgabeobjektes abgeschlossen. Sowohl der Empfanger als auch alle durch Botschaften angesprochenen Objekte konnen dabei ihren Zustand gelindert haben.
54
2 Smalltalk: Elemente der Sprache
Das Riickgabeobjekt einer Methode wird durch eine Riickgabeanweisung bestimmt. Ein Ruckgabeanweisung ist ein beliebiger Ausdruck, dem das Zeichen" "" als Riickgabeoperator vorangestellt ist. Nach der Evaluation des Ausdruckes der Riickgabeanweisung wird die AusfUhrung der Methode abgebrochen und das bei der Evaluation gelieferte Objekt als Riickgabeobjekt der Methode an den Sender iibermittelt. Eine Riickgabeanweisung muB sich am Ende einer Anweisungsfolge befmden, sie kann also als nur letzte Anweisung einer Methode oder eines Blockes auftreten. 1st in einer Methode keine Riickgabeanweisung enthalten, so wird implizit die Riickgabeanweisung "self angenommen. Es gilt somit die Vorgabe, daB der EmpHinger der Methode selbst das Riickgabeobjekt ist. Als Beispiel sei der Autbau und die AusfUhrung der zwei in Programm 2-1 angegebenen Methoden kurz erlautert. Der Deklarationsteil der Methode Coliection»isEmpty besteht nur aus dem Methodennamen (isEmpty), da fUr diese Methode keine Argumente vorgesehen sind. Der Anweisungsteil enthalt einen einzigen Ausdruck, namlich "self size = O. Wird die Botschaft isEmpty von einer Auspragung einer Unterklasse von Collection empfangen (Collection selbst ist eine abstrakte Klasse), so wird zuerst der Botschaftsausdruck self size ausgewertet, das heiBt, es wird die Botschaft size an den Empfanger (ein Behalterobjekt) selbst gesendet. Die dadurch aktivierte Methode antwortet mit einem Integer-Objekt, das die Anzahl der im Behalter gehaltenen Elemente angibt. Diesem Integer-Objekt wird sodann die Botschaft mit dem Selektor = und dem Parameter 0 gesandt, worauf als Antwort true geliefert wird, falls der Empfanger 0 ist, ansonsten false. Der gesamte Ausdruck "self size = 0 beschreibt also in Abhangigkeit von der Anzahl der im Empfanger enthaltenen Elemente das Objekt true oder false, welches wegen des Riickgabeoperators ( ") auch das Riickgabeobjekt der Methode darstellt. Man erkennt an dieser Diskussion, daB die Auswertung des Ausdruckes von links nach rechts erfolgt und daB der Riickgabeoperator auf das Ergebnis der Evaluation angewendet wird. Die Methode Collection class»with: tragt die Signatur with: anObject, die aus dem Methodennamen with: und dem Namen eines formalen Argumentes anObject zusammengesetzt ist. Nach einem Kommentar wird durch den VereinbarungsteillnewColiectionl die temporiire Variable newColiection deklariert, darauf folgt der Anweisungsteil, der aus einer Folge von drei Ausdriicken besteht, die durch Punkte separiert sind. Fur die Beschreibung der Wirkungsweise dieser Methode ist der Hinweis wichtig, daB es sich hier urn eine Klassenmethode handelt. Die Methode ist der Klasse Collection class (das ist die Metaklasse von Collection) zugeordnet, sie wird von deren (einziger) Auspragung, also vom Klassenobjekt Collection verstanden oder auf dem Wege der Verhaltensvererbung auch von den Unterklassen von Collection.
2.1 Methoden
55
Empflingt eine Collection-Klasse die Botschaft with:, dann wird diese Methode aktiviert. In einem ersten Schritt wird an den Empflinger selbst die Botschaft new gesandt, welche bewirkt, daB ein neues und noch leeres Behlilterobjekt als Ausprligung des des Empfangers erzeugt und der temporliren Variablen newColiection zugewiesen wird. An diesen eben erzeugten Behlilter wird die Botschaft add: anObject iibermittelt, wodurch anObject, also das Parameterobjekt, in den Behlilter eingefUgt wird. Wie man sich durch einen Blick in den Klassenbrowser iiberzeugen kann, ist es eine beabsichtigte Eigenheit der Methode Collection»add:, daB sie als Riickgabeobjekt nicht den Behlilter, sondern das eingefiigte Objekt liefert, sodaB es notwendig ist, die Methode mit dem Riickgabeausdruck 1\ newColiection abzuschlieBen. Insgesamt liefert die Methode daher eine neue Ausprligung des Empfangers, die als Behlilterobjekt das im Parameter angegebene Objekt enthlilt.
Freie Methoden Fiir Testzwecke kann auch Smalltalk-Code temporlir in einem Arbeitsbereich (Workspace) gehalten und zur Ausfiihrung gebracht werden. Solche Programme stellen freie Methoden dar, die nicht an eine Klasse gebunden sind und daher auch nicht im Kontext eines Objektes (Empfangers) ausgefUhrt werden. Freie Methoden (unbound methods) haben keinen Namen und kennen weder private noch gemeinsame Variable, sie konnen aber temporlire Variable erklliren und auf globale Variable zugreifen. Freie Methoden werden oft zu Demonstrationszwecken verwendet und in der in Programm 2-2 gezeigten Form dargestellt. Der hier gezeigte Arbeitsbereich enthlilt einen Text, von welchem erst (zusammenhlingende) Teile ausgewlihlt werden miissen, um als freie Methode interpretiert und zur AusfUhrung gebracht werden zu konnen . In der interaktiven Arbeitsumgebung geschieht die Auswahl des Textes durch Markierung, die gewiinschte AusfUhrung durch Auswahl aus einem dem Workspace zugeordneten Aktionsmenii. In der schriftlichen Darstellung wird die Zusammenfassung von Textteilen zu freien Methoden durch Gruppierung des Textes und die veranlaBte Aktion durch einen in spitzen Klammern eingeschlossenen Hinweis veranschaulicht. Ais Aktionsauswahl stehen <dolt>, <printlt> und zur VerfUgung. Aile diese Aktionen veranlassen die AusfUhrung der freien Methode, die wie jede Methode mit genau einem Riickgabeobjekt antwortet. Durch die Aktion <printlt> wird zuslitzlich das Riickgabeobjekt in Form einer Zeichenkette "ausgedruckt", durch wird ein Inspektor fUr das Riickgabeobjekt geoiTnet. Das Riickgabeobjekt einer freien Methode istjenes des letzten in die freie Methode einbezogenen Ausdruckes. Die als Reaktion auf die Aktionsaufforderung <printlt> ausgegebenen Zeichenketten werden durch die Methode printOn: erzeugt, deren generische Form in der Klasse Object definiert ist und somit von jedem Objekt verstan-
56
2 Smal1talk: Elemente der Sprache
den wird. In den meisten Klassen ist diese Methode redefmiert, um eine den Besonderheiten der Klasse entsprechende Ausgabeform zu bieten. In Programm 2-2 und in ahnlichen Fallen wird die durch <printlt> in einem Arbeitsbereich erzeugte Zeichenkette durch Fettdruck hervorgehoben. Entsteht bei der Evaluation einer freien Methode eine Warnung oder Fehlermel dung, so wird ihr Text (der bei einem laufenden Smalltalk-System in einem eigenen Fenster (notifier) angezeigt wird) durch kursiven Fettdruck wiedergegeben. Workspace 2
+3*6
<print/t> 30
I temp I temp := Set new. temp add: 'einElement'. temp add: 'nochEinElement'. <printlt> 'nochEinElement' temp <print/t> Set (,nochEinElement' 'einElement')
(1) (2)
(3) (4)
(1) Der Programmtext 2 + 3 * 6 wird zu einer freien Methode zusammengefaBt, durch die Aufforderung <printlt> wird veranlaBt, daB dieses Programm ausgeflihrt und das Ergebnis in Form einer Zeichenkette angezeigt wird. (Die Aufforderung <dolt> wiirde zwar die Exekution des Programmes veranlassen, nicht aber die Anzeige des Ergebnisses.) (2) Der in dieser Zeile beginnende und bis zur Aktionsaufforderung <printlt>
reich en de Text wird eben falls als freie Methode ausgeflihrt.
(3) Der Rtickgabewert von Collection»add: ist das Parameterobjekt. (4) Der Rtickgabewert der Evaluation des Ausdruckes, der nur aus der Variablen temp besteht, ist das dieser Variablen zugewiesene Mengenobjekt. Man vergieiche auch die Bemerkung zu Programm 2-1.
Programm 2-2
2.2
Freie Methoden in einem Arbeitsbereich (Workspace)
Ausdriicke
Ausdriicke (expressions) sind durch Zeichenfolgen dargestellte Programmelemente. Jeder Ausdruck beschreibt ein Objekt, das als Ergebnis der Evaluation des Ausdruckes geliefert wird, es wird auch als Wert des Ausdruckes bezeichnet.
57
2.2 Ausdriicke
Es kann zwischen folgenden Arten von Ausdriicken unterschieden werden:
1. 2. 3. 4. 5.
Literale Namen von Variablen und Konstanten Zuweisungsausdriicke Botschaftsausdrucke Blockausdriicke
In der Folge werden diese Formen von Smalltalk-Ausdriicken beschrieben und ihre Wirkung an Hand von Beispielen demonstriert.
2.2.1
Litera Ie
Literale sind lexikalische Elemente der Sprache, welche Objekte durch sich selbst alleine und vollstandig bezeichnen. Fur das Identiftzieren oder Erzeugen eines durch ein Literal bezeichneten Objektes ist weder eine Referenzierung anderer Objekte noch eine Evaluierung von Ausdrucken notwendig. Literale treten als Bestandteile des Quellcodes von Methoden auf. Workspace $a class $a=$a 12 class 12=12 True instanceCount X:= true. True instanceCount 12 islmmediate $a islmmediate true islmmediate
<printlt> <printlt> <printlt> <printlt> <printlt>
Character true Smalllnteger true 1 "vorher"
<printlt> <printlt> <printlt> <printlt>
1
"nachher"
(1) (2)
(3)
true true false
(1) Die zwei gleichen Literale (in der Position des Empflingers und des Argumentes der Methode ) bezeichnen ein und dasselbe Objekt, die Identitatspriifung ergibt true.
(2) Die Klassenmethode Behavior»instanceCount meldet die Anzahl der im Objektraum existierenden Auspragungen des Empflingers. (3) Das an die globale Variable X gebundene Objekt wurde nicht neu erzeugt, es gibt nach wie vor nur eine Auspragung der Klasse True.
Programm 2-3
Ansprechen von "a-priori"-Objekten dur,ch Literale
58
2 Smalltalk: Elemente der Sprache
Ob durch ein Literal ein bestehendes Objekt angesprochen wird oder ob ein neues Objektexemplar erzeugt wird, hangt von der Art des durch ein Literal bezeichneten Objektes abo Aus Programm 2-3 ist ersichtlich, daB fUr Instanzen der Klassen Character und Smalllnteger gilt, daB sie nicht erzeugt werden, sondern daB durch jedes gleiche Literal dasselbe Objekt (und nicht ein anderes, gleiches Objekt) angesprochen wird. Auspragungen dieser beiden Klassen sind a-priori existierende Objekte . Sie haben auch in dem Sinne eine Sonderstellung, als sie eine "unmittelbare" Existenz haben und im technischen Objektraum keinen Platz beanspruchen. Objekte mit dieser Eigenschaft antworten auf die Botschaft islmmediate mit true. Literale fUr Systemkonstante (true, false, nil) bezeichnen ebenfalls a-priori existierende Objekte. Aus den in Programm 2-4 angegebenen Beispielen wird deutlich, daB Literale fUr Objekte anderer Klassen, sofern sie iiberhaupt eine Literaldarstellung besitzen, zwar stets gleiche, aber nicht identische Objekte referenzieren, was bedeutet, daB bei der Auswertung des Literales durch den Kompiler ein neues Objekt erzeugt wird.
Workspace 12.3 = 12.3 12.3 = 12.3 12.3 class
<printlt> true <printlt> false <printlt> Float
Float instanceCount X:= 12.3 Float instanceCount
<printlt> 1149
"vorher"
<print/t> 1150
"nachher"
'hallo' = 'hallo' 'hallo' class
<print/t> <printlt> <printlt> <printlt>
#hallo = #hallo #hallo class
(1)
(2)
false ByteString true ByteSymbol
(3)
(1) Zwei gleiehe Literale bezeiehnen gleiehe Objekte, aber nieht dasselbe Objekt. (2) Es wurde ein neues Objekt erzeugt, unabhiingig davon, ob unter den 1149 bereits existierenden FlieBkommazahlen eine mit dem Wert 12.3 vorkommt. (3) FUr Symbole wird siehergestelit, daB sie systemweit eindeutig sind. Sie werden dureh Literale erzeugt, falls sie noeh nieht vorhanden sind.
Programm 2-4
Erzeugen von Objekten durch Evaluation von Literalen
59
2.2 Ausdriicke
In Programm 2-5 sind einige Beispiele zusammengestellt, aus den en die Notation von Literalen fUr Zablen hervorgeht. Ganze Zahlen konnen durch Literale dargestellt werden, die aus beliebig vielen Dezimalziffem bestehen, wobei es von der GroBe der Zabl abhiingt, ob bei der Evaluation des Literalausdruckes eine a-priori existierende Auspragung der Klasse Smalllnteger angesprochen wird oder ob eine Instanz der Klasse LargePositivelnteger (im Faile negativer Zahlen eine Instanz von LargeNegativelnteger) erzeugt wird (man vergleiche dazu auch Programm 2-23). FlieBkommazahlen sind durch einen Dezimalpunkt gekennzeichnet, sie konnen auch mit einem Exponenten notiert werden. Workspace 123 class -12345678987654321 class
8rn 8rn class 16rFF 123.22 class 0.22 class 12.45e4 12.45e-4 16r1245e2 12.45e4 class 12.45d4 class 12.45s4 class
<printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt> <printlt>
Smalllnteger LargeNegativelnteger
63
Smalllnteger 255 Roat Float 124500.0 0.001245 1197538 Float Double FixedPoint
(1)
(2) (3)
(1) Zahlenliterale konnen mit einer vorgebbaren Basis notiert werden. Die Basis wird in dezimaler Form angegeben und durch das Zeichen "r" (radix) vom darautTolgenden ZitTernteil getrennt. Das Literal Srn bezeichnet somit die Oktalzahl 77. (2) FlieBkommazahlen mit Exponentialnotation. (3) Eine FlieBkommazahl zur Basis 16.
Programm 2-5
Beispiele zur Notation von Literalen fur Zahlen
Ganze Zahlen konnen mit beliebiger Basis b (2 :s; b :s; 36) notiert werden, wobei die Ziffem 0 - 9 durch die "Ziffem" A - Zergiinzt werden. Ganze Zahlen mit beliebiger Basis konnen auch als Mantisse von FlieBkommazahlen in Exponentialdarstellung auftreten, die Exponenten miissen jedoch als Dezimalzahlen angegeben werden.
60
2 SmalItalk: Elemente der Sprache
Wie durch die AusfUhrung des ersten in Programm 2-6 gezeigten Ausdruckes zu erkennen ist, existieren Literale fUr Zahlen, Zeichen, Zeichenketten, Symbole sowie fUr Felder, sofern ihre Elemente selbst durch Literale darstelIbar sind. Eine LiteraldarstelIung besitzen somit Instanzen der Klassen: Character, FixedPoint, Integer (inklusive alIer Unterklassen), Float, Double, True, False, Array (exklusive der Unterklassen und nur fUr jene Instanzen, deren Elemente selbst durch Literale bezeichnet werden konnen), String, Symbol, ByteArray und UndefinedObject. Workspace
"{1} Feststellen, welche Klassen eine Methode mit dem Selektor isLiteral zugeordnet haben."
Browser aliClasseslmplementing: #isLiteral <printlt> #(Object Character FixedPoint Integer Roat Double True False Array String Symbol ByteArray UndefinedObject)
(1)
"{2} Priiten, ob ein Objekt eine Literaldarstellung hat."
$a isLiteral (1.2) isLiteral (1/2) isLiterai (1/2)
(1/2) class
<print/t> <printlt> <printlt> <print/t> <printlt>
true true false
(2)
(1/2)
(3)
Fraction
(1) Das Ergebnis dieses Programmes zeigt, daB der Methodenname isLiteral
tiberladen ist und daB entsprechende Methoden in den angeflihrten Klassen implementiert sind. (2) Objekte, die eine Literaldarstellung haben, antworten auf isLiteral mit true. Bruchzahlen (Instanzen der Klasse Fraction) haben keine Literaldarstellung. (3) Hier wird der Ausdruck evaluiert und das Ergebnis in Form einer Zeichenkette dargestellt.
Programm 2-6
Uberpriifen, ob Objekte eine Literaidarstellung besitzen
Objekte, die eine Literaldarstellung haben, antworten auf die Botschaft isLiteral mit true, andere Objekte mit false. Programm 2-7 bietet einen Uberblick iiber die Implementationen der Methode isLiteral. Die Methode Object»isLiteralliefert als Ergebnis false. Da aIle anderen Klassen von Object erben, gilt prinzipiell fUr aIle Klassen, daB ihre Auspragungen keine Literalform haben, sofern dies nicht durch Redefmition dieser Methode abgeiindert wird. Einige Klassen, namlich jene, deren
61
2.2 Ausdriicke
Instanzen durch Literale darstellbar sind, lindem diese Methode derart ab, daB sie das Ergebnis true Hefem, was sodann auch auf die jeweiligen Unterklassen vererbt wird. Beispielsweise antwortet die Methode Integer»isLiteral mit dem Riickgabeobjekt true, das bedeutet, daB auch samtliche Unterklassen von Integer (das sind die Klassen: Smallinteger, Largelnteger, LargeNegativeInteger und LargePositivelnteger) auf die Botschaft isLiteral mit true antworten und eine Literalform besitzen.
KlassenBrowser Object methodsFor: 'testing' isUteral "Feststellen, ob der Empfanger eine Literalform besitzt, die vom Compiler erkannt wird." (1 )
"false Array methodsFor: 'testing' isUteral
"Feststellen, ob der Empfanger der Klasse Array angehOrt und ob aile seine Elemente eine Literalform besitzen."
(self isMemberOf: Array) if False: ["false] self detect: [:element I element isLiteral not] ifNone: ["true]. "false
(2) (3)
(1) In allen anderen Klassen, in denen isLiteral implementiert ist, antwortet die Methode mit true. Eine Ausnahme bildet nur die Klasse Array. (2) Unterklassen von Array haben keine Literaldarstellung. (3) Eine Literaldarstellung existiert fur eine Auspriigung der Klasse Array nur dann, wenn auch alle Elemente eine Literaldarstellung haben.
Programm 2-7
Implementationen der Methode isLiteral
Selbstverstlindlich muB die Literalform von Objekten yom Scanner erkannt und yom Kompiler entsprechend weiterverarbeitet werden konnen. Es ist daher ein tiefer Eingriff in das System notwendig, um zusatzlichen Objektarten eine Literalform zu verleihen. Die Methode isLiteralliefert nur einen Hinweis darauf, ob eine Literalform existiert, keinesfalls kann sie jedoch die Existenz einer Literalform festlegen.
62
2 Smalltalk: Elemente der Sprache
Objekte mit einer Literalform sind im allgemeinen grundlegende, systemnahe Objekte, wie etwa Zahlen, Zeichen oder Zeichenketten. Solche Objekte konnen nicht weiter spezialisiert werden, so daB von ihren Klassen auch kaum Subklassen defmiert werden miissen, fur deren Instanzen eine Literalform zu beriicksichtigen ware. Einen Sonderfall stellt die ebenfalls in Programm 2-7 gezeigte Methode Array»isLiteral dar. Hier wird iiberpriift, ob der Empfanger tatsachlich der Klasse Array (und nicht etwa einer ihrer Unterklassen) angehort, so daB diese Methode zwar von Auspragungen der Unterklassen verstanden wird, aber nur fUr Instanzen der Klasse Array selbst mit true antwortet. Einige Beispiele und Hinweise zur Literaldarstellung von Arrays sind in Programm 2-8 zusammengefaBt. Workspace #(1 2 3) isLiteral (Array with: 1 with: 2 with: 3) isLiteral (Array with: 1 with: 1/2 with: 3) isLiteral #( 1 1/2 3) isLiteral #( 1 1/23)
<print/t> <printlt> <print/t> <print/t> <printlt>
true true false
(1) (2)
true (3) #(1 1 #1 2 3)
(1) Dieses Feld ist zwar nicht durch ein Literal implizit, sondem explizit durch eine Methode erzeugt worden, es ist aber auf Grund der Tatsache, daB seine Elemente eine Literaldarstellung haben, selbst durch ein Literal darsteJlbar. (2) Ein solches Feld kann nicht durch ein Literal dargestellt werden, da sein zweites Element keine Literaldarstellung hat. . (3) MiBachtet man die Tatsache, daB der Bruch 112 (a Fraction) nicht durch ein Literal reprasentiert werden kann, so kann es zu einem Fehler kommen. Das hier angeflihrte Literal bezeichnet sehr wohl ein Feld, allerdings eines mit 5 Elementen, von denen eines das Symbol J" ist, welches auch als Methodenname flir Divisionsoperationen verwendet wird. Symbole werden sowohl in ihrer Literaldarstellung als auch in ihrer "Druckausgabe" durch ein fl.ihrendes Nummernzeichen (#) gekennzeichnet.
Programm 2-8
Zur Literaldarstellung von Arrays
Die hier an Hand des Methodennamens isLiteral gezeigte Technik, in der Klasse Object eine Voreinstellung fUr aIle Unterklassen zu setzen, die nur in wenigen Sonderfallen revidiert werden muB, ist auch fUr viele andere FaIle niitzlich. So liefern beispielsweise die "Testmethoden" Object»isNii
2.2 Ausdriicke
63
Object»isString und Object»isSymboi als Ergebnis false, sie werden jedoch in den Klassen UndefinedObject, String und Symbol redefmiert.
2.2.2 Konstante Konstante sind in ihrem Kontext eindeutige Namen, die unablinderlich an ein Objekt gebunden sind. Eine Konstante referenziert somit wiihrend der Zeit ihrer Giiltigkeit stets ein und dasselbe Objekt. Beispielsweise bezeichnet der Name nil stets genau die einzige Instanz der Klasse UndefinedObject, ahnliches gilt fUr Systemkonstanten wie true, false oder Smalltalk. Zu den Konstanten konnen auch self, super und thisContext geziihlt werden. Zwar referenziert der in einer Methode vorkommende Name self immer den jeweiligen Empninger der Methode, also jenes Objekt, welches die Methode aktiviert hat, dieses ist jedoch von Fall zu Fall verschieden, weshalb self manchmal auch als spezielle Variable oder Pseudovariable bezeichnet wird. 1st der Bezeichner self jedoch an einen Objektkontext gebunden und somit im strengen Sinne erst ein Name fUr ein Objekt, dann bleibt er unabiinderlich mit diesem Objekt verbunden. Es gibt keine Mogiichkeit, ihn wie eine Variable durch eine Zuweisung an ein anderes Objekt zu binden. Der Name super bezeichnet stets dasselbe Objekt wie self, er ist also ein Synonym fUr self. Allerdings kann super nur dann an Stelle von self gesetzt werden, wenn es darum geht, dem referenzierten Objekt, also dem Empfanger der aktiven Methode, alias self, eine Botschaft zu iibersenden. Dabei wird aber der Mechanismus der Verhaltensvererbung wesentlich beeinfluBt und zwar derart, daB die Suche nach der passenden Methode nicht in der Klasse des Empfangers begonnen wird, sondern in deren unmittelbarer Superklasse. Dadurch wird es moglich, eine in der Oberklasse festgelegte Methode zu redefmieren und sich trotzdem der Dienste dieser Methode zu bedienen. Wenn der Empfanger der laufenden Methode als Riickgabeobjekt oder als Parameter einer anderen Methode spezifiziert werden soll, darf er nicht durch den Namen super, sondern nur durch self bezeichnet werden. Ebenso ist die Zuweisung von super an eine Variable nicht zuliissig, wohl aber von self. SchlieBlich sei noch auf die Konstante thisContext hingewiesen, die in einer aktivierten Methode jenes Objekt referenziert, welches als Instanz der Klasse MethodContext den Exekutionsstack enthiilt und die Verbindung zum Sender (genauer zu des sen aktiven Methodenkontext) aufrecht erhiilt. Wie noch an einer spiiteren Stelle (Abschnitt 14.2) gezeigt wird, kann auf diese Weise erreicht werden, daB die AusfUhrung einer Methode von Eigenschaften des Senders abhlingig gemacht werden kann.
64
2 Smalltalk: Elemente der Sprache
Die aktuellen Parameter einer Methode sind ebenfalls Konstante, ein Name eines Methodenparameters darf daher nicht auf der linken Seite eines Zuweisungsausdruekes stehen.
2.2.3 Variable Variable sind in ihrem Kontext eindeutige Namen, die zu jedem Zeitpunkt ihrer Giiltigkeit an genau ein Objekt gebunden sind, welches jedoeh in zeitlicher Abfolge durch beliebige andere Objekte ersetzt werden kann. Eine Variable kann also wlihrend der Zeit ihrer Giiltigkeit hintereinander verschiedene Objekte referenzieren.
Workspace
I tempVar I tempVar := 12. tempVar := Set with: tempVar. tempVar := OrderedColiection with: tempVar. tempVar <printlt> OrderedCollection (Set (12»
(1)
(2) (3)
(1) Deklaration einer temporliren Variablen, die wlihrend der Ausflihrung einer freien Methode giiltig ist.
(2) Auf der rechten Seite dieser Zuweisung bezeichnet tempVar das Objekt 12, welches als aktueller Parameter der an die Klasse Set gesandten Methode with: dient. Das neu erzeugte und mit dem Objekt 12 ngeflillte" Behlilterobjekt (eine Instanz der Klasse Set) wird durch die Zuweisung ab nun und bis auf weiteres durch tempVar benannt. Eine lihnliche Vorgangsweise wird durch die nlichste Anweisung beschrieben. (3) Der letzte Ausdruck dieser freien Methode besteht nur aus der Variablen tempVar, das durch diese Variable bezeichnete Objekt bildet somit ihren Riickgabewert. Die Methode Coliection>>printOn: liefert als nDruckdarstellung" eines Behlilterobjektes den Klassennamen gefolgt von der Aufzlihlung seines Inhaltes, der in Klammem gesetzt ist.
Programm 2-9
Belegung einer Variablen mit untersehiedlichen Objekten
Variable sind in Smalltalk nieht statiseh typisiert, das heiBt, daB bei der Deklaration einer Variablen lediglich ihr Name vereinbart wird, daB dariiber
2.2 Ausdrucke
65
hinaus aber keine Einschriinkung bezuglich der Art der an den Namen bindbaren Objekte festgelegt wird. Variable konnen hintereinander Instanzen beliebiger Klassen referenzieren. Programm 2-9 demonstriert dies an Hand eines Beispieles. Hier wird die Variable tempVar als temporiire Variable vereinbart und zeitlich nacheinander mit Objekten der Klassen Smalllnteger, Set und OrderedCollection belegt. Bei der Evaluation einer Variablen wird das von der Variablen bezeichnete Objekt geliefert. Variablennamen werden nach den Regeln fUr Bezeichner (identifier) gebildet, sie konnen aus beliebig vielen Buchstaben (letter) und Ziffern (digit) bestehen, wobei das erste Zeichen ein Buchstabe sein muB. Fur die Bildung von Bezeichnem gilt aueh das Unterstreichungszeichen ,,_" als Buchstabe. Die mit einer besonderen Bedeutung belegten Namen nil, true, false, self, thisContext und super sind keine zuliissigen Variablennamen. Um die Eindeutigkeit der Namen zu gewiihrleisten, mussen sich die Bezeiehner der lokalen Variablen (temporiire Variable sowie Methoden- und Bloekargumente) von allen Bezeiehnem der im Siehtbarkeitsbereich liegenden nichtlokalen Variablen unterscheiden.
2..2.4 Zuweisungen Eine weitere Art eines Ausdruekes ist die Zuweisung. Durch eine Zuweisung wird ein Objekt an eine Variable gebunden, wobei die bis dahin bestehende Bindung eines zumeist anderen Objektes an diese Variable verloren geht. Der Wert einer Zuweisung istjenes Objekt, das an die Variable zugewiesen wird. Ais Zuweisungsoperator dient die Zeiehenkombination ,,:=", in fruheren Smalltalk-Versionen [171 wurde das Zeichen ,,~" fUr diesen Zweck verwendet. In den bisherigen Beispielen sind bereits mehrfach Zuweisungen vorgekommen, ohne das dies besonders hervorgehoben wurde. In Programm 2-10 werden gezielt Beispiele fUr Zuweisungen betrachtet. Bei der Evaluation eines Zuweisungsausdruckes wird zuerst der Ausdruck auf der rechten Seite des Zuweisungsoperators evaluiert und dessen Ruckgabeobjekt an den auf der linken Seite des Zuweisungsoperators stehenden Variablennamen gebunden. Man vergleiche dazu aueh das in Programm 2-9 angefUhrte und kommentierte Beispiel. Da auf der reehten Seite einer Zuweisung ein beliebiger Ausdruck stehen darf, ist auch nieht ausgeschlossen, an diese Stelle selbst eine Zuweisung zu setzen, wodurch Mehrfachzuweisungen formuliert werden konnen. In der mit (1) markierten Zeile von Programm 2-11 ist ein Beispiel fUr eine Mehrfachzuweisung gezeigt.
66
2 Smalltalk: Elemente der Sprache
Workspace
I x yz I x :=25. x. y:= -12. z. (z := x + y) * 2. z
<printlt> 25 <printlt> nil <printlt> 26 <printlt> 13
(1) (2)
(3)
(1) Das als Ergebnis der Evaluation des Literales 25 erhaltene Objekt, namlich "25", wird der temporaren Variablen x zugewiesen, wie auch aus der Ausftihrung der in der folgenden Zeile angegebenen Aktion (das ist die Evaluation des Ausdruckes x) ersichtlich ist. (2) Die Variable z ist noch mit nil belegt. (3) Der Wert der Zuweisung z := x + y ist das Objekt »13", dieses wird mit 2 multipliziert, so daBais Ergebnis 26 ausgegeben wird.
Programm 2-10 Zuweisungsausdriicke
Workspace
Ix y I
x := y := 12.5.
x
x=y.
<printlt> 12.5 <printlt> true
x:= 12.5. y:= 12.5. x=y
<printlt> false
(1)
(2)
(1) Nach der Ausftihrung dieses Ausdruckes referenzieren x und y dasselbe Objekt. Der Ausdruck ist aquivalent zu y := 1.25. x := y. (2) Nach der Ausfiihrung dieses Ausdruckes referenzieren x und y verschiedene, aber gleiche Objekte.
Programm 2-11 Mehrfachzuweisung
2.2 Ausdriicke
67
2.2.5 Botschaftsausdrucke Ein Botschaftsausdruck (message expression) besteht aus der Angabe eines Empfangers und einer an diesen zu sendenden Botschaft, welche sich aus einem Selektor und den entsprechenden aktuellen Parametern zusammensetzt. Der Empfanger und die Parameterobjekte werden selbst wieder durch Ausdrucke beschrieben. Der Selektor wird in literaler Form direkt angegeben und bei der Evaluation als Symbol interpretiert. Es kann zwischen unaren, binaren und SchlUsselwortbotschaften unterschieden werden.
Unare Botschaften Botschaften, die nur aus dem Selektor bestehen und keine Argumente verIangen, werden als uniire Botscha/ten bezeichnet. Sie aktivieren Methoden, die nur auf den Zustand des Empfangers Bezug nehmen und daruber hinaus fUr ihre Aktionen keine aktuellen Zusatzinformation benotigen. Methoden mit uniiren Selektoren dienen haufig zum Testen von Eigenschaften des Empfangers oder fUr den lesenden Zugriff auf eine seiner Instanzvariablen (Akzessormethoden). Beispiele dafUr sind die bereits vorgestellten Methoden Object»size oder Object»isLiteral, die in vielen Klassen redefiniert sind oder auch die Klassenmethode Behavior»new, welche eine neue Instanz erzeugt, wenn sie an ein Klassenobjekt gesandt wird. Unare Selektoren sind Bezeichner, sie konnen also aus beliebig vielen Buchstaben (dazu zahlt auch das Zeichen ,,_") und Ziffern gebildet werden, wobei als erstes Zeichen ein Buchstabe gesetzt sein muB.
Schliisselwortbotschaften Benotigt eine Methode Parameter, so besteht ihre Signatur (message pattern) aus einem Selektor und der entsprechenden Anzahl von Namen fUr formale Parameter. Es ist dabei eine Eigenheit von Smalltalk, daB in diesem Fall der Methodenname (selector) aus mehreren Schlusselwortern (keywords) zusammengesetzt ist, wobei die Schlusselworter nach den selben Regeln wie Bezeichner (identifier) gebildet werden, jedoch mit einem Doppelpunkt abzuschlieBen sind. Die Selektoren von Schliisselwortbotscha/ten (keyword messages) sind somit derart gegliedert, daB nach jedem Doppelpunkt ein Parameter eingefUgt werden kann. In Programm 2-1 wurde bereits die Methode Coliection>>With: erwahnt, die einen Schliisselwortselektor und einen Parameter besitzt. Methoden fUr den schreibenden Zugriff auf Instanzvariable (Mutatormethoden) haben ebenfalls Signaturen dieser Form.
68
2 Smalltalk: Elemente der Sprache
Eine ahnliche Methode mit zwei Parametem ist in Programm 2-12 angefiihrt. Diese tragt den Selektor with:with:, der mit zwei Parametem versorgt wird, je einen nach jedem der beiden Doppelpunkte. Zum Identifizieren dieser Methode geniigt prinzipiell die Angabe Collection>>With:with:, man kann jedoch durch die Angabe der vollstiindigen Signatur Coliection>>With: firstObject with: secondObject auf die Bedeutung der Parameter hinweisen. Es ist in jedem Fall giinstig, den Selektor (die Teile des Selektors) und die Parameter so zu ben ennen, daB dadurch die Bedeutung der Methode gut charakterisiert wird. An einer spateren Stelle wird im Zusammenhang mit einer Fallstudie iiber den Zahlungsverkehr zwischen Banken eine Methode mit der Signatur Bank» transferiereBetrag: einBetrag vonKtoNr: knrVon anEmpf!nger: einName nachKtoNr: knrNach beiBank: biz mitText einText undDatum: einDatum beschrieben. Diese Methode hat den Selektor transferiereBetrag:vonKtoNr:anEmpf!nger:nachKtoNr:beiBank: mitTextundDatum: und insgesamt sieben Argumente, deren Namen gemeinsam mit den Schliisselworten die Bedeutung der Methode kommentieren.
KlassenBrowser Collection class methodsFor: 'instance creation' with: firstObject with: secondObject
"Erzeugen einer neuen Instanz des Empfangers. welche beide Argumente enthalt"
I newColiection I
newColiection := self new. newCollection add: firstObject. newCollection add: secondObject. 1\ newCollection
Programm 2-12 Eine Methode mit Schliisselwortselektoren
2.2 Ausdriicke
69
Binare Botschaften Fiir Botschaften mit genau einem Parameter existiert eine Sonderform, die dadurch gekennzeichnet ist, daB spezielle Selektoren gebildet werden konnen, die nicht durch einen Doppelpunkt zu beenden sind. Dadurch ist es moglich, Ausdriicke in einer Form zu schreiben, die der in der Arithmetik geliiufigen Infix-Notation von Operatoren entspricht. Beispielsweise ist fUr die Addition von numerischen Objekten die Methode ArithmeticValue»+ aNumber vorgegeben. Die Signatur dieser Methode besteht aus dem biniiren Selektor »+" und einem Argument. Das Ergebnis der Evaluation des Ausdruckes x + 2 ist das Riickgabeobjekt, das erhalten wird, wenn dem von der Variablen x bezeichneten Objekt die Botschaft + mit dem Argument 2 gesandt wird. Die Moglichkeit zur Bildung binarer Selektoren ist nur eine Konzession an eine gewohnte Schreibweise, nicht aber ein Abgehen yom Konzept, einem identiflZierten Objekt eine Botschaft (unter Beigabe von Parameterobjekten) zu senden und ein Riickgabeobjekt entgegenzunehmen. In den bisherigen Beispielen wurden bereits mehrfach binare Selektoren verwendet, vor aHem fUr arithmetische Operationen. Auch die iiblichen Vergleichsoperationen der Art x <= y werden durch binare Botschaften aktiviert. Ebenso bedienen sich die Methoden Object>>= anObject und Object»-= anObject zur Priifung auf Gleichheit (Nichtgleichheit) zweier Objekte sowie die Methoden Object»= anObject und Object»-anObject zur Uberpriifung der Identitat (Nichtidentitat) zweier Objekte binarer Selektoren. In Abschnitt 2.5.1 sind weiterfUhrende Hinweise zur Bildung binarer Selektoren gegeben.
Verkettung von Botschaftsausdriicken Dem Wert eines Botschaftsausdruckes kann unmittelbar eine Botschaft gesendet werden, ohne daB er zwischendurch an eine Variable gebunden wurde. Auf diese Weise konnen Botschaftsiibermittlungen verkettet werden, wobei jede in der Kette befindliche Botschaft an das Ergebnisobjekt des unmittelbar vorher evaluierten Botschaftsausdruckes gesandt wird. Um sinnvoUe Ketten von Botschaften formulieren zu konnen, ist es daher notwendig, die Regeln flir die Abarbeitung von verketteten Botschaftsausdriicken zu beachten. Die Evaluation von verketteten Botschaftsausdriicken erfolgt nach folgenden Prazedenzregeln:
1. Unare Botschaften haben Vorrang vor binliren Botschaften. 2. Binlire Botschaften haben Vorrang vor Schliisselwortbotschaften. 3. In Klammem gesetzte Ausdriicke werden vorrangig evaluiert, so daB die Reihenfolge der Evaluation durch Klammerung gesteuert werden kann.
70
2 Smalltalk: Elemente der Spraehe
Botsehaftsausdriieke gleieher Prazedenzstufe werden von links naeh reehts evaluiert. Diese Eigensehaft muB besonders bei arithmetisehen Ausdriieken beachtet werden, da arithmetische Operationen zumeist durch Methoden mit binaren Selektoren durchgefUhrt werden, die untereinander aIle gleiehe Prazedenz haben. Programm 2-13 enthalt einige Beispiele fUr verkettete unare Botsehaften. Man entnimmt aus dem Vergleich der Folge von nieht verketteten Anweisungen mit der darauffolgenden Anweisung mit verketteten uniiren Botschaften, daB die auf gleieher Priizedenzstufe stehen unaren Botschaften von links nach rechts interpretiert werden, so daB in beiden FaIlen dasselbe Ergebnis erhalten wird.
Workspace "Einzelne unare Botschaften."
Ix I
x := -2.499 abs.
x:= x floor. x odd
<printlt> 2.499 <printlt> 2 <printlt> false
(1)
(2) (3)
"Eine aquivalente Kette unarer Botschaften."
-2.499 abs floor odd
<printlt> false
"Eine andere Kette unarer Botschaften."
-2.499 floor abs odd
<printlt> true
(1) ArithmeticValue»abs liefert den Absolutwert des Empfangers. (2) Number»floor antwortet mit der groBten ganzen Zahl, die kleiner oder gleich dem Empflinger ist. (3) Number>>Odd stellt fest (true I false), ob der Empflinger ungerade ist.
Programm 2-13 Verkettung unarer Botschaften Einige Beispiele fUr verkettete binare Botsehaften sind in Programm 2-14 zusammengestellt. Es ist daraus zu erkennen, daB die gewohnten Prazedenzregeln fUr binare Operatoren in Small talk nicht gelten. Ein Beispiel fUr die Verkettung uniirer und biniirer Botschaften ist in Programm 2-15 gegeben. Schliisselwortbotsehaften konnen ohne Klammerung nieht verkettet werden, da bei der Interpretation immer so viele Schliisselworte wie moglieh zu einem einzigen Selektor zusammengefaBt werden.
71
2.2 Ausdriicke
Workspace "Einzelne binare Botschaften."
I xl
x:= 2 + 3. x:=x*6
<printlt> 5 <printlt> 30
"Eine aquivalente Kette binarer Botschaften." 2
+3* 6
<printlt> 30
(1)
"Eine andere Kette binarer Botschaften." 2
+ (3 * 6)
<printlt> 20
(1) Der Ausdruck wird von links nach rechts abgearbeitet, alle binaren Botschaften haben gleiche Prazedenz!
Programm 2-14 Verkettung binlirer Botschaften
Workspace "Einzelne unare und binare Botschaften."
IxI
x := -2.449 floor. x :=X abs. 20 +x
<printlt> -3 <printlt> 3 <printlt> 23
"Eine aquivalente Kette unarer und binarer Botschaften." 20
+ -2.499 floor abs
<printlt> 23
(1)
"Eine andere Kette unarer und binarer Botschaften." (20
+ -2.499) floor abs
<printlt> 17
(2)
(1) Man erkennt aus dem Vergleich, daB zuerst die unaren Botschaften gesandt werden und erst dann die binare Botschaft.
(2) Durch die Klammerung wird zuerst die binare Botschaft (Addition) ausgeftihrt, die unaren Botschaften werden an das Additionsergebnis gesandt.
Programm 2-15 Verkettung unarer und binlirer Botschaften
72
2 Smalltalk: Elemente der Sprache
In Programm 2-16 wird versucht, ein Mengenobjekt durch die Methode Coliection(Set»>With:with: zu erzeugen, das bereits mit zwei Objekten (das sind die Zahlen 1 und 2) genult ist und in diese nunmehr existierende Menge mit Hilfe von Set»add: ein drittes Objekt (die Zahl 3) hinzuzuftigen.
Workspace
<printlt> wilh.with:add:isanewmessage (1) (Set with: 1 with: 2) add: 3; yourself <printlt> Set (1 23) (2)
Set with: 1 with: 2 add: 3
(1) Der Selektor with:with:add: ist im System noch nicht bekannt, deswegen wird eine Warnung ausgegeben. Wird die Warnung ignoriert und der Ausdruck evaluiert, kommt es zu einem Fehler: Message not understood: #With.with:add:.
(2) Da die Methode Collection»add: das Argument als Riickgabeobjekt liefert, ist es notwendig, die Botschaft yourself nachzusenden, die nichts anderes bewirkt als den Empflinger zu liefern. Die hier angewendete Kaskadierung von Botschaften wird im nachsten Abschnitt erlautert.
Programm 2-16 Interpretation von Schliisselwortem
Workspace
(Set with: 1+3*3 squared with: 2) add: 80+2; yourself <printlt> Set (36282) (Set with: (1 +3*3) squared with: 2) add: 80+2; yourself <printlt> Set (2 144 82)
(2)
(Set with: 1+(3*3) squared with: 2) add: 80+2; yourself <printlt> Set (82 2)
(3)
(1)
(1) Das Element 36 erhalt man durch: (1+3)'3 2
(2) Das Element 144 erhalt man durch: «1+3)'3)2 (3) Da die Ausdriicke 1+(3*3) squared und 80 + 2 das gleiche (sogar dassel be) Ergebnis liefern, besteht diese Menge nur aus zwei Elementen, da Mengen nicht zwei gleiche Elemente enthalten konnen!
Programm 2-17 Verkettung verschiedener Arten von Ausdriicken
2.2 Ausdriicke
73
Der Versuch, diese Wirkung mit dem ersten Ausdruck zu erzielen schlagt fehl, wei! die Interpretation des Ausdruckes bewirkt, daB eine Botschaft with:with:add: an Set gesendet wird, die nicht verstanden wird. Erst durch die Klammernsetzung entsteht ein verketteteter Botschaftsausdruck und zwar derart, daB die eingeklammerten Schliisselworter zu einem Selektor with :with: zusammengefaBt werden und das verbleibende Schliisselwort add: einen eigenen Selektor bildet. Aus Programm 2-17 ist zu erkennen, daB unare vor binaren Botschaftsausdriicken evaluiert werden und diese wieder vor Botschaftsausdriicken mit Schliisselwortern.
Kaskadierung von Botschaften Sollen ein und demselben Objekt hintereinander mehrere Botschaften iibermittelt werden, so ist es nicht notig, fUr jede Botschaftsiibermittlung einen eigenen Botschaftsausdruck zu formulieren, was bedeuten wiirde, den Empfanger in jedem Botschaftsausdruck gesondert angegeben zu miissen. Es ist vielmehr moglich, die Botschaften durch Strichpunkte voneinander getrennt zu einer Kaskade zusammenfassen und diese in einem (kaskadierten) Botschaftsausdruck zu formulieren. Bei der Evaluierung werden die einzelnen Botschaften der Reihe nach an denselben Empfanger gesandt. Workspace
"(1) Mehrere Botschaften an ein und denselben Empfanger."
I sammlung I sammlung sammlung sammlung sammlung sammlung sammlung
:= Set new. add: 12. add: 25. remove: 12. add: 32.
<printlt> Set (25 32)
"(2) Ein aquivalenter kaskadierter Botschaftsausdruck."
I sammlung I
sammlung := Set new. sammlung add: 12; add: 25; remove:12; add: 32. <printtt> Set(25 32) sammlung
Programm 2-18 Getrennte und kaskadierte Botschaftsausdriicke
74
2 Smalltalk: Elemente der Sprache
Programm 2-18 zeigt an einem Beispiel die Wirkungsweise von kaskadierten Botschaften. In den Programmen 2-6 und 2-17 wurden ebenfalls kaskadierte Botschaften verwendet.
2.3
Blocke
Wird an ein Objekt eine Botschaft adressiert, so wird die entsprechende Methode auf die bereits beschriebene Weise in der Klasse des EmpHingers und wenn notig in deren Oberklassen gesucht. Sobald die Methode gefunden ist, wird sie fUr den Empfanger ausgefUhrt, anderenfalls wird der Vorgang der Methodensuche abgebrochen und an den Empfanger die Botschaft doesNotUnderstand: aMessage gesendet. Diese Methode ist in der Klasse Object definiert und wird daher von allen Unterklassen verstanden, sie reagiert im Normalfall mit einer Fehlermeldung und bietet die Moglichkeit zum interaktiyen Aufruf des Debuggers. Die aktivierte Methode selbst fiihrt ihre Anweisungen sequentiell in der gegebenen Reihenfolge aus, wobei die jeweils nachste Anweisung erst durchgefUhrt wird, wenn die vorangehende durch Ubermittlung des Riickgabewertes ihre Erledigung signalisiert. Auf diese Weise konnen zwar beliebige Sequenzen von Aktionen in vorgegebener Reihenfolge veranlaBt, nicht aber von Bedingungen abhiingig gemacht werden. Eine bedingte Nachrichteniibermittlung wird erst durch B10cke ermoglicht, die somit die Grundlage fUr Kontrollstrukturen in Small talk bilden. Ein Block stellt eine Folge von Anweisungen dar, deren AusfUhrung bis zur expliziten Aktivierung hintangehalten wird. Blocke sind Objekte (Auspragungen der Klasse BlockClosure), sie konnen Variablen zugewiesen werden und durch Ubersenden von Aktivierungsnachrichten beliebig oft ausgefUhrt werden. Die in einem Block vorkommenden Variablen konnen beziiglich des Blokkes global sein, sie konnen dem Block bei der Aktivierung als Parameter iibergeben werden oder sie konnen innerhalb des Blockes als temporare Variable vereinbart sein. Die beziiglich des Blockes globalen Variablen sind aIle jene Variablen, die im Kontext der Blockdefmition sichtbar sind, also auch die temporaren Variablen jener Methode, in welcher der Block definiert wird.
75
2.3 Blocke
2.3.1
Die Syntax von Blocken
1m einfachsten Fall besteht ein Blockausdruck aus einer Foige von Anweisungen, die in eckige Klammern eingeschlossen ist. Ein solcher Block enthlilt weder Argumente noch temporlire Variable, seine Aktivierung erfolgt durch die Nachricht value. Das folgende Beispiel (Programm 2-19) zeigt einen Block, durch dessen Aktivierung eine im Kontext definierte Angabe eines Tagesdatums urn einen Tag weitergezlihlt wird. Der Variablenname blockO soIl andeuten, daB der dadurch bezeichnete Block keine Argumente hat. Workspace
I blockO datum I
datum := Date readFrom: '1/1/1900' readStream. blockO := [datum := datum addDays: 1]. blockO value. <printlt> 2 January 1900 datum blockO value; value; value. <printlt> 5 January 1900 datum
(1)
(2) (3)
(4)
(1) An dieser Stelle wird die Variable datum mit dem DatumsobjeiCt '1.1.1900' belegt. Die Umwandlung der Zeichenkette in ein intermediiires Objekt der Klasse ReadStream hat nur technische Bedeutung, ist aber fUr das Verstlindnis des Beispieles unwesentlich. (2) Da noch keine Aktivierung des Blockes stattgefunden hat, trligt datum den ursprunglich zugewiesenen Wert! (3) Nach der einmaligen Aktivierung des Blockes bezeichnet die Variable datum den 2.1.1900. (4) Nach weiterer dreimaliger Aktivierung des Blockes durch Kaskadierung der Botschaft value trligt datum den Wert 5.1.1900.
Programm 2-19 Ein Block ohne Argumente Urn durch den Namen der Variablen, an die ein Block gebunden werden soli, auf die Anzahl der Argumente des Blockes hinzuweisen, wird fUr einen Block mit N Argumenten im Folgenden der Name blockN gewlihlt. In [47] werden Blocke mit keinem, einem oder zwei Argumenten als niladische, monadische und dyadische Blocke (niladic-, monadic-, dyadic-block) bezeichnet. Argumente werden unmittelbar zu Beginn des Blockes vereinbart, wobei den Argumentnamen jeweils ein Doppelpunkt vorangestellt wird. Die Liste
76
2 Smalltalk: Elemente der Sprache
der Argumentnamen ist von den Anweisungen durch einen senkrechten Strich zutrennen. Ein Beispiel flir einen Block mit einem Argument ist in Programm 2-20 gegeben. Hier wird eine Variation des vorangehenden Beispieles gezeigt, in der die Anzahl der Tage, um die ein Datum weitergezahIt werden soil, durch einen Parameter festgelegt wird.
Workspace
I block1
datum I datum := Date readFrom: '1/1/1900' readStream. block1 := [ :tage I datum := datum addDays: tagej. block1 value: 1. datum <printlt> 2 January 1900 block1 value: 3. datum. block1 class
<print/t> 5 January 1900 <printlt> BlockClosure
(1)
(2)
(3) (4)
(1) Dieser Block besitzt eine Argumentvariable mit Namen tage. (2) Durch value: wird ein Block mit einer Argumentvariablen aktiviert und mit einem aktuellen Parameterobjekt versorgt. (3) Hier wird das jeweilige Datum um 3 Tage weitergeziihlt. (4) block1 ist eine Ausprligung der Klasse BlockClosure.
Programm 2-20 Ein Block mit einem Argument Eventuelle lokale Variable des Blockes werden nach den Argumenten und vor den Anweisungen zwischen und senkrechten Strichen angeflihrt. Insgesamt hat ein Block somit folgende allgemeine Form: [ :argVar1 :argVar2 ... I I tempVar1 tempVar2 ... Anweisung1. Anweisung2.
I
Die Methode zur Aktivierung von Blocken hiingt von der Anzahl der vom Block erwarteten Argumentobjekte abo Blocke ohne Argument werden durch die unare Botschaft aBlockO value
77
2.3 Blocke ausgefUhrt. Blocke mit beliebig vielen Argumenten verstehen die Nachricht aBlockN valueWithArguments: anArray
wobei die Argumente der Reihe nach in einem entsprechend dimensionierten Feld (Behalterobjekt der Klasse Array) gesammelt sein mussen. Blocke mit einem, zwei oder drei Argumenten konnen durch Schlusselwortbotschaften der Form aBlock1 value: arg, aBlock2 value: arg1 value: arg2 aBlock3 value: arg1 value: arg2 value: arg3
aktiviert werden.
2.3.2 Die Klasse BlockClosure Wie aus der Evaluation des Ausdruckes in Zeile (4) von Programm 2-20 deutlich wird, sind Blocke Auspragungen der Klasse BlockClosure, einer direkten Subklasse von Object. Einige der Methoden dieser Klasse sind so stark mit der Basisfunktionalitat von Smalltalk verb un den, daB sie an dieser Stelle vorgestellt werden. KlassenBrowser BlockClosure methodsFor: 'controlling' repeat
"Wiederholtes Evaluieren des Empfangers. Ein Abbruch muB yom Empfanger erzwungen werden." self value. [self value] repeat
(1 )
(2)
(1) Diese rekursive Methode enthiilt keine explizit angegebene Abbruchbedingung, sie sollte nur verwendet werden, wenn der Empfangerblock einen Abbruch zuverliissig sicherstellt! (2) Die Anweisung konnte kiirzer lauten: self value repeat, die vorliegende Form kann yom Kompiler optimiert werden und ist daher eiflZienter.
Programm 2-21 Unbedingte Wiederholung eines Blockes
78
2 Smalltalk: Elemente der Sprache
Programm 2-21 zeigt die Methode BlockClosure»repeat, welche die Evaluation des Empflingerblockes beliebig oft und ohne eine explizit vorgesehene Abbruchbedingung wiederholt. Eine weitere Methode, durch die eine wichtige Kontrollstruktur realisiert wird, ist in Programm 2-22 angeflihrt. Der Empflinger dieser Methode muB ein argumentloser Block sein, der bei seiner Evaluation true oder false ergibt. Der Empfanger und der ebenfalls argumentlose Parameterblock werden abwechselnd evaluiert und zwar so lange, bis der Empfanger false ergibt. Dabei ist selbstverstandlich notwendig, daB be ide Blocke tiber Variable gekoppelt sind, um sich gegenseitig beeintlussen zu konnen. Eine entsprechende Methode BlockClosure»whileFalse: steht ebenfalls zur Verfligung. Der in Programm 2-23 gezeigte Arbeitsbereich enthaIt einige Beispiele flir die Anwendung dieser Methoden. Zum Verstandnis dieser Beispiele ist zu erwahnen, daB in Smalltalk ganze Zahlen beliebiger GroBe dargestellt werden konnen. Wird eine ganze Zahl (sei es durch ihre Literaldarstellung, sei es als Ergebnis einer arithmetischen Operation) erhalten, die groBer als die groBtmogliche Auspragung der Klasse Smallinteger ist, so wird automatisch eine Instanz der Klasse LargePositiveInteger erzeugt, ebenso wird eine "zu kleine" Auspragung von LargePositiveInteger in eine Instanz von Smalllnteger numgewandelt". Analoges gilt im negativen Bereich flir die Klasse LargeNegativelnteger. KlassenBrowser BlockClosure methodsFor: 'controlling'
whileTrue: aBlockO
"Wiederholtes Evaluieren des Arguments, aBlockO, und zwar so lange der Empfanger bei der Evaluation true ergibt." 1\
self value ifTrue: [aBlockO value. [self value] whileTrue: [aBlockO value]]
(1)
(2) (3)
(1) Es wird vorausgesetzt, daB die Evaluation des Empfangers (ein durch self bezeichneter Block), entweder true oder false ergibt. (2) Fur den Fall, daB die Evaluation des Empfangers true ergibt, wird der Argumentblock aBlock evaluiert. Es wird vorausgesetzt, daB aBlockO keine Argumente hat. (3) Die Rekursion kann nur dann abbrechen, wenn die Evaluation des Empfangers false ergibt.
Programm 2-22 Bedingte Wiederholung eines Blockes
2.3 Blocke
79
Die erste in Programm 2-23 gezeigte freie Methode fmdet die grol3tmogliche Smalllnteger-Zahl dadurch, dal3 im Empfangerblock der Botschaft whileTrue: nach der Klasse der Testgrol3e testlnteger gefragt wird und der Argumentblock diese Testgrol3e (diese ist anfangs mit 0 initialisiert) solange urn 1 erhoht, bis das Ergebnis nicht mehr eine Auspragung von Smalllnteger ist. Die DurchfUhrung dieser Methode nimmt betrachtliche Zeit in Anspruch, was auch von einer derartigen "Gewaltmethode" nicht anders zu erwarten. Diese Methode erhOht von null beginnend in Schritten von eins einen Zahler so lange, bis das Ergebnis so grol3 ist, daB es nicht mehr als Auspragung der Klasse Smalllnteger dargestellt werden kann und daher in eine Auspragung von LargePositivelnteger umgewandelt wird. Workspace "(1) Bestimmen der groaten ganzen Zahl, die Auspragung der Klasse Smalllnteger ist"
I testlnteger I testlnteger := O. [testlnteger class = Smalllnteger] whileTrue: (testlnteger := testlnteger + 1]. testlnteger - 1 <printlt> 536870911 "(2) Ebenso, jedoch wesentlich schneller."
I testlnteger increment I testlnteger := O. increment:= 1000000. [increment> 1] while True: [ [testlnteger class = LargePositivelnteger] whileFalse: [testlnteger := testlnteger + increment]. testlnteger := testlnteger - increment. increment := increment /10]. testlnteger + 1 <printlt> 536870911 n(2) Ebenso, noch schneller, wei! das Ergebnis in einer Klassenvariable vortiegt. n
Smalllnteger maxVal Smalllnteger maxBits
2**29 - 1 = 536870911
<printlt> 536870911 <printlt> 29 <printlt> true
Programm 2-23 Iteration durch Blockwiederholung Eine wesentliche Verbesserung des Laufzeitverhaltens bringt die zweite der gezeigten Methoden, die das Ziel durch groBere, aber dafiir weniger Schritte erreicht. Diese freie Methode ist auch ein Beispiel fUr ineinandergeschachtelte Blockiterationen.
80
2 Smalltalk: Elemente der Sprache
SchlieBlich sei noch erwahnt, daB bei der Initialisierung der Klasse SmallInteger eine Klassenvariable mit dem (masehinenabhangigen) groBtmogiiehen Wert belegt wird, der tiber die Methode Smalllnteger»maxVal abgerufen werden kann. Ein Blick in den Klassenbrowser ergibt, daB dieser Wert auf eine etwas andere als die hier gezeigte Art bestimmt wird.
2.3.3 Primarmethoden Die bisher angesprochenen und diskutierten Methoden greifen aIle aufbereits vorhandene, ebenfalls in Smalltalk geschriebene und daher in der Klassenhierarchie verankerte Methoden zuriick. Auf diese Weise werden aus Methoden, die elementares Verhalten von einfachen Objekten beschreiben, schrittweise leistungsfahigere Methoden zusammengesetzt. Beim Einsatz solcher Methoden wird man in der Praxis auf deren Komplexitlit oft erst aufmerksam, wenn im FaIle eines Fehlers die Sequenz des Nachrichtenflusses und die jeweils betroffenen Objekte im Debugger verfolgt werden. Offensichtlich ist es tiberhaupt nieht moglich, Methoden zu definieren, ohne auf bereits existierende Methoden zuriickzugreifen. Es stellt sich daher die Frage nach den grundlegenden Methoden, die in dem Sinne atomar sind, daB sie selbst nieht auf anderen Methoden aufbauen und daher auch nieht als Folge von Smalltalkausdrticken beschrieben sind. Solche Methoden werden hier Primiirmethoden (primitive methods) genannt, sie bilden die Basis der Funktionalitlit von Smalltalk. Primlirmethoden werden direkt von der virtuellen Maschine des Smalltalk-Systems ausgefUhrt. Als Beispiel sind in Programm 2-24 zwei Primlirmethoden der Klasse BlockClosure angefUhrt, welche die AusfUhrung von Blocken veranlassen. Da Blocke die wesentlichen sprachlichen Konstruktonselemente fUr bedingte und wiederholte Naehrichtentibermittlung bilden, sind diese Methoden die Grundlage fUr die Realisierung von Kontrollstrukturen in Smalltalk. Primlirmethoden unterscheiden sich von "normalen" Methoden dadureh, daB vor der ersten Smalltalkanweisung eine Registrierungsangabe der Form <primitive: primtivNummer> steht, wobei primitivNummer die Literaldarstellung einer ganzen Zahl (Ausprligung von Smalllnteger) bedeutet, unter welcher die jeweilige Methode registriert und fUr die virtuelle Masehine auffmdbar ist. Ein dieser Registrierungsangabe eventuell folgender Smalltalkcode wird nur dann aktiviert, wenn die Primitivroutine aus irgendeinem Grunde nicht ordnungsgemlil3 ausgefUhrt werden konnte und daher scheiterte. Beispielsweise kann man aus Programm 2-24 erkennen, daB die Methode fUr die Evaluation eines Blockes ohne Argumente (BlockClosure»value) durch die unter der Nummer 501 registrierte Primlirmethode erfolgt. Die auf
81
2.3 Blocke
die Registrierungsangabe folgenden Smalltalkanweisungen legen einen Code zur Fehlerbehandlung fest, der nur dann ausgefiihrt wird, wenn die eigentliche Primarmethode scheitert und eine Fehlerbedingung signalisiert.
KlassenBrowser BlockClosure methodsFor: 'evaluating' value
"Evaluieren des Empfangerblockes. Die Methode scheitert, wenn der Empfanger Argumente erwartet."
<primitive: 501> "self valueWithArguments: #() valueWJthArguments: anArray
"Evaluieren des Empfangerblockes. Das Argument ist ein Feld (Instanz von Array), dessen Elemente die Blockargumente sind. Die Methode scheitert, wenn die Lange des Feldes nicht der Anzahl der Argumente entspricht, die der Empfangerblock erwartet."
<primitive: 500> (anArray isMemberOf: Array) (1) ifTrue: [self error: 'This block expects ',self numArgs printString, , argument(s),] (2) ifFalse: [self error: 'BlockClosure>>ValueWithArguments: requires an Array'] (1) Hier wird getestet, ob das Argument eine Auspragung der Klasse Array ist.
(2) Die Methode BlockClosure>>numArgs liefert die Anzahl der Argumente, die der Block zu seiner Evaluation benotigt.
Programm 2-24 Prirnarmethoden der Klasse BlockClosure 1m vorliegenden Fall wird durch die Anweisung self valueWithArguments:
#0 versucht, das gewiinschte Ergebnis auf anderem Wege zu erhalten. Die Methode BlockClosure»valueWithArguments: ist ebenfalls eine Prirnarmethode, in deren Code zur Fehlerbehandlung schlieBlich versucht wird, das aufgetreteneProblem zu analysieren. Mogliche Fehlerursachen sind entweder, daB das bei der Blockaktivierung iibergebene Argument gar kein Array ist oder daB dessen Dirnensionierung nicht mit der Anzahl der Argumente des Empfangers iibereinstimmt. In jedem dieser Falle wird durch self error: ein das Problem erklarender Fehlertext ausgegeben.
82
2 Smalltalk: Elemente der Sprache
In [47] werden Objekte, fUr welche die Methode valueWithArguments: argumentArray vorgesehen ist, als "evaluierbare Objekte" (valuables) bezeichnet. Blocke bilden einen Sonderfall von evaluierbaren Objekten, fUr den die Evaluationsvorschrift in der Sprache festgelegt ist, wobei die Elemente des Argumentes argumentArray der Reihe nach an die Argumentvariablen des Blockes gebunden werden.
2.4
Kontrollstrukturen
1m Unterschied zu den meisten Programmiersprachen sind in Small talk Kontrollstrukturen nicht Bestandteil der Sprache, sondern verschiedenen Klassen zugeordnete Methoden. Es ist daher auch leicht moglich, zusatzlich zu den vorhandenen Kontrollstrukturen durch Festlegen entsprechender Methoden jederzeit weitere Kontrollstrukturen einzurichten. "Kontrollmethoden" sind zumeist in den Methodenkategorien controlling oder enumerating zusammengefaBt. Kontrollstrukturen werden durch bedingte oder iterative AusfUhrung von BlOcken realisiert, die als Argumente von Kontroll- oder Enumerationsmethoden auftreten, wobei die Empfanger der Botschaften die steuernde Funktion iibernehmen. In den Programmen 2-21 und 2-22 wurden bereits Kontrollmethoden vorgestellt, die der Klasse BlockClosure selbst zugeordnet sind, so daB ein Block als Empfanger dieser und abnlicher Methoden auch die steuernde Funktion iibernimmt. In den Klassen False und True sind die flir die bedingte DurchfUhrung von Blocken wesentliche Methoden der Art Boolean»ifTrue:ifFalse implementiert. Diese Methoden sind von so fundamentaler Bedeutung, daB die Klassen False und True ahnlich wie die Klasse BlockClosure nicht unabhaogig von der Funktion der virtuellen Maschine gesehen werden konnen und daher im direkten Zusammenhang mit der Sprachbeschreibung vorgestellt werden. In der Folge werden auch einige wesentliche Enumerationsmethoden der Klassen Number, Integer und Interval angeflihrt, durch welche numerische Iterationen ausgefUhrt werden sowie die Methode Collection»do:, welche die Basis fUr die Iteration iiber Elemente von Bebalterobjekten bildet. 1m weiteren Sinne konnen auch Signale (Auspragungen der Klasse Signal) als Kontrollobjekte verstanden werden, die im FaIle des Eintretens einer Ausnahmesituation entsprechend festgesetzte Reaktionen auslosen konnen. Dieser Mechanismus (exception handling) ist jedoch hauptsachlich fUr die Bewliltigung von Fehlersituationen vorgesehen.
83
2.4 Kontrollstrukturen
2.4.1
Die Klassen False und True
Die Klasse Boolean, welche in der Klassenhierarchie als direkte Subklasse von Object eingerichtet ist, bietet das allgemeine Protokoll, das von den Objekten true und false verstanden wird. In Programm 2-25 sind die in dieser Klasse festgelegten logischen Operationen zusammengefaBt. KlassenBrowser Boolean methodsFor: 'logical opereation' eqv: aBoolean
"Feststellen (true I false), ob der Empfanger und das Argument aquivalent sind." A
self = aBoolean
(1)
xor: aBoolean
"Feststellen (true I false), ob der Empfanger und das Argument nicht aquivalent sind. Exclusives ODER. " A
(self =
aBoolean) not
(1)
(1) Die Primlirmethode Object>>= anObject ergibt true genau dann, wenn der Empfanger und das Argument identisch sind, ansonsten false, ihr binlirer Selektor "-" besteht aus zwei Zeichen "=".
Programm 2-25 Logische Operationen der Klasse Boolean Die unveranderlichen, a-priori existierenden, im Objektraum permanent verankerten und daher der virtu ellen Maschine direkt bekannten Objekte true und false sind jedoch nicht Auspragungen der Klasse Boolean, sie sind vielmehr die jeweils einzige Instanz ihrer Unterklassen True und False. Wie aus der direkten Gegenuberstellung in Programm 2-26 erkenntlich ist, sind die Selektoren der aussagenlogischen Operationen Negation, Konjunktion und Disjunktion ubedaden, wodurch das spezifische Verhalten der "logischen" Objekte auf ihre Zugehorigkeit zu unterschiedlichen Klassen zUrUckgeftihrt wird. Beispielsweise antwortet die Methode True>>! aBoolean mit self, also mit true, ohne daB auf das Argument aBoolean Bezug genommen wird, weil die Disjunktion bereits dann true ergibt, wenn einer der beiden Operanden true ist. Die Methode False»\ aBoolean hingegen antwortet mit dem Ergebnis der Evaluation des Argumentes aBoolean, weil das Ergebnis noch nicht aus dem Empflinger alleine festgestellt werden kann.
84
2 Smalltalk: Elemente der Sprache
KlassenBrowser Boolean subclass: #True instanceVariableNames: " classVariableNames: " poolDictionaries: " category: 'Kernel-Objects'
Boolean subclass: #False instanceVariableNames: " classVariableNames: " poolDictionaries: " category: 'Kernel-Objects'
True methodsFor: 'logical operation'
False methodsFor: 'logical operation'
not Afalse
not Atrue
& altemativeObject AalternativeObject
& altemativeObject Aself
(1)
1aBoolean Aself
1aBoolean AalternativeObject
(1)
(1) Die Zeichen "&" und "I" sind binare Selektoren.
Programm 2-26 Logisches Verhalten der Objekte true und false
KlassenBrowser True methodsFor: 'controlling'
False methodsFor: 'controlling'
itTrue: altemativeBlock AalternativeBlock value
itTrue: altemativeBlock Ani!
ifFalse: alternativeBlock Ani!
ifFalse: alternativeBlock AalternativeBlock value
itTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock AtrueAlternativeBlock value
ifTrue: trueAlternativeBlock ifFalse: falseAltemativeBlock AfalseAlternativeBlock value
and: alternativeBlock AalternativeBlock value
and: altemativeBlock Aself
or: alternativeBlock Aself
or: alternativeBlock AalternativeBlock value
Programm 2-27 Kontrollverhalten der Objekte true und false
85
2.4 Kontrollstrukturen
Programm 2-27 zeigt, ebenfalls in direkter Gegeniiberstellung, einige der verfUgbaren Kontrolloperationen. Man beachte, daB bei den Methoden mit den Selektoren ifTrue: und if False: fUr den Fall, daB der Argumentblock nicht evaluiert wird, der Wert des Botschaftsausdruckes nil ist, was auch das Ergebnis der Evaluation eines leeren Blockes ist. Die Methoden mit den Selektoren and: und or: entsprechen der Konjunktion und Disjunktion mit dem Unterschied, daB als Argument jeweils ein Block erwartet wird. Alle Blocke, deren Evaluation durch die in Programm 2-27 zusammengefaBten Methoden kontrolliert wird, sind Blocke ohne Argumente. Beispiele fUr die Anwendung dieser Kontrollmethoden sind in Programm 2-28 gezeigt.
Workspace
< 2) ifTrue: ['ja'] (2 < 1) ifTrue: ['ja'] (2 < 1) ifTrue: ['ja'] if False: [] (2 < 1) ifTrue: ['ja'] ifFalse:['nein'] (2 < 1) if False: ['nein'] ifTrue:['ja'] (1
<printlt> <printlt> <printlt> <printlt> <printlt>
'ja' nil nil
'nein' 'nein'
Programm 2-28 Beispiele fUr Kontrollmethoden von true und false
2.4.2 Enumerationsmethoden Enumerationsmethoden veranlassen die wiederholte Evaluation eines Blokkes, der als Argument der Methode beigestellt wird. Die Anzahl der Wiederholungen der Blockevaluation ist dabei direkt durch eine Eigenschaft des Kontrollobjektes festgelegt.
Wiederholte und durch das Kontrollobjekt unbeeinfluBte Evaluation eines Blockes Die in Programm 2-29 gezeigte Methode Integer»timesRepeat: aBlockO bewirkt, daB der als Argument vorzugebende Block wiederholt evaluiert wird, wobei die Anzahl der Wiederholungen durch den Wert des Empfangers fest vorgegeben ist. Von dem zu wiederholenden Block wird vorausgesetzt, daB er keine Argumente besitzt, was durch die Bezeichnung aBlockO ausgedriickt wird. Die einzelnen Evaluationen des Blockes werden nicht durch das kontrollierende Objekt beeinfluBt.
86
2 Smalltalk: Elemente der Sprache
KlassenBrowser Integer methodsFor: 'enumerating' timesRepeat: aBlockO "Evaluieren des Argumentes, aBlockO, und zwar so oft, wie es durch den Wert des Empfangers vorgegeben ist."
I count I
count := 1. [count <= self] whileTrue: [aBlockO value. count := count + 1]
(1)
(1) Man beachte, daB dieser Ausdruck bei der Evaluation nicht direkt true oder false ergibt, sondern einen logischen Block, der bei seiner Evaluation (innerhalb der Methode whileTrue:) mit true oder false antwortet.
Programm 2-29 Wiederholte Evaluierung eines Blockes
Diese Methode wird auf die Methode BlockClosure»whileTrue: (Programm 2-22) zuriickgefiihrt, die ihrerseits wieder auf der Primarmethode BlockClosure»value (Programm 2-24) aufbaut. An diesem Beispiel ist gut zu erkennen, wie Methoden aufeinander zuriickgreifen und letztendlich auf einer Primlirmethode aufbauen.
Workspace "Unbedingte, unbeeinfluBte Wiederholung eines Blockes."
I datum I
datum := Date readFrom: '1/1/1900' readStream. <printlt> January 1,1900 datum.
31 timesRepeat: [datum := datum addDays: 1). <printlt> February 31, 1900 datum Programm 2-30 Beispiel fur die unbeeinfluBte Blockwiederholung
2.4 Kontrollstrukturen Programm 2-30 enthlilt als Beispiel eine Anwendung der Methode Integer»timesRepeat: aBlockO. Man vergleiche dieses Beispiel mit jenem in Programm 2-19.
Wiederholte und durch das Kontrollobjekt beeinfluBte Evaluation eines Blockes Bei einer weiteren Gruppe von Kontrollmethoden wird ein Block (mit genau einem Blockparameter) wiederholt evaluiert, wobei das Kontrollobjekt bei jeder Evaluation ein anderes Objekt als aktuellen Blockparameter liefert. KlassenBrowser
Number methodsFor: 'intervals' to: stop by: step do: aBlock1
"Evaluieren von aBlock1 mit jedem Glied einer Zahlenfolge als Blockargument Die Zahlenfolge beginnt mit dem Empfanger, jedes folgende Element wird urn step inkrementiert und zwar so lange die Elemente <= stop sind."
(Interval from: self to: stop by: step) do: aBlock1
(1)
Interval methodsFor 'enumerating' do: aBlock1
"Evaluieren von aBlock1 mit jedem Element des Empfangers als Blockargument."
I n end I n :=0.
end := self size - 1. [n <= end] whileTrue: [aBlock1 value: start + (step * n). n := n + 1]
(2) (3)
(1) Durch die Methode Interval class>>from:to:by: wird eine entsprechende Instanz der Klasse Interval erzeugt, dieser wird die Botschaft do: gesendet. (2) Die Iteration tiber die Ausprligung von Interval, welche eine arithmetische Zahlenfolge darstellt, wird auf die Methode Boolean>>whileTrue: zurtickgeftihrt. (3) Urn den Rundungsfehler klein zu halten, wird nicht wiederholt inkrementiert, sondern jedes Element "unabhlingig" bestimmt.
Programm 2-31 Iteration tiber eine arithmetische Zahlenfolge
88
2 Smalltalk: Elemente der Sprache
Kontrollobjekte mit dieser Eigenschaft sind beispielsweise Instanzen der Klasse Interval, die eine endliche arithmetische Zahlenfolge reprasentieren. Solche Objekte zahlen die Glieder dieser Folge fur die wiederholte Evaluation des Blockes auf, worauf die Bezeichnung "Enumeration" Bezug nimmt. Die Anzahl der Wiederholungen des Blockes ist durch die Anzahl der Glieder der arithmetischen Folge festgelegt. Jede Auspragung der Klasse Interval tragt die Instanzvariablen start, stop und step, die jeweils mit einer Zahl initialisiert sind wodurch die arithmetische Folge it = start < i2 < ... < ik = ik_t*step < ... < in <= stop festgelegt wird. Programm 2-31 zeigt die Methode Interval»do:, aus der ersichtlich ist, wie die Bildung der einzelnen Glieder der Zahlenfolge auf die Methode BlockClosure>>WhileTrue: (und damit letztlich wieder auf die Primitivmethode BlockClosure>>Value) zurtickgeflihrt wird. Ein Beispiel fiir die durch eine arithmetische Folge gesteuerte Blockiteration ist in Programm 2-32 unter Punkt (3) gegeben. Die dort unter den Punkten (1) und (2) evaluierten Ausdrticke sollen zur Erlauterung von Zahlenfolgen dienen.
Workspace
"(1) Erzeugen von arithmetischen Foigen (Instanzen der Klasse Interval)." (2 to: 8 by: 2) (2 to: 8 by: 2) class
<printlt> (2 to: 8 by: 2) <printlt> Interval
"(2) Feststellen der Elemente einer arithmetischen Zahlenfolge, die durch eine Auspragung der Klasse Interval! reprasentiert wird."
I ordColl1
ordColI:= OrderedColiection new. (Interval from: 2 to: 8 by: 2) do: [:element I ordColl add: element]. <printlt> OrderedColiection (2 4 6 8) ordColl "(3) Durch eine arithmetische Foige beeinfluBte Blockwiederolung."
I datum I
datum := Date readFrom: '1/1/1900' readStream. <printlt> January 1, 1900 datum.
2 to: 8 by: 2 do: [:tage I datum := datum addDays: tage]. <printlt> January 21, 1900 datum
Programm 2-32 Blockiteration mit arithmetischer Aufzlihlung
89
2.4 Kontrollstrukturen
Behiilterobjekte haben ebenfalls die Eigenschaft von Kontrollobjekten, die bei der wiederholten Evaluation eines Blockes ihre Inhaltsobjekte aufziihlen und als aktuellen Blockparameter anbieten.
KlassenBrowser
Collection methodsFor: 'enumerating' do:aBlock1 "Evaluieren des Argumentes mit jed em Element des Empfangers als Blockargument."
self subclassResponsibility Programm 2-33 Iteration tiber die aufgeziihlten Elemente eines Behiilters
In Programm 2-33 wird durch die Methode Collection>>do: daraufhingewiesen, daB alle Behiilterobjekte eine solche Aufzahlungsmethode verstehen, daB aber die spezielle Implementation in den Subklassen angegeben sein muB. Kommt diese Methode zur AusfUhrung, so wird eine Fehlermeldung ausgegeben, die darauf hinweist, daB eine spezifische Implementation in einer Unterklasse vergessen wurde. Ein Beispiel fUr die Wirkungsweise der Methode OrderedCollection>>do: (siehe Programm 4-18) ist in Programm 2-34 gegeben.
Workspace
I ordColI summe I
ordColI := OrderedCollection new. summe :=0. 1 to: 100 do: [:element I ordColI add: element]. ordColI do: [:element I summe := summe + element]. summe <printlt> 5050
(1)
(2)
(1) Hier wird ein Behalterobjekt mit den Zahlen 1 bis 100 angeftillt. (2) Die Elemente des Behalters werden aufgezahlt und durch den wiederholten Block summiert.
Programm 2-34 Blockiteration mit Aufziihlung der Elemente eines Behiilters
90
2 Smalltalk: Elemente der Sprache
2.5
Weiterfiihrende Bemerkungen
2.5.1
Binare Selektoren
Binare Selektoren werden vom Kompiler nur dann erkannt, wenn sie aus h6chstens zwei Zeichen bestehen, die aus einer festgelegten Menge spezieller Zeichen (siehe Programm 2-36) stammen mussen. Als weitere Einschrankung gilt, daB das Zeichen ,,-" nur an erster Stelle stehen darf. In Programm 2-35 sind Methoden zusammengestellt, mir deren Hilfe die in der Klassenvariablen TypeTable der Klasse Scanner gehaltene Zeichentypisierungstabelle selektiv ausgelesen wird, urn jene Zeichen zu erhalten, die fUr binare Selektoren zuIassig sind. Scanner class methodsFor:
binarySelectorAsciiValues "Bestimmen der ASCII-Werte jener Zeichen, die als binare Selektoren gelten."
I binarylndices I
binarylndices := OrderedCollection new. 1 to: TypeTable size do: [:index I (TypeTable at: index) = :f#:xBinary) ifTrue: [binarylndices add: index] ]. 1\ binarylndices asArray
acceptsAsBinarySelector: aCharacter "Feststellen, ob aCharacter vom Compiler als binarer Selektor akteptiert wird." 1\
self binarySelectorAsciiValues includes: aCharacter aslnteger
binarySelectors "Bestimmen jener Zeichen, die als binare Selektoren zulassig sind." 1\
self binarySelectorAsciiValues collect: [:index I Character value: index]
Programm 2-35 Feststellen, welche Zeichen als binare Selektoren geiten Programm 2-36 zeigt die mit Hilfe dieser Methoden erhaltene Zeichenmenge. Programm 2-37 gibt ein Beispiel fUr eine Methode mit dem binaren Selektor ,,±" ant. Man beachte, daB auch der binare Selektor ,,-+" zulassig ware, nicht aber "+-".
2.5 Weiterflihrende Bemerkungen
91
Workspace
Scanner binarySelectors <printlt> #($1 $% $& $* $+ $, $- $1 $< $= $> $1 $@ $\ $- $± $x So $+) Scanner acceptsAsBinarySelector: $@ <printlt> true Scanner acceptsAsBinarySelector: $§ <printlt> false Programm 2-36 Fur binare Selektoren zulassige Zeichen
Number methodsFor: 'Toleranzintervalle'
± aValue "Erzeugen eines Toleranzintervalles der Lange aValue*2. syrnrnetrisch urn den Empfanger."
AToleranzintervali von: (self - aValue) bis: (self + aValue) Programm 2-37 Eine Methode mit einem binaren Selektor Weitere Beispiele flir Methoden, die mit binaren Selektoren ausgestattet wurden, konnen den Programmen 4-33 und 5-1 entnommen werden.
2.5.2 Indirekte BotschaftsilbermiHlung In einem Botschaftsausdruck ist der Selektor stets in Literalform fest vorgegeben, die Parameter hingegen konnen Ergebnisse der Evaluation von Ausdrukken sein, ebenso der Empfanger. In manchen Flillen kann es jedoch erforderlich sein, an einer bestimmten Stelle in einer Methode einem Objekt eine Botschaft zu senden, ohne daB bei der Erstellung der Methode bekannt ist, um welche Botschaft es sich handelt. Eine solche indirekte Botschaftsiibermittlung kann mit Hilfe der Methode Object>>perform:withArguments: durchgeflihrt werden. Das erste Argument dieser Methode ist der zu sendende Selektor (eine Auspragung einer Unterklasse von Symbol), das zweite Argument ist ein Feld (eine Auspragung der Klasse Array), das die Argumente in passender Anzahl und Reihenfolge entt
Dieses Zeichen wird durch die Tastenkombination +- erzeugt.
92
2 Smalltalk: Elemente der Sprache
halten muG. In Programm 2-38 sind zwei Beispiele angefiihrt, in denen jeweils das direkte und indirekte Senden derselben Botschaft gegeniibergestellt wird.
"Oirektes und indirektes Senden der binaren Botschaft #+." 20
+5
20 perform: #+ with: 5
<printlt> 25 <printlt> 25
"Oirektes und indirektes Senden der Schllisselwortbotschaft #W~h:with:w~h:." Set with: 1 with: 'zwei' with: 'III'
I selector argArray I
<print/t> Set ('III' 1 'zwei')
selector:= #with:with:with:. argArray := #(1 'zwei' 'III'). Set perform: selector withArguments: argArray <printlt> Set ('III' 1 'zwei')
Programm 2-38 Indirektes Senden einer Methode
Workspace
I string selector argArray I
string := 'with'. string := string copyWith: $:. string := string, string, string. selector := string asSymbol. argArray := #(1 'zwei' 'III'). Set perform: selector withArguments: argArray <printlt> Set ('III' 1 'zwei')
(1)
(2) (3)
(1) Die Methode SequenceableCollection>>CopyWith: liefert eine Kopie des Empflingers, an die das Argument (an letzte Stelle) angehiingt ist. (2) Der binare Selektor m" verkettet zwei Zeichenketten, den Empflinger und das Argument (SequenceableCollection(String»>. ). Der Variablen string wird somit die Zeichenkette 'with:with:with:' zugewiesen. (3) Die Zeichenkette wird in ein Symbol umgewandelt, damit sie als Selektor dienen kann.
Programm 2-39 Konstruktion eines Selektors
2.5 Weiterfuhrende Bemerkungen
93
Die indirekte Ubermittlung einer Botschaft erlaubt es auch, die zu sendende Botschaft selbst erst zu konstruieren, was in Programm 2-39 an einem Beispiel demonstriert ist. In Abschnitt 14.3 wird gezeigt, wie mit Hilfe dieser Technik eine Botschaft, die von einem Objekt nicht verstanden wird, an ein anderes Objekt weitergeleitet werden kann.
2.5.3 Blocke und "Lexical Scoping" Die Bedeutung eines Programmes muB von den Namen von lokal vereinbarten Variablen unabhangig sein, sodaB die konsistente Umbenennung dieser Variablen keinen EinfluB auf das Ergebnis der Evaluation hat. Die konsistente Anderung der Namen von Blockargumenten und temporaren Variablen eines Blockes bedarf keiner Diskussion, da es klar ist, daB beispielsweise die beiden folgenden Blacke aquivalent sind: [:arg
II temp I temp := O. temp := temp + arg]
[:x II tit := O. t := t
+ x]
wei! im zweiten Block lediglich die Argumentvariable arg in x und die temporare Variable temp in t umbenannt wurde und weil die Namen dieser VariabIen innerhalb des Blockes vereinbart sind. Einer genaueren Betrachtung bedarf die Situation bei lokal vereinbarten Variablen, die bezuglich eines Blockes global sind. Damit die oben erwahnte Forderung gilt, muB die Evaluation dieser Variablen immer in der Umgebung ihrer Deklaration (lexical scope) und nicht in der Umgebung der Aktivierung der Methode (dynamic scope) erfolgen, eine Forderung, die auch als "lexical scope rule" bezeichnet wird [40]. Mit anderen Worten, diese Variablen mussen bei der Blockevaluation jene Objekte referenzieren, die sie bei der Definition des Blockes referenziert haben. Um dies en Fall demonstrieren zu kannen, wird in Programm 2-40 eine Klasse BlockHolder festgelegt, die nur eine Klassenvariable Block besitzt, welche dazu dient, einen Block zu referenzieren und tiber die ZugrifTsmethode BlockHolder class»block verfugbar zu machen. Durch die Klassenmethode BlockHolder class»defineBlockNoReturn wird ein Block erzeugt und an die Klassenvariable zugewiesen. Dieser Block enthiilt eine in der Methode temporar vereinbarte Variable text als blockglobale Variable, die unmittelbar vor der Definition des Blockes mit der Zeichenkette 'BlockOhneReturn: erzeugt' belegt und nach der Defmition um die Zeichenkette " gespeichert' erweitert wird.
94
2 Smalltalk: Elemente der Sprache
Object subclass: #BlockHolder instanceVariableNames: " classVariableNames: 'Block' poolDictionaries: " category: 'BlockTest' BlockHolder class methodsFor: 'accessing'
block "Block
blockZustand "Feststellen der Variablen 'text', in welcher die Historie des Blockes dokumentiert wird. Diese ist das einzige Element auf dem StapeL" "Block outerContext privateTempAt: 1 BlockHolder class methodsFor: 'test-operation'
defineBlockNoReturn "Definieren eines Blockes im Kontext dieser Methode. Dieser Block kann zwar evaluiert werden, es wird jedoch der Fehler: 'Context cannot return' gemeldet!"
I text I text := 'BlockOhneReturn: erzeugt'. Block := [text := text, " evaluiert'). text := text, " gespeichert'. "text useBlock "Verwenden eines Blockes, der im Kontext einer anderen Methode definiert ist Die Variable 'text' (im Kontext dieser Methode) ist NICHT die Variable text im Kontext des verwendeten Blockes. Bei der Evaluation des Blockes wird die hier definierte Variable 'text' NICHT verandert. Smalltalk beruht auf lexical scoping."
I text I text := 'useKontext'. Block value. "text Programm 2-40 Defmition und Verwendung eines Blockes
Bei jeder Evaluation des Blockes werden die Zeichen " evaluiert' an die Zeichenkette angebangt, so daB man erkennen kann, wie oft der Block die Botschaft value empfangen hat. Die Methode BlockHolder class»useBlock
2.5 Weiterfiihrende Bemerkungen
95
enthalt eine temporare Variable, die ebenfalls den Namen text tragt und mit 'useKontext' initialisiert wird, bevor der Block evaluiert wird. Mit Hilfe der Methode BlockHolder clasS»blockZustand kann der Kontext des Blockes (eine Auspragung der Klasse BlockContext) untersucht und die darin enthaltene Variable text ausgelesen werden. Urn die Bedeutung der globalen Variablen in einem Block zu veranschaulichen, werden die beschriebenen Methoden, wie in Programm 2-41 gezeigt, mehrfach ausgeftihrt und ihre Wirkung untersucht. Nach der Defmition des Blockes und seiner Bindung an die Klassenvariable Block ist des sen globale Variable text mit der Zeichenkette 'BlockOhneReturn: erzeugt, gespeichert' belegt. Der Block steht somit global zur Verftigung und kann von verschiedenen Methoden aus aktiviert werden. Dies geschieht nun im Rahmen der Ausftihrung der Methode BlockHolder class»useBlock, welche dem Block die Botschaft value sendet. Aus der Untersuchung des Blockzustandes ist zu erkennen, daB der Block tatsachlich evaluiert wurde, da die Zeichenkette nun lautet: 'BlockOhneReturn: erzeugt, gespeichert, evaluiert'. Zusatzlich ist auch zu erkennen, daB die temporare Variable text der Methode useBlock nichts mit der gleichnamigen globalen Variablen des Blockes zu tun hat. Fur die Evaluation des Blockes gilt jener Kontext, der bei seiner Defmition aktuell war und nicht der Kontext der aktivierenden Methode. Dies entspricht der Forderung des lexical scoping.
Workspace BlockHolder defineBlockNoReturn. <printlt> 'BlockOhneReturn: erzeugt, gespeichert' BlockHolder blockZustand. <printlt> 'BlockOhneReturn: erzeugt, gespeichert' BlockHolder useBlock .<printlt> 'useKontext' BlockHolder blockZustand. <printlt> 'BlockOhneReturn: erzeugt, gespeichert, evaluiert' BlockHolder useBlock; useBlock. <printlt> 'useKontext' BlockHolder blockZustand. <printlt> 'BlockOhneReturn: erzeugt, gespeichert, evaluiert, evaluiert, evaluiert'
Programm 2-41 Zur Verwendung von globalen Variablen in Blocken
96
2 Smalltalk: Elemente der Sprache
Lexical scoping ist eine Eigenschaft der meisten Programmiersprachen, so daB es iiberfliissig erscheinen mag, diesem Thema einen breiteren Raum zu geben. Es gibt jedoch Smalltalk-Implementationen, in denen diese Forderung nicht erftillt ist, was baufig zu Diskussionen iiber vermeintliche Fehler in Programmen ftihrt. t Ein weiterer Grund ftir die Behandlung dieses Themas liegt darin, daB es in Small talk leicht moglich ist, die Kontexte von Methoden und Blocken zu untersuchen. Diese sind als Auspragung der Klassen MethodContext oder BlockContext ebenfalls Objekte, sie konnen daher durch Botschaften angesprochen und durch spezielle Inspektoren untersucht werden. Ein Beispiel daftir ist die in Programm 2-40 gezeigte Methode BlockHolder class»blockZustand. An einer anderen Stelle (Abschnitt 14.2) ist gezeigt, wie aus dem Kontext einer Methode festgestellt werden kann, welches Objekt als Sender die Methode aktiviert hat und dam it der Empfanger des Riickgabeobjektes ist. Die bisher als Beispiele gewahlten Blocke hatten aIle die Eigenschaft, daB sie keinen Riickgabeausdruck enthielten. EnthlUt ein Block einen Riickgabeausdruck, so wird bei dessen Evaluation die Methode abgebrochen (und nieht nur der Block beendet) und das Ergebnis als Riickgabeobjekt der Methode an deren Sender iibermittelt. In Programm 2-42 ist die Blockdefmition aus Programm 2-40 dahingehend abgeandert, daB der einzige im Block enthaltene Ausdruck als Riickgabeausdruck formuliert ist.
BlockHolder class methodsFor: 'test-operation' defineBlockWdhReturn
"Definieren eines Blockes im Kontext dieser Methode. Dieser Block kann das ROckgabeobjekt nicht Obergeben. es wird der Fehler: 'Unhandled exception: Context cannot return' gemeldet!"
I text I text := 'BlockMitReturn: erzeugt'. Block := [Atext := text, " evaluiert']. text := text, " gespeichert'. Atext Programm 2-42 Defmition eines Blockes mit einer Riickgabeanweisung
t Man vergleiche die immer wiederkehrenden Diskussionen in comp.lang.smalltalk
2.5 Weiterfuhrende Bemerkungen
97
Workspace BlockHolder defineBlockWithReturn. <printlf> 'BlockMitRetum: erzeugt, gespeichert' BlockHolder useBlock.
<printlt> 'Context cannot retum' -> tenninate>
BlockHolder blockZustand. <printlf> 'BlockMitReturn: erzeugt, gespeichert, evaluiert'
Programm 2-43 Ein Ruckgabeobjekt kann nicht ubergeben werden
Wird dieser Block in einer ahnlich Situation wie der in Programm 2-41 gezeigten evaluiert, so kommt es zu dem in Programm 2-43 veranschaulichten Problem. Der Block wird definiert und dabei an die Klassenvariable Block gebunden, er tragt, wie vorhin erlautert, den Kontext der definierenden Methode mit sich, der allerdings in diesem Fall nieht mit dem Kontext der aufrufenden Methode verknupft ist. Aus diesem Grunde kann der Block durch die Methode useBlock zwar evaluiert werden, der ProzeB bricht jedoch mit einer Fehlermeldung ab, weil es dem Block nicht moglich ist, das Ruckgabeobjekt an den unbekannten Adressaten zu ubermitteln. Ein solches Problem tritt nieht auf, wenn ein Block mit einem Ruckgabeausdruck in derselben Methode aktiviert wird, in der er auch defmiert wurde.
2.5.4 Benennung von Variablen Die Regeln fUr die Bildung von Namen verlangen, daB globale Variable (dazu zlihlen auch die Namen von Klassen) sowie Klassenvariable mit einem GroBbuchstaben beginnen mussen [17]. Versucht man, bei der Definition einer Klasse solche Namen klein zu schreiben, wird zwar ein Wamhinweis gegeben (Static variable names should be capitalized.) und ein Anderungsvorschlag gemacht, der aber nicht akzeptiert werden muB. Wird einer Klasse auf direktem Wege, etwa durch die Methode TestClass addClassVarName: 'neu'
eine weitere Klassenvariable hinzugefUgt, so erfolgt dies ohne Uberpriifung der Einhaltung von Namensvorschriften. Gleiches gilt fUr den Fall, daB ein vorgefertigtes Variablenverzeichnis einer Klasse direkt als Verzeichnis ihrer Klassenvariablen zugeordnet wird, beispielsweise durch:
98
2 Smalltalk: Elemente der Sprache
I classDict I
classDict := Pool Dictionary new. classDict at: #x put: 'mein Name ist kleingeschrieben'. TestClass setClassPool: classDict.
Ebenso konnen durch direkte Eintragung in das Systemverzeichnis Smalltalk globale Variable festgelegt werden, deren Namen nicht mit einem GroBbuchstab en beginnen: Smalltalk at: #globalString put: 'so dOrfte ich nicht heiBen'
Wenn auch die hier erwahnten Methoden nur flir einen sehr systemnahen Gebrauch gedacht sind, zeigen sie doch, daB die erwahnten Regeln flir die Namensgebung von Variablen nur den Charakter von Konventionen haben, gegen die aber leicht verstoBen werden kann. Es ist somit nicht ausgeschlossen, daB flir ein Objekt sowohl Instanzvariable als auch Klassenvariable und Poolvariable mit gleichem Namen existieren konnen. Enthalt der statischen Horizont eines Objektes mehrere Variable mit gleichern Namen, so hangt es von der Strategie des Suchens nach der Bindung des Namens ab, welche dieser Variablen angesprochen wird. Die Suche nach der Bindung eines Objektes an einen Namen erfolgt in der Reihenfolge: Instanzvariable, Klassenvariable, Poolvariable und globale Variable, sie wird so lange fortgeflihrt, bis sich ein Sucherfolg einstellt. Das bedeutet, daB beispielsweise eine globale Variable nieht "aufkurzem Wege" erreicht werden kann, wenn eine gleichnamige Instanzvariable, Klassenvariable oder Poolvariable existiert. In jedem Fall besteht jedoch die Moglichkeit, eine Variable "auf langem Wege" tiber das Verzeichnis anzusprechen. So wiirde man das an eine globale Variable x gebundene Objekt sicher durch Smalltalk at: #x erreichen, auch dann, wenn eine Instanzvariable x existiert. Wird beim Kompilieren einer Methode ein verwendeter Name nicht gefunden, so wird der Vorgang abgebrochen und zur Deklaration des Namens aufgefordert. Ein bedenklicher Schwachpunkt liegt dann vor, wenn einer Klasse mehrere Variablenverzeichnisse zugeordnet sind, die Variable mit gleichen Namen enthalten. Wie aus Abbildung 1-20 ersichtlich ist, sind die Variablenverzeichnisse in einer Auspragung der Klasse Set zusammengefaBt. Beim Durchsuchen einer Menge werden die Elemente in jener Reihenfolge angesprochen, die ihrer Position in der zugrundeliegenden Hashtabelle entsprieht. Welches Poolverzeichnis von mehreren moglichen beim Suchen einer Variablenbindung zuerst durchsucht wird, hlingt somit nicht nur von seinem Namen (genauer vom Hashwert seines Namens) ab, sondern moglicherweise auch von der Reihenfolge des Zuordnens der Verzeichnisse, namlich dann, wenn die Verzeichnisnamen eine Kollision in der Hashtabelle verursachen. Man vergleiche dazu die Methode Class»bindingFor:, welche die Suche nach der Bin-
99
2.6 Aufgaben
dung eines gegebenen Namens durchfUhrt und die dort verwendete Instanzmethode Set»do:, durch welche tiber die Elemente einer Menge iteriert wird! Diesem Problem wird offensichtlich auch bei der Standardisierung von Smalltalk Rechnung getragen, indem verlangt wird, daB die Variablenpools nicht in einer Menge, sondem in einer sequentiellen Anordnung organisiert sein mtissen [47].
2.6
Aufgaben
Aufgabe 2.1 Folgende Anweisungen werden in einem Workspace durchgefUhrt. "Vorerst wird sichergestellt, daB X1 und X2 nicht als globale Variable definiert sind." Smalltalk removeKey: #X1 ifAbsent: []. Smalltalk removeKey: #X2 ifAbsent: []. <doff> ByteSymbol instanceCount X1 := #abc "X1 wird global erkl~rt" ByteSymbol instanceCount X2 := #abc "X2 wird global erkl~rt" ByteSymbol instanceCount
<printlt> <printff> <printff> <printlf> <printlf>
18064 #abe
18066 #abe
18067
a) Wodurch erkHiren sich diese Ergebnisse? Sprechen sie fUr oder gegen die Behauptung, daB Symbole durch ihre Literalform erzeugt werden und daB Symbole systemweit eindeutig sind, so daB jedes Symbol nur genau einmal vorkommen kann? Urn sicherzustellen, daB unter den 18064 bereits existierenden Bytesymbolen das gegenstandliche Symbol 4I=abc nicht schon vorkommt, wird versucht, diese Frage auffolgende Weise zu beantworten: ByteSymbol alllnstances includes: #abc <printlt> true
b) Was bedeutet dieses Ergebnis fUr die Beantwortung von Frage a)?
100
2 Smalltalk: Elemente der Sprache
Losung von Aufgabe 2.1 a) Die auf den ersten Blick unverstandlichen Ergebnisse erkHiren sich aus der Tatsache, daB die Namen von globalen Variablen, die im Systemverzeichnis Smalltalk eingetragen sind, selbst Symbole sind. Durch die Zuweisung von *abc zu der neu deklarierten globalen Variablen Xl werden also zwei neue Symbole erzeugt: '*'Xl und ,*,abc. Bei der darauffolgenden Zuweisung von ,*,abc an die neu deklarierte globale Variable X2 wird nur mehr das Symbol '*' X2 erzeugt, wiihrend das Literal ,*,abc ein bereits existierendes Symbol referenziert. b) Man wird feststellen, daB dieser Ausdruck immer zu true evaluiert wird, unabhlingig davon, nach welchem Symbol gefragt wird. Bei der Obersetzung des ausgewiihlten Textes als ungebundene Methode wird aus dem Literal das Symbol erzeugt und bei der unmittelbar darauffolgenden Ausftihrung aufgefunden. Folgende Vorgangsweise kann angewendet werden, um die Frage der urspriinglichen Existenz von ,*,abc zu beantworten: "Aktion 1." X:= ByteSymbol allinstances "X wird global erklllrt' <dolt>
"Aktion 2." X includes: #abc <printlt> false Dabei ist wichtig, die Untersuchung in zwei getrennten Aktionen durchzuftihren, dam it bei der Erzeugung eines Behlilters mit allen existierenden Symbolen das Literal ,*,abc noch nicht interpretiert ist!
Aufgabe 2.2 Toleranzintervalle In Programm 2-37 ist eine Methode angegeben, die aus einer Zahl ein Toleranzintervall erzeugt. Man definiere eine Klasse Toleranzintervall und formuliere jene Methoden, die notwendig sind, um in einem Arbeitsbereich folgendes Ergebnis zu erhalten: 12 ± 2 <printlt> [10, 14]
Losung von Aufgabe 2.2 Programm 2-44 zeigt zuerst die Definition der Klasse Toleranzintervall, flir deren Ausprligungen zwei Instanzvariable vorgesehen sind, in denen die Untergrenze und die Obergrenze des Intervalles festgehalten werden. Es wird
101
2.6 Aufgaben
vorausgesetzt, daB fiir diese Instanzvariablen namenskonforme lesende und schreibende Zugriffsmethoden existieren. Weiterhin ist eine Methode Toleranzintervall class»von:bis: zur Erzeugung einer Auspragung gezeigt, die von der Methode Number»± (Programm 2-37) vorausgesetzt wird. Das verlangte Druckbild wird von Toleranzintervall»printOn: erzeugt. Object subclass: #Toleranzintervall instanceVariableNames: 'von bis ' classVariableNames: " poolDictionaries: " category: 'Demo' Toleranzintervall class methodsFor: 'instance creation' von: untergrenze bis: obergrenze
"Erzeugen eines Toleranzintervalles." "super new von: untergrenze; bis: obergrenze
(1)
Toleranzintervall methodsFor: 'printing' printOn: aStream aStream nextPutAlI: '[', self von printString, " " self bis printString, ']' (1) Die ZugrifTsmethoden auf die Instanzvariablen werden vorausgesetzt.
Programm 2-44 Erzeugen und "Ausdrucken" von Toleranzintervallen
Aufgabe 2.3 Aussagenlogische Operationen Folgende Anweisungen werden in einem Workspace durchgeflihrt:
1<2&4<2 1<2&2<4
<printlt> false <printlt> true
4 <2 & 1 <2
<printlt>
1 < 2 I 4 >2
<printlt>
Unhandled exception: Message not understood: #< Unhandled exception: Message not understood: #>
W odurch konnen diese auf den ersten Blick eigenartigen Ergebnisse erklart werden?
102
2 Smalltalk: Elemente der Sprache
Losung von Aufgabe 2.3 AIle in den angegebenen Ausdriicken angesprochenen Methoden haben binare Selektoren, so daB die Evaluation von links nach rechts ausgefiihrt wird, weil keine Klammem eingefligt sind. Die richtig erscheinenden Ergebnisse der ersten beiden Ausdriicke kommen dadurch zustande, daB die Methode True»& alternativeObject als Ergebnis den Parameter alternativeObject liefert (vergleiche Programm 2-26), welcher in beiden Fiillen eine Instanz von Smallinteger ist, welche die Methode Smallinteger>>< aNumber versteht und entsprechend mit true oder false reagiert. Dies kann durch schrittweise Evaluation der Teilausdriicke von links nach rechts iiberpriift werden:
1<2 true & 4
4<2
<printlt> true <printlt> 4 <printlt> false
"/\ alternativeObject"
Das Ergebnis des gesamten Ausdruckes ist das Riickgabeobjekt des zuletzt evaluierten Ausdruckes 4 < 2 und nicht des Ausdruckes true & false, der zuletzt evaluiert worden ware, wenn der verkettete Ausdruck (1 < 2) & (4 < 2) gelautet hatte. Die Fehlersituation in den letzten beiden Ausdriicken kann auf iilmliche Weise erkllirt werden. Die Methode False»& alternativeObject (vergleiche Programm 2-26) antwortet mit dem Objekt false, das keine Methode mit einem Selektor < kennt, so daB ein Laufzeitfehler gemeldet wird. Dies kann ebenfalls durch schrittweise Evaluation der Teilausdriicke veranschaulicht werden:
4<2
false & 1 false < 2
<printlt> false <printlt> false <printlt>
"/\ self"
Unhandled exception: Message not understood: #<
3
Ein erster Einsatz von Smalltalk
In diesem Kapitel werden einige Beispiele geboten, die einen ersten Eindruck von der objektorientierten Betrachtung eines Realitiitsausschnittes und dessen Modellierung durch Objekte in einem Objektraum vermittelt sollen. Ein wei teres Ziel dieses Kapitels ist es, die elementaren Schritte bei der Erstellung einer einfachen Anwendung aufzuzeigen und auch den Einsatz der wichtigsten Werkzeuge des Smalltalk-Systems zu demonstrieren. Die in den vorangehenden Kapiteln erliiuterten Strukturen und Mechanismen werden dabei an praktischen Beispielen in einer ganzheitlichen Sicht dargestellt, wobei sich der Bogen von Uberlegungen zum Entwurf von Klassen bis zur Erzeugung einer einfachen Benutzerschnittstelle spannt. Als Beispiele sollen einfache Ziihlwerke dienen, deren Wirkungsweise und Aufbau in wenigen Worten zu beschreiben ist, so daB ihre Modellierung und Realisierung in Smalltalk ohne eigene Entwurfsphase direkt vorgenommen werden kann. Auf die hier zu Demonstrationszwecken entwickelten Zlihlwerke wird an anderen Stellen zUriickgegriffen.
3.1
Beispiel: einfache Zihlwerke
Ein einfaches Ziihlwerk, wie es in Abbildung 3-1 schematisch dargestellt ist, moge aus einem Gehiiuse bestehen, das mit zwei Drucktasten ausgestattet ist, die eine zum Zuriicksetzen des Ziihlwerkes und die andere zum Auslosen eines Ziihlvorganges. Der jeweilige Ziihlerstand kann in einem Fenster mit einer sechsstelligen Anzeige abgelesen werden. Das Ziihlregister hat die Funktion eines Ringziihlers, der von seinem hOchsten Stand aus durch einen weiteren Ziihlvorgang ohne Uberlaufanzeige auf Null gesetzt wird. Nimmt man so ein Ziihlwerk in die Hand und driickt zuerst auf die Riickstelltaste und nachher einmal auf die Zllhlktaste, so wird man durch einen Ablesevorgang feststellen, daB das Anzeigefeld die Zahl 1 zeigt. G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
104
3 Ein erster Einsatz von Smalltalk
Registeranzeige ~.-
Z1thltaste
~ RuckstelItaste
Abbildung 3-1
Ein Zahlwerk in der realen Welt
Dieses in seinem Autbau und in seiner Funktionalitat sehr einfache reale Objekt kann fast eins zu eins aus dem realen in den konzeptionellen Objektraum abgebildet werden. Die in Abbildung 3-2 verwendete Symbolik zur Charakterisierung von Objekten im konzeptionellen Objektraum entspricht der bereits im ersten Kapitel angegebenen Darstellungsweise.
lieslahlerstand
zanIe start
zw start zw zahls. zw liesZahlerstand <printlt> 1 Workspace !--_ _ _ _ _ _- - I
Abbildung 3-2
Ein Ziihlwerk im Objektraum
In der rechten Hiilfte der Abbildung 3-2 ist ein Ausschnitt eines in einem Arbeitsbereich (workspace) befindlichen Programmes gezeigt, welches die vorher genannten Aktionsfolge beschreibt. Hier wird vorausgesetzt, daB die Variable zw ein Ziihlwerk bezeichnet, welches im Objektraum existiert und die gesendeten Botschaften versteht und somit die zugehOrigen Methoden der Reihe nach ausfiihrt, so daB schlieBlich als Ergebnis der an das Zahlwerk gesendeten Nachricht liesZAhlerstand die Zabl 1 geliefert wird. Die beschriebenen Aktionen werden bei der interaktiven Arbeit mit dem Smalltalk-System dadurch ausgelost, daB der Programmausschnitt zuerst markiert und anschlie-
3.1 Beispiel: einfache Ziihlwerke
105
Bend durch Auswahl des Meniipunktes <printlt> als freie Methode aktiviert wird. Bevor nun gezeigt wird, wie Ziihlwerke deflOiert und die Methoden flir die Nachrichten z!hle, start und liesZ!hlwerk formuliert werden konnen, so11 ein genauerer Blick auf den Aufbau eines einzelnen Zahlwerkexemplares geworfen und seine Zugehorigkeit zur Klasse Zahlwerk veranschaulicht werden. Selbstverstandlich ist dies das Ergebnis der erst spater gezeigten Definitionen, jedoch erscheint es giinstig, sich mit der angestrebten Situation vertraut zu machen, um die folgenden Programmstiicke (Methoden) leichter verstehen zu konnen.
Object
meinZahlwerk
l ahlwerk
einZahlwerk self register
Abbildung 3-3
Inspektion eines Ziihlwerkes im Objektraum
Abbildung 3-3 zeigt ein Objekt mit Namen meinZ!hlwerk, das durch ein Inspektionswerkzeug "geoffnet" ist, sodaB man seinen Aufbau einsehen kann. Es ist zu erkennen, daB es eine Instanzvariable register enthiilt, die mit dem Zahlobjekt ,,1" belegt ist und daB es auBerdem wie jedes Objekt eine "Pseudovariable" self enthiilt, iiber die es sich selbst referenziert.t Zusatzlich ist in der Abbildung durch das Symbol fur die Instanzierungsbeziehung angedeutet, daB dieses Objekt eine Auspragung der Klasse Z!hlwerk ist, welche in der Klassenhierarchie als Subklasse der Klasse Object positioniert ist. Ein Blick in das Ionere des Klassenobjektes zeigt einen Ausschnitt aus dem Methodenverzeichnis, der erkennen laBt, daB die Klasse fur ihre Auspragungen Methoden mit den Namen liesZ!hlerstand, z!hle und start bereitt Der Zugriff auf ein Objekt tiber self ist eine Systemeigenschafi, self ist nicht in der Strukturschab lone der Klasse enthalten und daher keine Instanzvariable.
106
3 Ein erster Einsatz von Smalltalk
hlilt. In der Strukturschablone der Klasse ZAhlwerk ist die Instanzvariable register vorgerichtet, was aber in der Abbildung nicht graflsch dargestellt ist. Um die gezeigte Situation realisieren zu konnen, ist es in einem ersten Schritt notwendig, die neue Klasse Zahlwerk zu defmieren und in der bestehen den Klassenhierarchie als Unterklasse von Object zu positionieren. Object subclass: :fI:lahlwerk instanceVariableNames: 'register' classVariableNames: " poolDictionaries: " category: 'MeBinstrumente' Programm 3-1
Defmition der Klasse Zahlwerk
Der in Programm 3-1 gezeigte Ausdruck bewirkt die Erzeugung der Klasse Zlihlwerk. Bei seiner AusfUhrung wird an das Klassenobjekt Object die mit entsprechenden Parameterobjekten versehene Botschaft subclass:instanceVariableNames:classVariableNames:pooIDictionaries:category: gesandt, wodurch die Erzeugung der neuen Klasse und ihre EinfUgung in die Klassenhierarchie erfolgt. Die AusfUhrung dieses Programmes kann wieder in einem Arbeitsbereich des laufenden Smalltalk-Systems (durch Hervorheben des Textes und Auswahl von <dolt> aus dem AktionsmenU) veranlaBt werden, jedoch wird in der Praxis die Programmierung stets in einem Browser durchgefUhrt. Browser sind Entwicklungswerkzeuge, die es erlauben, durch die gesamte Klassenhierarchie (System Browser) oder eingeschrankt auf Teile davon (Category Browser, Class Browser) Uber die Methodenkategorien bis zu den einzelnen Instanz- und Klassenmethoden zu navigieren. Klassen sind in Klassenkategorien gruppiert, ebenso mUssen die Methoden jeder Klasse einer Methodenkategorie zugeordnet sein. Diese Kategorisierung hat nur deklarative und organisatorische Bedeutung. In Abbildung 3-4 ist ein Systembrowser gezeigt, in we1chem die Definition der Klasse Zahlwerk (diese ist der Klassenkategorie MeBinstrumente zugeordnet) ersichtlich ist. Weiterhin ist daraus zu erkennen, daB fUr Instanzmethoden dieser Klasse unter anderen die Methodenkategorien accessing, operating und initialize angelegt sind. Da keine Kategorie ausgewahlt ist, wird im Methodenfenster auch keine Methodenliste angezeigt. 1m Editierbereich ist der in Programm 3-1 gezeigte Ausdruck eingetragen, er kann durch die Auswahl aus demzugeordneten Aktionsmenii ausgefUhrt werden. Nach der Einrichtung der Klasse Zahlwerk konnen nun in einem nachsten Schritt Methoden fUr diese Klasse erstellt werden. Programm 3-2 zeigt die Definition von Methoden fUr den Zugriff auf die Instanzvariable und fUr die Initialisierung eines Ziihlwerkes.
107
3.1 Beispiel: einfache Zlihlwerke
'-
.,$ m
'0,
-(D ....,
(D
}-
C
(D
U)
(D
E (lJ
Z
(D
E ::::;
~
'-
if)
"-'
v)
(J>
E (lJ
if)
c
'Uj
::0 Z (D 1J) (lJ 'r:: (D (j) c(lJ ::0 (lJ ?":;;: C @
>
(D
'C @
c(lJ
>m
c
(3
0
0
;c:; 0
(5
m ...... m iXl <5
Abbildung 3-4
2'
<:) 0)
SystemBrowser mit Defmition der Klasse Z~hlwerk
Prinzipiell sind die Instanzvariablen eines Objektes fUr jede seiner Methoden sichtbar und zugreifbar, so daB spezielle Zugriffsmethoden nicht unbedingt notwendig sind. Es entspricht jedoch einem vielfach akzeptierten Programmierstil, den direkten Zugriff auf Instanzvariable auf Methoden (mit einem von der Instanzvariablenabgeleiteten Namen) zu beschriinken, wodurch die Wartbarkeit von Software erhoht wird. Es wird in der Folge
108
3 Ein erster Einsatz von Smalltalk
immer angenommen, daB fUr Instanzvariable "namenskonforme" Zugriffsmethoden dieser Art eingerichtet sind. Zahlwerk methodsFor: 'private-accessing'
(1)
register
"Lesen der Instanzvariablen (Akzessormethode)." 1\
register
register: anlnteger
"Schreiben der Instanzvariablen (Mutatormethode)." register := anlnteger (1) Die in der Folge aufgelisteten Methoden sind der Klasse lahlwerk zugeordnet und in die Methodenkategorie private-accessing eingeordnet. Der Methodentext wird in einer Form angegeben, die durch die Meniiauswahl in einem Browser erhalten wird.
Programm 3-2
Namenskonforme Zugriffsmethoden auf die Instanzvariablen
Zahlwerk methodsFor: 'accessing' liesZihlerstand
"Feststellen des Zahlerstandes." 1\
self register
Zahlwerk methodsFor: 'operating' start
"Zuriicksetzen des Zahlers." self register: 0 zihle
"Zahlen." self register: ((self register +1) rem: 1000000) (I) Zahlen modulo 1000000 zur Simulation eines sechsstelligen Ringziihlwerkes.
Programm 3-3
Methoden zum Bedienen von Zablwerken
(1)
3.1 Beispiel: einfache Zlihlwerke
109
Programm 3-3 enthlilt jene Methoden, die das funktionale Verhalten von Zlihlwerksobjekten bewirken. In diesen Methoden wird ein direkter Zugriff auf die Instanzvariable register vermieden, vielmehr wird auf die eben erwlihnten Zugriffsmethoden zurUckgegriffen. Um die Funktion der beschriebenen Methoden testen zu konnen, ist es notwendig, ein Zlihlwerksobjekt (eine Ausprligung der Klasse ZAhlwerk) im Objektraum zu erzeugen und sicherzustellen, daB es durch eine Variable referenziert wird. Dies kann, wie in Abbildung 3-5 gezeigt, in einem Arbeitsbereich (workspace) erfolgen. Die Klasse ZAhlwerk erbt wie jede Klasse eine Klassenmethode new, durch welche eine neue Ausprligung erzeugt wird, wobei die Instanzvariablen mit dem Objekt nil belegt sind. Wiirde man naeh den bisherigen Vorarbeiten die in Abbildung 3-5 gezeigten Anweisungen ausftihren, so erhielte man als Folge der an das neue Zlihlwerk gesandten Botsehaft zAhle zur Laufzeit die Fehlermeldung Unhandled exception: Message not understood: #+, weil in der Methode zAhle an das Objekt, das die Instanzvariable register referenziert (das ist unmittelbar nach der Erzeugung des Zlihlwerkobjektes das Objekt nil), die Botsehaft ,,+" mit dem Argument" 1" iibermittelt wird. Diese Nachrieht wird zwar (unter anderen) von Objekten der Klasse Smalllnteger (also von im Computer direkt darstellbaren ganzen Zahlen) verstanden, nieht aber yom Objekt nil. Diese Fehlersituation kann erst zur Laufzeit des Programmes erkannt werden und nieht bereits zur Zeit der Ubersetzung des Methodencodes, weil Variable in Smalltalk keinen statischen Typ tragen und somit Objekte beliebiger Klassenzugehorigkeit referenzieren konnen. Um das Auftreten eines solchen Fehlers zu vermeiden ist es daher notwendig, unmittelbar nach der Erzeugung eines Zlihlwerkes, jedenfalls noeh vor dem ersten Zlihlvorgang, die Variable register mit einem sinnvollen Objekt zu initialisieren.
ZAhlwerk methodsFor: 'initializing' initialize
"Initialisieren eines Ziihlwerkes." self register: 0 ZAhlwerk class methodsFor: 'instance creation'
new "Erzeugen eines initialisierten Ziihlwerkes." 1\
super new initialize
Programm 3-4
Methoden zur Erzeugung und Initialisierung von Zlihlwerken
110
3 Ein erster Einsatz von Smalltalk
Es ist giinstig, notwendige Initialisierungen im Rahmen einer ldassenspezifischen Erzeugungsmethode durchzufiihren, so daB Objekte mit nicht initialisierten Zustandsvariablen gar nicht erst in Umlauf kommen. Diese Vorgangsweise ist in Programm 3-4 gezeigt. In der Methode ZAhlwerk»new wird zuerst durch super new die geerbte Instanzierungsmethode aktiviert, welche eine nicht initialisierte Auspragung der Klasse Z~hlwerk liefert, der unmittelbar darauf die Botschaft initialize iibermittelt wird, wodurch die Instanzvariable register mit dem Objekt 0 belegt wird. Durch den Riickgabeoperator wird veranlafit, daB das neue und bereits initialisierte Ziihlwerk als Riickgabeobjekt ausgeliefert wird. Man beachte, daB Z~hlwerk class»new eine Klassenmethode ist und daher von der Klasse Z~hlwerk verstanden wird, hingegen ist Z~hlwerk»initialize eine Instanzmethode, die an Auspriigungen dieser Klasse zu senden ist. Da die Klassenmethode new der Klasse Z~hlwerk derart festgelegt wurde, daB bereits initialisierte Zahlwerkobjekte erzeugt werden, kann das in Abbildung 3-5 in einem Arbeitsbereich (workspace) gezeigte Programm nunmehr fehlerfrei ausgefiihrt werden. In dem zu einer freien Methode zusammengefaBten Programmtext wird vorerst eine temporare Variable zw vereinbart und an diese ein neu erzeugtes und bereits initialisiertes Zahlwerkobjekt gebunden. Diesem Objekt wird sodann ein Zahlbefehl iibermittelt, schlieBlich wird es mit Hilfe eines Inspektors untersucht.
Abbildung 3-5
Erzeugung und Inspektion eines Ziihlwerkes
Man erkennt in der linken Halfte des Inspektorfensters eine Liste mit den Eintragungen self und register. In dieser Liste ist die (einzige) Zustandsvariable register ausgewahlt, ihr Wert wird im rechten Teilfenster angezeigt. Die Existenz eines Objektes im Objektraum beginnt mit seiner Erzeugung und ist so lange sichergestellt, wie es durch andere im Objektraum befindliche
3.2 Beispiel: Ziihlwerke mit Datum
111
Objekte referenziert wird. Bei der Durchfdhrung des gezeigten Programmes wird das neu erzeugte Ziihlwerk vorerst an die temporare Variable zw gebunden, durch die Botschaft inspect wird sodann ein Inspektorobjekt erzeugt, welches den Zustand des Zahlwerobjektes visualisiert und dieses daher ebenfalls an sich bindet. Nach Beendigung des Programmes verliert zwar die Variable zw ihre Giiltigkeit, die Existenz des Ziihlwerkes ist aber durch das Inspektionsobjekt gesichert. Erst nach dem SchlieBen des Inspektor-Fensters werden beide Objekte mangels Referenzierung unansprechbar, sie werden bei nachster Gelegenheit durch den automatisch ablaufenden Mechanismus der Speicherbereinigung (garbage collection) eliminiert, der von ihnen beanspruchte Platz im Objektraum wird fdr neue Objekte verfugbar gemacht. Abbildung 3-5 zeigt mit Hilfe der Smalltalk-Werkzeuge Workspace und Inspector die gleiche Situation, die in den Abbildungen 3-2 und 3-3 durch einen schematischen Blick in den Objektraum veranschaulicht wurde. Durch die beschriebene Entwicklungsarbeit ist die Klassenhierarchie urn die Klasse Zahlwerk erweitert worden, es kannen daher von nun an beliebig viele Zahlwerke erzeugt und in Applikationen eingesetzt werden.
3.2
Beispiel: Z8hlwerke mit Datum
Urn Zahlwerke der beschriebenen Art zum Zahlen von Ereignissen iiber l1ingere Zeitraume verwenden zu kannen, ware es giinstig, diese mit einer zusatzlichen Anzeige zu versehen, in der das Datum des letzten Zahlwerkstarts ersichtlich ist. Zahlwerke dieser neuen Art, sie mage ZahlwerkMitDatum genannt werden, t soIlen die gleichen Eigenschaften wie die vorhin beschriebenen Zahlwerke haben und zusatzlich die Maglichkeit bieten, das vermerkte Datum jederzeit ablesen zu kannen. Es ist daher naheliegend, die neue Klasse ZahlwerkMitDatum durch Subklassenbildung von der Klasse Zahlwerk abzuleiten, urn dadurch deren Eigenschaften (Instanzvariable und Methoden) zu erben. Abbildung 3-6 zeigt eine Auspragung der Klasse ZahlwerkMitDatum im Objektraum samt den mit diesem Objekt in Beziehung stehenden weiteren Objekten. Die Definition der Klasse ZahlwerkMitDatum und die Erweiterung der Initialisierungsmethode sind in Programm 3-5 zusammengefaBt. Die fdr die
t
In Smalltalk ist es iiblich, aus mehreren Worten zusammengesetzte Bezeichnungen zu verwenden und diese zusammenzuschreiben, den Beginn eines W Ortes aber durch einen GroBbuchstaben hervorzuheben.
112
3 Ein erster Einsatz von Smalltalk
Instanzvariable datum vorausgesetzten namenskonformen Zugriffsmethoden sind nicht explizit angegeben. ,----~~~~~~~~~~~~~- -~-----
------------------------ -- - - - - - - , .
zwd := Zahl\lverkMitDatum new_ zwd zahle_
Zahlwerk
_ _ _ _ ______________ _
l _~~~~~~~~~~~~~~~_.
Abbildung 3-6
Inspektion eines ZtthlwerkMitDatum im Objektraum
subclass: #ZahlwerkMitDatum instanceVariableNames: 'datum' classVariableNames: " poolDictionaries: " category: 'MeBinstrumente'
Z~hlwerk
ZahlwerkMitDatum methodsFor: 'initializing'
initialize "Initialisieren eines lahlwerkes." super initialize. self datum: Date today
Programm 3-5
Defmition der Klasse ZtthlwerkMitDatum
3.2 Beispiel: Zlihlwerke mit Datum
113
ZtlhlwerkMitDatum methodsFor: 'accessing'
liesDatum "Anzeigen des Datumsvermerkes." 1\
self datum
ZtlhlwerkMitDatum methodsFor: 'operating' start
"ZurOcksetzen des Zahlers und Vermerken des aktueUen Datums." super start. self datum: Date today (1) Zuerst erfolgt die allgemeine Initialisierung durch die geerbte Methode, dann die k1assenspezifische Initialisierung.
Programm 3-6
Methoden zum Bedienen von Zlihlwerken mit Datum
Programm 3-6 enthlilt die Methoden, die zum Bedienen eines mit Datum versehenen Zlihlwerkes notwendig sind, soweit sie nicht aus der Oberklasse Ztihlwerk geerbt werden. Abbildung 3-7 zeigt die Erzeugung einer Ausprligung der Klasse zahlwerkMitDatum sowie deren Untersuchung durch Inspektoren in der Arbeitsumgebung von Smalltalk. An Hand dieses Beispieles wird nochmals auf die Vererbung von Struktur und Verhalten hingewiesen. Die Strukturvererbung ist aus den geoffneten Inspektoren dadurch zu erkennen, daB Ausprligungen der Klasse ZtlhlwerkMitDatum nicht nur die in dieser Klasse vereinbarte Instanzvariable datum aufweisen, sondem auch die aus der Klasse Ztlhlwerk geerbten Instanzvariable register. Dieser Sachverhalt kann auch den Abbildungen 3-6 und 3-7 entnommen werden. Abbildung 3-6 enthlilt auch einen Hinweis auf den Mechanismus der Aktivierung von Methoden und damit auf die Verhaltensvererbung. Die breiten, grauen Pfeile veranschaulichen die Schritte, die fUr das Aufsuchen der Methode liesZtlhlerstand durchlaufen werden. Das Objekt meinZtlhlwerk empflingt die Botschaft liesZtlhlerstand (1) und sucht in seiner Klasse (ZtlhlwerkMitDatum) nach der entsprechenden Methode (2). Diese wird dort nicht gefunden (in der Klasse ZtlhlwerkMitDatum sind nur die in Programm 3-5 angegebenen Methoden definiert), deshalb wird der Suchvorgang in der unmittelbaren Oberklasse (Ztlhlwerk) fortgesetzt (3) und dort mit Erfolg beendet. Die gefundene Methode wird yom EmpHinger aktiviert und liefert als
114
3 Ein erster Einsatz von Smalltalk
Riickgabeobjekt die von der Instanzvariablen register des Zahlwerkes referenzierte Auspragung der Klasse Smalllnteger.
zVHah!o .
zw inspect zvv inspect
<dolt>,.
AbbUdung 3-7
Erzeugung und Inspektion eines Zahlwerkes mit Datum
Sendet man an ein Objekt eine Botschaft, fUr die weder in ihrer Klasse noch in einer der Oberklassen eine entsprechende Methode gefunden wird, so wird eine Methode doesNotUnderstand: gesucht und aktiviert. Eine solche ist jedenfaUs in der Klasse Object vorhanden, sie erzeugt im Standardfall in einem Fenster eine Fehlermeldung und bietet mehrere Moglichkeiten interaktiv zu reagieren, beispielsweise den laufenden ProzeB abzubrechen, eventuell fortzusetzen oder auch direkt einen Debugger aufzurufen. Aus dem skizzierten Vorgang zum Aufsuchen einer Methode fUr eine empfangene Botschaft geht auch hervor, wie der Fall behandelt wird, wenn Methoden gleichen Namens fUr mehrere auf dem Vererbungspfad liegende Klassen definiert sind. Da der Suchvorgang bei der eigenen Klasse beginnt und den Vererbungspfad entiang notfalls bis zur Wurzel der Klassenhierarchie (Klasse Object) fortgesetzt wird, hat eine in der eigenen Klasse definierte Methode (allgemeiner: eine Methode einer in der Hierarchie tiefer liegenden Klasse) Vorrang gegeniiber einer in einer Oberklasse definierten Methode gleichen Namens. Auf diese Weise konnen geerbte Methoden durch andere ersetzt werden. Das Abandern (im Extremfall auch AuBerkraftsetzen) von geerbten Methoden wird als Methodenredefinition oder Methodenersetzung (overriding) bezeichnet. In der Klasse ZAhlwerkMitDatum werden die aus der Oberklasse geerbten Methoden mit den Selektoren initialize und start redefmiert.
3.3 Beispiel: Erweiterte Zlihlwerke
115
Stellt man bei der Betrachtung der Zuordnung von Methoden gleichen Namens zu mehreren Klassen nicht die Klasse, sondem den Methodennamen in den Mittelpunkt, kommt man zum Begriff des Po[ymorphismus. Eine Methode heiBt polymorph, wenn sie von Objekten unterschiedlicher Klassen verstanden wird oder mit Argumenten unterschiedlicher Art versehen werden kann.
3.3
Beispiel: Erweiterte Zihlwerke
Fur umfangreiche Zahlvorgange ist ein Zlihlwerk mit einem nur sechsstelligen Zahlregister unzureichend. Dieser Mangel kann entweder durch VergroBerung des Zahlregisters oder durch HinzufUgen eines zweiten Zahlregisters zum Zahlen der Oberlaufe des ersten Registers gemildert werden. Zwar ware die Modellierung eines Zahlwerkes mit einem beliebig groBen Register die einfachste Losung (in Smalltalk ist die Verwendung potentiell beliebig groBer ganzer Zahlen ohne Oberlaufproblematik moglich), doch solI hier der Weg der Konstruktion von erweiterten Zahlwerken mit zusatzlichen Zlihlvorrichtungen beschritten werden. Vorerst werden Oberlegungen zum Entwurf solcher Objekte (sowohl in der Realitat als auch im Modell) angestellt. Eine Losungsvariante ware, eine vorhandene Konstruktion von Zahlwerken (etwa Z~hlwerkMitDatum) so zu erweitem, daB in ihr ein zweites Zlihlregister untergebracht wird und daB die Funktionalitat dieser Anderung entsprechend angepaBt wird. Eine andere Losungsvariante konnte darin bestehen, daB zwei Exemplare vorhandener Zlihlwerke (eines davon mit Datum) genommen und in einem gemeinsamen Gehause zusammengebaut werden, wobei die Funktionsanforderungen an das zusammengesetzte Zahlwerk an die eingebauten Teilzlihlwerke in geeigneter Weise weiterzugeben waren. Jede der beiden Varianten konnte nach auBen hin die gleiche Funktionalitat aufweisen, namlich auf die Botschaften "start", "zahle" und "liesZahlerstand" in gleicher Weise zu reagieren. In der Folge werden beide Varianten kurz gezeigt, die dabei eingesetzten Modellierungsarten werden verglichen und ihre jeweiligen Vor- und Nachteile diskutiert.
3.3.1
Zihlwerke mit zweitem Register
Die erste Variante bedeutet eine Erweiterung und Revision des bestehenden Bauplanes fUr Zahlwerke mit Datumsfunktion auf Modellebene, also die
116
3 Ein erster Einsatz von Smalltalk
Definition einer Subklasse von ZAhlwerkMitDatum, etwa auf die in Programm 3-7 gezeigte Art. ZAhlwerkMitDatum subclass: #"SuperzAhlwerk instanceVariableNames: 'register2 ' classVariableNames: " poolDictionaries: " category: 'MeBinstrumente' SuperzAhlwerk methodsFor: 'initializing'
initialize "Initialisieren des Ziihlwerkes." super initialize. self register2: 0
Programm 3-7
Die Klasse SuperzAhlwerk
SuperzAhlwerk methodsFor: 'accessing'
liesZihlerstand "Feststellen des Ziihlerstandes." Aself register
+ (self register2*1000000)
SuperzAhlwerk methodsFor: 'operating'
start
"ZurUcksetzen des Ziihlwerkes." super start. self register2: 0 zihle
"Ziihlen." super zAhle.
"Wenn nach einem Ziihlvorgang das erste Register 0 zeigt, dann hat ein Oberlauf stattgefunden, dieser wird im zweiten Register geziihlt." self register = 0 ifTrue: [self register2: (self register2
Programm 3-8
+ 1)]
Methoden zur Bedienung eines Superziihlwerkes
Wegen der Erweiterung eines Ziihlwerkes durch ein zweites Register mussen aBe von den Oberklassen geerbten Methoden fUr die Bedienung eines
3.3 Beispiel: Erweiterte Zahlwerke
117
Zahlwerkes adaptiert werden, um das zusatzliche Register zu beriicksichtigen. Diese Methoden sind Programm 3-8 in zusammengefaBt. 1m folgenden wird kurz der ProzeB der Initialisierung einer Instanz der Klasse Superzahlwerk beleuchtet mit dem Ziel, den Mechanismus der Methodenvererbung und die Bedeutung der Pseudovariablen self und super nochmals zu veranschaulichen sowie einen Eindruck von den Moglichkeiten des Smalltalk-Debuggers zu vermitteln.
"lnitialJsieren eines ZahhNerkes'" self register: o. "Haltepunkt fOrlnspektion im Debugger"
self
o Debugger-Aufbau:
t Auswahlliste def aktiven Methaden in def Aktivierungsreihenfoige 2. Arbeitsbereich Lum Editieren du ausgewahlte Methode 1 Inspektor fur die Instanzvariablen des jeweiligen Empfangers 4. lnspektor fUr die temporaren Varlablen der jeweiligen Methode
Abbildung 3-8
InitialisierungsprozeB eines Superzahlwerkes
Zu diesem Zweck sei voriibergehend in die Methode initialize der Klasse Zahlwerk (Programm 3-4) ein Programmhaltepunkt (self halt) eingeftigt. Dies
118
3 Ein erster Einsatz von Smalltalk
kann mit Hilfe eines Browsers durch Editieren des Codes und nachfolgender Kompilation durch Auswahl aus dem Aktionsmenii interaktiv erreicht werden. Bei der Erzeugung eines Superzl:1hlwerk-Objektes, beispielsweise durch Ausftihrung von SuperzAhlwerk new in einem Arbeitsbereich, wird das neue Objekt initialisiert (die Methode new wird aus der Klasse za.hlwerk geerbt, sie enthiilt die Initialisierungsanweisung). An der eingeftigten Unterbrechungsstelle wird der ProzeB angehalten, wodurch die Maglichkeit gegeben ist, interaktiv den Debugger aufzurufen. Das dieser Situation entsprechende Debugger-Fenster ist in Abbildung 3-8 gezeigt. Man erkennt aus dem angezeigten Teil des Methodenstapels, daB an eine Auspriigung der Klasse SuperzAhlwerk zuerst die Methode initialize der eigenen ~lasse, sodann die gleichnamige Methode der Klasse ZAhlwerkMitDatum und schlieBlich jene der Klasse ZAhlwerk aktiviert wurde. 1m Arbeitsbereich zum Editieren der ausgewiihlten Methode ist die Anweisung, die zur Unterbrechung geftihrt hat, hervorgehoben. 1m Inspektor des Empfangers kannen die Instanzvariablen (register, datum und register2) angewiihlt und das von ihnen referenzierte Objekt angezeigt werden. An der Stelle des Programmhaltepunktes wurde die Instanzvariable register bereits initialisiert, wahrend die anderen Instanzvariablen noch mit dem Objekt nil belegt sind, was aber aus der Abbildung nicht zu ersehen ist.
3.3.2 Die Klassenhierarchie der Zihlwerke An dieser Stelle solI die in den bisherigen Beispielen entworfene Klassenhierarchie nochmals iiberblicksmiiBig betrachtet werden, und zwar getrennt nach Struktur, Verhalten und Implementierung.
Kiasse Object
Za.h[werk Zah!werkMltDatum Superzahfwerk
Tabelle 3-1 Vererbung von Struktur in der Hierarchie von Ziihlwerken
3.3 Beispiel: Erweiterte Zlililwerke
119
Tabelle 3-1 zeigt die Position der Klassen in der Klassenhierarchie und die in den Klassen definierten sowie die aus den Oberklassen geerbten Instanzvariablen. Die jeweilige Unterklasse ist, was die Struktur ihrer Auspragungen betrifTt, eine Erweiterung ihrer Oberklasse, da es in Smalltalk nicht moglich ist, Instanzvariable von der Vererbung auszuschlieBen. Ein ZahlwerkMitDatum etwa ubernimmt durch Vererbung die Struktureigenschaften einer Instanz der Klasse Zahlwerke (es besitzt wie dieses eine Komponente register) und erweitert diese durch eine zusatzliche Komponente datum. Die von den jeweiligen Oberklassen geerbten Instanzvariablen sind in Tabelle 3-1 durch Schattierung gekennzeichnet. Fur die gezeigten Klassen bleibt auch die Bedeutung der Instanzvariablen bei ihrer Vererbung in eine Unterklasse gleich, so hat etwa die Instanzvariable datum in der Klasse Superzahlwerk die gleiche Bedeutung wie in der Klasse lahlwerkMitDatum, sie halt in Auspragungen beider Klassen das Datum des letzten Ziihlwerkstarts fest. In diesem Fall sind die Auspragungen der Unterklassen in ihrer Struktur und in der Bedeutung ihrer Komponenten Erweiterungen der Auspragungen der Oberklassen. Dies entspricht einer sinnvollen Anwendung der Vererbungsbeziehung. was jedoch wegen des Fehlens einer statischen Typisierung und wegen der Moglichkeit, Methoden in Unterklassen beliebig redefinieren zu konnen, in Smalltalk nicht erzwungen wird.
Verhalten/Methoden
start Zahlwerk
self register: 0
Zahlwerk MitDatum
super start self datum: Date today
Superzahlwerk
super start. self register2: 0
lies zahler stand
lies Datum
self register
Tabelle 3-2 Vererbung von Verhalten in der Hierarchie von Zahlwerken Die in dies en Klassen definierten und fUr das Verhalten wesentlichen Methoden sind in Tabelle 3-2 zusammengestellt.
120
3 Ein erster Einsatz von Smalltalk
Es ist unumglinglieh, daB die Methode start in jeder Klasse neu festgelegt werden muB, weil beim Neustart eines Ziihlwerkes jede Komponente zuriiekzusetzen ist. Diese Methoden sind jedoeh so realisiert, daB sie nur die in der jeweiligen Klasse selbst definierten Instanzvariablen mit einem Startwert belegen und fUr die geerbten Instanzvariablen auf die in der Oberklasse defmierte Methode start zuriiekgreifen. Beispielsweise setzt die Methode start der Klasse Superzahlwerk die Instanzvariable register2 direkt auf Null (self register2: 0), das Zuriieksetzen der geerbten Instanzvariablen wird jedoeh nieht direkt durehgefUhrt, sondern dureh Aktivieren der Methode start in der Oberklasse (super start) veranlaBt. Die Methode start wird somit zwar formal in jeder Klasse neu festgelegt, sie erweitert jedoeh nur das geerbte Verhalten, ohne dieses zu verandern und damit funktional zu redefmieren. Die Vererbung der Methoden zahle und liesZahlerstand kann fUr die Klassen ZAhlwerkMitDatum und SuperzAhlwerk untersehiedlieh bewertet werden. Auspriigungen der Klasse ZAhlwerkMitDatum verhalten sieh vollkommen gleieh wie Instanzen von zahlwerk und zwar nieht nur, was die Namen der Methoden (Signaturen) anbelangt, sondern aueh was die Methoden selbst betrifft, weil in jedem Fall ein und derselbe Code ausgefUhrt wird. Eine Veranderung dieser Methoden wird daher aueh in beiden Klassen wirksam. In diesem Sinne sind Auspriigungen von ZAhlwerkMitDatum aueh Ziihlwerke, weil sie iiberall dort sieher eingesetzt werden konnen, wo Instanzen von ZAhlwerk erwartet werden. Die Umkehrung gilt nieht, wenn ein Objekt der Klasse ZAhlwerkMitDatum erwartet wird, kann an dieses die Naehrieht liesDatum gesendet werden, die von einem "normalen" Ziihlwerk nieht verstanden wird. In dies em Sinne entsprieht hier die Superklasse-SubklasseBeziehung einer Supertyp-Subtyp-Beziehung. Der Polymorphismus der Methoden zAhle und liesZAhlerstand entsprieht bei Betraehtung der Klassen ZAhlwerk und ZAhlwerkMitDatum einem Teilmengenpo!ymorphismus (inclusion polymorphism) weil er dureh die erwiihnte Methodenvererbung entsteht und nieht dureh Benennung an sieh versehiedener Methoden mit gleiehem Namen erzwungen wird. Die Bezeiehnung "Teilmengenpolymorphismus" folgt aus der Ansehauung, daB die Menge der Auspriigungen der Subklasse eine Teilmenge der Auspriigungen der Superklasse ist. In Smalltalk wird jedoeh jedes Objekt als Auspriigung genau seiner Klasse betraehtet und nieht gleiehzeitig aueh als Auspriigung der Oberklassen. Das Verhiiltnis der Klasse SuperzAhlwerk zu ihrer Superklasse ZAhlwerkMitDatum ist hinsiehtlieh der Methodenvererbung anders zu bewerten, da hier die betraehteten Methoden zAhle und liesZAhlerstand in der Subklasse redefmiert werden. Die Methode SuperzAhlwerk»liesZAhlerstand beispielsweise greift nieht auf die gleiehnamige Methode der Superklasse zuriiek, sondern veranlaBt einen eigenstiindigen Ablesevorgang des Ziihlerstandes. Ahnliehes gilt fUr die Methode SuperzAhlwerk»zahle, welche zwar dureh super zAhle auf die entspreehende Methode der Superklasse zuriiekgreift, was
3.3 Beispiel: Erweiterte Zahlwerke
121
jedoch eher einer Wiederverwendung von Code (code reuse) entspricht als einer Erweiterung ererbten Verhaltens.
3.3.3 Zusammengesetzte Ziihlwerke Die zweite der erwahnten Varianten der Realisierung von erweiterten Zahlwerken besteht in der Konstruktion eines zusammengesetzten Zahlwerkes, das als Komponenten je ein Zahlwerk der bereits definierten Arten Zahlwerk und ZahlwerkMitDatum besitzt und das die erwartete Funktionalitat dadurch erfiillt, daB es auf die Methoden seiner Komponenten in geeigneter Weise zuriickgreift. Programm 3-9 zeigt die Defmition der Klasse Verbundzahlwerk samt den Methoden zur Erzeugung und Initialisierung ihrer Auspragungen. Da ein Verbundzahlwerk keine Spezialisierung eines bereits definierten Zahlwerkes ist, wird es in die Klassenhierarchie als SubkIasse von Object eingeftigt.
Object subclass: 4I=Verbundzahlwerk instanceVariableNames: 'zw1 zw2 ' classVariableNames: " poolDictionaries: " category: 'MeBinstrumente' Verbundzahlwerk methodsFor: 'initializing'
initialize
"Assemblieren und Initialisieren eines Verbundzllhlwerkes." zw1 := ZahlwerkMitDatum new. zw2 := Zahlwerk new.
(1)
Verbundzahlwerk class methodsFor: 'instance creation'
new
"Erzeugen eines initialisierten Zllhlwerkes." "super new initialize (1) Hier wird der hisher verborgene Unterschied zwischen initialize und start deutlich.
Programm 3-9
Die Klasse Verbundzahlwerk
3 Ein erster Einsatz von Smalltalk
122
Die flir die Bedienung eines Verbundzahlwerkes vorzusehenden Methoden sind in Programm 3-10 zusammengefaBt. Verbundz~hlwerk
methodsFor: 'accessing'
liesDatum
"Feststellen des Datumsvermerkes." (1)
"zw1 liesDatum Verbundz~hlwerk
methodsFor: 'operating'
liesZiihlerstand
"Feststellen des Zlihlerstandes."
"zw1
liesZ~hlerstand
+ (zw2
lies~hlerstand
* 1000000)
start
"Zurucksetzen des Zlihlwerkes."
zw1 start. zw2 start zihle
"Zahlen."
zw1
z~hle.
"Wenn nach einem Zahlvorgang das erste Register 0 zeigt, dann hat ein Oberlauf stattgefunden, dieser wird im zweiten Register gezahlt."
zw1 liesZ~hlerstand = 0 ifTrue: [zw2 z~hle] (1) Delegation des Lesevorganges an die Komponente, welche die Datumsfunktion einbringt.
Programm 3-10 Methoden zur Bedienung eines Verbundzahlwerkes Der Aufbau eines dieser Definition entsprechenden Verbundzlihlwerkes ist in Abbildung 3-9 gezeigt. Hier ist auch der Vorgang skizziert, der beim Senden der Botschaft liesDatum an ein Verbundzahlwerk ablauft. Das Objekt vzw empfangt die Botschaft liesDatum (1), sucht und findet in seiner Klasse die entsprechende Methode (2), welche die Anforderung durch eine gleichnamige (iibedadene) Methode an seine Komponente zw1 weitergibt (3), die ihrerseits in ihrer Klasse nach der zugehOrigen Methode sucht (4) und diese auch fmdet. Als Ergebnis wird jenes Datumsobjekt zuriickgegeben, das von der Instanzvariablen datum der in das Verbundzahlwerk eingebauten Auspragung der Klasse Z~hlwerkMitDatum gehalten wird.
3.3 Beispiel: Erweiterte Zahlwerke
(2)
,
123
.
• {a}
I
•
.. liesDatum <doH:>
Abbildung 3-9
Inspektion eines Verbundzahlwerkes im Objektraum
Verbundzlihlwerke sind ein Beispiel fUr komplexe Objekte, das sind Objekte, die selbst wieder aus (moglicherweise ebenfalls komplexen) Objekten zusammengesetzt sind. Allerdings sind in einem technischen Sinn in Smalltalk aIle Objekte (sofern sie Instanzvariable besitzen) komplexe Objekte, da die Instanzvariablen in jedem Fall mit Objekten belegt sind. Es sei auch darauf hingewiesen, daB in der Klasse Verbundzahlwerk keine namenskonformen Zugriffsmethoden fUr die Instanzvariablen zw1 und zw2 vorausgesetzt werden, vielmehr wird in den gezeigten Methoden immer direkt auf die Instanzvariablen zugegriffen. Dadurch werden die Komponenten eines
124
3 Ein erster Einsatz von Smalltalk
Verbundziihlwerkes von auBen nieht zugreitbar, sodaB es beispielsweise nieht moglieh ist, einer Komponente direkt einen Zahlbefehl zu senden und dadureh das Zahlwerk zu manipulieren. Allerdings ist die dadureh erreichte Sieherheit nur sehwaeh, da systemnahe Methoden verfUgbar sind, welehe es erlauben, die fUr ein Objekt defmierten Instanzvariablen zu erfragen und diese aueh direkt an Objekte zu binden. Eine Mutatormethode ist aueh deswegen nieht erforderlieh, weil die Komponenten eines Verbundzahlwerkes bei dessen Initialisierung ein fUr alle Mal zugeordnet und nieht mehr ausgetauseht werden sollen. Ein Vergleieh der beiden Varianten von erweiterten Ziihlwerken zeigt, daB ein Verbundzahlwerk einen einfaeheren Aufbau als ein Superzahlwerk aufweist. Es ist aus vorgefertigte Komponenten zusammengesetzt, die nur uber "offentliehe" Methoden angesproehen, also nur "naeh Gebrauehsanweisung" verwendet werden, wahrend ein Superzahlwerk auf den Zugriff auf geerbte Struktur und die Redefinition geerbter Methoden angewiesen ist. Eine in der Klasse ZAhlwerkMitDatum notwendige Fehlerkorrektur oder eine Abanderung der Implementation (beispielsweise eine Umbenennung der Instanzvariablen register mit entspreehender Anderung der privaten Zugriffsmethoden) hat, sofern das offentliehe Protokoll gleiehbleibt, auf ein Verbundziihlwerk keine Auswirkung, was fUr ein Superzahlwerk nieht ausgesehlossen werden kann. Aus solchen Grunden ist der zweiten Variante (VerbundzAhlwerk) der Vorzug gegenuber der ersten Variante (SuperzAhlwerk) zu geben. Samtliehe der vorgestellten Klassen besehreiben Zahlwerke, die fUr ihre Bedienung ein gleiehes Protokoll besitzen, das dureh die Selektoren start, zAhle und liesZAhlerstand eharakterisiert ist. 1m Falle der Klassen VerbundzAhlwerk und ZAhlwerk (samt ihren Unterklassen) entsprieht der Polymorphismus dieser Methoden einem ad hoc-Polymorphismus, da diese Klassen nieht in Vererbungsbeziehung stehen und die Gleichnamigkeit der Methoden willkurlieh erzeugt wurde.
3.4
Visualisierung von Zihlwerken
In dies em Kapitel wurde bisher an Hand einfacher Beispiele gezeigt, wie Objekte der Realitat modelliert und in Small talk realisiert werden konnen. Ebenso wurde versueht, einen ungefcihren Eindruek von einigen Werkzeugen der Smalltalk-Entwieklungsumgebung zu vermitteln. Dieser einfUhrende Uberbliek soll noeh mit einem Hinweis auf die Mogliehkeiten der Visualisierung von Objekten und der Gestaltung von Benutzersehnittstellen abgesehlossen werden.
3.4 Visualisierung von Zahlwerken
125
Die bisher in den Beispielen erzeugten Objekte, zumeist Auspragungen einer der definierten Zahlwerksklassen, spielten die Rolle eines Modelles (model) fUr ein in der Realitat existierendes Objekt. Um solche Objekte in einer Anwendung im Rahmen einer Benutzeroberflache wirksam zu machen, konnen sie einerseits mit Objekten gekoppelt werden, welche die Rolle einer visuellen Sicht (view) fUr Modellobjekten spielen und andererseits mit Objekten, welche die Funktion von Schnittstellen zum Verhalten der Modellobjekte (controller) bieten. Die Kommunikation zwischen solchen zusammengehorigen und untereinander in Abhangigkeit stehenden Objekten erfolgt durch einen speziellen Mechanismus, der an einer spateren Stelle noch im Detail behandelt wird. Fur die interaktive und visuelle Konstruktion von Benutzeroberflachen und die automatische Generierung von view- und controller-Objekten fUr gegebene model-Objekte stehen Werkzeuge zur VerfUgung, deren Arbeitsweise in aller Kurze demonstriert werden soll. Das Ziel ist die Gestaltung und Realisierung einer Benutzeroberflache fUr ein Zahlwerk in Form eines Fensters mit einer Anzeige fUr den Zahlerstand und je einer Schaltflache fUr das Starten und Zlihlen. ApplicationModel subclass: #VisuaIZa.hlwerk instanceVariableNames: 'register' classVariableNames: " pool Dictionaries: " category: 'MeBinstrumente' VisualZahlwerk methodsFor: 'private-accessing' register "register register: anlnteger register llIl1wl: an Integer
Visuallahlwerk methodsFor: 'initialize' initialize
"Initialisieren eines visualisierbaren Zahlwerkes." register := 0 asvalue Visuallahlwerk class methodsFor: 'instance creation' new
"Erzeugen eines initialisierten visualisierbaren Zlihlwerkes." "super new initialize
Programm 3-11 VisualZahlwerk, eine visualisierbare Variante von Za.hlwerk
126
3 Ein erster Einsatz von Smalltalk
Da das dem Werkzeug zugrundeliegende Methodengeriist (framework) geringftigige Anderungen in der Klasse Zahlwerk verlangt, ist deren Definition unter dem Namen VisualZahlwerk in Programm 3-11 gezeigt, wobei die notwendigen Anderungen dureh Unterstreiehung hervorgehoben sind.
VisualZahlwerk methodsFor: 'operating'
liesZihlerstand
"Feststellen des Z1lhlerstandes." A
reg ister lla.l.u.e.
start
"Zurticksetzen des Ziihlerwerkes." self register: 0
zihle
"Z1lhlen." self register: «self register
lla.l.u.e. + 1) rem: 1000000)
Programm 3-12 Methoden zur Bedienung von visualisierbaren Zahlwerken Neben der Positionierung der Klasse als Subklasse von ApplicationModel beziehen sieh die notwendigen Anderungen auf einen einzigen Punkt: der Wert einer in der Ansicht darzustellenden Instanzvariablen muB in einem "Verpaekungsobjekt" (eine Auspragung der Klasse ValueHolder) eingehiillt sein und darf auf diese Weise nur indirekt von der Instanzvariablen referenziert werden. Die fUr das Verstandnis der Vorgangsweise muB erwahnt werden, daB jede Instanz von ValueHolder eine Instanzvariable value besitzt, iiber die das "zu haltende" Objekt referenziert wird. In Programm 3-13 sind die namenskonformen Zugriffsmethoden auf diese Instanzvariable gezeigt. Man erkennt, daB die Mutatormethode nieht nur die Funktion hat, ein neues Objekt an die Instanzvariable zu binden, sondern auch eine N aehrieht iiber die erfolgte "Wertanderung" zu verbreiten. Dies gesehieht dureh eine als "Abhangigkeitsmechanismus" bezeiehnete Vorgangsweise, die an einer spateren Stelle (Absehnitt 14.1.2) irn Detail besehrieben ist. Fiir ein visualisierbares Zahlwerk bedeutet das, daB immer dann, wenn sieh sein Zustand (konkret: das in einer Instanz der Klasse ValueHolder eingehiillte Register) dureh einen Ziihlvorgang oder dureh einen Neustart) geandert hat, das angekoppelte Ansiehtsobjekt den neuen Zustand seines Modellobjektes anfordert und in der Ansieht darstellt.
3.4 Visualisierung von Ziihlwerken
127
ValueHolder methodsFor: 'accessing'
value (1)
"value value: aValue value := aValue. self changed: #Value
(2)
(1) Das "gehaltene" Objekt wird zuriickgegeben.
(2) Nach dem Einsetzen eines neuen Objektes in den valueHolder wird den tiber einen als Abhangigkeitsmechanismus (Abschnitt 14.1.2) bezeichneten Mechanismus angekoppelten Objekten mitgeteilt, daB sich dec Zustand des Objektes geandert hat.
Programm 3-13 Ausschnitt aus der Klasse ValueHolder
-
-
'1
aVafueHo!der einVisual liihiwerk register, self
vatue
rneinZanlwork
Abbildung 3-10 Inspektion eines VisualZiihlwerkes im Objektraum
128
3 Ein erster Einsatz von Smalltalk
Abbildung 3-10 veranschaulicht ein Objekt der Klasse VisualZAhlwerk und die Belegung seiner Instanzvariablen register mit einer Instanz von ValueHolder. Nach dieser Vorbereitung kann der Vorgang des interaktiven Entwurfes einer Benutzeransicht fur ein Zahlwerk skizziert werden.
Abbildung 3-11 Werkzeuge zum Entwurf einer Benutzeransicht
3.5 Aufgaben
129
In Abbildung 3-11 sind einige daftir verfUgbare Werkzeuge abgebildet. In der Mitte befindet sich eine Entwurfsflache (Canvas) fUr ein Ansichtsfenster, in welches aus einem Repositorium (Palette) von einsetzbaren Funktionseinheiten Bestandteile der zu gestalten den Benutzeroberflache entnommen werden kannen. Den ausgewahlten Bestandteile sind sodann mit Hilfe eines Werkzeugen (Properties Tool) Eigenschaften zuzuordnen, unter anderen auch jene Methoden des Modellobjektes, die mit den Bestandteilen verbunden werden soIlen. Ein weiteres Werkzeug (Canvas Tool) ermaglicht das Ausrichten der ausgewahlten Komponenten der Ansicht und auch deren "Installation" fUr ein ModeIlobjekt. Auf der Abbildung ist durch Pfeile angedeutet, daB im spezieIlen Fall als Elemente des Ansichtsfensters ein Textfeld (fUr die Anzeige des Zlihlerstandes) und zwei Schaltflachen (Action Button) fUr das Starten und Zlihlen vorgesehen wurden. Weiterhin ist ersichtlich, daB der rechten Schaltfliiche durch das Properties Tool die Bezeichnung (Label) "Ziihlen" und die Aktion (Action) #zlthle zugeordnet sind. Die Aktion bezeichnet die Methode, die beim Betiitigen der Schaltfliiche an das angekoppelte Modellobjekt gesendet wird, im konkreten Fall also die Methode zum Auslasen eines Zlihlvorganges. Das der zu sendenden Nachricht (zahle) vorangesetzte Nummernzeichen erkliirt sich dadurch, daB Nachrichten Auspriigungen der Klasse Symbol sind, deren Literaldarstellung mit dem Zeichen ,,#" beginnt. Zu Testzwecken kann tiber das Canvas Tool ein Modellobjekt erzeugt und eine Ansicht dafUr geatTnet werden. 1m FaIle von Fehlern kannen diese interaktiv mit Hilfe eines Debuggers und Inspektors lokalisiert und entweder direkt oder tiber einen Browser beseitigt werden. Selbstverstandlich kannen so erzeugte Benutzeroberfliichen auch tiber Programme geatTnet und ihre Komponenten angesprochen werden.
3.5
Aufgaben
Aufgabe 3.1
Statistik.ziihlwerke
Wenn Ziihlvorgiinge tiber einen Zeitraum von mehreren Tagen erfolgen sollen, kann es von Interesse sein, den am Ende jeden Tages festgestellten Zlihlerstand zu protokollieren, sodaB fUr jeden Tag, beginnend mit dem Tag des ersten Zlihlvorganges, die kumulative Haufigkeit der gezlihlten Ereignisse zur VerfUgung steht. Man entwerfe eine Klasse Statistiklahlwerk, deren Auspriigungen die gewiinschte Eigenschaft aufweisen und ftige diese in die Klassenhierarchie der Zlihlwerke ein.
130
3 Ein erster Einsatz von Smalltalk
Losung von Aufgabe 3.1 Programm 3-14 zeigt, daB die Klasse Statistikzahlwerk als Subklasse von lahlwerk eingerichtet und mit der zusiitzlichen Instanzvariablen histogramm versehen wurde. Bei der Initialisierung wird diese Instanzvariable mit einem leeren Verzeichnis (Auspriigung der Klasse Dictionary) belegt. Bei jedem Ziihlvorgang wird der abgelesene Zahlerstand unter dem Tagesdatum in das Verzeichnis eingetragen, wobei eine fUr das gleiche Datum vorliegende Eintragung iiberschrieben wird, da Verzeichnisse die Eindeutigkeit des Schliissels sicherstellen. Die kumulativen Haufigkeiten werden somit fUr jeden Tag, an dem ein Ereignis gezahlt wurde, in das Verzeichnis eingetragen. zahlwerk subclass: :fI:Statistikzahlwerk instanceVariableNames: 'histogramm ' classVariableNames: " pool Dictionaries: " category: 'Messinstrumente' Statistikzahlwerk methodsFor: 'initialize' initialize
"Initialisieren des Zahlwerkes." super initialize. histogramm := Dictionary new Statistikzahlwerk methodsFor: 'operating' start
"Zuriicksetzen des Zahlwerkes." super start. histogramm := Dictionary new zahle
"Zahlen." super zahle. histogramm at: Date today put: self liesZahlerstand
Programm 3-14 Die Klasse Statistikzahlwerk
Aufgabe 3.2 PlusMinus-Ziihlwerke Man definiere eine Klasse PlusMinusZahlwerk, deren Auspragungen den jeweiligen Ziihlerstand nieht nur um eins erhOhen, sondem auch um eins vermindem konnen.
4
Objektsammlungen
Objekte, die dazu entworfen sind, mehrere Objekte zu umfassen oder zu enthalten, werden Sammlungen, Kollektionen (collections) oder Sammelbehiilter genannt, umgekehrt werden die in ihnen enthaltenen Objekte als Inhalt oder als Elemente des Sammelbehalters bezeichnet. Sammlungen mussen immer dann eingesetzt werden, wenn mehrere Objekte zu einer Einheit zusammengefaBt und durch einen einzigen Namen bezeichnet werden sollen. In manchen Fallen haben Behalter nur die technische Funktion, andere Objekte zusammenzuhalten, ohne dabei eine eigene Bedeutung als Objekt der Realitlit des Anwendungsgebietes zu tragen. Dies ist beispielsweise der Fall, wenn im Objektraum die Tatsache darzustellen ist, daB Person en eine oder mehrere, auch beliebig viele Adressen haben konnen. Diese werden in einem Behalterobjekt gesammelt und mit einem einzigen Namen bezeichnet, ohne daB der Sammelbehalter dabei mit einem eigenen Begriff in Zusammenhang gebracht wird. In anderen Fallen konnen Behalterobjekte selbst eine Bedeutung in der zugrundeliegenden Realitat haben, etwa dann, wenn der Behalter eigene Eigenschaften aufweist, die sich nicht ausschlieBlich aus den Eigenschaften der Inhaltselemente ergeben. Beispielsweise konnen die Kunden einer Firma oder die Bucher einer Bibliothek als Sammlungen betrachtet werden, die als solche einen eigenen Wert haben, was sich auch in Bezeichnungen wie "Kundenstock" oder "Bucherbestand" auBert. Sammelbehalter konnen durch unterschiedliche Eigenschaften ihres Aufbaues und ihres Verhaltens charakterisiert werden. Sie konnen eine fest vorgegebenes oder aber ein belie big veranderbares Fassungsvermogen haben, ihre Elemente konnen ungeordnet oder aber nach bestimmten Kriterien in den Behalter eingef1igt werden und sind entweder wahlfrei oder nur in bestimmter Reihenfolge wieder zu entnehmen. Die Smalltalk-Klassenhierarchie enthalt bereits eine groBe Zahl an Klassen, deren Auspragungen Kollektionen mit verschiedenen Eigenschaften sind. In der Folge werden nur die wichtigsten davon erwahnt und ihre Eigenschaften kurz vorgestellt. G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
132
4 Objektsammlungen
4.1
Die Hierarchie der Kollektionen
Abbildung 4-1 zeigt einen kleinen Ausschnitt aus der Teilhierarchie der Sammelbehlilter. ~---~~
.... .. ....... .. ~
Abbildung 4-1
~
~
~.~
..
~~
..
~~
..
~ . ~ . - . - . -----------
Ausschnitt aus der Klassenhierarchie der Kollektionen
An der Spitze der Teilhierarchie aller Sammelbehalterklassen steht die abstrakte Klasse Collection, sie legt das gemeinsame Verhalten aller BehaIterobjekte fest. Es ist ein Charakteristikum einer abstrakten Klasse, daB sie fur aIle Unterklassen Methoden bereitsteIlt, die auf wenigen spezifischen und in den Unterklassen zu implementierenden Methoden aufbauen. Fur SammeibehaIter sind letztere lediglich die Methoden: Collection>>add: newObject
"Fuge newObject als weiteres Element in den Empfanger ein und antworte mit newObject Diese Botschaft wird von Instanzen der Subklassen von ArrayedCoilection nieht verstanden."
4.2 Generelle Methoden von Kollektionen
133
Collection>>remove: oldObject ifAbsent: anExceptionBlockO "Entferne oldObject aus dem Empfanger. So lite der Empfanger mehrere Elemente enthalten, die gleich oldObject sind, so wird nur eines entfernt. Enthalt der Empfanger kein Element, das gleich oldObject ist, so wird das Ergebnis der Evaluation von anExceptionBlock als Riickgabeobjekt geliefert, ansonsten oldObject. Diese Botschaft wird von instanzen der Subklassen von SequenceableColiections nieht verstanden."
Collection>>do: anOperationBlock1 "Evaluiere anOperationBlock1 mit jedem Element des Empfangers als Argument."
welche durch den Ausdruck self subclassResponsibility die Verantwortung fUr die konkrete Implementation an die Unterklassen delegieren. Diese Methoden werden in der Folge als "Schliisselmethoden" bezeichnet, weil erst durch sie die in der Klasse Collection festgeschriebene Funktionalitat den Auspragungen der Unterklassen erofi'net wird, ihre Bedeutung geht aus den Kommentaren hervor. Weiterhin erkennt man aus den Kommentaren, daB nicht aIle Methoden fUr alle Unterklassen sinnvoll sind. Es sind also die Unterklassen nicht in jedem Fall eine Spezialisierung ihrer Oberklassen, mit anderen Worten, nicht jede dieser Vererbungsbeziehungen entspricht konzeptionell einer "is-a-Beziehung". Auspragungen von Unterklassen konnen auch nicht in jedem Fall an die Stelle einer Auspragung einer Oberklasse treten, die Klassenhierarchie entspricht also auch nicht einer Typhierarchie. Die Struktur der Klassenhierarchie von Small talk entspricht in vielen Bereichen einer Pragmatik der Wiederverwendung von Code [26], [20]. Beispielsweise ist es aus konzeptioneller Sicht nicht gerechtfertigt, die Klasse Dictionary als Unterklasse von Set zu positionieren, weil ein Verzeichnis keine besondere Art einer Menge ist, was sich auch darin auBert, daB die beiden Klassen sehr verschiedene Protokolle besitzen. Allerdings sind Verzeichnisse als Mengen von Zuordnungen (Instanzen der Klassen Association) zwischen "Schltisselobjekten" und "Wertobjekten" implementiert, wodurch sich die Moglichkeit der Wiederverwendung von Methoden ergibt, die der Klasse Set zugeordnet sind.
4.2
Generelle Methoden von Kollektionen
In der Folge werden einige Methoden zusammengefaBt, die fUr alle Sammelobjekte charakteristisch sind. Viele dieser Methoden werden in den Unterklassen redefmiert, manche auch fur ungtiltig erkliirt.
134
4 Objektsammlungen
4.2.1
Kardinalitiit und Kapazitiit
Jede Ansammlung von Objekten hat eine KardinaliHit (Anzahl der enthaltenen Elemente) und eine KapaziHit (Fassungsvermogen). KlassenBrowser
Collection methodsFor: 'accessing' size
"Bestimmen der Anzahl der Elemente des Empfangers (Kardinalitat}."
I tally I tally:= O. self do: [:each I tally := tally + 1J. "tally
(1)
capacity
"Bestimmen der der momentanen Kapazitat des Empfangers."
(2)
"self size
(1) Hier wird auf die spezifische Methode do: einer konkreten Unterklasse zuruckgegritTen. (2) Filr Behliiter, deren Kapazitlit groBer ist als ihre Kardinalitat, wird diese Methode redefiniert.
Programm 4-1
Zugriff auf die GroBe eines Sammelbehlilters
Fur viele Arten von Behiiltern sind Kardinalitiit und Kapazitiit immer gleich. Beispielsweise sind Felder (Instanzen von Array) oder Zeichenketten (Instanzen einer Subklasse von String) immer voll gefiillte Behlilter, sodaB ihre Kardinalitlit und ihre Kapazitlit gleich sind. Es gibt aber auch Behlilter, die jeweils groBer dimensioniert sind, als es ihrer momentanen Kardinalitlit entspricht, sie besitzen also eine "Vorratskapazitlit" fUr zusiitzliche Elemente. Ein Beispiel dafUr sind Mengen (Instanzen von Set), deren Elemente in Hashtabellen gespeichert sind, fUr die ein maximaler Besetzungsgrad vorgegeben ist, so daB ihre Kapazitlit stets groBer als ihre Kardinalitiit ist. Auch Auspriigungen der Klasse OrderedCollection konnen eine Kapazitiit haben, die groBer als ihre Kardinalitlit ist. Die Unterscheidung zwischen Kardinalitiit und Kapazitlit erfolgt auf der Basisebene des konzeptionellen Objektraumes und setzt voraus, daB bei der Zlihlung der Elemente eines Behlilters nur "Nutzelemente" betrachtet werden.
4.2 Generelle Methoden von Kollektionen
135
N utzelemente sind so1che Elemente, die letztlich durch "Verwaltungsmethoden" eines Behalters in diesen eingebracht oder daraus wieder entfemt wurden. In einem spateren Abschnitt wird im Rahmen einer systemnaheren Betrachtung erlautert, daB in einem technischen Sinn ein Sammelobjekt immer voll muB, moglicherweise aber Elemente enthlilt, die durch offentliche Zugriffsmethoden nicht erreicht werden konnen. Programm 4-1 zeigt die allgemeinen Methoden fUr die Feststellung von Kardinalitat und Kapazitat einer Kollektion. Die Methode Collection»size bestimmt die Kardinalitat durch Abzahlen der Elemente. In vielen Behalterklassen wird diese Methode durch eine etl1zientere ersetzt.
4.2.2 Einffigen und Entfernen von Elementen Wie bereits erwlihnt, werden die elementaren Operationen zum EinfUgen und Entfemen einzelner Elemente einer Kollektion erst durch die "Schliisselmethoden" in den konkreten Unterklassen implementiert. Auf diesen autbauende Methoden rum Einfligen und Entfemen von mehreren Objekten sind in den Programmen 4-2 und 4-3 zusammengefaBt, sie werden in den Beispielen dieses Abschnittes wiederholt verwendet. KlassenBrowser Collection methodsFor: 'adding'
addAlI: aCollectionOfNewElements
"Einfilgen aller Elemente des Argumentes in den Empfanger. Oas Ruckgabeobjekt ist das Argument aColiectionOfNewElements." aColiectionOfNewElements do: [:each I self add: each]. " aColiectionOfNewElements
(1)
(1) Hier wird auf die spezifischen, in den Unterklassen zu implementierenden "Schliisselmethoden" zuriickgegriffen.
Programm 4-2
EinfUgen von Elementen in Sammlungen
Man beachte, daB sowohl die Methoden zum Einfligen und Entfemen einzeIner Elemente (Collection»add : newObject, Collection»remove: oldObject) als auch die entsprechenden Methoden flir ganze Objektsammlungen (Coliection»addAII: aColiection, Coliection»removeAII: aColiection) als
136
4 Objektsammlungen
Riickgabeobjekt nicht den veranderten Behalter selbst liefern, sondern die jeweils eingefiigten oder entfernten Elemente beziehungsweise Elementsammlungen. Das Nichtberiicksichtigen dieser Situation ist eine Mufige Ursache fUr Fehler. Mochte man den in seinem Inhalt veranderten Sammelbehalter zur VerfUgung haben, so kann dies durch kaskadiertes Senden der Botschaft yourself (vergleiche Programm 4-5) erreicht werden.
Collection methodsFor: 'removing' remove: oldObject
"Entfernen von oldObject aus dem Empfanger. Es wird ein Fehlersignal gesetzt, wenn oldObject kein Element des Empfangers ist." A
self remove: oldObject ifAbsent: [self notFoundError]
(1)
removeAlI: aCollectionOfOldElements
"Entfernen aller Elemente des Argumentes aus dem Empfanger. Das Ruckgabeobjekt ist das Argument aCollectionOfOldElements."
aColiectionOfOldElements do: [:each I self remove: each]. A aColiectionOfOldElements Programm 4-3
(1)
Entfernen von Elementen aus Sammlungen
4.2.3 Enumeration Enumerationsmethoden veranlassen ein Sammelobjekt, die Kontrolle tiber die wiederholte Evaluation eines als Argument beigestellten Blockes zu iibernehmen und zwar derart, daB der Block mit jedem Element des Behiilters als Blockargument genau einmal evaluiert wird. Die Reihenfolge der Aufziihlung des Inhaltes hangt von der Art des Sammelbehalters abo 1m vorangehenden Kapitel wurde bereits auf Enumerationsmethoden fUr die Realisierung von Kontrollstrukturen hingewiesen. AIle Enumerationsmethoden fUr Sammelobjekte greifen auf die Methode Collection>>do: zuriick, die fUr jede konkrete Unterklasse von Collection verftigbar sein muB.
Transformation der Elemente Die Methode Collection»collect: (Programm 4-4) sammelt die Ergebnisse der Transformation der Elemente des Empfangers in einem neuen Behiilter
4.2 Generelle Methoden von Kollektionen
137
von der gleichen Art wie der des Empfangers. Die Transformation wird durch den Argumentblock beschrieben, der als aktuelles Argument jeweils ein Element des Empflingers erhlilt und dessen Evaluationsergebnis ein Element des neuen Sammelbehlilters bildet. Es hlingt vom Argumentblock ab, ob der neue Behlilter mit denselben, eventuell in ihrem Zustand verlinderten Inhaltsobjekten gefullt wird, die auch der Empflinger enthlilt oder ob durch den Block andere Objekte als Ergebnis geliefert werden.
KlassenBrowser
Collection methodsFor: 'enumerating' collect: aTransformerBlock1
"Evaluation von aTransformerBlock1 mit jedem Element des Empfangers als Argument. Das RUckgabeobjekt ist ein neuer Behiilter der gleichen Art wie der Empfanger. in welch em die Evaluationsergebnisse gesammelt sind."
I newColiection I
newColiection := self species new. self do: [:each I newColiection add : (aTransformerBlock1 value: each)]. 1\ newColiection
(1) (2)
(1) Object>>Species liefert wie Object>>Class die Klasse des Empflingers. diese
Methode wird in einigen Klassen redefiniert. (2) Hier wird auf die spezifischen Methoden do: und add: einer Unterklasse zuriickgegrifTen.
Programm 4-4
Einsammeln transformierter Elemente
Beispiele fUr die Transformation von Elementen sind im Programm 4-5 gegeben. Hier wird zuerst ein leerer Behlilter als Ausprligung der Klasse Ordered Collection erzeugt und mit unterschiedlichen, jeweils mit einigen Elementen versehenen Sammelobjekten gefullt. Man beachte, daB in diesem Beispiel die Inhaltsobjekte des Behlilters ebenfalls Sammelbehlilter sind. Durch die in Punkt (2) angegebenen freien Methoden werden die Elemente einmal durch ihre Kardinalitliten und einmal durch ihre Kapazitliten ersetzt. Wiihrend die Kardinalitiiten aller Elemente gleich der GroBe ihres Inhaltes sind, gilt das nicht fur die Kapazitliten. Das erste Elemente der geordneten Sammlung ordColI, die Menge {I, 2, 3}, hat eine Kardinalitiit von 3 und eine Kapazitiit von 7.
138
4 Objektsammlungen
Workspace
"(0) Erzeugen einer geordneten Sammlung von Behiilterobjekten."
I ordColl1
ordColl := Ordered Collection new add: (Set with: 1 with: 2 with: 3); add: #(1 'eins' 2 'zwei'); add: 'drei'; yourself.
(1)
"(1) Ausgabe der geordneten Sammlung."
<printlt> OrderedColiection (Set (1 2 3) #(1 'eins' 2 'zwei') 'drei') "(2) Bestimmen der Kardinalitiiten und Kapazitiiten der Elemente." ordColl collect: [:elem I elem size]. <printlt> OrderedColiection (3 4 4) ordColl collect: [:elem I elem capacity]. <printlt> OrderedColiection (7 4 4) (1) Die Botschaft yourself bewirkt, daB dieser Ausdruck bei seiner Evaluation das Behlilterobjekt und nicht das zuletzt eingefligte Element liefert.
Programm 4-5
Beispiele fUr Enumeration mit Transformation
Auswahl von Elementen Die Methoden Collection»select: und Collection»reject: (Programm 4-6) erzeugen einen neuen Behiilter der gleichen Art wie der Empfanger und fUllen dies en mit jenen Objekten des Empfangers, mit denen die Evaluation des als Argument beigestellten Diskriminatorblockes true (false) ergibt. Programm 4-7 setzt das laufende Beispiel fort und demonstriert die Auswahl von Elementen. In Punkt (3) werden aus der geordneten Sammlung ordColi jene Elemente ausgewlihlt, deren Kapazitat gleich ihrer Kardinalitat ist, es sind dies die an zweiter und dritter Stelle stehenden Elemente. Diese Elemente werden durch den zweiten Teil des Ausdruckes mit Hilfe der Methode Collection»collect: durch ihre Klassen ersetzt. Man erkennt insgesamt, daB die Ausprligungen der Klassen Array (Felder) und ByteString (Zeichenketten) genau fur die GroBe ihres Inhaltes dimensioniert sind. Punkt (4) zeigt ein analoges Ergebnis ftir die Methode Collection»reject:.
139
4.2 Generelle Methoden von Kollektionen
KlassenBrowser Collection methodsFor: 'enumerating'
select: aDiscriminatorBlock1
"Das Riickgabeobjekt ist ein neuer Behalter von der Art des Empfangers mit jenen Elementen, mit denen die Evaluation des Argumentblockes true ergibt"
I newColiection I
newColiection := self species new. self do: [:each I (aDiscriminatorBlock1 value: each) ifTrue: [newColiection add: each)). " newColiection
reject: aDiscriminatorBlock1
"Das Riickgabeobjekt ist ein neuer Behlilter von der Art des Empfangers mit jenen Elementen, mit denen die Evaluation des Argumentblockes das Ergebnis false liefert." "self select: [:element I (aDiscriminatorBlock1 value: element)
Programm 4-6
=
false]
Auswahlen von Elementen
Workspace
"Fortsetzung von Programm 4-5" "(3) Auswahl jener Elemente, deren Kardinalitat und Kapazitat gleich ist und Bestimmen ihre Klassen." (ordColI select: [:elem I elem size = elem capacity]. <printlt> OrderedCollection (#(1'eins' 2 'zwei') 'drei') (ordColI select: [:elem I elem size = elem capacity]) collect: [:elem I elem class]. <printlt> OrderedCollection (Array ByteString)
"(4) Verwerfen jener Elemente, deren Kardinalitat und Kapazitat gleich ist und Bestimmen der Klassen der verbleibenden Elemente." (ordColl reject: [:elem I elem size = elem capacity]) collect: [:elem I elem class]. <printlt> OrderedCollection (Set)
Programm 4-7
Beispiele fUr Enumeration mit Auswahl
140
4 Objektsammlungen
Auffinden von Elementen Das gezielte Aufsuchen eines Elementes mit einer bestimmten Eigenschaft erfolgt durch die Methode Coliection>>detectifNone: (Programm 4-8), welche als Ergebnis das erste aufgefundene Element liefert, das die vorgegebene Eigenschaft erfUllt. Enthiilt die Kollektion mehrere Elemente mit der gesuchten Eigenschaft, so hiingt es von der Reihenfolge der Enumeration und somit von der Klasse des Empflingers ab, welches Element als Riickgabeobjekt geliefert wird. Wird kein entsprechendes Element gefunden, so wird das Ergebnis der Evaluation des als zweiten Parameter anzugebenden Ausnahmeblockes geliefert. Die Methode Collection»detect: greift auf diese Methode zuriick und gibt einen Ausnahmeblock vor, der ein Fehlersignal setzt, welches zu einer interaktiven Meldung Bement not found fUhrt. KlassenBrowser
Collection methodsFor: 'enumerating' detect: aDiscriminatorBlock1 ifNone: exceptionBlockO
"Evaluation von aBlock1 mit jedem Element des Empfangers als Argument Oas Ruckgabeobjekt ist das erste Element, mit dem die Evaluation des Blockes true ergibt."
self do: [:each I (aDiscriminatorBlock1 value: each) ifTrue: ["each]]. "exceptionBlockO value Collection methodsFor: 'testing' includes: anObject
"Feststellen (true I false), ob ein dem Argument gleiches Objekt im Empfanger enthalten ist."
self do: [:each I anObject = each ifTrue: ["true]]. "false
(1 )
(1) Man beachte, daB der Operator" 1\" den Riicksprung aus der Methode bewirkt.
Programm 4-8
Suchen eines Elementes, das eine Eigenschaft erftillt
Programm 4-9 zeigt in Punkt (5) ein Beispiel fUr das Autrmden eines Elementes. Die freie Methode in Punkt (6) verwendet die Methode Collection»includes:, welche feststellt, ob ein als Parameter anzugebendes Objekt (abhiingig von der Art des Empfangers dasselbe oder ein gleiches Objekt) im Sammelbehiilter enthalten ist oder nicht.
4.2 Generelle Methoden von Kollektionen
141
Workspace "Fortsetzung von Programm 4-5" "(5) Suchen des ersten Elementes, dessen Kapazitat groBer als 4 ist"
(ordColl detect: [:elem I elem capacity> 4]
<printlt> Set (1 2 3)
"(6) Feststellen, ob ein bestimmtes Array enthalten ist."
ordColl includes: Array new. <printlt> false ordColl includes: *(1 'eins' 2 'zwei').. <printlt> true Programm 4-9
Beispiele fUr das Aufsuchen eines Elementes
Akkumulation von Elementen Eine weitere in der Klasse Collection festgelegte und daher fUr aile Kollektionen verfUgbare Methode Collection»injectinto: dient zur Akkumulation der Elemente eines Behalters. Diese Methode (Programm 4-10) verlangt als Parameter ein Initialobjekt und einen Block, der die Akkumulationsvorschrift enthiilt. KlassenBrowser Collection methodsFor: 'enumerating' inject: initialValue into: anOperationBlock2 "Akkumulation eines bei der Evaluation des Argumentes, anOperationBlock2, erhaltenen Objektes, ausgehend von dem Startobjekt, startValue. Die Akkumulationsoperation ist im Argumentblock festgelegt.
I nextValue I
nextValue := initialValue. self do: [:each I nextValue := anOperationBlock2 value: nextValue value: each]. "nextValue Programm 4-10 Akkumulation von Elementen Selbstverstlindlich muB das Initialobjekt auf die Akkumulationsmethode reagieren konnen. 1m Programm 4-11 sind in Fortsetzung des laufenden Beispieles einige Anwendungen der Methode Collection»inject:into: gezeigt.
142
4 Objektsammlungen
Unter Punkt (7) wird eine arithmetische Akkumulation durchgeftihrt, indem der Startwert 0 sukzessive durch Addition um die KapaziHiten der Inhaltselemente von ordColi erhOht wird. Workspace
"Fortsetzung von Programm 4-5" "(7) Bilden der Summe der Kapazitaten aller Elemente." ordColi inject: 0 into: [:total :element I total
<print/t> 15
+ element capacity).
"(8) Sammeln des Inhaltes aller Elemente in einem neuen Behalter. " ordColi inject: (OrderedColiection new) into: [:all :element I all addAII: element; yourself]. <printlt> OrderedColiection (1 2 31'eins' 2 'zwei' $d $r $e $i) ordCoil inject: (Set new) into: [:all :element I all addAII: element; yourself]. <printlt> Set (1 2 3 $i 'zwei' $r 'eins' $d $e)
"(9) Verketten der Klassennamen, getrennt durch ein Leerzeichen." (ordColi collect: [:elem I elem class]) inject: " into: [:start :elem I start, elem name, ' ') <printlt> 'Set Array ByteString ,
Programm 4-11 Beispiele fur Akkumu!ation von Elementen Die unter Punkt (8) angeftihrten freien Methoden geben als Startobjekt jeweils einen leeren Behlilter vor. Die Akkumulationsvorschrift besteht aus der Methode Collection»add:, durch welche aIle Elemente der Elemente von ordColi in den als Startobjekt vorgegebenen Behlilter eingeftillt werden. SchlieBlich ist noch unter Punkt (9) gezeigt, wie die Klassennamen der Elemente von ordCol! durch die Akkumulationsvorschrift der Verkettung zu einer einzigen Zeichenkette zusammengefaBt werden konnen.
4.3
Objekte mit indizierten Instanzvariablen
Kollektionen sind komplexe Objekte, die andere Objekte umfassen oder enthalten, was es auch rechtfertigt, sie als Sammlungen oder (Sammel)behlilter zu
4.3 Objekte mit indizierten Instanzvariablen
143
bezeichnen. Sie haben eine feste Kapazitat, bis zu der sie mit Elementen aufgerullt werden konnen. In diesem Abschnitt soU nun ein Blick in eine tiefere Eben des konzeptioneUen Objektraumes geworfen werden, urn die Struktur von SammelbehaItem zu erkennen.
4.3.1
Variable Klassen
Die Struktur eines Objektes ist durch die Anzahl der Instanzvariablen bestimmt, die samt ihren Namen in der Strukturschablone der zugehorigen Klasse festgelegt sind. Bisher wurden auf Systemebene nur Klassen betrachtet, deren Strukturschablone eine feste Zahl von namentlich aufgezahlten Instanzvariablen enthalt. Klassen mit einer konstanten Strukturschablone werden deshalb auch als konstante Klassen bezeichnet. Jede Auspragung einer solchen Klasse hat gleich viele und mit jeweils den gleichen Bezeichnem versehene Instanzvariable. Die Instanzierung erfolgt durch die Methode Behavior»new, welche an eine Klasse gesandt wird und als Riickgabeobjekt eine neue Instanz dieser Klasse liefert. Workspace "Definition einer konstanten Klasse." Object subclass: #ConstantClass instanceVariableNames: 'x ' classVariableNames: " poolDictionaries: " category: 'Test' <dolt> ConstantClass isVariable
<printlt> false
"Instanzierung der konstanten Klasse ConstantClass." ConstantClass new size
<printlt> 0
Programm 4-12 Defmition und Instanzierung einer konstanten Klasse Es gibt aber auch Klassen mit einer variablen Strukturschablone, welche zusatzlich zu den benannten Instanzvariablen (named instance variables) noch indizierte Instanzvariable (indexed instance variables) besitzt. Indizierte Instanzvariable werden durch einen ganzzahligen Index bezeichnet, dessen
4 Objektsammlungen
144
Zablung immer mit 1 beginnt. Die Strukturschablone ist in dem Sinne variabel, als die Anzahl der indizierten Instanzvariablen einer Auspriigung erst bei der Instanzierung festgelegt wird. Klassen mit einer variablen Strukturschablone werden variable Klassen genannt. In Programm 4-12 und Programm 4-13 sind die Einrichtung und Instanzierung konstanter und variabler Klassen gegeniibergestellt. Die als Beispiel gewiihlte konstante Klasse ConstantClass wird als direkte Subklasse von Object festgelegt, ihre Schablone enthiilt die benannte Instanzvariable x. Sie antwortet wie jede konstante Klasse auf die Klassenmethode Behavior»isVariable mit false, ihre Instanzen besitzen keine indizierten Instanzvariablen und antworten daher auf die Botschaft size mit o.
Workspace "Definition einer variablen Klasse." ConstantClass variableSubclass: #VariableClass instanceVariableNames: 'y , classVariableNames: " poolDictionaries: " category: 'Test' <dolt> VariableClass isVariable
<print/t> true
"Instanzierung der variablen Klasse VariableClass."
<print/t> a VariableClass (VariableClass new: 3) size <printlt> 3 (VariableClass new: 3) inspect <dolt> Siehe Abbildung 4-3
VariableClass new: 3
Programm 4-13 Definition und Instanzierung einer variablen Klasse Die variable Klasse VariableClass wird schlieBlich als direkte Unterklasse von ConstantClass positioniert. Aus dem Beispiel ist zu erkennen, daB eine variable Klasse durch die Klassenmethode Class» variableSubclass: instanceVariableNames: classVariableNames: pool Dictionaries: category:
erzeugt wird, deren Selektor sich von jenem der entsprechenden Methode fUr konstante Klassen nur dadurch unterscheidet, daB das SchHisselwort subclass
145
4.3 Objekte mit indizierten Instanzvariablen
durch variableSubclass ersetzt ist. Die Strukturschablone der Klasse VariableClass enthalt somit zwei benannte Instanzvariable, das ist die Instanzvariable x, welche aus der Oberklasse (ConstantClass) geerbt wurde sowie die in der Klasse selbst festgelegte benannte Instanzvariable y, sie sieht weiterhin eine von Instanz zu Instanz unterschiedliche Anzahl von indizierten Instanzvariablen vor. Eine variable Klasse ist auch daran zu erkennen, daB sie auf die Botschaft isVariable mit true antwortet. Abbildung 4-2 zeigt schematisch ein variables Klassenobjekt und eine Auspragung im konzeptionellen Objektraum, wobei nur die Strukturschablone und die Struktur der Auspragung betrachtet wird.
'10
[3]
variable Klasse"
O,"n~1
Auspragung [size} Instanzierungsbeziehung
Abbildung 4-2
«
«
«
«
«
«
«
«
«
« « «.
Variable Klassen und ihre Auspragungen
Aus den angefiihrten Beispielen ist zu ersehen, daB eine variable Klasse durch Behavior»new: anlnteger instanziert wird, wobei der Parameter anlnteger angibt, wie viele indizierte Instanzvariable fUr die neue Auspragung vorzusehen sind. Eille bereits existierende Auspragung einer variablen Klasse hat eine unveranderliche GroBe, es konnen ihr daher "zu Lebzeiten" Instanzvariable weder hinzugefiigt noch weggenommen werden! Die Anzahl der Instanzvariablen kann die durch die Methode Object>>Size abgefragt werden kann. 1m letzten Ausdruck von Programm 4-13 wird eine Auspragung der Klasse VariableClass mit drei indizierten Instanzvariablen erzeugt und durch einen Inspektor betrachtet, der in Abbildung 4-3 wiedergegeben ist. Man erkennt
146
4 Objektsammlungen
daraus, daB das inspizierte Objekt neben den zwei benannten Instanzvariablen x, und y noch drei indizierte Instanzvariable tragt, die durch die Indizes 1, 2 und 3 charakterisiert sind.
benannte !nstanzvariab!e intiizierte !nstanzvariable
Abbildung 4-3
Inspektion einer Auspragung von VariableClass
4.3.2 Das Basisprotokoll variabler Klassen Wahrend der Zugriff auf benannte Instanzvariable innerhalb eines Objektes (genauer: in Methoden, die von einem Objekt als Empfanger aktiviert wurden) direkt tiber den Namen moglich ist, konnen indizierte Instanzvariable nur tiber Zugriffsmethoden angesprochen werden. Durch die Zugriffsmethoden Object»at: anlndex put: anObject wird der Instanzvariablen mit dem Index anindex das Objekt anObject zugewiesen, durch Object»at: anlndex wird das von der Instanzvariablen referenzierte Objekt geliefert. Object»size liefert die Anzahl der in einem Objekt vorkommenden indizierten Instanzvariablen. Die genannten Methoden werden in vielen Klassen redefiniert oder auch auBer Kraft gesetzt. Urn trotzdem fUr systemnahe Methoden einen direkten Zugriff auf die Instanzvariablen zu ermoglichen, stehen zusatzlich die Methoden Object»basicAt:put: und Object»basicAt: sowie Object»basicSize zur VerfUgung, von denen erwartet wird, daB sie in keiner Klasse redefmiert werden. Beispielsweise liefert die Methode Object>>Size mit der Anzahl der indizierten Instanzvariablen des Empfangers dessen Kapazitat. Diese Methode wird durch Collection»size (Programm 4-1) redefmiert, so daB BehaIter auf die Botschaft size mit ihrer Kardinalitat antworten. Durch die (hoffentlich nicht redefmierte) Methode Object»basicSize kann jedoch die Dimensionierung des Behalterobjektes festgestellt werden.
4.4 Einige wichtige Behlilterklassen
147
Programm 4-14 enthlilt einige freie Methoden, in denen ein ZugrifT auf indizierte Instanzvariable erfolgt.
Workspace
I names nameString I
names := VariableClass new: 3.
'1
"(1) Schreiben von indizierten Instanzvariablen." names
at: 1 put: 'Wolfgang'; at: 2 put: 'Amadeus'; at: 3 put: 'Mozart'.
"(2) Lesen von indizierten Instanzvariablen."
names at: 3.
<printlt> 'Mozart'
nameString := names at: 1. 2 to: names size do: [:index I nameString := nameString, ' " (names at: index)). nameString <printlt> 'Wolfgang Amadeus Mozart'
(1)
(1) Hier wird die Verkettungsmethode SequenceableCollection», verwendet (siehe dazu Abschnitt 4.4.1).
Programm 4-14 Beispiele fUr den Zugriff auf indizierte Instanzvariable
4.4
Einige wichtige Behilterklassen
In den folgenden Abschnitten werden einige wichtige Klassen von Sammelbehliltern der Smalltalk-Klassenhierarchie vorgestellt. Die Auswahl der Klassen erfolgt einerseits nach ihrer Bedeutung fUr die Programmierung und andererseits nach ihren konzeptionellen Eigenschaften. Behlilterklassen konnen durch verschiedene Eigenschaften charakterisiert und in Gruppen eingeteilt werden. In der Folge werden zwei Gruppierungsmerkmale in den Vordergrund geriickt: einerseits das Fassungsvermogen von Sammelbehliltern und andererseits die Anordnung ihrer Elemente.
148
4 Objektsammlungen
Fassungsvermogen von Sammelbehiiltern Betrachtet man die Arbeitsebene des konzeptionellen Objektraumes und konzentriert man sich dabei auf Methoden fUr das EinfUgen von Elementen in einen Sammelbehlilter, so teilen sich die Behlilterklassen in zwei Gruppen. Die erste Gruppe umfaBt Klassen, deren Auspragungen ein konstantes Fassungsvermogen besitzen. Instanzen dieser Klassen sind Behlilter mit "starren Wlinden", sie konnen stetes nur Elemente aufnehmen, fur die es innerhalb ihrer Dimensionierung einen Platz gibt. Aus solchen Behaltern konnen Elemente auch nicht entfernt, sondern nur durch andere Elemente ersetzt werden. Die charakteristische Botschaft fUr das EinfUgen eines Elementes in einen solchen Behlilter ist at: anlndex put: an Element. Zu dieser Gruppe gehoren die Unterklassen von ArrayedCollection, unter anderen die Klassen Array und ByteString. Die zweite Gruppe von Klassen hat die Eigenschaft, daB ihre Ausprligungen ein variables Fassungsvermogen besitzen und mit beliebig vielen Elementen gefUllt werden konnen, auch das Entfernen ihrer Elemente ist moglich. Instanzen dieser Klassen vermitteln den Eindruck, daB sie Behlilter mit "flexibien Wlinden"t sind, die beliebig gedehnt werden konnen und daher auch beliebig vielen Elementen Platz bieten. Elemente werden durch die Botschaft add: an Element in einen solchen Behlilter aufgenommen und durch remove: anElement ifAbsent: anExceptionBlock wieder entfernt. Vertreter dieser Gruppe sind unter anderen die Klassen Ordered Collection, SortedCollection, Set, und Dictionary.
Anordnung der Elemente in einem Sammelbehiilter Eine andere Moglichkeit zur Charakterisierung von Sammelobjekten liegt in der Anordnung ihrer Elemente. Auch hier kann man grob zwischen zwei Gruppen unterscheiden. Zur ersten Gruppe gehoren Sammlungen, deren Elemente vollkommen ungeordnet sind. Bei solchen Behliltern ist es nicht sinnvoll, von einem ersten, zweiten oder letzten Element zu sprechen. In diese Gruppe fUgen sich die Klassen Set und Dictionary ein. Die zweite Gruppe umfaBt Klassen, deren Ausprligungen ihre Inhaltselemente in einer bestimmten Anordnung enthalten. Solche Behlilter sind derart strukturiert, daB ihre Elemente durch ganzzahlige Indexnummern festgelegte Positionen einnehmen. Hier ist es wohl moglich, von einem ersten, zweiten und auch einem letzten Element zu sprechen. Die Klassen dieser Gruppe unterscheiden sich hauptslichlich durch die Art und Weise, wie die t In [47] wird zwischen contractible Collection und extensibleColiection unterschieden.
4.4 Einige wiehtige Behalterklassen
149
Anordnung der Elemente erzeugt wird. Zu dieser Gruppe zahlen die Klassen OrderedColiection, SortedColiection, Array und String, deren gemeinsame Verhalten beziiglieh des geordneten Einftigens von Elementen in der abstrakten Klasse SequenceableColiection zusammengefaBt ist.
4.4.1
Die abstrakte Klasse SequenceableColiection
Die Klasse SequenceableCollection erftillt die von der Oberklasse Collection auferlegte Verpfliehtung zur Implementation der Enumerationsmethode do:, welche in Programm 4-15 wiedergegeben ist. Diese Methode wird den konkreten Unterklassen vererbt und kann nur von diesen ausgeftihrt werden, da SequenceableCollection selbst eine abstrakte Klasse ist, fUr deren Instanzen (die nieht erzeugt werden sollten) noeh keine indizierten Instanzvariablen erklart sind.
KlassenBrowser
SequenceableCollection methodsFor: 'enumerating' do: anOperationBlock1
"Evaluation des Argumentblockes mit jed em Element des Empfangers."
1 to: self size do: [:i I anOperationBlock1 value: (self at: i)) Programm 4-15 Die Methode SequenceableCollection»do: Die ebenfalls von der Klasse Collection ihren Unterklassen auferlegte Verpfliehtung zur Implementation der Sehliisselmethoden mit den Signaturen add: newObject und remove: oldObject ifAbsent: an Exception Block wird in dieser Klasse (noeh) nieht erfUllt. Weiterhin stellt SequenceableColiection ihren Unterklassen gemeinsame Methoden fUr den Zugriff auf die Elemente zur Verftigung, unter anderen: SequenceableCollection>>first "Bestimmen des ersten Element des Empfangers. Wenn der Empfanger leer ist, wird ein Fehlersignal gesetzt."
SequenceableCollection>>last "Bestimmen des letzten Elementes des Empfangers. Wenn der Empfanger leer ist, wird ein Fehlersignal gesetzt."
150
4 Objektsammlungen SequenceableColiection>> indexOf: an Element ifAbsent: exception Block "Bestimmen des Index des ersten Auftretens von anElement. Wenn der Empfiinger ein gleiches Element nicht entMlt, wird das Evaluationsergebnis von exception Block geliefert."
SequenceableColiection>> indexOfSubColiection: aSubColiection startingAt: anlndex "Bestimmen des ersten Index des Empfangers, ab dem seine Elemente mit den Elementen des Argumentes, aSubCollection, iibereinstimmen. Die Suche beginnt bei anlndex."
SequenceableColiection>>COpyWlth: newElement "Das Riickgabeobjekt ist eine um 1 groBeren Kopie des Empfiingers, die als letztes Element newElement enthalt."
SequenceableColiection>>, aSequenceableColiection "Das Riickgabeobjekt ist eine mit dem Argument verkettete Kopie des Empfangers."
4.4.2 Die Klasse Array Die Funktionalitlit der Instanzen von Array ist bereits in den Oberklassen vorgegeben und wird von diesen geerbt. Die in der Klasse Array selbst festgelegten Methoden redefinieren diese Methoden teilweise dureh einen effizienteren Code, fUgen jedoeh kaum weitere Funktionalitlit hinzu. Wesentlieh ist zu erwlihnen, daB in der abstrakten Klasse ArrayedCollection die Verpfliehtung zur Implementation der Sehliisselmethoden mit den Signaturen add: newObject und remove: oldObject ifAbsent: anExceptionBlock erfUllt wird, allerdings derart, daB dureh die Anweisung self shouldNotlmplement erkllirt wird, daB diese Methoden fUr die Unterklassen nieht zullissig sind. Werden diese Methoden trotzdem von Ausprligungen einer Unterklasse von ArrayedColiection aktiviert, so wird ein Fehlersignal gesetzt. Einige Beispiele fUr den Umgang mit Feldern sind in Programm 4-16 zusammengefaBt. Hier ist aueh gezeigt, wie auf den Versueh reagiert wird, auf einen auBerhalb der Dimensionierung liegenden Index zuzugreifen oder die nieht zullissige Botsehaft add: newObject an ein Array zu senden. Weiterhin werden in Programm 4-16 unter den Punkten (3) und (4) Methoden zum Erweitern und Verketten angewendet, die in der Oberklasse SequenceableColiection definiert sind und von dieser geerbt werden. Die Methode SequenceableColiection>>CopyWith: erzeugt eine Kopie des Emprangers mit einer urn eins groBeren Kardinalitlit, die iiber ihre zusatzliehe (indizierte) Instanzvariable das Argument der Methode referenziert. Die
151
4.4 Einige wichtige Behalterklassen
Methode SequenceableColiection», erzeugt ebenfalls ein neues Objekt, dessen Kapazitat gleich der Summe der Kapazitaten des Empflingers und des Argumentes ist und welches die Elemente des Argumentes nach denen des Empfangers enthiilt. Workspace
I array1
array2 I array1 := #(3 2 8 5 2 8 6 7 8). array2 := #(2 8). "(1) Zugriff auf Elemente."
array1 first. array1 at: 5. array1 at: 10. array1 add: 9.
<printlf> 3 <printlt> 2 <printlt> Unhand/eel exception: Subscript out of bounds <printlf> Unhand/eel exception: This message is not appropriate for this object
"(2) Such en von Elementen."
array1 indexOf: 7 ifAbsent: [0]. <printlf> 8 array1 indexOf: 9 ifAbsent: [0]. <printlt> 0 "(3) Suchen von Teilfolgen."
array1 indexOfSubColiection: array2 startingAt: 4. <printlt> 5 "(4) Erweitern und Verketten."
array1 copyWith: array2. array1, array2
<printlf> #(3 2 8 5 2 8 6 7 8 #(2 8» <printlf> #(3 2 8 5 2 8 6 7 8 2 8)
Programm 4-16 Beispiele fur Methoden von Array
4.4.3 Die Klasse ByteString Die Klasse ByteString wird deshalb erwahnt, well sie die erste konkrete Subklasse von Collection ist, deren Auspragungen Zeichenketten darstellen. Sie unterscheidet sich von anderen Sammelbehalterklassen besonders dadurch, daB ihre Auspragungen "typisiert" sind, da ihre Elemente nur Instanzen der Klasse Character sein durfen, was in der Methode mit der Signatur at: an Index put: aCharacter auch uberpriift wird. Beispiele fUr die Verwendung und Manipulation von Zeichenketten kommen bereits an vielen anderen Stellen vor, ohne daB darauf besonders hinge-
152
4 Objektsammlungen
wiesen wurde. 1m Programm 4-11 wird etwa unter Punkt (9) die Akkumulation mehrerer Zeichenketten zu einer einzigen Zeichenkette vorgenommen, wobei die Methode SequenceableColiection», zur Anwendung kommt, die auch von der Klasse ByteString geerbt wird. Programm 4-17 enthiilt einige weitere Beispiele fUr die Manipulation von Zeichenketten. Workspace
I string1
string2 I string1 := 'Oas ist eine Zeichenkette'. string2 := 'zeichen'. "(1) Such en einer Teilkette." string 1 findString: string2 startingAt: 1.
<printlt> 0 "nicht gefunden"
"(2) Ersetzen eines Zeichens und nochmaliges Suchen der Teilkette." string2 at: 1 put: $Z; yourself. string1 findString: string2 startingAt: 1.
<printlt> 'Zeichen' <printlt> 14
"(3) Ersetzen eines Zeichens durch ein Objekt, das nicht der Klasse Character angehOrt." string2 at: 1 put: 'Z'.
<printlt> Unhandled exception:
Strings only store CharactefS
Programm 4-17 Beispiele fUr die Manipulation von Zeichenketten
4.4.4 Die Klasse Ordered Collection Auspriigungen der Klasse OrderedColiection sind Sammelbehiilter, deren Elemente eine lineare Anordnung besitzen, die von AuBen durch gezieltes EinfUgen und Entfernen von Elementen festgelegt wird. Eine geordnete Ansammlung hat, sofern sie nicht leer ist, immer ein erstes und ein letztes Element, weiterhin hat jedes Element (mit Ausnahme des ietzten) einen Nachfolger und ebenso jedes (mit Ausnahme des ersten) einen Vorgiinger. Die Positionen der Elemente werden vom ersten Element beginnend durchnumeriert. Geordnete Ansammlungen sind flexible Behiilter, die in ihrem Fassungsvermogen nicht beschriinkt sind. Elemente konnen zu einer geordneten Ansammlung jederzeit in eine vorzugebende Position hinzugefUgt oder aus einer Position entfemt werden. Wird beispielsweise aus einer Instanz von OrderedColiection das erste Element
4.4 Einige wichtige Behlilterklassen
153
entfernt, so nimmt das bisher zweite Element dessen Position ein und ist nunmehr das erste Element. Wird ein Element an die n-te Position einer geordneten Ansammlung eingefUgt, so werden die bisher an den Positionen n, n+ 1, ' " stehenden Elemente auf eine urn jeweils eins hohere Position verschoben. Eine Positionsnummer unterscheidet sich also von einem Index in einem Feld dadurch, daB sie nicht fest mit einem Platz fUr ein Element verbunden ist, sondern immer relativ zum ersten Element gezlihlt wird. Fur geordnete Ansammlungen sind unter anderen folgende Methoden (zuslitzlich zu jenen, die von SequenceableColiection und Collection geerbt werden) charakteristisch: OrderedColiection>>after: anElement "Antworte mit dem Nachfolger des Argumentes anElement Wenn dieses entweder nicht im Empfanger enthalten ist oder keinen Nachfolger hat. setze ein Fehlersignal."
OrderedColiection>>before: anElement "Antworte mit dem Vorgiinger des Argumentes an Element. Wenn dieses entweder nicht im Empfanger enthalten ist oder keinen Vorganger ha~ setze ein Fehlersignal."
OrderedColiection>>add: newObject after: anElement "FUge newObject als Nachfolger von anElement in den Empfanger ein. Antworte mit newObject"
OrderedColiection>>add: newObject before: oldObject "FUge newObject als Vorgiinger von anElement in den Empfanger ein. Antworte mit newObject."
OrderedColiection>>addFirst: newObject "FUge newObject an die erste Position des Empfangers ein."
OrderedColiection>>addLast: newObject "FUge newObject an die letzte Position des Empfangers ein."
OrderedCollection>>removeFirst "Entferne das erste Element des Empfangers. Wenn der Empfanger leer ist. setze ein Fehlersignal."
OrderedCollection>>removeLast "Entferne das letzte Element des Empfangers. Wenn der Empfanger leer is~ setze ein Fehlersignal."
Der Klasse OrderedColiection ist von ihrer Oberklasse Collection die Verpflichtung auferlegt worden, Schlusselmethoden mit den Selektoren add :. remove:ifAbsent: und do: zu implementieren. Dies ist die Voraussetzung fUr die Anwendbarkeit der in Collection festgelegten allgemeinen Methoden fUr Behlilterobjekte, vor aHem fUr den Einsatz der Enumerationemethoden. Diese Methoden sind in Programm 4-18 gezeigt.
154
4 Objektsammlungen
KlassenBrowser OrderedeColiection methodsFor: 'adding' add: newObject
"Kommentar siehe: Abschnitt 4.1." 1\
self addLast: newObject
(1 )
remove: oldObject ifAbsent: anExceptionBlockO
"Kommentar siehe: Abschnitt 4.1" firstlndex to: lastlndex do: [:index I oldObject = (self basicAt: index) ifTrue: [self removelndex: index. 1\0IdObject]]. 1\ anExceptionBlockO value
(2)
OrderedeColiection methodsFor: 'enumerating' do: anOperationBlock1
"Kommentar siehe: Abschnitt 4.1" firstlndex to: lastlndex do: [:index I anOperationBlock1 value: (self basicAt: index)) (1) Die Methode OrderedCollection>>addLast: mgt das neue Element an die letzte Position ein, falls der Empfanger noch Kapazitiit hat, ansonsten wird das Objekt "gedehnt". Dieser Vorgang wird an einer anderen Stelle erlautert.
(2) Durch OrderedCollection»removelndex: wird das Element aus seiner absoluten Position entfernt, die Nachfolger riicken um eine Position nach vorne.
Programm 4-18 Die Schliisselmethoden der Klasse OrderedCollection
Eine genauere Betrachtung der in Programm 4-18 angegebenen Methoden gibt einen Einblick in die innere Struktur der Instanzen von OrderedCollection und vermittelt auch einen ersten Eindruck von der Realisierung flexibler Sammelehlilter. In Abbildung 4-4 ist der Autbau eines solchen Objektes schematisch gezeigt. Jede geordnete Sammlung enthlilt die zwei benannten Instanzvariabien firstlndex und lastlndex sowie ein Feld von indizierten Instanzvariablen, das im gezeigten Beispiel die Dimension 5 hat. Die Werte von firstlndex und lastlndex stecken jenen Bereich ab, von dem die Inhaltselemente des Behlilters referenziert werden. Instanzvariable mit Indizes kleiner als firstlndex oder
155
4.4 Einige wiehtige Behiilterklassen
groBer als lastlndex sind mit nil belegt und bilden die freie Kapazitat des Behalters, die zur Aufnahme weiterer Nutzelemente zur Verfugung steht. Der in der Abbildung dargestellte Zustand wird dureh die AusfUhrung des unter Punkt (1) von Programm 4-20 angegebenen Codes erreieht. Der Einfaehheit halber sind die von den indizierten Instanzvariablen referenzierten Objekte nieht gesondert als solche dargestellt, sondern direkt dureh ihre Literaldarstellung angegeben. In Abbildung 4-4 ist angedeutet, daB eine geordnete Sammlung von zwei Siehten aus betraehtet werden kann, einmal aus der Basissieht der teehnisehen Realisierung und einmal aus jener Sieht, die das fUr die Arbeit mit geordneten Sammlungen eharakteristische Protokoll bietet. Da es in Smalltalk nieht moglieh ist, einen Teil der verfugbaren Methoden derart als privat zu erklaren, daB sie aueh tatsaehlieh unzuganglieh sind, stehen diese auf versehiedenen Ebenen des Objektraumes angesiedelten Methoden gleiehzeitig zur VerfUgung. Es liegt in der Hand des Anwenders, sieh nur der Methoden des Arbeitsprotokolles zu bedienen und dadureh diese Ebenen nieht zu vermisehen. Fiir die Untersuehung des Aufbaues von solchen Sammelbehaltern ist es jedoeh ein Vorteil, beide Ebenen zur VerfUgung zu haben und praktiseh gegeniiberstellen zu konnen.
ArbeiisprotokoH
at:
bas!cAt: basicAtput:
atput add: aooFirst: add:after: removaF!rSi remowdfAbsent:
ordCoH basicAt: 1 !
~
1'-'. . . I
2
ordCoU size ordCo!! basicSize - i - - -.
Abbildung 4-4
ordCoil
Siehten eines Behalters der Art OrderedColiection
156
4 Objektsammlungen
Auf der linken Seite von Abbildung 4-4 sind die Basiszugriffsmethoden angegeben, sie sprechen die (indizierten) Instanzvariablen direkt iiber ihre Indizes an. Die rechte Seite zeigt Zugriffsmethoden, welche die Nutzelemente eines Behalterobjektes iiber deren Position en adressieren. Man erkennt, daB die Methoden Object»at: (vergleiche Programm 4-19) und Object»at:put: redefmiert wurden und als Argumente nicht die Indizes der Instanzvariablen, sondern die Positionsnummern der Elemente erwarten, wahrend die entsprechen den Methoden mit dem Schliisselwort basicAt: unverandert sind. Analoges gilt fUr die Methoden mit den Selektoren size (basicSize) und inspect (basiclnspect). Weiterhin ist in der Skizze angedeutet, daB der Bereich fUr die Nutzelemente, der im gegebenen Beispiel die Position en I, 2 und 3 umfaBt, zumindest innerhalb der Kapazitat des Behalters flexibel ist. In einem spateren Abschnitt wird gezeigt, wie diese Flexibilitat auch iiber momentane Kapazitatsgrenzen hinweg erreicht werden kann.
KlassenBrowser
OrderedeColiection methodsFor: 'accessing' at: anlnteger
"Das Ruckgabeobjekt ist das Element in Position anlnteger. Diese Methode sollte nur von Klienten gesandt werden, die genaue Kenntnisse uber die Positionen der Elemente besitzen."
anlnteger islnteger if False: ["self nonlntegerlndexError: anlnteger]. (an Integer < 1 or: [anlnteger + firstlndex - 1 > lastlndex]) ifTrue: [" self subscriptBoundsError: anlnteger] ifFalse: ["super at: anlnteger + firstlndex - 1] (1) (1) Nach entsprechenden Priifungen wird die Positionsnummer anInteger in den
Index umgerechnet und direkt auf die indizierte Instanzvariable zugegritTen.
Programm 4-19 Redefmition der Methode Object»at: Die im Programm 4-20 angefUhrten freien Methoden sollen helfen, die geschilderte Situation zu demonstrieren. Nach der unter Punkt (I) angegebenen Erzeugung und Fiillung einer geordneten Sammlung wird diese auf Basisebene (2) und auf Arbeitsebene (3) untersucht und inspiziert. Die Ubereinstirnmung der Evaluation der Ausdriicke mit der in der Skizze veranschaulichten Situation ist leicht zu erkennen.
157
4.4 Einige wichtige Behalterklassen
Workspace
I ordColl I
ordCol! := Ordered Collection new: 5. "(1) FOllen des Behlilters mit Elementen und darauffolgendes Entfernen des ersten." ordCol! addAII: #(0 102030 ). ordCol! removeFirst. ordCol! <printlt> OrderedColiection (10 20 30) "(2) Inspektion des Behalters auf der Basisebene." ordCol! basiclnspect. <dolt> Siehe Abbildung 4-3 linke Seite. ordCol! basicAt: 1. <printlt> nil ordCol! basicSize. <printlt> 5 "(3) Inspektion des Behlilter auf der Arbeitssebene." ordCol! inspect. ordCol! at: 1. ordCol! size
<dolt>
Siehe Abbildung 4-3 rechte Seite.
<printlt> 10 <printlt> 3
Programm 4-20 Erzeugen und Inspizieren einer geordneten Sammlung Abbildung 4-5 zeigt, daB fUr Instanzen der Klasse OrderedColiection auch eigene Inspektoren vorgesehen sind, welche die interne Struktur der Objekte verbergen und nur deren Arbeitssicht bieten.
ordCoH basicinspect <dolt>
AbbUdung 4-5
ordCol! inspect <dolt>
Inspektion von geordneten Sammlungen
158
4 Objektsammlungen
In Programm 4-21 wird das in Programm 4-20 begonnenen Beispiele fortgesetzt. Durch die unter Punkt (4) ausgefiihrten Methoden wird zuerst der Behalter bis zur Kapazitatsgrenze geflillt, was daraus zu erkennen ist, daB die Kardinalitat (ordColl size) und die Kapazitat (ordColl basicSize) gleich sind. Danach werden unter Punkt (5) zwei weitere Elemente hinzugefligt, so daB die Kardinalitat den Wert 7 erreicht. Eine Oberpriifung der Kapazitat ergibt, daB diese nunmehr flir 10 Elemente ausreicht, also verdoppelt wurde. Diese scheinbare "Dehnung" des Objektes erfolgt durch eine Vorgangsweise, die nicht nur im Bereich der Kollektionen von Bedeutung ist, sie wird in einem spateren Abschnitt erlautert.
Workspace "Fortsetzung von Programm 4-20" ordColI size
<printlt> 3
"(4) Auffiillen des Behalters mit Elementen." ordColl add: 40; add: 50. ordColI size. <printlt> 5 <printlt> 5 ordColl basicSize.
"(5) Hinzufiigen weiterer Elemente." ordColl add First: 60; add: 70. ordColl size <printlt> 7 ordColl basicSize. <printlt> 10
"(6) Die Kapazitat wurde vergro6ert, der Behalter wurde 'gedehnt'!" ordColi.
<printlt>
OrderedCollection (60 10 20 30 40 50 70)
Programm 4-21 Scheinbare Dehnbarkeit eines Behlilterobjektes
Die Methode OrderedCollection»add: (Programm 4-18) fligt ein Element jeweils an die letzte Position. Werden in eine geordnete Sammlung Elemente stets nur durch diese Methode eingeftigt, so entspricht die Anordnung der Elemente im Behlilter der zeitlichen Reihenfolge ihres Einftigens.
4.4 Einige wichtige Behlilterklassen
159
4.4.5 Die Klasse SortedColiection Sortierte Anordnungen sind flexible Sammelehalter, in denen die Elemente eine Anordnung haben, die nieht von auBen aufgepragt wird, sondem sich aus einer Eigenschaft der Elemente selbst ergibt. Ais Auspragungen einer Unterklasse von OrderedCollection erben sie deren Eigenschaft, die Elemente iiber ihre Position en anzusprechen mit Ausnahme der Moglichkeit, Elemente gezielt an bestimmte Positionen einzufUgen. Methoden mit Selektoren der Art addLast:, add First:, add:after: und add:before: sind daher in der Klasse Sorted Collection aufgehoben, irn Falle ihrer Aktivierung wird ein Fehlersignal gesetzt. Jeder Behalter mit sortierter Anordnung referenziert iiber seine Instanzvariable sortBlock einen Block, der den Code zur Steuerung der Einordnung von Elementen enthalt. Der logische Block mit zwei Blockargumenten muB so gestaltet sein, daB er bei der Evaluierung mit zwei Argumentobjekten dann true ergibt, wenn das erste Objekt vor das zweite zu reihen ist, ansonsten false. Die Klasse Sorted Collection halt in einer Klassenvariable den Vorgabeblock [:x :y I x < y], der einem neu erzeugten Behlilter immer dann zugeordnet wird, wenn kein anderer Block explizit angegeben wird. Ohne nahere Angabe werden also die Elemente in eine sortierte Anordnung "in aufsteigender Sortierreihenfolge" eingetragen, wobei damit gemeint ist, daB x vor y gereiht wird, wenn die Relation x < y erfUllt ist. Ob diese Relation fUr zwei Objekte x und y erfUllt ist, wird durch eine Methode mit dem binaren Selektor < festgestellt, die von der Klassenzugehorigkeit der Objekte x und y bestirnmt wird. Programm 4-22 zeigt die Vorgangsweise beirn alphabetischen Sortieren von Worten. Unter Punkt (1) wird ein Feld erzeugt, dessen Elemente Zeichenketten sind, welche die W orte eines Satzes bilden. Die Sortierung erfolgt dadurch, daB die Elemente des Feldes der Reihe nach in eine leere Auspragung der Klasse SortedCollection eingefUgt werden. Dies kann, wie unter Punkt (2) angegeben, implizit dadurch erreicht werden, daB dem Feld die "Umwandlungsbotschaft" asSorted Collection gesandt wird, welche bewirkt, daB eine neue sortierte Sammlung (mit dem erwahnten Vorgabeblock) erzeugt und mit den Elementen des Feldes gefUllt wird. Beim EinfUgen der Elemente wird die Anordnungsvorschrift beriicksichtigt, was auch aus der Druckdarstellung des Behlilters samt seinem Inhalt hervorgeht. 1m letzten Teil des Programmes werden die nunmehr alphabetisch sortierten Zeichenketten auf eine bereits friiher gezeigte Art wieder zu einer einzigen Zeichenkette zusammengefiigt, wobei an jedes Wort am Ende noch eine Zeichenkette angehlingt wird, die jeweils nur aus einem Leerzeichen besteht, durch welches die einzelnen Worte voneinander getrennt werden.
160
4 Objektsamm1ungen
Workspace
"Sortieren von Worten einer Zeichenkette."
I kommentar
worte liste nonsense I kommentar := 'Antworte mit der KardinaliUH des Empfi:1ngers'.
"(1) Zerlegen der Zeichenkette in einzelne Worte." worte := Scanner new scanFieldNames: kommentar. (1) <printlt> #(,Antworte' 'mit' 'der' 'Kardinalitiit' 'des' 'Empfiingers')
"(2) Sortieren der Worte nach dem Alphabet." liste := worte asSorted Collection. <printlt> SortedColiection ('Antworte' 'der' 'des' 'Empfiingers' 'Kardinalitiit' 'mit')
"(3) Verketten der Worte zu einer Zeichenkette." nonsense := liste inject: " into: [:start :wort I start, wort, ' 'I. <printlt> 'Antworte der des Empfiingers Kardinalitiit mit '
(2)
(1) Hier wird die Fiihigkeit des Scanners genutzt, eine Zeichenkette (nach den Regeln der Smalltalk-Syntax) in einzelne Teile (token) zu zeriegen.
(2) Vergleiche Punkt (9) vonProgramm 4-11.
Programm 4-22 Alphabetisches Sortieren von Worten einer Zeichenkette
Workspace
"Variante von Programm 4-22." "(2b) Sortieren der Worte nach ihrer Lange." worte asSortedColiection: [:x :y I x size < y size].
(1)
<printlt> SortedCollection ('mit' 'des' 'der' 'Antworte'
'Empfiingers' 'Kardinalitiit')
(1) Vorgabe eines Blockes, der festlegt, daB kiirzere Zeichenketten vor liingeren positioniert werden sollen.
Programm 4-23 Vorgabe eines Sortierb1ockes
161
4.4 Einige wichtige BehlHterklassen
Programm 4-23 gibt eine Variante an, in der nicht der Vorgabeblock als Anordnungsvorschrift verwendet wird, sondem ein spezieller Block, der dann zu true evaluiert wird, wenn die Uinge des ersten Argumentes kleiner ist als die Llinge des zweiten Argumentes. Aus dem Ergebnis ist die nunmehrige Anordnung der Worte ersichtlich. Ein weiteres Beispiel ist irn Programm 4-24 gezeigt. Hier werden ebenfalls Zeichenketten angeordnet, allerdings werden jene Zeichenketten vorangereiht, in den en der Buchstabe "a" nicht 6fter vorkommt als in den Nachfolgem.
Workspace
I block sortColI stringArray I "(0) Erzeugen eines Feldes mit Zeichenketten."
stringArray := #(,SxxxxxOOOaa2' '4xxxxOOaaaa4' '2xxOOOOOOOa1' '3xxxOOaaaaaS' '0000000000' '1xOOOOOOaaa3'). (1) "(1) Festlegen eines Sortierblockes."
block
:= [:x :y I (x occurrencesOf: $a) <= (y occurrencesOf: $a)].
(2)
"(2) Erzeugen und FUllen einer sortierten Sammlung."
sortColI := SortedCollection sortBlock: block. sortColI addAII: stringArray; yourself. <printlt> SortedColiection ('0000000000' '2xxOOOOOOOa1' 'SxxxxxOOOaa2' '1 xOOOOOOaaa3' '4xxxxOOaaaa4' '3xxxOOaaaaa5') (1) Die zu sortierenden Zeichenketten sind so gewahlt, daB das letzte Zeichen als Zahl interpretiert die Haufigkeit des Buchstaben »a" in der Zeichenkette angibt. Die Richtigkeit des Ergebnisses kann daher auf einen Blick erkannt werden.
(2) Coliection>>OccurrencesOf: anObject liefert als Ergebnis die Haufigkeit des Vorkommens von anObject im Behalter.
Programm 4-24 Sortieren von Zeichenketten nach der Hliufigkeit von $a
Wie fUr aIle vorgestellten Klassen von Sammelbehliltem ist auch fUr sortierte Anordnungen die Schliisselmethode SortedCollection»add: angegeben und derart kommentiert, daB ein Eindruck von ihrer Funktion geboten wird (Programm 4-25).
162
4 Objektsammlungen
KlassenBrowser
SortedCollection methodsFor: 'adding' add: newObject "EinfOgen von newObject in den Empfanger. Das ROckgabeobjekt ist newObject"
I nextlndex I
self isEmpty ifTrue: ["super add Last: newObject). nextlndex := self indexForlnserting: newObject. self insert: newObject before: nextlndex. " newObject
(1) (2) (3)
(1) 1st der Behiilter noch leer, so wird das Element ohne besondere Vorkehrungen eingeftigt. (2) Es wird (durch binllres Suchen) jener Basisindex bestimmt, bei dem das neue Element eingetragen werden muB. (3) Die auf Basisebene arbeitende Einftigemethode schaffi zuerst durch Verschieben von Elementen an der angeforderten Indexposition Platz, wobei eine VergrOBerung des Behlllters (vergleiche Programm 4-31) notwendig sein kann.
Programm 4-25 Die Schliisselmethode SortedCollection»add:
4.4.6 Die Klasse Set Auspragungen der Klasse Set sind flexible Sammelbehalter mit wohlunterscheidbaren Elementen, die keine besondere Anordnung besitzen. Sie entsprechen Mengen im mathematischen Sinne. Mengen verstehen nur das von Collection geerbte Protokoll, wobei die Methoden Object»at: und Object»atput fUr den Zugriff auf die Instanzvariablen aufgehoben sind. Sie werden ahnlich wie geordnete Sammlungen auf Basisebene durch Behlilter dargestellt, deren Kapazitat stets groBer ist als ihre Kardinalitat, wobei die indizierten Instanzvariablen eine geschlossene Hashtabelle bilden. Die Elemente einer Menge werden durch die Methode Object>>hash (die in vielen Unterklassen durch eine spezifische Methode ersetzt wird), auf eine ganze Zahl (Smallinteger) abgebildet, aus welcher der Basisindex fUr eine
4.4 Einige wiehtige Behalterklassen
163
Hashtabelle bestimmt wird. Beim Einriehten von neuen Klassen muB siehergestellt werden, daB je zwei ihrer Instanzen, die beim Vergleieh (Selektor =) true ergeben, aueh auf die Botsehaft hash mit dem gleiehen Ergebnis reagierenoEs ist jedoeh moglieh, daB zwei ungleiehe Objekte den gleiehen Hashwert liefem, was zu einer Kollision in der Hashtabelle fiihrt, die dureh eine Kollisionsbehandlung entseharft wird. Programm 4-26 zeigt die Sehliisselmethode Set»add:, die so mit Kommentaren versehen ist, daB die wesentliehen Sehritte des Einfiigens eines neuen Elementes siehtbar werden.
KlassenBrowser Set methodsFor: 'adding'
add: newObject
"Einfligen von newObject in den Empfanger. Oas RUckgabeobjekt ist newObject"
I index I
=
newObject nil ifTrue: [AnewObject]. index := self findElementOrNiI: newObject. (self basicAt: index) = nil ifTrue: [self atNewlndex: index put: newObject]. AnewObject
(1)
(2) (3)
(1) Das Objekt nil kann nicht Element einer Menge sein, weil es zur Kennzeichnung unbesetzter Platze der Hashtabelle verwendet wird. (2) Es wird jener Basisindex bestimmt, an dem entweder newObject bereits in der Menge vorkommt oder bei dem es einzutragen ware. Der Basisindex wird mittels newObject hash (und eventuell Verfolgung einer Kollisionskette) bestimmt. Wenn notwendig, wird der Empfanger vergroBert (vergieiche Programm 4-31 ). (3) 1st die Position unbesetzt, so ist newObjeet noch nicht Element der Menge und wird daher eingeftigt.
Programm 4-26 Die Sehliisselmethode Set»add: Beispiele fUr den Einsatz von Mengen werden an vielen Stellen, besonders aber im naehsten Kapitel geboten, so daB an dieser Stelle darauf verziehtet wird.
164
4 Objektsammlungen
4.4.7 Die Klasse Dictionary Auspragungen der Klasse Dictionary sind Verzeichnisse, in die Objekte unter einem eindeutigen Schliissel eingetragen und wieder aufgefunden werden konnen. Die charakteristischen Botschaften fUr den Zugriff auf Verzeichniseintrage sind at: aKey und at: aKey put: anObject. 1m Unterschied zu Methoden anderer Behalterklassen mit gleichen Selektoren kann allerdings als Argument nach dem Schliisselwort at: ein beliebiges Objekt als Schliissel der Eintragung stehen. Verzeichnisse sind als Mengen realisiert und somit flexible Sammlungen, ihre Elemente sind Schliissel-Wert-Paare. Die Zuordnung eines Schliissels zu einem Wert wird durch eine Auspragung der Klasse Association reprasentiert. 1m Programm 4-27 werden vorerst einige Beispiele flir Assoziationen gezeigt. Unter Punkt (1) wird durch die Instanzierungsmethode Association class»key:value: eine Assoziation mit dem Schliissel ""EUR (ein Symbol) und dem Wert 'Euro' (eine Zeichenkette) erzeugt, Punkt (2) demonstriert, wie daraus der Schliissel und der Wert erhalten werden kann, durch die Methoden unter Punkt (3) werden Schliissel und Wert einer Assoziation verlindert.
Workspace
I as soc I "(1) Erzeugen einer Assoziation mit SchIOssel4#=EUR und Wert: 'Euro' ".
assoc := Association key: 4#=EUR value: 'Euro'. <printlt> 4#=EUR->'Euro' "(2) Feststellen des SchlOssels und des Wertes der Assoziation."
assoc key. assoc value.
<printlt> 4#=EUR <printlt> 'Euro'
"(3) Verlindernvon SchlOssel und Wert einer Assoziation." assoc value: 'EURO'. assoc key: 'eur'
<printlt> 4#=EUR->'EURO' <printlt> 'eur'->'EURO'
Programm 4-27 Beispiele fUr Assoziationen Die Funktionalitat von Verzeichnissen wird eben falls an einem Beispiel demonstriert. Punkt (1) von Programm 4-28 zeigt die Einrichtung eines Verzeichnisses, in welches zwei Eintragungen mit den Schliisseln ""OEM und
4.4 Einige wichtige Behalterklassen
165
4FATS gemacht werden. Durch die Methode Dictionary»at:put: werden die Assoziationen zuerst aufgebaut und dann in die Menge eingefUgt. Der Ausdruck (2) bewirkt, daB eine Assoziation direkt erzeugt und als solche durch die Methode Dictionary»add: eingebracht wird. SchlieBlich sind unter Punkt (3) Ausdriicke zusammengefaBt, die den Inhalt des Verzeichnisses nach verschiedenen Gesichtspunkten untersuchen.
Workspace
I dict I "(1) Erzeugen eines Verzeichnisses mit zwei Eintragungen."
dict := Dictionary new at: #ATS put: 'Osterreichische Schilling'; at: #DEM put: 'Deutsche Mark'; yourself. <printlt> Dictionary (#DEM->'Deutsche Mark' #ATS->'Osterreichische Schilling' ) "(2) EinfOgen einer Assoziation in das Verzeichnis."
dict add: (Association key: #EUR value: 'Euro'); yourself. <printlt> Dictionary (#DEM->'Deutsche Mark' #EUR->'Euro' #ATS->'Osterreichische Schilling' ) "(3) Untersuchen des Verzeichnisses."
dict at: #ATS.
<printlt> 'Osterreichische Schilling' <printlt>
dict associationAt: #ATS. #ATS->'Osterreichische Schilling' dict keys.
<printlt> Set (#ATS #DEM #EUR) <printlt>
diet values OrderedCollection fEuro' 'Osterreichische Schilling' 'Deutsche Mark1
Programm 4-28 Beispiele fUr Verzeichnisse Verzeichnisse werden bereits im Smalltalk-System selbst intensiv angewendet. Es wurde bereits erwiihnt, daB das Systemverzeichnis Smalltalk, welches die globalen Variablen enthiilt sowie die Datenpools als Verzeichnisse besonderer Art realisiert sind. Sie spielen auch bei der Realisierung von Mehrfachbeziehungen zwischen Objekten eine wichtige Rolle, wenn die Partnerobjekte direkt iiber einen Schliissel erreicht werden sollen.
166
4.5
4 Objektsammlungen
Sammelbehalter mit variabler Kapazitat
In Abschnitt 4.3 wurde gezeigt, daB Sammelobjekte Auspriigungen einer variabIen Klasse sind, die bei ihrer Instanzierung mit einer vorzugebenden Anzahl von indizierten Instanzvariablen ausgestattet werden. Es ist jedoch nicht moglich, wiihrend der Lebenszeit solcher Objekte ihre Dimensionierung und dam it ihre Kapazitiit zu iindern. Andererseits wurden im vorangehenden Abschnitt Behiilterobjekte nach ihrem Fassungsvermogen eingeteilt, wobei zwischen starren Behiiltern mit fester Kapazitiit und flexiblen Behiiltern mit variabler Kapazitiit unterschieden wurde. Dieser schein bare Widerspruch lost sich auf, wenn die Betrachtungsebenen streng getrennt werden. Auf der Basisebene haben aIle Sammelbehiilter eine feste, unabiinderliche Dimensionierung, der im technischen Objektraum die Zuteilung eines Speicherbereiches mit fester GroBe entspricht. Einer Auspriigung einer variablen Klasse konnen wiihrend ihrer Lebenszeit indizierte Instanzvariable weder hinzugeftigt noch weggenommen werden. Bei starren Behiiltern wird diese Eigenschaft auf der Arbeitsebene unveriindert beibehalten. Die fUr soIche Sammelobjekte charakteristischen Zugriffsmethoden tragen die Signaturen at: anlndex und at: anlndex put: anObject, wobei anlndex die Nummer der Instanzvariablen direkt bezeichnet. Fiir flexible Behiilter sind auf Arbeitsebene Methoden fUr das EinfUgen und Entfernen von Inhaltselementen charakteristisch, weIche Signaturen der Art add: anObject oder remove: anObject ifAbsent: anExceptionBlock tragen. Die Flexibilitiit soIcher Sammelobjekte wird auf folgende Weise in zwei Stufen realisiert. Die erste Stufe einer begrenzten Flexibilitiit wird dadurch erreicht, daB ein Behiilter immer etwas groBer dimensioniert wird, als der Anzahl seiner aufzunehmenden Elemente entspricht, seine Kapazitiit ist zumeist groBer als seine Kardinalitiit, was bereits in Abschnitt 4.4.4 am Beispiel von geordneten Ansammlungen gezeigt wurde. Reicht beim Hinzuftigen eines Elementes in einen flexiblen Behiilter seine Kapazitiit nicht mehr aus, so wird in einer zweiten Stufe seine Kapazitiit scheinbar erhoht. Dies geschieht dadurch, daB in einem ersten Schritt ein anderer, jedoch groBer dimensionierter Behiilter der gleichen Art erzeugt wird, die Elemente in einem zweiten Schritt aus dem urspriinglichen Sammelbehiilter in den neuen, groBeren "umgefUllt" werden und daB schlieBlich in einem dritten Schritt der alte Behiilter durch den neuen ersetzt wird und zwar so, daB systemweit aIle Namen, die den alten Behiilter bezeichnet haben, nunmehr den neuen referenzieren. Der auch in seiner Kapazitiit vergroBerte Behiilter ist auf technischer Ebene ein anderes Objekt, das auf Arbeitsebene allen Objekten, die den urspriinglichen Behiilter referenzierten, von dies en unbemerkt "unterschoben" wurde.
4.5 Sammelbehlilter mit variabler Kapazitlit
167
Dieser Mechanismus wird an Hand der Klasse OrderedCollection demonstriert. 1m Programm 4-18 wurde gezeigt, daB die Schliisselmethode OrderedCollection»add: ihre Aufgabe an die Methode Orderedcoliection»addLast: (Programm 4-29) weitergibt. KlassenBrowser OrderedeColiection methodsFor: 'accessing' add Last: newObject
"Einfugen von newObject als letztes Element in den Empfanger.Das Ruckgabeobjekt ist newObject" lastlndex = self basicSize ifTrue: [self makeRoomAtLast). lastlndex := lastlndex + 1. self basicAt: lastlndex put: newObject. " newObject
(1) (2)
(1) Wenn nach dem letzten Element kein Platz mehr ist, wird durch self makeRoomAtLast Platz geschatTen (vergJeiche Abbildung 4-4). (2) FaIls noch Platz ist, wird das Element direkt eingefiigt.
Programm 4-29 Die Methode OrderedColiection»addLast:
KlassenBrowser OrderedeColiection methodsFor: 'private' makeRoomAtLast
"Schaffen von Platz fUr ein Element nach dem letzten Element des Empfangers."
ifTrue: ["self increaseCapacity).
(1)
(2)
(1) Der Empfanger wird transparent durch einen groBeren ersetzt. (2) Es wird durch verschieben der Elemente nach dem letzten Element Platz geschatTen.
Programm 4-30 Skizze von OrderedColiection»makeRoomAtLast
168
4 Objektsammlungen
In dieser Methode wird gepriift, ob das neue Element direkt eingefUgt werden kann, oder ob es notwendig ist, durch OrderedCollection»makeRoomAtLast erst den notwendigen Platz zu beschaffen. Aus der in Programm 4-30 angegebenen Skizze ist zu ersehen, daB versucht wird, innerhalb des Behlilters durch Verschieben der Elemente fUr das einzuftigende Element Platz zu machen und daB die KapazitlitsvergroBerung durch Erzeugung eines neuen Sammelbehlilters nur dann erfolgt, wenn keine Kapazitlit mehr vorhanden ist. Die KapazitlitsvergroBerung wird durch die Methode OrderedCollection»increaseCapacity gestartet und durch OrderedCollection»changeCapacityTo: (Programm 4-31) durchgefUhrt. KlassenBrowser
OrderedeCollection methodsFor: 'private' increaseCapacity "ErhOhen der Kapazitat des Empfangers."
self changeCapacityTo: self size
+ self growSize.
(1)
changeCapacityTo:newCapacity "Erzeugen eines neuen, grtiBeren BeMltes und Transferieren der Elemente."
I newSelf I
newSelf := self copyEmpty: newCapacity. newSelf setlndicesFrom: 1. firstlndex to: lastlndex do: [ :index I newSelf addLastNoCheck: (self basicAt: index)]. self become: newSelf
(2) (3) (4)
(1) Collection>>growSize liefert das Wachstumsinkrement. (2) Erzeugen eines neuen, leeren Behlllters mit angegebener Kapaziilit. (3) Umftillen der Elemente. Die Methode OrderedCollection>>addLastNo Check verzichtet beim Einftigen der Elemente auf die Priifung auf vorhandenen Platz, dieser ist durch die vorangehenden Aktionen sichergestellt. (4) Vertauschen aller Referenzen auf den alten und den neuen Behlllter.
Programm 4-31 KapazitlitsvergroBerung einer geordneten Ansammlung Die einzelnen fUr die Kapazitlitserweiterung notwendigen Aktionen sind aus den im Programm 4-31 eingefUgten Kommentaren zu entnehmen. Einer besonderen Erwlihnung bedarf die Methode Object>>become: otherObject, durch welche slimtliche Referenzen auf den Empfanger mit jenen auf das
4.5 Sammelbehlilter mit variabler Kapazitat
169
Argument vertauscht werden. Diese systemnahe und auGerst machtige Methode ermoglicht nicht nur die Realisierung von flexiblen Sammelbehaltem auf die eben beschriebene Art, sondem kann auch in anderen Bereichen eingesetzt werden. A1lerdings ist diese Methode in ihrer DurchfUhrung sehr zeitaufwendig, da der gesamte Objektraum nach Referenzen auf die in Frage kommenden Objekte durchsucht werden muG, so daG ihr Einsatz von Fall zu Fall wohl zu iiberlegen ist.
x1
y1
a2
b2
- --t> Abbildung 4-6
Referenzen vor x1 become: b2 Referenzen nach x1 become: b2 unveranderte Referenzen
Transparente Vertauschung zweier Objekte
Die Wirkung der Methode Object»become: otherObject ist in Abbildung 4-6 durch einen Blick in den Objektraum veranschaulicht. Das Augenmerk ist auf zwei Objekte gerichtet, welche durch objekt1 und objekt2 identiflziert sind. Jedes dieser Objekte hat drei Instanzvariable, nlimlich dep, i1 und i2 beziehungsweise dep, j1 und j2. Die Instanzvariablen dep und die von ihnen referenzierten Objekte depListe1 und depListe2 sind fUr die momentane Betrachtung nicht relevant und werden daher auGer Acht gelassen. In der Ausgangssituation mogen die Namen x1 und y1 das Objekt objekt1 bezeichnen, ebenso a2 und b2 das Objekt objekt2. Weiterhin tragt die Instanzvariable i2 von objekt1 eine Referenz auf objekt2. Diese Situation ist in der Abbildung durch diinne Pfeile mit einer hohlen Spitze charakterisiert.
170
4 Objektsammlungen
Wird nun in einer aktivierten Methode der Ausdruck x1 become: b2 evaluiert, so werden aIle Referenzen auf die durch x1 und b2 benannten Objekte, also auf die Objekte objekt1 und objekt2 vertauscht, so daB die durch dicke Pfelle mit voller Spitze charakterisierte Situation erhalten wird. Beispielsweise bezeichnet jetzt x1 und y1 (und alle weiteren Namen, die bisher objekt1 benannt haben) nunmehr objekt2 und umgekehrt. Dies trifft auch auf die Instanzvariable i2 zu, die nicht mehr objekt2, sondern ihr "eigenes" Objekt objekt1 referenziert. Die durch gestrichelte Pfeile gezeigten Referenzen bleiben unverlindert, da sie sich weder auf objekt1 noch objekt2 beziehen.
4.6
Aufgaben
Aufgabe 4.1
Sortieren von Zeichenketten
1m Programm 4-32 wurde unter Punkt (1) ein Beispiel angegeben, in dem Zeichenketten in eine sortierte Anordnung eingefUgt werden und zwar so, daB eine Zeichenkette vor einer anderen vorgereiht wird, wenn sie das Zeichen "a" ($a) weniger oder hOchsten gleich oft enthlilt. Man verallgemeinere dieses Beispiel derart, daB der Buchstabe, dessen Hliufigkeit fUr die Anordnung maBgebend ist, nicht fest im Code verankert ist, sonder frei als Parameter vorgegeben werden kann.
Losung von Aufgabe 4.1 Programm 4-32 zeigt unter Punkt (1) einen Block, der einen Parameter erwartet und als Ergebnis der Evaluation einen anderen Block mit zwei Argumenten liefert, der genau den Aufbau eines Sortierblockes mit der gewiinschten Eigenschaft besitzt. Dieser Ergebnisblock ist im Programm 4-32 durch Fettdruck gekennzeichnet. Wird dieser Block, wie unter Punkt (2) gezeigt, mit dem Literal $a als Argument evaluiert und das Ergebnis als Sortierblock einer Instanz von Sorted Collection zugeordnet, so entsteht dieselbe Wirkung wie in Programm 4-24. Wird der Block beispielsweise wie unter Punkt (3) mit dem Argument $x evaluiert, so werden die Zeichenketten nach der Hliufigkeit des in ihnen enthaltenen Buchstaben "x" im Behlilter angeordnet. Die fUr die Demonstration gewlihlten Zeichenketten sind so aufgebaut, daB sie jeweils mit einem Zahlzeichen beginnen, das auf die Anzahl der Buchsta-
4.6 Aufgaben
171
ben "x" hinweist und mit einem Zahlzeichen enden, durch welches die vorkommenden Buchstaben "a" gezahlt werden. Diese Zeichen sind durch Fettdruck hervorgehoben, so daB die Richtigkeit der Ergebnisse auf einen Blick iiberpriift werden kann. Workspace
I block sortColI stringArray I "(0) Erzeugen eines Feldes mit Zeichenketten." stringArray := #('5xxxxxOOOaa2' '4xxxxOOaaaa4' '2xxOOOOOOOa1' '3xxxOOaaaaa5' '0000000000' '1xOOOOOOaaa3'). "(1) Festlegen eines Sortierblockes." block := [:char I [:x:y I (x occurrencesOf: char) <= (y occurrencesOf: char))]. "(2) Erzeugen einer sortierten Sammlung: Sortierkriterium: Haufigkeit von $a." sortColI := SortedCollection sortBlock: (block value: Sa). sortColI addAII: stringArray; yourself. <printlt> SortedCollection ('0000000000' '2xxOOOOOOOa1' '5xxxxxOOOaa2' '1 xOOOOOOaaa3' '4xxxxOOaaaa4' '3xxxOOaaaaa5')
"(3) Umwandlung in eine sortierten Sammlung: Sortierkriterium: Haufigkeit von $x." sortColI asSortedCollection: (block value: $x). <printlt> SortedCollection ('0000000000' '1 xOOOOOOaaa3' '2xxOOOOOOOa l' '3xxxOOaaaaa5' '4xxxxOOaaaa4' '5xxxxxOOOaa2').
Programm 4-32 Erzeugung eines Sortierblockes
Aufgabe 4.2 Kreuzprodukte Das Kreuzprodukt zweier Mengen ist eine Menge, deren Elemente aus allen geordneten Paare gebildet werden, deren erste Komponente ein Element der ersten Menge und deren zweite Komponente ein Element der zweiten Menge ist. Beispielsweise gilt:
(l, 2, 3) x (a, b) = (, <1 b>, <2 a>, <2 b>, <3 a>, <3 b» Ebenso kann das Kreuzprodukt aus n ~ 2 Mengen gebildet werden, welches eine Menge ist, deren Elemente aile geordneten n-Tupel sind, deren i-te Komponente ein Element der i-ten Menge ist.
172
4 Objektsammlungen a) Man formuliere eine Methode Set»x aSet, die als Riickgabeobjekt das Kreuzprodukt aus dem Empfanger und dem Argument bildet. Die Paare sollen durch Felder (Instanzen von Array) mit zwei Elementen dargestellt werden. b) Man gebe eine Methode Set>>crossProductWithAII: anArrayOfSets an, welche das Kreuzprodukt aus dem Empfanger und allen im Argument enthaltenen Mengen bildet.
Losung von Aufgabe 4.2 a) Kreuzprodukt zweier Mengen Set methodsFor: 'kartesisches Produkt'
x aSet "Das Riickgabeobjekt ist das kartesische Produkt aus dem Empfanger und dem Argument. Der binare Selektor x wird auf der Tastatur durch xx erzeugt."
I result I result := Set new: (self size * aSet size * 3 II 2). self do: [:selfElem I aSet do: [:argElem I result add: (Array with: selfElem with: argElem))). "result
(1) (2) (3) (4)
(I) Da die Kardinalitiit der Ergebnismenge bekannt ist, wird ihr bereits bei der Erzeugung eine Kapazitiit verliehen, die urn 50 % tiber der Kardinalitiit Iiegt, wodurch ein wiederhoites Expandieren der Menge beim Autrtillen vermieden wird. (2) Iteration tiber die Elemente des Empfangers (auBere Schleife). (3) Iteration tiber die Elemente des Argumentes fur jedes Element des Empflingers (innere Schleife). (4) Ftir jede Elementkombination wird ein entsprechendes Paar gebildet und in die Ergebnismenge eingefugt.
Programm 4-33 Das Kreuzprodukt zwischen zwei Mengen Programm 4-33 bildet das Kreuzprodukt aus dem Empfanger und dem Argument, von dem erwartet wird, daB es eine Instanz der Klasse Set ist. Die einzelnen Schritte werden in den Kommentaren erlautert.
4.6 Aufgaben
173
Ein Beispiel fUr die Anwendung dieser Methode ist in Punkt (1) von Programm 4-35 angegeben. b) Kreuzprodukt mehrerer Mengen Methoden fUr die Bildung von Kreuzprodukten mehrerer Mengen sind aus Programm 4-34 zu entnehmen. Durch Set»prepareCrossAdd wird eine neue Menge erzeugt, die alle Elemente des Empfangers enthlHt, jedoch nicht direkt, sondern "eingepackt" als jeweils einziges Element eines Feldes. Die Elemente dieser Menge konnte man als eindimensionale Tupel bezeichnen. Set methodsFor: 'kartesisches Produkt'
prepareCrossAdd
"Aile Elemente des Empfangers werden als jeweils einziges Element eines Feldes gesetzt. Diese Felder werden in einer (neuen) Menge gesammelt, die das Riickgabeobjekt bildet." 1\
self collect: [:elem I Array with: elem]
crossAdd: aSet
"Erweitern der Tupel des Empfangers mit den Elementen des Argumentes urn eine Dimension. Das Riickgabeobjekt ist eine Menge, deren Elemente die neuen Tupel sind. "
I result I
result := Set new: (self size * aSet size * 3 1/ 2). self do: [:selfElem I aSet do: [:argElem I result add: {selfElem copyWith: argElem)]]. 1\ result
crossProductWrthAII: anArrayOfSets
"Bestimmen des kartesischen Produktes aus dem Empfanger und jenen Mengen, welche Elemente des Argumentes anArrayOfSets sind."
I result I
result := self prepareCrossAdd. anArrayOfSets do: [:set I result := result crossAdd: set]. 1\ result
Programm 4-34 Bildung von Kreuzprodukten mehrerer Mengen Die Methode Set»crossAdd: aSet geht von der Annahme aus, daB die Elemente des Empfangers bereits Tupel mit beliebiger Dimension sind. Sie bildet eine Art Kreuzprodukt aus Empfanger und Argument, indem sie die
174
4 Objektsammlungen
Elemente des Empfangers durch Verkettung mit den Elementen des Argumentes um eine Dimension erweitert. Durch diese beiden Hilfsmethoden kann die eigentliche Methode zur Bildung des Kreuzproduktes, Set>>crossProductsWithAII: anArrayOfSets, sehr einfach gestaltet werden. Es gentigt, den Empfanger durch Set»prepareCrossAdd vorzubereiten und sodann in einer Schleife tiber die Elemente des Argumentes das Ergebnis schrittweise aufzubauen. Workspace
I menge1
menge2 menge31 menge1 := menge with: 1 with: 2 with: 3. menge2 := menge with: 'a' with: 'b'. menge3 := menge with: 'x' with: 'y'. "(1) Bilden des Kreuzproduktes aus menge1 und menge2."
menge1 x menge2 <print!f> Set (#(1 'a') #(1 'b') #(2 'b') #(2 'a') #(3 'b') #(3 'a'» "(2) Bilden des Kreuzproduktes menge1 x menge2 x menge3."
menge1 crossProductWithAII: (Array with: menge2 with: menge3). <print!f> Set (#(1 'a' 'x') #(1 'b' 'x') #(2 'b' 'x') #(2 'a' 'x') #(3 'b' 'x') #(3 'a' 'x') #(1 'a' 'y') #(1 'b' 'y') #(2 'b' 'y') #(2 'a' 'y') #(3 'b' 'y') #(3 'a' 'y'» "(3) Bilden des Kreuzproduktes (menge1 x menge2) x menge3."
menge1 x menge2 x menge3 <print!f> Set (#(#(3 'b1 'y') #(#(3 'a') 'x') #(#(3 'a') 'y') #(#(1 'a') 'x') #(#(1 'b') 'x') #(#(1 'b') 'y') #(#(2 'b') 'x') #(#(2 'b') 'y') #(#(1 'a') 'y') #(#(2 'a') 'x') #(#(2 'a') 'y') #(#(3 'b') 'x'» Programm 4-35 Beispiele fUr Kreuzprodukte von Mengen Programm 4-35 zeigt unter Punkt (2) ein Beispiel fUr diese Methode. Man beachte den Unterschied zu Punkt (3), in dem das Ergebnis des Ausdruckes menge1 x menge2 x menge3 ausgegeben ist. Dieser Ausdruck wird von links nach rechts evaluiert, so daB zuerst das Kreuzprodukt aus menge1 und menge2 gebildet wird, welches schlieBlich zu einem Kreuzprodukt mit menge3 verkntipft wird. Die Elemente des Ergebnisses sind daher Paare, deren erste Komponente selbst ein Paar ist.
5
Mengen und Relationen
In diesem Kapitel wird ein tieferer Einblick in die Struktur und das Verhalten von Sammelbehiiltem gegeben und zwar dadurch, daB zuerst das Methodenspektrum der Klasse Set erweitert und dann eine weitere Behiilterklasse Relation als Subklasse von Set eingerichtet wird. Die gebotenen Beispiele beziehen sich auf Operationen, die aus dem Bereich der relationalen Datenbanken bekannt sind. Weiterhin wird an Hand der gegebenen Beispiele die Realisierung von mehrfach polymorphen Operationen (multi-polymorphic operations) erliiutert.
5.1
Mengenoperationen
In der vorgegebenen Klassenhierarchie von VisualWorks\Smalltalk® sind zahlreiche Methoden fUr die Verwaltung von Mengen vorgesehen, die speziellen Methoden fur die Mengenvereinigung, Mengendifferenz und fUr die Bildung des kartesischen Produktes von Mengen sind allerdings zu ergiinzen. Methoden fUr die Operationen der Vereinigung, Durchschnittsbildung und Differenzbildung zweier Mengen sind im Programm 5-1 zusammengestellt. Diesen Methoden wurden in Anlehnung an die in der Mathematik iibliche Bezeichnungsweise biniire Selektoren zugeordnet. Sie sind so ausgelegt, daB als Riickgabeobjekt stets ein neues Mengenobjekt geliefert wird und die Operandenmengen unversehrt erhalten bleiben. Die Mengenelemente selbst werden nicht kopiert, so daB beispielsweise das Ergebnis einer Mengenvereinigung ein neues Mengenobjekt ist, welches dieselben Objekte enthiilt, die auch in jenen Mengen enthalten sind, die vereinigt wurden. Programm 5-2 enthiilt in einem Arbeitsbereich ausgefUhrte Beispiele, welche die Wirkungsweise dieser Methoden demonstrieren.
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
176
5 Mengen und Relationen
Set methodsFor: 'set algebra' +aSet "Bestimmen der Vereinigungsmenge aus dem Empfanger und dem Argument." "self copy addAII: aSet; yourself
(1)
1\ aSet "Bestimmen der Schnittmenge aus dem Empfanger und dem Argument." "self select: [ :i I aSet includes: i ) \aSet "Bestimmen der Differenzmenge zwischen dem Empfanger und dem Argument." "self reject: [ :i I aSet includes: i ] (1) Die Methode Set»addAII: flillt den Empfanger mit den Elementen des Argumentes auf und bildet in diesem Sinne bereits die Vereinigung, allerdings destruktiv durch Veranderung des Empfangers.
Programm 5-1
Vereinigung, Durchschnitt und Differenz zweier Mengen
Workspace
I set1
set21
"Erzeugen zweier Mengen." set1 := Set withAII: #(1 234). set2 := Set withAII: #(3 4 5 6).
(1)
"Mengenvereinigung."
<printlt> Set (1 2 3 4 5 6)
set1 + set2. "Mengendurchschnitt"
<printlt> Set (34)
set1 /\ set2. "M engendifferen." set1 \ set2
<printlt> Set (12)
(1) Die K1assenmethode Set clasS>>WithAII: aColiection erzeugt eine neue Menge, die aile Elemente von aColiection enthalt.
Programm 5-2
Beispiele fUr Mengenoperationen
177
5.2 Relationen
Eine weitere wichtige Operation ist die Bildung des kartesischen Produktes zweier oder mehrerer Mengen, welches auch als Kreuzprodukt bezeichnet wird. Diese Operation wurde bereits in Aufgabe 4.2 des vorangehenden Kapitels angesprochen und in deren Losung vorgestellt. Das kartesische Produkt zweier Mengen ist ebenfalls eine Menge, die aus allen geordneten Paaren besteht, deren erster Partner ein Element der ersten Menge und deren zweiter Partner ein Element der zweiten Menge ist. Das kartesische Produkt X(Mb M2, ... , MJ der Mengen Mb M2, .. . , Mn ist entsprechend defmiert als X(Mb M2, .. . ,Mn) := {<eb e2, . .. , en> lei
E
Mb e2
E
M2, ... en
E
Mnl
die Menge aller geordneter Tupel mit n Elementen, deren i-tes Element der Menge Mj, i = 1, ... , n angehort. Beispiele fUr das Kreuzprodukt zweier Mengen sind auch im Programm 5-13 enthalten.
5.2
Relationen
Eine Teilmenge eines kartesischen Produktes, Rn ~ X(Mb M2, ... , MJ wird als n-stellige Relation bezeichnet. Ein Tupel erfUllt die Relation Rm wenn es ein Element dieser Relation ist. In man chen Fiillen wird eine Relation durch eine Bildungsregel charakterisiert. Beispielsweise bezeichnet die zweistellige Relation R(x I x
E
Z, Y E Z, X < y I
die (unendliche) Menge aller Paare <X, y> ganzer Zahlen mit x
178
5 Mengen und Relationen
Relationen konnen weiterhin dureh die Operationen der Relationenalgebra in andere Relationen ubergefiihrt werden. Dazu gehoren die Operationen Selektion (Auswahl von Tupel einer Relation naeh einem vorgegebenen Kriterium), Projektion (Einsehriinkung auf vorgegebene Komponenten der Tupel) und Verbund zweier Relationen (Verkettung der Tupel naeh einem vorgegebenen Kriterium). Diese Operationen bilden die Grundlage rur Datenmanipulationsspraehen von relationalen Datenbanken [14], [41], [13], [20]. In der Folge wird eine neue Klasse Relation in die Klassenhierarehie eingerugt und mit einigen Methoden versehen, die das rur Relationen eharakteristisehe Verhalten bewirken.
5.2.1
Die Klasse Relation
Da Relationen aile wesentliehen Eigensehaften von Mengen haben und nur wenige Methoden von Mengen zu adaptieren sind, ist es naheliegend, die Klasse Relation als Subklasse von Set in die Klassenhierarehie einzurugen. Die Elemente einer Relation mussen eine einheitliehe Struktur aufweisen. In der gezeigten Implementation wird jedoeh nur verlangt, daB die Elemente einer Relation Tupel mit gleieher Anzahl von Komponenten sind, eine Zugehorigkeit der Komponenten zu bestimmten Klassen oder Wertebereichen wird nieht gefordert, urn das Beispiel nieht zu umfangreieh und damit unubersiehtlieh werden zu lassen. Es ware nun naheliegend, rur die Relationen eine Instanzvariable zu definieren, welche die Anzahl der Komponenten angibt, aus denen ihre Tupel aufgebaut sein muss en. Die Dirnensionalitat einer Relation ware bei ihrer Initialisierung festzulegen und bei jedem Einfiigen eines weiteren Tupels ware zu priifen, ob dessen Komponentenanzahl mit der vorgegebenen Dirnensionalitat ubereinstirnmt. Diese Vorgangsweise wurde es aueh ermogliehen, einer leeren Relation eine Dimensionszahl zuzuordnen. Eine andere Mogliehkeit besteht darin, fiir Relationen keine zusatzliehe Instanzvariable vorzusehen und in eine neue, noeh leere Relation ein Tupel mit belie big vielen Komponenten aufzunehmen, allerdings darur Sorge zu tragen, daB jedes weitere Tupel gleiehe GroBe besitzt. In dies em Faile kann einer leeren Relation keine Dimensionalitat zugesehrieben werden, da diese erst naeh dem Einftigen des ersten Tupels festgelegt ist. Obwohl die erstgenannte Vorgangsweise aus einer konzeptionellen Sieht vorteilhaft erseheint, wurde die zweite Variante gewahlt, weil sie mit einem geringeren Implementationsaufwand verbunden ist. t Fur die Tupel einer Relation wird vorausgesetzt, daB sie Ausprligungen einer Unterklasse von SequenceableCollection sind, in den Beispielen wer-
179
5.2 Relationen
den Tupel stets durch Instanzen von Array dargestellt. Die Komponenten der Tupel werden uber ihre Indizes angesprochen und nicht uber Namen, wie es im relationalen Datenmodell ublich ist. Set variableSubclass: #Relation instanceVariableNames: " classVariableNames: " poolDictionaries: " category: 'Collections-Unordered' Relation methodsFor: 'testing' isRelation
"Oas ROckgabeobjekt ist true." (1)
"true isTupelCompatibleWith: aTupel
"Festellen, ob das Argument zu den Tupeln des Empfangers paBt." "self isEmpty ifTrue: [true] ifFalse: [self tupelDimension = aTupel size]
(2)
tupelDimension
"Bestimmen der Tupeldimension." "self isEmpty ifTrue: [0] ifFalse: [self anyTupel size]
(3)
anyTupel
"Oas ROckgabeobjekt ist ein beliebiges Element des Empfangers oder nil." "self detect: [:elem I true] ifNone: [nil] (1) AIle anderen Klassen antworten mit false, also: Object>>isRelation "false.
(2) Es wird hier nur die Anzahl der Elemente (Dimensionalitlit) gepriift, nicht jedoch die Wertebereiche (Klassenzugehorigkeit) der Elemente. (3) Diese Methode kann auch fUr andere Behlilterklassen niitzlich sein, so daB sie der Klasse Collection zugeordnet werden sollte.
Programm 5-3
t
Testmethoden fUr Relationen
Das ist auch dadurch begriindet, daB in der zugrundeliegenden Smalltalk-Version (VisualWorks\[email protected]) einige Methoden dec Klasse Set "ad hoc" programmiert sind, so daB sie auf die Einrichtung einer Subklasse nicht vorbereitet sind und daher zu iindern waren.
180
5 Mengen und Relationen
Programm 5-3 zeigt neben der Definition der Klasse Relation einige Methoden, welche Eigenschaften von Relationen testen und Hilfsfunktionen fiir andere Methoden erfiillen . Man erkennt, daB die Methode Relation»tupeIDimension fUr leere Relationen 0 ergibt und fUr nichtleere Relationen die GroBe eines willkiirlich durch Relation»anyTupel ausgewahlten Tupels liefert. Die Methode Relation»isTupeICompatibleWith: aTupel dient zur Uberpriifung, ob das Argument aTupel die gleiche GroBe hat wie die bereits in der Relation befindlichen Tupel und daher in die Relation aufgenommen werden kann. Die im Programm 5-4 angegebene Methode Relation»add: ist die zentrale Methode, iiber welche samtliche Einfiigeoperationen durchgefiihrt werden. Es sei daran erinnert, daB sich auch die Enumerationsmethoden der Klasse Collection dieser Methode bedienen, wenn sie Elemente in einen neuen Behalter einfiigen, ebenso die Erzeugungsmethoden der Art Collection class>>With:. In dieser Methode wird gepriift, ob ein in die Relation aufzunehmendes Tupel zu den bereits vorhandenen Tupel paJ3t, bevor die gleichnamige Methode der Superklasse aktiviert wird. Auf diese Weise wird sichergesteIlt, daB aIle Tupel einer Relation den gleichen Anforderungen geniigen, also die gleiche Anzahl von Komponenten haben. Es sei nochmals darauf hingewiesen, daB auf eine Uberpriifung, der Wertebereiche (KlassenzugehOrigkeit) der Elemente des Tupels verzichtet wird.
Relation methodsFor: 'adding' add:aTupel
"Einfiigen des Tupels in den Empfiinger, dieser ist das Riickgabeobjekt."
(self isTupelCompatibleWith: aTupel) if False: [self error: 'Tupel does not fit.'J. Asuper add: aTupel
(1)
(1) Die Uberpriifung der Kompatibilitat erfolgt ientral an dieser Stelle.
Programm 5-4
Einfiigen von Tupel in Relationen
Durch die folgenden in einem Arbeitsbereich ausgefiihrten freien Methoden (Programm 5-5) wird die Wirkunsweise der Methoden demonstriert. Man beachte, daB in beiden Relationen rel1 und rel2 ein gleiches Tupel #(1 2 3) vorkommt, welches auf Grund der von der Klasse Set geerbten Mengeneigenschaft nur einmal in der Vereinigung rel1 + rel2 auftritt.
181
5.2 Relationen
Der letzte Ausdruck von Programm 5-5 verursacht bei seiner Evaluation eine Fehlermeldung, da in der Methode Relation»add: (Programm 5-4) festgestellt wird, daB das einzufUgende Tupel nicht in die Relation paBt.
Workspace "Aufbauen von zwei kompatiblen Relationen."
I rel1
rel2 I rel1 := Relation new: 5. rel1 add: #(1 2 3); add: #(1 2 6 ); add: #(2 3 5); yourself. <printlt> Relation (#(2 3 5) #(1 2 6) #(1 2 3» rel2 := Relation new: 5. rel2 add: #(7 8 5); add: #(6 7 8); add: #(1 23); yourself. <printlt> Relation (#(7 8 5) #(6 7 8) #(1 2 3» "(Mengen)Vereinigung der Relationen" rel1 + rel2. <printlt> Relation (#(1 23) #(235) #(1 26) #(785) #(678» "(Mengen)Differenz der Relationen, Methode: Set»\" rel1 \ rel2. <printlt> Relation (#(1 2 6) #(2 3 5» "Versuch, ein zu grof3es Tupel in die Relation einzufugen." rel1 add: #(1 2 3 4). <printlt> Unhandled exception: 'Tupe/ does not fit'
Programm 5-5
Beispiele fUr Mengenoperationen mit Relationen
In einem nachsten Schritt konnen nun die relationalen Operationen implementiert werden.
5.2.2 Die Selektion von Relationen Die relationale Operation Selektion wahlt aus den Tupel einer Relation jene aus, die einer vorgegebenen Bedingung entsprechen. 1m Programm 5-6 ist eine Methode Relation»selectAt:value:using: gezeigt, welche die Auswahl von einem Vergleich einer Tupelkomponente mit einem vorgegebenen Wert abhangig macht, wobei die Art des Vergleiches durch einen als Parameter vorzugebenden Block festgelegt wird, welcher selbst zwei Blockargumente erwartet. Die Auswahl wird durch die Enumerationsmethode Collection»select:
182
5 Mengen und Relationen
durchgefUhrt, welche jene Tupel in eine neue Relation aufnimmt, fUr die der mit den entsprechenden Parametem versorgte Block zu true evaluiert wird. Diese allgemeine Methode wird in zwei als Beispiel angefUhrten spezielleren Methoden Relation»selectAt: valueEqual: und Relation»selectAt: valueless: verwendet. Relation methodsFor: 'relational algebra' selectAt: index value: aValue using: compareBlock "SELECT: Auswahl eines Tupels durch Vergleich einer Komponente mit einem Wert." 1\
self select: [:tupel I compareBlock value: (tupel at: index) value: aValue]
selectAt: index valueEqual: aValue "SELECT: Auswahl eines Tupels. wenn eine Komponente gleich einem Wert ist."
I\self selectAt: index value: aValue using: [:arg1 :arg21 arg1=arg2] selectAt: index valueless: aValue "SELECT: Auswahl eines Tupels. wenn eine Komponente kleiner als ein Wert ist."
I\self selectAt: index value: aValue using: [:arg1 :arg21 arg1<arg2] Programm 5-6
Die relationale Operation "Selektion" - Teill
1m Programm 5-7 sind eine zusatzliche allgemeine sowie eine spezielle Methode gezeigt, welche fUr die Selektion zwei Tupelkomponenten miteinander vergleichen. Relation methodsFor: 'relational algebra' selectAt: index1 andAt: index2 using: compareBlock "SELECT: Auswahl eines Tupels durch Vergleich (=) zweier Tupelkomponenten." 1\
self select: [:tupel I compareBlock value: (tupel at: index1) value: (tupel at: index2)]
selectAt: index1 lessThanAt: index2 "SELECT: Auswahl eines Tupels durch Vergleich «) zweier Tupelkomponenten. "
I\self selectAt: index1 andAt: index2 using: [:arg1 :arg21 arg1<arg2] Programm 5-7
Die relationale Operation "Selektion" - Teil2
183
5.2 Relationen
Programm 5-8 enthlilt einige Beispiele fur Anwendungen dieser Methoden. Das Ergebnis der Selektion einer Relation ist wieder eine Relation, deshalb k6nnen die Selektionsoperationen verkettet werden, wie dies unter Punkt 3a durchgefUhrt wird. Da die Ergebnisse einer Selektion dariiberhinaus noch gleiche Dimension haben, sind sie beziiglich der Mengenoperationen kompatibel und k6nnen durch diese verkniipft werden, was in den Beispielen 3b, 4 und 5 von Programm 5-8 durchgefUhrt ist. Workspace
I rel1 I
rel1 := (Relation new: 11) add: #(1 2 3); add: #(1 2 6 ); add: #(2 3 3 ); add:#(4 9 9); add: #(1 5 8); yourself.
"(1) Selektion aller Tupel mit t3 =3." rel1 selectAt: 3 valueEqual: 3. <printlf> Relation (#(1 23) #(2 3 3))
"(2) Selektion aller Tupel mit t2 < t3'" rel1 selectAt: 2 lessThanAt: 3. <printlt> Relation (#(1 5 8) #(1 2 3) #(1 2 6))
"(3a) Selektion aller Tupel mit t3 =3 UNO t2 < t3." (rel1 selectAt: 3 valueEqual: 3) selectAt: 2 lessThanAt: 3. <printlt> Relation (#(1 23»
"(3b) Selektion aller Tupel mit t3 =3 UNO t2 < t3'" (rel1 selectAt:3 valueEqual: 3) /\ (rel1 selectAt: 2 lessThanAt: 3). <printlt> Relation (#(123»
"(4) Selektion aller Tupel mit t3 =3 OOER t2 < t3'" (rel1 selectAt: 3 valueEqual: 3) + (rel1 selectAt: 2 lessThanAt: 3). <printlf> Relation (#(1 5 8) #(1 2 3) #(2 3 3) #(1 2 6))
"(5) Selektion aller Tupel mit t3 =3 UNO NICHT t2 < t3'" (rel1 selectAt: 3 valueEqual: 3) \ (rel1 selectAt: 2 lessThanAt: 3). <printlt> Relation (#(2 3 3))
Programm 5-8
Beispiele fUr Selektionsoperationen
Betrachtet man eine Relation als eine TabeUe, deren Zeilen den Tupeln entsprechen und die in jeder Spalte eine Komponente jedes Tupels enthlilt, so entspricht die Selektion einer Auswahl jener Zeilen, die der Selektionsbedingung entsprechen.
184
5 Mengen und Relationen
5.2.3 Die Projektion von Relationen Durch die Projektionsoperation werden die Tupel einer Relation auf jene Komponenten reduziert, auf welche die Projektion durchgefUhrt wird, aBe iibrigen Komponenten werden verworfen. In der Tabellensicht einer Relation entspricht die Projektion einem Streichen von Spalten, gefolgt von einem Streichen eventuell vorkommender Duplikatzeilen, urn die Mengeneigenschaft einer Relation aufrecht zu erhalten. Die im Programm 5-9 angegebene Methode Relation»projectAt: liefert als Ergebnis die Projektion des Empfangers auf die im Argument anzugebenden Tupelkomponenten.
Relation methodsFor: 'relational algebra' projectAt: anlndexArray "Bestimme eine Relation, welche die Projektion des Empfangers auf jene Dimensionen ist, die durch das Argument anlndexArray, gegeben sind."
I tupDim newDim I self isEmpty ifTrue:[Aself]. tupDim := self tupelDimension. newDim := anlndexArray size. (1) Aself collect: [:tupelll newTupel newlndex I newTupel := Array new: newDim. newlndex := O. anlndexArray do: [:i I newlndex:= newlndex +1. newTupel at: newlndex put: (tupel at: i)). newTupel] (1) Es wird ohne Priifung vorausgesetzt, daB aile Elemente von anlndexArray giiltige Indizes der Tupel des Empfangers sind, daB keiner mehrfach vorkommt und daB mindestens einer vorliegt.
Programm 5-9
Die relationale Operation "Projektion"
Diese Methode erzeugt durch die Enumerationsmethode Relation(Collection»>collect: eine neue Relation, in welche Tupel eingefUllt werden, die ihrerseits durch den Argumentblock der Methode Array(Coliection»>do: aus den Tupelkomponenten des Empflingers selektiv aufgebaut werden. In einem Arbeitsbereich ausgefUhrte Beispiele fUr die Anwendung dieser Projetionsmethode konnen dem Programm 5-10 entnommen werden. Man
185
5.2 Relationen
kann den Ergebnissen entnehmen, daB in den meisten Fallen die Anzahl der Tupel der Ergebnisrelation kleiner ist als jener der Ausgangsrelation. Workspace
I rel1 I rel1 := (Relation new: 11) add: #(1 2 3); add: #(1 2 6 ); add: #(2 3 3 ) add:#(49 9); add: #(1 58); yourself. "Projektion rel1 [1,2] und rel1 [2, 1], es entstehen binare Relationen." rel1 projectAt: #(1 2).
<printlt> Relation (#(1 2) #(2 3) #(1 5) #(4 9»
rel1 projectAt: #(2 1).
<printlt> Relation (#(2 1) #(3 2) #(5 1) #(9 4»
"Projektion rel1 [1,2,3] auf aile Tupelemente, es entsteht eine Kopie." rel1 projectAt: #(1 2 3).
<printlt> Relation (#(1 2 3) #(2 3 3) #(1 2 6) #(1 5 8) #(4 9 9» "Projektion rel1 [1], es entsteht eine unare Relation." rel1 projectAt: #(1).
<printlt> Relation (#(1) #(2) #(4»
Programm 5-10 Beispiele fUr Projektionsoperationen
5.2.4 Der Verbund von Relationen Das Ergebnis des Verbundes zweier Relationen ist eine Relation, deren Tupel aus einer Verkettung von Tupeln der Operandenrelationen entstanden sind, wobei die Verkettung nach verschiedenen Kriterien erfolgen kann. Ein Verbundkriterium wird durch die Angabe je einer Tupelkomponente t jeder der beiden Operanden und eine auf diese Komponenten anzuwendende Vergleichsoperation festgelegt. Zwei Tupel werden zu einem Tupel der Ergebnisrelation dann verkettet, wenn sie den Vergleich erflillen. Eine einfache Form des Verbundes ist der Gleichverbund tiber zwei Verbundkomponenten, bei dem die Tupel dann zu einem Tupel der Ergebnisrelation verkettet werden, wenn die beiden Verbundkomponenten gleich sind. t Yerbundoperationen iiber Mengen von Tupeikomponenten (beispieisweise zusammengesetzte Schliissel) werden hier nicht betrachtet.
186
5 Mengen und Relationen
Die im Programm 5-11 angegebene Methode Relation»joinAt: mylndex with:aRelation at: rellndex using: compareBlock bewirkt den Verbund tiber die Komponente mylndex der Empfangerrelation mit der Komponente rellndex der Argumentrelation aRelation, wobei die Gtiltigkeit des Vergleiches durch Evaluation des Argumentblockes compareBlock mit den Verbundkomponenten als Blockargumente festgestellt wird.
Relation methodsFor: 'relational algebra' joinAt: mylndex with: aRelation at: rellndex using: compareBlock
"JOIN : Verbund Uber die Elemente an den Positionen myindex und rellndex. Die Verkettung der Tupel wird durch compareBlock gesteuert."
I result I
aRelation isRelation ifFalse: [self error: 'Join argument must be a relation']. result := Relation new: (self size * aRelation size * 3 / / 2). self do: [:selfElem I aRelation do: [:argElem I (compareBlock value: (selfElem at: mylndex) value: (argElem at: rellndex)) ifTrue: [result add: (selfElem, argElem)]]]. (1) 1\ result
equiJoinAt: mylndex with: aRelation at: rellndex
"EQUIJOIN: Gleichverbund Uber die Elemente an den Positionen mylndex und rellndex." 1\
self joinAt: mylndex with: aRelation at: rellndex using: [:arg1 :arg21 arg1 = arg2]
greaterJoinAt: mylndex with: aRelation at: rellndex
"GREATERJOIN: GroBerverbund Uber die Elemente an den Positionen mylndex und rellndex." 1\
self joinAt: mylndex with: aRelation at: rellndex using: [:arg1 :arg2 I arg1 > arg2]
x aRelation
"Kartesisches Produkt." 1\
self joinAt: 1 with: aRelation at: 1 using: [:arg1 :arg21 true]
(1) Hier erfolgt die Verkettung der Tupel.
Programm 5-11 Verbund von Relationen tiber je eine Komponente
187
5.2 Relationen
Aus dieser allgemeinen Verbundmethode sind zwei speziellere Methoden abgeleitet, nlimlich fUr den Gleichverbund und den GroBerverbund. Ein Verbund mit beliebigen Vergieichsoperationen heiBt auch Theta-Verbund. Zuslitzlich ist im Programm 5-11 die Methode Relation»x angefUhrt, welche die allgemeine Verbundmethode derart spezialisiert, daB in jedem Fall alle Tupel der einen Relation mit allen Tupeln der anderen Relation verkettet werden. Das Ergebnis dieser Operation wird auch als Kreuzprodukt zweier Relationen bezeichnet.
Workspace
I rel1
rel2 I rel1 := (Relation new: 11) add: #(1 23); add: #(1 2 6 ); add: #(2 3 3 ); add:#(4 9 9); add: #(1 5 8); yourself. rel2 := (Relation new: 5) add: #(3 8); add: #(2 6); add: #(1 2); yourself.
"Gleichverbund rel1 (3) = reI2(1)." rel1 equiJoinAt: 3 with: rel2 at:1. <printlt> Relation (#(1 2 3 3 8) #(2 3 3 3 8»
"GroBerverbund rel1 (3) > reI2(2)." rel1 greaterJoinAt: 3 with: rel2 at:2. <printlt> Relation (#(1 2 3 1 2) #(2 3 3 1 2) #(1 2 6 1 2) #(1 5 8 1 2) #(1 5 8 2 6) #(4 9 9 2 6) #(4 9 9 1 2) #(4 9 9 3 8»
"Verbund und Projektion(rel1 (3) = reI2(1))[1, 2, 3]." (rel1 equiJoinAt: 3 with: rel2 at:1) projectAt: #(1 2 3). <printlt> Relation (#(1 2 3) #(2 3 3»
"Natiirlicher Gleichverbund rel1 (3) = reI2(1)." rel1 naturalJoinAt: 3 with: rel2 at: 1. <printlt> Relation (#(1 2 3 8) #(2 3 3 8»
Programm 5-12 Beispiele fUr Verbundoperationen Programm 5-12 zeigt in einem Arbeitsbereich Beispiele fUr die vorgestellten Methoden, in denen die Relationen rel1 und rel2 nach mehreren Kriterien verbunden werden.
188
5.3
5 Mengen und Relationen
Mehrfach polymorphe Methoden
In den vorangehenden Abschnitten wurden sowohl fUr die Klasse Set als auch fur deren Subklasse Relation Methoden fUr die Bildung eines Kreuzproduktes festgelegt und beiden der biniire Selektor "x" zugeordnet. Diese beiden Methoden haben unterschiedliche Bedeutung. Die Methode Set»x (Programm 4-33) erwartet als Argument eine Menge, also eine Instanz der Klasse Set oder einer Unterklasse von Set, sie liefert als Ergebnis eine Menge, deren Elemente Paare von Elementen der beiden durch die Operation verkniipften Mengen sind. Die Methode Relation»x (Programm 5-11) erwartet als Argument eine Relation, also eine Menge, deren Elemente durch Instanzen von Array dargesteHte Tupel sind. Sie liefert als Ergebnis eine Relation, deren Tupel durch Verkettung der Tupel der beiden Operanden gebildet werden. 1m Programm 5-13 sind Beispiele fUr diese Methoden gegeniibergestellt. Es werden dort zwei Relationen rel1 und rel2 erzeugt, die durch die Methode Collection»asSet in Mengen set1 und set2 umgewandelt werden. Das erste Beispiel zeigt eine Menge von Paaren als Ergebnis des Kreuzproduktes zweier Mengen. 1m zweiten Beispiel wird das Kreuzprodukt aus einer Menge und einer Relation gebildet, wobei das gleiche Ergebnis erhalten wird (die Reihenfolge der Elemente hat bei Mengen keine Bedeutung). In beiden Fiillen wurde die Methode Set»x aktiviert, die von ihrem Argument erwartet, daB es das Protokoll einer Menge versteht, was sowohl fUr Auspriigungen von Set als auch von Relation zutrifft. Das dritte Beispiel zeigt das Kreuzprodukt zweier Relationen. Man erkennt, daB die Ergebnisrelation Tupel enthiilt, die durch Verkettung aus den Tupel der Operandenrelationen entstanden sind. Bei der Bildung des Kreuzproduktes aus Relationen wurde beispielsweise aus den Tupeln <1 2> und <5> das Tupel <1 2 5> gebildet, wiihrend bei der Bildung des Kreuzproduktes aus den entsprechenden Mengen das Tupel (Paar) «12> <5» entstand. In diesem Fall wurde die Methode Relation»x aktiviert, die von ihrem Argument voraussetzt, daB es das Protokoll einer Relation versteht, urn die Tupel verketten zu konnen. 1m vier ten Fall wird versucht, das Kreuzprodukt aus einer Relation und einer Menge zu bilden, was fehlschlagen muB, da die Methode Relation»x keine Relation als aktuellen Parameter erhiilt, was schlieBlich in der Methode Relation»joinAt:with:at:using: durch einen Test abgefangen wird und zur Fehlermeldung Unhandled exception: 'Join argument must be a relation' fUhrt. Diese Situation ist unbefriedigend, weil es keinen Grund gibt, daB das Kreuzprodukt zwischen einer Menge und einer Relation (in dieser Reihen-
5.3 Mehrfach polymorphe Methoden
189
folge) sehr wohl gebildet werden kann, das Kreuzprodukt zwischen einer Relation und einer Menge jedoch nicht. Die Ursache eines solchen Problemes ist darin zu sehen, daB die beiden an der Operation beteiligten Objekte technisch nicht "gleichberechtigt" sind, da eines die Rolle des Empfangers der Methode spielt und das andere als Argument dient. Der Empfanger ist insofern bevorzugt, als durch ihn (genauer: durch seine Klassenzugehorigkeit) bestimmt wird, welche Methode aktiviert wird. Workspace
I rel1
rel2 set1 set2 I rel1 := (Relation new: 5) add: #(1 2); add: #(3 4); yourself. rel2 := (Relation new: 5) add: #(5); add: #(6); yourself. set1 := rel1 asSet. set2 := rel2 asSet.
"(1) Kreuzprodukt zweier Mengen." set1 x set2. <printlt> Set (#(#(1 2) #(6)) #(#(1 2) #(5)) #(#(3 4) #(5)) #(#(3 4) #(6)))
"(2) Kreuzprodukt einer Menge und einer Relation." set1 x rel2. <printlt> Set (#(#(1 2) #(5)) #(#(1 2) #(6» #(#(3 4) #(5)) #(#(3 4) #(6)))
"(3) Kreuzprodukt zweier Relationen." rel1 x rel2. <printlt> Relation (#(3 4 5) #(3 4 6) #(1 2 5) #(1 2 6))
"(4) Kreuzprodukt einer Relation mit einer Menge." rel1 x set2. <printlt> Unhandled exception: 'Join argument must be a relation'
Programm 5-13 Kreuzprodukte zwischen Mengen und Relationen In den meisten Hillen ist es eindeutig, welche Objekte Trager der durch eine Methode beschriebenen Eigenschaft sind und welche Objekte nur eine Zusatzinformation fUr die AusfUhrung der Methode liefern. In vielen Flillen ist es eine Entwurfsentscheidung, welcher Klasse eine Methode zugeordnet werden solI und welche an der Methode beteiligten Objekte in die Rolle von Parametern versetzt werden. So ist es klar, daB Methoden fUr den Zugriff auf Instanzvariable eines Objektes nur jener Klasse zugeordnet sein konnen, in der diese defmiert sind, oder einer ihrer Unterklassen. Ebenso wird auBer Zweifel stehen, daB eine
190
5 Mengen und Re1ationen
Methode, durch die ein Geldbetrag auf ein Bankkonto eingezahlt wird, einer Kontoklasse zuzuordnen ist und daB der Geldbetrag nur eine Zusatzinformation fUr den Buchungsvorgang darstellt. Das Buchen von Zah1ungsvorgangen ist ein VerhaItensmerkmal eines Kontos und kann nicht sinnvoll einem Geldbetrag zugeschrieben werden. Nicht sofort klar ist zum Beispiel, ob eine Methode, die eine Firma mit einer Person verbindet mit der Bedeutung, daB diese Person als Kunde der Firma gilt, der Firmenklasse oder der Personenklasse zugzuordnen ist. Die Variante Firma»akzeptiereKunde: einePerson ist ebenso denkbar wie die Variante Person»wAhleFirma: eineFirma so daB es yom Entwurf der Applikation abhangen wird, welcher Sicht der Vorzug zu geben ist. In allen diesen Fiillen gilt jedoch, daB die Klasse des Empfangers alleine die Methode bestimmt. Es gibt aber auch Faile, in denen die Auswahl der durchzufUhrenden Methode nur durch gleichzeitige Betrachtung der KlassenzugehOrigkeit mehrerer Objekte vorgenommen werden kann. So ein Faliliegt bei der Methode Relation»x vor, bei der die durchzufUhrende Aktion nicht nur von der Klasse des Empfangerobjektes, sondem auch von jener des Parameterobjektes abhangt. Derartige Falle treten insbesonders bei der binaren Verkniipfung zweier Operanden auf, wobei die Klassen der Operanden eine gemeinsame Oberklasse haben, in deren Unterklassen jedoch eine Redefinition von Methoden vorgenommen ist. Eine prinzipiell mogliche, aber nicht zu empfehlende Losung ware, die Methode Relation»x (Programm 5-11) auf die im Programm 5-14 gezeigt Art abzuandem.
Relation methodsFor: 'relational algebra' x aSetOrRelation "CARTESIAN PRODUCT"
(aSetOrRelation isMemberOf: Relation) ifTrue: ["Code fUr Relation»x aRelation, siehe Programm 5-11 '1. (aSetOrRelation isMemberOf: Set) ifTrue: ["Code fUr Set»x aSet, siehe Programm 4-33"]
(1)
(1) Es ware auch: [llsuper x aSetOrRelation] eine Losung, allerdings nur, wei! hier der Spezialfall voriiegt, daB Set eine Superkiasse von Relation ist.
Programm 5-14 Ein untauglicher Versuch fUr die Methode Relation»x
5.3 Mehrfach polymorphe Methoden
191
In dieser Methode wird zuerst gepriift, welcher Klasse (Set oder Relation) das Argument angehort und davon die durchzufiihrende Aktion abhangig gemacht. Fur den Fall, daB das Argument eine Relation ist, wird der ursprungliche im Programm 5-11 angefiihrte Code eingesetzt, ist das Argument eine Menge, so wird der bereits der Klasse Set zugeordnete Code Set»x in dieser Methode dupliziert. Ein Nachteil dieser Vorgangsweise ist, daB beim HinzufUgen weiterer Klassen, deren Auspragungen als Argumente in Frage kommen, die Methode entsprechend erganzt werden muB. Weiterhin entspricht es nieht dem Stil der objektorientierten Programmierung, klassenspezifisches Verhalten anders als durch Zuordnung der Methoden zu Klassen und dem damit verbundenen Polymorphismus zu losen. Bei der Aktivierung der Methode Relation»x ist bekannt, daB der Empranger eine Auspragung der Klasse Relation ist, wahrend die Klasse des Argumentes unbekannt ist. Man kann nun die Durchfiihrung der gewunschten Aktion, im gegenstandlichen Fall also die Berechnung des Kreuzproduktes, gezielt an eine Methode des Argumentes delegieren, der die Klasse ihres Argumentes bekannt ist. Dies erfolgt in der im Programm 5·15 vorgestellte Methode Relation»x, welche die ursprungliche im Programm 5-11 festgelegte gleichnamige Methode ersetzt. Diese delegiert die Aufgabe an ihr Argument, aSetOrRelation, und sendet dies em die Botschaft crossProductFromRelation: self. Eine Methode mit diesem Selektor ist allen in Frage kommenden Klassen (Set und Relation) zugeordnet, sie kann davon ausgehen, daB bei widmungsgemaBer Verwendung ihr Argument, aRelation, eine Instanz der Klasse Relation ist.
Relation methodsFor: 'relational algebra' x aSetOrRelation
"Kartesisches Produkt." "aSetOrRelation crossProductFromRelation: self Relation methodsFor: 'double dispatching' crossProductFromReiation: aRelation "aRelation jOinAt: 1 with: self at: 1 using: [:arg1 :arg2 I true]
Set methodsFor: 'double dispatching' crossProductFromRelation: aRelation "aRelation asSet x self
Programm 5-15 "Zweifachzuteilung" der Methode Relation»x
192
5 Mengen und Relationen
Die Vorgangsweise, eine Operation auf die erHiuterte Art auf zwei Methoden aufzuteilen und damit indirekt von zwei Klassen abhangig zu machen, kann als "Zweifachzuordnung" (double dispatching) bezeichnet werden [22], [24]. Ein Blick in die Subklassen von Number der Smalltalk-Klassenhierarchie zeigt, daB diese Vorgehensweise bei den arithmetischen Operationen und bei den Vergleichsoperationen von Zahlen intensiv angewendet wird, da in diesen Fallen vor der Durchfiihrung der eigentlichen Operation jeweils eine Umwandlung zwischen den unterschiedlichen Zahlendarstellungen erfolgen
muG. Die Technik der Mehrfachzuordnung kann auch bei Operationen mit mehr als zwei Operanden angewendet werden, jedoch wachst die Anzahl der fUr eine Operation notwendigen Methodenaktivierungen und auch die Anzahl der Methoden selbst stark mit der Anzahl der Operanden.
5.4
Aufgaben
Aufgabe 5.1
AuBerer Verbund von Relationen
Durch einen auBeren Verbund zweier Relationen (outer join) wird eine Relation erzeugt, deren Tupel eine Verkettung von Tupeln der Operandenrelationen sind. 1m Unterschied zu einem Gleichverbund oder Theta-Verbund werden nieht nur die "zusammenpassenden" Tupel der Operandenrelationen verkettet und in die Ergebnisrelation aufgenommen, sondem zusatzlieh aueh jene Tupel einer der beiden Operandenrelationen, fUr die kein passendes Tupel in der Partnerrelation gefunden wurde. Letztere Tupel werden urn die entspreehende Anzahl von Komponenten erweitert, die aIle mit einem "Nullwert" belegt sind. Je naehdem, ob die linke oder rechte Operandenrelation die dureh "Nullwerte" erganzten Tupelliefem solI, wird von linken und reehten auBeren Verbunden gesprochen. Man defmiere die Methoden Relation»leftOuterJoinAt:with:at:using: und Relation»rightOuterJoinAt:with:at.using: welche die erwlihnten liuBeren Verbunde erzeugen, wobei die Nullwerte dureh das Symbol :ft:NULL dargestellt werden.
Aufgabe 5.2
Natiirlicher Gleichverbund
Ais Ergebnis eines (normal en) Gleichverbundes zweier Relationen entsteht eine Relation, deren Tupel die zwei stets gleiehen Verbundkomponenten der
193
5.4 Aufgaben
Operanden enthalten. Bei einem natiirlichen Gleichverbund wird eine dieser beiden Komponenten eliminiert, so daB die Dimension des Ergebnisses um eins kleiner ist als die Summe der Dimensionen der Operanden. Man entwerfe eine Methode Relation»naturaIJoinAt:with :at:, die einen natiirlichen Gleichverbund zwischen dem Empfanger und der Argumentrelation iiber die durch die Indizes angegebenen Komponenten erzeugt.
Losung von Aufgabe 5.2 Programm 5-16 entbalt einen Vorschlag fUr die Bestimmung des natiirlichen Gleichverbundes zweier Relationen. Ein Beispiel fUr diese Methode ist bereits im Programm 5-12 enthalten. Relation methodsFor: 'relational algebra'
naturalJoinAt: mylndex with: aRelation at: rellndex
"Natiirlicher Gleichverbund."
I indexArray selfDimension I
selfDimension := self tupelDimension. indexArray := selfDimension + aRelation tupelDimension. indexArray := (1 to: indexArray) asArray copyWithout: (selfDimension + rellndex). 1\ (self equiJoinAt: mylndex with: aRelation at: rellndex) projectAt: indexArray
(1)
(1) Aus einem Feld mit allen Indizes der Ergebnisrelation wird der nunmehrige Index der Verbundkomponente von aReiation entfemt. Die Variable indexArray enthlilt somit alle Indizes, aufwelche das Ergebnis des Verbundes projiziert werden muB.
Programm 5-16 Natiirlicher Gleichverbund zweier Relationen
Aufgabe 5.3
Relationen im Sinne des Relationenmodells
Bei Relationen im Sinne des relationalen Datenmodells werden die Komponenten der Tupel als Attribute von Objekten interpretiert, sie werden nicht durch Indizes, sondern durch Attributnamen bezeichnet und durch diese auch in den Operationen angesprochen. Weiterhin werden den Relationen Einschrlinkungen auferlegt, die vorgeben, daB Relationen nur solche Teilmengen des Kreuzproduktes sein diirfen,
194
5 Mengen und Relationen
die zusiitzliche Bedingungen erfUllen. Eine solche Einschriinkung ist die Forde rung, daB eine vorgegebene Attributmenge (Primiir)schliissel in der Relation ist. Da die Tupel einer Relation durch einen Schliissel eindeutig identifiziert werden, bedeutet diese Einschriinkung, daB in einer Relation keine zwei Tupel mit gleicher Schliisselauspriigung vorkommen diirfen. a) Man fUhre in der Klasse Relation aIle notwendigen Anderungen durch, damit die Komponenten der Tupel durch Attributnamen angesprochen werden konnen. Man beachte, daB auch bei der Erzeugung von Relationen durch Mengenoperationen und relationale Operationen die Attributnamen bereitgestellt werden miissen. b) Man ermogliche fUr Relationen die Festlegung eines Primiirschliissels und iindere siimtliche Methoden, welche Tupel in Relationen einfUgen, derart ab, daB die geforderte Schliisseleigenschaft sichergestellt wird.
Aufgabe 5.4 Zweifach polymorphe Methode Es wird angenommen, das die abstrakte Klasse Rechtsperson und ihre konkreten Subklassen Firma, Institution und Privatperson eingerichtet sind. Firmen, Institutionen und Privatpersonen konnen sich gegenseitig Auftriige erteilen, jedoch hiingt die Art des Auftrages sowohl von der Art des Auftraggebers als auch von der Art des Auftragnehmers abo Es sollen die Methoden fUr die Auftragsvergabe nach der double dispatching-Technik eingerichtet werden, wobei das Ergebnis einer Auftragsvergabe durch eine Zeichenkette der Form: 'Auftrag von Firma an Privatperson '
angedeutet werden solI.
Losung von Aufgabe 5.4 In jeder der in Frage kommenden Operandenklassen, das sind hier die Klassen Firma, Institution und Privatperson, muB der Vorgang der Auftragserteilung auf zwei Methoden aufgeteilt werden, und zwar auf eine "Auftragserteilungsmethode" und eine "Hilfsmethode", wobei so viele Hilfsmethoden festzulegen sind, wie es unterschiedliche Arten von Auftragspartner gibt. 1m Programm 5-17 ist dies fUr die Klasse Firma gezeigt. Die "Auftragserteilungsmethode" triigt hier den Selektor auftragAn:, die Hilfsmethoden heiBen auftragVonFirma:, auftragVonlnstitution: und auftragVonPrivatPerson:. Durch die Wahl der Methodennamen ist die jeweilige Richtung der Teilaktivitiit angedeutet.
5.4 Aufgaben
195
Jeder dieser Klassen muG eine Methode auftragAn: zugeordnet werden. Diese Methoden unterscheiden sich nur durch den Namen der an das Argument zu sendenden Hilfsmethode, der die KlassenzugehOrigkeit des Senders ausdriickt. Wenn man die im Programm 5-17 angedeutete Namenskonvention einhlilt, kann man statt je einer Auftragsmethode in den Klassen Firma, Institution und Privatperson, eine Methode der abstrakten Klasse Rechtsperson zuordnen, was im Programm 5-18 gezeigt ist. Firma methodsFor: 'auftragswesen'
(1)
auftragAn: eineRechtsperson "Beauftragen einer Rechtsperson." "eineRechtsperson auftragVonFirma: self Firma methodsFor: 'double dispatching'
(1)
auftragVonFirma: eineFirma "Entgegennahme eines Auftrages von einer Firma." "'Auftrag von Firma " eineFirma name, 'an Firma " self name auftragVonlnstitution: einelnstitution "Entgegennahme eines Auftrages von einer Institution." "'Auftrag von Institution', einelnstitution name, ' an Firma ',self name auftragVonPrivatperson: einePrivatperson "Entgegennahme eines Auftrages von einer Privatperson." "'Auftrag von Privatperson', einePrivatperson name,' an Firma', seH name (1) Analoge Methoden miissen auch fUr die Klassen Institution und Rechtsperson festgelegt werden!
Programm 5-17 Zweifach polymorphe Auftragsmethoden
Rechtsperson methodsFor: 'auftragswesen' beauftrage: eineRechtsperson I selector I selector := ('auftragVon', self class name, ':') asSymbol. "eineRechtsperson perform: selector with: self Programm 5-18 Auftragsdelegation durch eine indirekte Methode
5 Mengen und Relationen
196
Workspace
If pi I f := Firma newName: 'X-Ges.m.b.H.'. p := Privatperson newName: 'So Freud'. i := Institution newName: 'AI'. f auftragAn: p.
(1)
<printlt>
'Auftrag von Firma X-Ges.m.b.H. an Privatperson S. Freud'
p auftragAn: 1.
<printlt>
'Auftrag von Privatperson S. Freud an Firma X-Ges.m.b.H.'
i auftragAn: i.
<printlt>
'Auftrag von Institution AI an Institution AI'
f beauftrage: p.
<printlt>
'Auftrag von Firma X-Ges.m.b.H. an Privatperson S. Freud' (1) Die Methode Rechtsperson class»newName: erzeugt eine Auspragung initialisiert die Instanzvariable name.
Programm 5-19 Beispiele fUr die Vergabe von Auftragen In der Methode Rechtsperson»beauftrage: ist der Selektor der an das Argument zu sendenden Hilfmethode nicht fest vorgegeben, sondern wird erst konstruiert. Dies geschieht durch Verkettung der drei Zeichenketten 'auftragVon', dem Namen der aktuellen Empflingerklasse und ':' sowie Umwandlung der erzeugten Zeichenkette in ein Symbol. Die nunmehr konstruierte Botschaft wird mit dem Argument self versehen durch indirekte Botschaftsiibermittlung (perform:with:) an das Methodenargument (den Auftragspartner) gesendet. Programm 5-19 zeigt einige Beispiele fUr die entwickelten Methoden. Man sieht, daB die Ergebnisse der Evaluation der beiden Ausdriicke f auftragAn: p und f beauftrage: p gleich sind, die Methoden unterscheiden sich nur durch die Art der aktivierung der Hilfsmethode.
6
Objektstrukturen
Jedes mit Instanzvariablen ausgestattete Objekt kann als komplexes Objekt gesehen werden, da es tiber seine Instanzvariablen andere Objekte zugeordnet hat. Die Tatsache, daB ein Objekt mittels einer Instanzvariablen ein anderes Objekt referenziert, solI als Objektzuordnung bezeichnet werden. Durch eine Objektzuordnung wird ein Partnerobjekt (Zielobjekt) an ein Trligerobjekt (Quellobjekt) gebunden. Die Zuordnung ist einseitig, das Trligerobjekt kennt sein Partnerobjekt und kann es innerhalb seiner Methoden durch Ansprechen der betreffenden Instanzvariablen jederzeit erreichen, eine Navigation in umgekehrter Richtung ist hingegen nicht moglich. Auf Systemebene betrachtet ist die Objektzuordnung die einzige Moglichkeit, Objekte miteinander zu verbinden und auf diese Weise Objektstrukturen aufzubauen. Aus einer konzeptionellen Sieht konnen solche Beziehungen zwischen Objekten verschiedene Bedeutungen haben. Beispielsweise kann eine Objektzuordnung bedeuten, daB das Zielobjekt nur dazu dient, eine unmittelbare Eigenschaft des Trligerobjektes zu beschreiben, in einem solchen Fall solI von einer Attributzuordnung oder auch Attributbeziehung gesprochen werden. In einem anderen Fall kann durch die Zuordnung eine Aggregationsbeziehung realisiert sein, in welcher das Zielobjekt als Bestandteil des Quellobjektes interpretiert werden kann. Eine Objektzuordnung kann aber auch die Tatsache ausdrticken, daB das Zielobjekt mit dem Trligerobjekt in einer allgemeinen Assoziationsbeziehung steht, etwa urn fUr das Trligerobjekt leicht ansprechbar zu sein und Dienstleistungen direkt anfordem zu konnen. Wenn auch die verschiedenen Arten der konzeptionellen Beziehung letztlich durch das gleiche technische Konstruktionselement realisiert werden, nlimlich durch die Referenzierung eines Objektes mit Hilfe einer Instanzvariablen, so werden doch die Methoden, durch welche solche Beziehungen eingerichtet oder verlindert werden, die jeweilige Semantik der Beziehung zu beriicksichtigen haben. Dies ist notwendig, urn die Integritlit der Objekte des Anwendungsgebietes selbst und auch die Integritlit ihrer Beziehungsstruktur entsprechend den Modellvorgaben sicherzustellen. G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
198
6 Objektstrukturen
Betrachtet man die im Objektraum existierenden Objekte als Knoten eines gerichteten Graphen und die tiber die Instanzvariablen hergestellten Objektzuordnungen als Kanten, dann wird durch eine Objektzuordnung eine neue Kante erriehtet, die vom Tragerobjekt zum Partnerobjekt weist. Das bedeutet auch, daB die Menge aller jener Objekte, die vom Tragerobjekt tiber einen Weg erreichbar sind, urn die Menge der vom Partnerobjekt erreichbaren Objekte im Sinne der Mengenvereinigung erweitert wird. Die durch die Errichtung der Zuordnung bedingte VergroBerung der Kardinalitat der Erreichbarkeitsmenge des Tragerobjektes kann dabei sehr unterschiedlich ausfallen, die Kardinalitat der Erreichbarkeitsmenge des Partnerobjektes andert sich dabei nicht. Wenn das Partnerobjekt bereits vor der Errichtung der Zuordnung ein Element der Erreichbarkeitsmenge des Tragerobjektes war, llndert sich deren Kardinalitat nieht. Dieser Fall tritt beispielsweise dann ein, wenn das neu zuzuordnende Partnerobjekt bereits tiber eine andere Instanzvariable dem Tragerobjekt direkt oder indirekt zugeordnet ist oder wenn das Tragerobjekt sich in der neuen Zuordnung selbst referenziert. Der andere Extremfallliegt vor, wenn die Erreichbarkeitsmengen des Quellobjektes und des Zielobjektes vor der Errichtung der Zuordnung disjunkt sind, so daB die Kardinalitat der Erreichbarkeitsmenge des Tragerobjektes urn jene des Partnerobjektes vergroBert wird. Solange sich die Betrachtung auf den konzeptionellen Objektraum oder den technischen Objektraum transienter Objekte beschrllnkt, spielt die Kardinalitat der Erreiehbarkeitsmenge eines Objektes keine besondere Rolle. MuB man jedoch Eigenschaften eines Objektraumes fUr persistente Objekte beriicksichtigen, etwa beim Einsatz einer Objektbank (objektorientierten Datenbank), hat dieser Aspekt sehr wohl eine Bedeutung. Eine Moglichkeit, bei der Errichtung einer Zuordnung die VergroBerung der Kardinalitat der Erreichbarkeitsmenge des Tragerobjektes gering zu halten, wird im Zusammenhang mit indirekten Zuordnungen gezeigt.
6.1
Elementare Zuordnungsmethoden
Unabhangig von der Bedeutung einer Beziehung und ihren sonstigen Eigenschaften werden in jedem Fall Beziehungen durch schreibenden Zugriff auf eine Variable eingerichtet und durch lesenden Zugriff abgefragt. Durch die in Programm 6-1 an Hand der Namenszuordnung zu einer Person gezeigten elementaren Methoden konnen diese Beziehungen explizit nach auBen zuganglich gemacht werden.
6.2 Attributzuordnungen
199
Object subclass: #Person instanceVariableNames: 'name vornamen adresse' classVariableNames: " poolDictionaries: " category: 'Personen' Person methodsFor: 'accessing'
name: einName
"Mutatormethode (Errichten einer Zuordnung): Festlegen des Namens" name := einName
name
"Akzessormethode (Navigation zum Partnerobjekt): Nennen des Namens" J\name
Programm 6-1
Elementare Zuordnungsmethoden
In vielen Hillen ist es vorteilhaft, Zuordnungen ausschlieBlich durch derartige Methoden zu verwalten und einen direkten Zugriff auf Instanzvariable in anderen Methoden zu vermeiden. Dadurch ergibt sich die Moglichkeit, Zugriffskontrollen zentral zu implementieren und zu verwalten, ohne daB dadurch andere Methoden betroffen werden. Viele Implementationstechniken und Frameworks setzen voraus, daB fUr aIle Instanzvariablen namenskonforme Zugriffsmethoden der angefuhrten Art eingerichtet sind. Allerdings kann man diese Vorgangsweise aus konzeptioneIler Sicht auch als problematisch beurteilen, weil dadurch gegen das Prinzip der Objektkapselung verstoBen und die innere Struktur eines Objektes nach auBen sichtbar gemacht wird [6]. Vor der Erlauterung verschiedener Eigenschaften von Objektzuordnungen werden Attributbeziehungen behandelt, die einen wichtigen Sonderfall von Objektzuordnungen bilden.
6.2
Attributzuordnungen
Eine Objektzuordnung hat den Charakter einer Attributzuordnung, wenn das Zielobjekt nur dazu dient, eine unmittelbare Eigenschaft des Quellobjektes festzulegen, ansonsten aber keine weitere eigenstandige Bedeutung hat. In diesem Fall soU das Zielobjekt als Attribut bezeichnet werden.
200
6 Objektstrukturen
In Programm 6-1 wurde bereits die Zuordnung eines Namens zu einer Person angesprochen, welche als Attributbeziehung gesehen werden kann. Auch die Adresse kann als Attribut einer Person betrachtet werden, wenn ihr aus konzeptioneller Sicht keine Bedeutung als eigenstiindig existierendes Objekt mit veranderlichen Eigenschaften zugesprochen werden soU.
1
Iname - - . Person
Person
name (A) vornamen (A) adresse (A)
O.. n
(A)
String
String
vornamen - .
I 0 ..1 a)
(A)
b) adresse
--.
(A)
String
L-i Modell I Abbildung 6-1
Notation von Attributbeziehungen in einem Modell
Abbildung 6-1 zeigt die Notation von Attributbeziehungen in einem Modell. 1m linken Teil der Abbildung ist eine Kurzform angegeben, in der die Namen der Attributbeziehungen in das Klassensymbol eingetragen sind. 1m rechten Teil der Abbildung ist dieselbe Situation im Detail dargestellt. Durch dieses Modell wird ausgedriickt, daB jede Person die Attribute Name, Vornamen und Adresse besitzt. Die ausflihrliche Darstellung zeigt zusatzlich, daB die Zielobjekte der Klasse String angehoren sollen und daB die direkte Navigation nur vom Quellobjekt zum Zielobjekt moglich ist. In der Abbildung wird durch den Zusatz "(A)" auf die Attributeigenschaft hingewiesen. Zusatzlich ist im konkreten Beispiel verlangt, daB jede Person genau einen Namen haben muB, jedoch belie big viele Vornamen besitzen kann, was jedoch mit der Attributeigenschaft selbst nichts zu tun hat. An dieser Stelle sei auf die unterschiedliche Bedeutung eines Klassensymbols in einem Modell und im Objektraum hingewiesen. In einer Modelldarstellung, die auch als Klassendiagramm bezeichnet wird, steht das Klassensymbol stellvertretend flir aile seine moglichen Auspragungen, also flir die jeweilige Extension der Klasse. Die im Modell gezeigt Struktur gilt somit flir jede Auspragung der angegebenen Klasse. Ein Klassensymbol im Objektraum hingegen bezeichnet das individuelle Klassenobjekt, also die einzige Auspragung seiner Metaklasse. Dieser Unterschied tritt nur dann deutlich hervor, wenn Klassen selbst vollwertige Objekte sind.
6.2 Attributzuordnungen
201
Zielobjekte einer Attributbeziehung sind im allgemeinen wenig strukturierte, einfache Objekte, wie Zahlen, Zeichen, Zeichenketten oder Symbole. Die durch Attribute vermittelte Information ist ihr "Wert", der als allgemein verstandlich vorausgesetzt werden kann und daher keiner weiteren Interpretation bedarf. Attribute konnen durch folgende Eigenschaften charakterisiert werden [3], [4]: • Attribute, beispielsweise Zahlen, sind eine allgemein bekannte Abstraktion und haben eine allgemein akzeptierte Bedeutung, • Attributewerte besitzen oft eine vordefmierte Bezeichnung (Literale), • Attribute und ihre Namen sind oft direkt irn System verankert, sie mtissen nicht mehr defmiert werden, • die durch ein Attribut dargestellte Information ist sein Wert selbst, dieser wird oft direkt durch den vordefmierten Namen ausgedriickt. Ob ein Objekt den Charakter eines Attributes hat, ist jedoch irn allgemeinen keine Eigenschaft des Objektes selbst, sondem hangt von seiner konzeptionellen Rolle abo Ausprligungen der Klassen Smalllnteger (beispielsweise 1996, -5) und Character (beispielsweise $a, $z) sind unmittelbare a-priori-Objekte und haben daher in jedem Fall Attributcharakter. Dies gilt ebenso fUr die Auspragungen der Klassen True (true), False (false) und UndefinedObject (nil), welche der virtuellen Maschine direkt bekannte Unikate sind. Weiterhin konnen aIle Symbole (Auspragungen der Unterklassen von Symbol, namlich ByteSymbol und TwoByteSymbol) als systemweit eindeutige und unveranderliche Objekte zu jenen Objekten gezahlt werden, die auf alle FaIle Attribute darstellen. Allen eben erwahnten Objekten ist gemeinsam, daB sie weder veranderbar noch kopierbar sind und daB sie (mit Ausnahme der Symbole) auch nicht erzeugt und vemichtet werden konnen und somit keinen Lebenszyklus aufweisen. Attribute sind konzeptionell gesehen Werte und keine mit Identitat und Verhalten ausgestatteten Objekte. Sie reprasentieren eine Eigenschaft eines bestirnmten Objektes und konnen nicht mehreren Objekten gemeinsam angehoren, sie sind ausschlieBlich tiber ihr Tragerobjekt erreichbar [36]. Es ist daher eine wesentliche Forderung fUr eine Attributzuordnung, daB das Attributobjekt selbst keinen Veranderungen unterworfen werden darf. Eine Anderung einer Attributbeziehung darf daher nie durch Verlinderung des Attributobjektes, sondem nur durch Zuordnung eines anderen Objektes erfolgen. Ftir die oben erwahnten Objektarten ist eine Anderung prinzipiell nicht moglich, so daB in diesen Fallen keine besonderen Vorkehrungen zu treffen sind. Ftir Objekte, die zwar veranderbar sind, jedoch in einer Zuordnung die Rolle eines Attributes spielen solI en, sind jedoch MaBnahmen zur Sicherstellung der Attributeigenschaften einzuhalten. Sofern es sich nicht um permanent existierende Objekte handelt, ist die Existenz eines Attributobjektes nur durch seine Zuordnung zu einem Trager-
202
6 Objektstrukturen
objekt begriindet, es sollte sich daher nur fUr die Dauer der Zuordnung im Objektraum befinden. Ein solches Objekt ist im Objektnetz dadurch gekennzeichnet, daB es genau eine unveranderliche Eingangskante besitzt. Eine MaBnahme zur Sicherstellung dieser Forderung ist, daB ein Attributobjekt unmittelbar vor der Einrichtung der Zuordnung erzeugt wird, moglichst ohne daB es vorher an eine Variable gebunden war. Fiir den haufigen Fall, daB Zahlen oder Zeichenketten die Rolle von Attributen spielen, empfiehlt es sich daher, diese in ihrer Literaidarstellung als Parameter der Zuordnungsmethode anzufUhren. Dieser Forderung kommt auch entgegen, daB die Ergebnisse arithmetischer Operationen stets neue Zahlenobjekte liefern und nicht vorhandene Objekte modifizieren. Beim Entwurf von Klassen, deren Auspragungen als Attributobjekte dienen soIlen, ist auf diese Eigenschaft zu achten, wie auch am Beispiel der an anderer Stelle entworfenen Klasse Money gezeigt wird. Die Forderung, daB ein Objekt unmittelbar nach seiner Entlassung aus einer Attributbeziehung auch seine Existenz verliert, ist dann erftillt, wenn es von keinem anderen Objekt als von seinem Tragerobjekt referenziert wird. Dies erklart sich daraus, daB ein Objekt genau dann, wenn es im Objektraum von keinem Objekt mehr erreichbar ist, durch den automatisch ablaufenden Mechanismus der Speicherbereingung aus dem Objektraum entfernt wird. Die Einhaltung dieser Forderung kann zwar nicht zentral sichergestellt werden, sondern nur durch entsprechende Beriicksichtigung in jenen Methoden, welche Anderungen der Attributzuordnungen bewirken. Als Regel kann gelten, daB die Anderung eines Attributes nur durch Zuordnung eines neuen Objektes vorgenommen werden soll, nieht durch Zuordnung eines bereits in einem anderen Zusammenhang bestehenden Objektes oder durch Abanderung des Zustandes eines Attributobjektes. In Programm 6-2 sind Beispiele fUr diese Vorgangsweise gezeigt. In einer objektorientierten Programmiersprache, in der es moglich ist, neben den eigentlichen Objekten auch "Daten" zu verwenden, erscheint die Diskussion iiber Attributobjekte iiberfliissig, da Attribute durch Daten und nicht durch Objekte dargestellt werden. In Smalltalk ist ein rein objektorientiertes Paradigma realisiert, bei dem selbst Zahlen und Zeichen, also Entitaten, die einen "Wert" darstellen, der Charakter von Objekten verliehen ist. Da es manchmal notwendig ist, den" Wertcharakter" von Objekten zu betonen, kann durch die Betrachtung von Objekten als Attributobjekte diesen die fUr "Daten" charakteristische Kopiersemantik aufgepragt werden. In Programm 6-2 ist unter Punkt (2) darauf hingewiesen, daB die Eigenschaft einer Attributzuordnung auch durch Zuweisung einer Kopie eines bestehenden Objektes erreicht werden kann. Urn auf der sicheren Seite zu sein, kann der Kopiervorgang bereits in den Zuordnungsmethoden vorgesehen werden. Diese Vorgangsweise ist in Programm 6-3 an Hand der Attributzuordnung eines Namens zu einer Person gezeigt. Die Methode tragt hier den
203
6.2 Attributzuordnungen
Namen nameAlsAttribut: urn sie von der Methode name: unterscheiden zu kannen. Workspace
I person1
person21
"(1) Zwei Personen wird der gleiche (aber nicht derselbe) Name zugeordnet" person1 := Person newMitNamen: 'Maier'. person2 := Person newMitNamen: 'Maier'. person1 name = person2 name
(1) <printlt>
false
"(2) Person1 soli den gleichen Namen erhalten, den Person2 bereits besitzt, hier ist es wesentlich, daB eine Kopie des Attributobjektes erzeugt wird!" person1 name: person 2 name copy
"(3) Der Name von Person1 soli von 'Maier' auf 'Mayer' korrigiert werden." person1 name: 'Mayer'.
"(4) Die Namensanderung sollte jedoch nicht durch Zustandsanderung erfolgen:" person 1 name at: 3 put: $y (1) Durch die hier verwendete Erzeugungsmethode wird einer Person bei der Erzeugung sofort ein Name zugewiesen, wodurch der Modellannahme Rechnung getragen wird, daB eine Person einen Namen besitzen muB! Die Methode selbst ist in Programm 6-11 angegeben.
Programm 6-2
Beispiele fur Operationen mit Attributobjekten
Person methodsFor: 'accessing-attributes' nameAlsAttribut: einName
"Schreibzugriff (Errichten einer Attributzuordnung): Festlegen des Namens." name := einName copy nameAlsAttribut
"Lesezugriff: Nennen des Namensattributes." Aname copy Programm 6-3
Methoden fUr eine Attributzuordnung
204
6 Objektstrukturen
Da in der Klasse Object eine Methode copy vorgesehen ist, wird diese auf dem Weg der Methodenvererbung von allen Objekten verstanden. Fur den Fall, daB der Empfanger ein nichtkopierbares Objekt ist, wird jedoch an Stelle einer Kopie der Empfanger selbst geliefert. Das Zuweisen einer Kopie beim schreibenden Zugriff stellt sicher, daB das Attributobjekt unmittelbar vor seiner Zuweisung an die Instanzvariable erzeugt wird und daher nicht von einem anderen Objekt referenziert werden kann. Der Kopiervorgang beim lesenden Zugriff verhindert, daB das eigentliche Attribut einer moglichen Verlinderung ausgesetzt wird. Die unter Punkt (4) von Programm 6-2 angedeutete Vorgangsweise ware damit wirkungslos, weil die Verlinderung nicht das Attributobjekt, sondern eine Kopie betrifft. Dies gilt selbstverstandlich nur dann, wenn man die Attributzuordnungen ausschlieBlich durch solche Zugriffsmethoden verwaltet und nicht in anderen Methoden direkt auf die Instanzvariable zugreift. AuBerdem muB sichergestellt sein, daB die Kopien der Attributobjekte ausreichend tief sind. Diese Frage wird im folgenden Abschnitt angesprochen.
6.3
Objektkopien
1m vorigen Abschnitt wurde erwahnt, daB es fUr die Zuordnung eines Attributes notwendig sein kann, eine Kopie eines bestehenden Objektes zu erzeugen. Es wird daher eine kurze Betrachtung des Kopiervorganges und damit zusammenhlingender Fragen eingeschoben.
1
(A)
String
(A)
String
strasse ----.
Person
Adresse
1
(A)
1 ort ----.
adresse~
1
Y
(A)
plz ----.
Modell
Abbildung 6-2
Attributzuordnung eines Adressenobjektes
String
205
6.3 Objektkopien
Als Beispiel seien wieder Personen gewiihlt, denen eine Adresse zugeordnet is!. Zum Unterschied zu der Vorgabe in Abbildung 6-1 soIl jedoch angenommen werden, daB Adressen nicht einfach durch Zeichenketten dargestellt werden, sondern durch strukturierte Objekte, die aus einer StraBenangabe, einer Ortsangabe und einer Postleitzahl bestehen, was in Abbildung 6-2 in detaillierter Form gezeigt ist. 1st die Klasse Adresse nach den Modellangaben eingerichtet und sind fur ihre Instanzvariable die entsprechenden Zugriffsmethoden definiert, so wird die in Abbildung 6-2 gezeigt Situation durch folgenden Code erzeugt:
I adresse1
adresse2 person1 person21 adresse1 := Adresse new strasse: 'RathausstraBe 19'; ort: 'Wien'; plz: 1010 adresse2 := Adresse new strasse: 'Residenzplatz l' ort: 'WOrzburg'; plz: 97064 person1 := Person new adresse: adresse1 . person2 := Person new adresse: adresse2.
Es existieren im Objektraum zwei Personenobjekte, welche als Adressenattribut jeweils ein Adressenobjekt zugeordnet haben. Die Adressenobjekte sind selbst Trligerobjekte von Attributen.
person1
adresse1 str 0 ort 0 plz 0
adr
'RathausstraBe 19' 'Wien' 'A-1010'
person2 adr
adresse2 str 0 ort 0 plz 0
'Residenzplatz l' 'WOrzburg' '0-97064'
Abbildung 6-3
Personen mit unterschiedlichen Adressen
206
6 Objektstrukturen Wird nun durch person2 adresse: person 1 adresse
im Objektraum simuliert, daB die Person2 tibersiedelt ist und nunmehr dieselbe Adresse wie Person1 hat, so erhalt man das in Abbildung 6-4 gezeigte Resultat.
person1
adresse1
'Rathausstra6e 19' str 0 adr 0--+-----1. ort 0-+----. 'Wien' plz 0 'A-1010'
,----, ~ a~~:s:2 ~ I
I I
Abbildung 6-4
str
\."1_ .. -
ort \."1plz \."1_ , - - - -
__ .. 'Residenzplatz l'
"T - - - . .
~
'WOrzburg'
- - - .. '0-97064'
Personen mit identischen Adressen
Man sieht, daB durch den Zuordnungsvorgang nun beide Personen auf ein und dasselbe Adressenobjekt verweisen. Da damit auch das ursprtingliche Objekt adresse2 aus der Attributbeziehung entfemt wurde, hat es seine Existenz verloren, was in der Folge auch fUr des sen Attribute 'Residenzplatz 1', 'WOrzburg' und '0-97064' gilt. Hier ist allerdings die im Modell geforderte Attributeigenschaft einer Adresse nicht erfiillt, da das Objekt adresse1 von mehr als einem Objekt referenziert wird. Die Adressen von Person1 und Person2 sind identisch und konnen daher nicht unabhangig voneinander editiert werden. Mochte man beispielsweise die StraBenangabe der Adresse von Person1 von 'RathausstraBe 19' auf'Liebiggasse 4' korrigieren, so betrifft diese Korrektur auch die Adresse von Person2. Diese Situation ware erwtinscht, wenn man Adressen als eigenstandige Objekte des Applikationsgebiets (domain objects) und nicht als Attribute betrachtet. In dies em Falle entsprache die Zuordnung einer Adresse zu einer Person einer Assoziationsbeziehung, sie dtirfte daher im Modell nicht als Attributbeziehung ausgewiesen werden.
6.3 Objektkopien
207
Um die geforderte Attributeigenschaft zu erhalten, kann man durch person2 adresse: person1 adresse copy
erreichen, daB Person2 zwar nicht dieselbe, jedoch eine gleiche Adresse zugeordnet erhiilt, die im Objektraum entstehende Situation ist in Abbildung 6-2 dargestellt.
person1
adresse1
'RathausstraBe 19' str 0 adr 0--+-----. ort O-+--t'----+ 'Wien' plz 0 'A-1010' adresse3
person2 adr
Abbildung 6-5
str 0 ort plz 0 __ ~ __ • 'Residenzplatz l' 1 str \..... I 1 ort \..... -t - - - . . WOrzburg' 1 plz \..... L -.. - - - - - - - . '0-97064'
Personen mit gleichen Adressen
Man erkennt, daB durch den Kopiervorgang ein neues Adressenobjekt (adresse3) erzeugt und der Person1 als Attribut zugeordnet wurde. Auch hier wird das Objekt adresse2 nicht mehr referenziert, so daB es samt seinen Attri-
buten aus dem Objektraum entfernt wird. Allerdings ist der Kopiervorgang nicht tief genug gegangen, da die beiden nunmehr existierenden Adressenobjekte (adresse1 und adresse3) Objekte zugeordnet haben, welche die geforderte Attributeigenschaft nicht erfullen, weil sie von mehr als einem Tragerobjekt referenziert werden. Es ware daher notwendig gewesen, dem Objekt adresse3 als Attribute Kopien der Attribute von adresse1 zuzuordnen.
6.3.1
Seichte Kopien
Die durch die eben beschriebene Vorgangsweise erzeugte Kopie wird auch als seichte Kopie (shallow copy) bezeichnet. Eine seichte Kopie ist eine Kopie des
208
6 Objektstrukturen
Originals, deren Instanzvariable mit denselben Objekten belegt sind wie die des Originals. In der Klasse Object wird eine allgemeine Methode zum Erzeugen seichter Kopien bereitgestellt und an alle Unterklassen vererbt. Die Wirkung von Object»shaliowCopy entspricht im FaIle der im Beispiel herangezogenen Adressenobjekte der fiktiven Methode von Programm 6-4. Object subclass: #Adresse instanceVariableNames: 'strasse ort plz' classVariableNames: " poolDictionaries: " category: 'Attributobjekte' Adresse methodsFor: 'copying' shallowCopy
"Fiktive Methode zum Erzeugen einer seichten Kopie." 1\
self class new strasse := self strasse; ort := self ort; plz := self plz
Programm 6-4
Eine Methode fUr seichtes Kopieren
Allerdings wurde die in Abbildung 6-2 gezeigte Situation durch eine Methode mit Selektor 4Fcopy (und nicht durch 4FshaliowCopy) erhalten.
6.3.2 Tiefe Kopien Ein Blick in die Klassenhierarchie ergibt, daB in der Klasse Object die im Programm 6-5 gezeigten Methoden vorgesehen sind. Die Methode Object» copy erzeugt vorerst eine seichte Kopie und sendet dieser unmittelbar nach ihrer Erzeugung die Botschaft postCopy, die dafiir vorgesehen ist, weitere Kopiervorgange zu veranlassen. Dazu ist es jedoch notwendig, daB in der betroffenen Klasse eine spezielle postCopyMethode definiert wird, welche die wirkungslose Methode Object»postCopy redefmiert. Urn von Adressenobjekten die fUr eine At1ributbeziehung notwendigen tiefen Kopien zu erhalten, kann die in Programm 6-6 formulierte Methode dienen. Fur die durch eine postCopy-Methode kopierten Objekte konnen selbst wieder tiefe Kopien vorgesehen sein, so daB sich beliebig tiefe Kopiervorgange
209
6.3 Objektkopien
ergeben konnen. Es sind jedoch Vorkehrungen fUr jene Falle geboten, in denen durch zirkuIare Objektstrukturen "unendlich tiefe" Kopiervorgange entstehen wiirden. KlassenBrowser
Object methodsFor: 'copying' copy "Erzeugen einer Kopie des Empfangers. Fur Klassen, deren Auspragungen nicht kopiert werden sollen (konnen), ist diese Methode zu redefinieren."
"self shaliowCopy postCopy postCopy "Durchfiihren aller Aktionen, die nach dem Kopieren eines Objektes durch shaliowCopy notwendig sind. In den Subklassen ist durch Redefinition der Methode die notwendige Funktionalitat hinzuzufiigen."
"self Programm 6-5
Die Methoden Object>>copy und Object»postCopy
Adresse methodsFor: 'copying' postCopy "Eine Kopie eines Adressenobjektes 5011 auch Kopien der Adressenattribute erhalten."
super postCopy. strasse := strasse copy. ort := ort copy.
(1)
~~~oo~
~
(1) Da im Vererbungspfad zwischen den Klassen Adresse und Object keine Klasse liegt, welche die Methode postCopy implementiert, ist diese Anweisung hier ohne Wirkung, entspricht aber der Konvention.
(2) Dieser Kopiervorgang ist tiberfitissig, solange die Modellforderung eingehalten wird, daB Postleitzahlen Instanzen von SmallInteger sind, die als permanent existierende und der virtuellen Maschine direkt bekannte Objekte nicht kopiert werden konnen. SmallInteger>>ShaliowCopy liefert als Ergebnis den Empfanger selbst.
Programm 6-6
Eine Methode Adresse»postCopy
210
6 Objektstrukturen
1st die in Programm 6-6 gezeigte Methode implementiert, so erhiilt man durch den im Beispiel angesprochenen Code person2 adresse: person1 adresse copy
schliel3lich eine tiefe Adressenkopie und dam it die in Abbildung 6-2 wiedergegebene Situation.
person 1 adru-
p
person2 adro
..
-..
adresse1 str 0-ort 0 plz 0..,.
adresse3 str 0-ort 0 plz o~
l----P'" 'RathausstraBe 19'
-.
'Wien' 'A-1010'
~ 'RathausstraBe 19'
---
'Wien' 'A-1010'
~ KOR I Abbildung 6-6
Ein Adressenobjekt und eine maximal tiefe Kopie
Ob beim Kopieren eines Objektes ein zugeordnetes Partnerobjekt ebenfalls kopiert werden solI hangt einerseits von der Semantik der Zuordnung ab, andererseits auch von der Disziplin der Applikationsentwickiung. Wird durch die Zuordnung eine Assoziationsbeziehung zwischen Objekten mit einer selbstllndigen und unabhangigen Existenzberechtigung realisiert, so darf das assoziierte Partnerobjekt keinesfalls mitkopiert werden. Tragt zum Beispiel ein Dokument eine Referenz auf seinen Autor, so muB wohl eine Kopie des Textes denselben Autor referenzieren und nieht eine Kopie des Autors. Entspricht die Zuordnung einer Aggregationsbeziehung, bei welcher das Partnerobjekt die Bedeutung eines Bestandteiles des Tragerobjektes hat, so ist beim Kopieren des Tragerobjektes auch eine Kopie des aggregierten Partnerobjektes anzufertigen. Als Beispiel sei wieder ein Dokument gewahlt, welches aus mehreren Kapiteln besteht. In diesem Fall wird man nur von einer vollstllndigen Kopie des Dokumentes sprechen, wenn es auch Kopien aller Kapitel enthalt. 1m Faile einer Attributbeziehung sind bei einer strengen Auslegung der angegeben Attributeigenschaft ebenfalls Kopien der Attribute anzulegen, aUer-
6.4 Eigenschaften von Objektzuordnungen
211
dings kann man unterschiedlicher Meinung sein, wie tief der Kopiervorgang vorzunehmen ist. Genugt nicht etwa die in Abbildung 6-2 dargestellte geringere Kopiertiefe fUr Adressenattribute oder ist es notwendig, die in Abbildung 6-6 gezeigte maximale Tiefe zu erreichen? Bereits die in Abbildung 6-2 gezeigte Situation erlaubt es, die StraBenangabe der Adresse von Person1 zu verandem, ohne daB davon auch die StraBenangabe der Adresse von Person2 betroffen ist. Dies gilt jedoch nur dann zu, wenn man die Anderung durch Zuordnung einer neuen Zeichenkette vomimmt und nicht durch Editieren der Zeichenkette selbst. Diese Frage wird auch in [21] ausfUhrlich diskutiert, dort wird jedoch die optimistische Meinung vertreten, daB "atomare Objekte" nicht kopiert werden mussen, weil es selbstverstandlich ist, daB sie nie verandert sondem stets ersetzt werden. In diesem Fall muBte man die in Programm 6-6 angegebene Methode Adresse»postCopy nicht implementieren und konnte sich mit der Situation aus Abbildung 6-4 begnugen. Ein Vorteil dieser Sicht ist, daB der zusatzliche Aufwand unnotiger Kopiervorgiinge vermieden wird. Eine pessimistische Meinung ware anzunehmen, daB alles, was technisch verandert werden kann, moglicherweise auch verandert wird. In diesem Fall ware Vorsorge zu treffen, daB bereits in den Zugriffsmethoden auf Attribute die entsprechenden Kopieranweisungen enthalten sind, damit die Kopiersemantik der Attribute gewahrleistet wird. Diese Vorgangsweise ist in den Programmen 6-3 fUr einfache Attributzuordnungen und in den Programmen 6-10 und 6-11 fUr mehrfache Attributzuordnungen gezeigt. Sie ermoglicht auch eine direktere Umsetzung von Modellvorgaben in Objektverhalten.
6.4
Eigenschaften von Objektzuordnungen
Die allgemeinste Form einer Zuordnung ist von der Art, daB einem Tragerobjekt uber einen dazwischengeschalteten Sammelbehalter beliebig viele Partnerobjekte von beliebiger Art zugeordnet sein konnen. Urn die daraus resultierenden, vieIniltigen Objektstrukturen auf solche einzuschranken, die fUr einen Anwendungsfall sinnvoll sind, konnen beim Entwurf der Applikation den Zuordnungen Einschrankungen auferlegt werden. In der Folge werden Eigenschaften von Objektbeziehungen vorgesteUt, die durch Einschriinkungen charakterisiert sind. Einige dieser Eigenschaften, wie etwa die Multiplizitatseigenschaft, werden in Methoden der Objektmodellierung allgemein beriicksichtigt, andere Eigenschaften jedoch, wie beispielsweise die Eigenschaften der Homogenitat und Varietat, werden erst relevant, wenn man die Mogiichkeiten der in Smalltalk gegebenen dynamischen
212
6 Objektstrukturen
Typisierung in Betracht zieht. So manche Sichtweise mag auch deswegen ungewohnt erscheinen, weil die zugrundeliegende Begriffswelt nicht zwischen Daten und Objekten unterscheidet, sondem ausschlieBlich Objekte und deren Bezeichnung durch Namen mit einer reinen Referenzsemantik kennt. Da das Aufbauen von Zuordnungen eine wesentliche Verhaltenskategorie von Objekten ist, werden exemplarisch Methoden angegeben, die bei der Errichtung einer Zuordnung die Einhaltung verschiedener Integritatseigenschaften sicherstellen. Die angeftihrten Methoden sollen einerseits die Bedeutung der Eigenschaften dadurch deutlich machen, daB sie deren Kontrolle bei der Errichtung einer Zuordnung demonstrieren und andererseits als Beispiele ftir Implementationstechniken in Smalltalk dienen. Es wird jedoch damit nicht das Ziel verfolgt, einen Werkzeugkasten mit ausgefeilten fertigen Komponenten anzubieten. Es muB auch daraufhingewiesen werden, daB durch den Einsatz derartiger Zuordnungsmethoden alleine vorgegebene Integritatsbedingungen nicht garantiert werden konnen. Beispielsweise kann eine geforderte Varietatsbedingung dadurch verletzt werden, daB ein einem Quellobjekt zugeordnetes Attributobjekt einer Mutation unterzogen wird, so daB es nunmehr einer Klasse angehort, die im Rahmen der Varietatsbedingung nicht zulassig ist. Eigenschaften von Zuordnungen sind Integritatsbedingungen, welche den Zuordnungen auferlegt werden. Es werden zuerst statische Integritatsbedingungen behandelt, sie sind zu jedem Zeitpunkt und unabhangig von der Vorgeschichte des Tragerobjektes giiltig. 1m AnschluB daran wird auf einige dynamische Integritatsbedingungen eingegangen. Dynamische Einschrlinkungen beziehen sich auf zullissige Anderungen von Objektzuordnungen und legen somit dem Lebensweg eines Tragerobjektes Restriktionen auf.
6.5
Multiplizitat einer Zuordnung
Durch die Multiplizitiit wird festgelegt, wieviele Partnerobjekte einem Objekt im Rahmen einer Zuordnung mindestens und hochstens zugeordnet werden diirfen. Die Multiplizitatsangabe erfolgt durch ein Paar <min max>, wobei min (min >= 0) die Mindestanzahl und max (max >= min) die Hochstanzahl von assoziierten Partnem angibt. Zuordnungen mit Minimalmultiplizitiit min = 0 heiBen auch bedingte oder optionale Zuordnungen, weil durch sie kein zugeordnetes Partnerobjekt erzwungen wird. SoIl in einer Zuordnung die Anzahl der Partner unbeschrankt sein, so wird dies durch die Angabe der Maximalmultiplizitiit max = n
213
6.5 Multiplizitiit einer Zuordnung
festgelegt, wobei 'n' ein Symbol fUr eine beliebig groBe ganze Zabl ist. Zuordnungen mit einer Maximalmultiplizitiit max = 1 werden als Ein/achzuordnungen bezeichnet, gilt max> 1, so handelt es sich urn eine Mehr/achzuordnung. Multiplizitat ist somit eine Einschrankung der Anzahl der erlaubten Partnerobjekte, die den Instanzen einer Klasse durch eine in dieser Klasse festgelegte Zuordnung auferlegt ist. 1m Unterschied zur Multiplizitat, die als Klasseneigenschaft fUr alle Auspriigungen der Klasse gilt, soll die tatsachliche und moglicherweise variable Anzahl der im Rahmen einer bestimmten Zuordnung mit einem Objekt assoziierten Partnerobjekte als Kardinalitiit der Zuordnung bezeichnet werden. In der Literatur wird diese Unterscheidung oft nicht gemacht und beide Bezeichnungen als synonym betrachtet. Ais Beispiel sei die Zuordnung von Vornamen zu einer Person betrachtet, wobei angenommen wird, daB eine Person beliebig viele Vornamen haben kann, moglicherweise auch (noch) keinen Vornamen. Eine solche konditionale Mehr/achzuordnung ist in Abbildung 6-7 gezeigt. Da in diesem Beispiel nicht verlangt werden solI, daB das Partnerobjekt nur genau einem Tragerobjekt zugeordnet ist, handelt es sich hier nicht urn eine Attributzbeziehung, sondern urn eine allgemeine Objektzuordnung. Die im linken Teil der Abbildung angegebene Kurzform kann immer dann verwendet werden, wenn die Angabe der Art (Klasse) der Partnerobjekte entbehrlich ist.
Person vornamen (O ..n)
.-_--,a) Modell I
L1
Abbildung 6-7
String
Person I----~O .. n
I------i
vornamen-+
b)
Objektzuordnung mit Multiplizitatsangabe
Zur Realisierung dieser Zuordnung ist die Instanzvariable vornamen mit einem Behalterobjekt zu belegen, dessen Inhalt die (hier beliebig vielen) Vornamen sind. Ais Sammelbehalter kommt eine Auspragung einer konkreten Unterklasse von Collection in Frage, welche Art von Sammelbehlilter zu wlihlen ist, hangt von der gewtinschten ZugriiTsstrategie auf die Partnerobjekte abo Da die Beziehung zwischen einer Person und ihren zugeordneten Vornamen modelliert wurde, wird das Behalterobjekt nur als technisches Objekt
214
6 Objektstrukturen
gesehen, nicht aber als Zuordnungspartner. Es kann aber auch Hille geben, wo es angebracht erscheint, eine Sammlung selbst als Entitat zu sehen, die einem Tragerobjekt zugeordnet ist. Beispielsweise wird in der Fallstudie tiber das Bankwesen (Kapitel 11) das einem Bankenservice zugeordnete Bankenregister als eigene Entitat formuliert. In Programm 6-7 sind Methoden fUr die Verwaltung einer (O .. n)-Zuordnung angegeben. Man beachte, daB in diesem Modell (Abbildung 6-7) die Attributeigenschaft nicht vorgegeben ist. Ware die Attributeigenschaft verlangt, so mtiBten in den Methoden Person»addVorname: und Person» yornamen vorgesorgt werden, daB entsprechende Kopien zugeordnet oder geliefert werden. Dieser Fall wird im nachsten Abschnitt erlautert. Wenn die Multiplizitatsvorgabe verlangt, die Anzahl der Zuordnungspartner zu beschrlinken, mtissen die Methoden addName: und remoyeName: entsprechend modiftziert werden.
Person methodsFor: 'Zuordnung: Namen'
addVorname: einName
"Zuordnung vornamen (O.. n) : Hinzufiigen eines Partnerobjektes." Ayornamen add: einName
(1)
removeVorname: einName
"Zuordnung vornamen (O.. n) : Entfernen eines Partnerobjektes." Ayornamen remove: einName ifAbsent: [nil]
(2)
vornamen
"Zuordnung vornamen (O.. n): Nenne den Behalter mit allen Partnerbjekten." Ayornamen
cardVornamen
"Bestimmen der Anzahl der Vornamen (Kardinalitat der Beziehung)." Ayornamen size (1) Hier wird angenommen, daB bei der InitiaJisierung bereits ein Behiilterobjekt zugeordnet wurde, etwa durch vorname := OrderedColiection new.
(2) Das Rilckgabeobjekt ist entweder der eben entfernte Name oder nil, falls dieser nicht vorhanden war.
Programm 6-7
Zugriffsmethoden fUr eine (O .. n) Zuordnung
6.6 Mehrfache Attributzuordnungen
215
In Programm 6-8 ist dies fUr den Fall einer vorgegebenen Obergrenze gezeigt.
Person methodsFor: 'Zuordnung: Namen'
addVomameMultTest: einName
"Zuordnung vornamen (0..3): Hinzufiigen eines Partnerobjektes."
I cardMax I
cardMax := 3. (self cardVorname = cardMax) ifTrue: [self error: 'MulitipliziUUsverletzung']. "vornamen add: einName
Programm 6-8
Zuordnung mit Multiplizitlitstest
Die zu kontrollierende Einschrlinkung ist in dieser Methode durch den Ausdruck cardMax := 3 direkt festgeschrieben. Diese Vorgangsweise soIl eine bessere Verstlindlichkeit ergeben, sie wird deswegen auch in lihnlichen Methoden dieses Kapitels eingeschlagen. Es empfiehlt sich jedoch, derartige Metainformationen tiber die Modellvorgaben in der Klasse selbst (durch Klassen- oder Klasseninstanzvariable) zu verwalten und dadurch von den Methoden zu trennen.
6.6
Mehrfache AHributzuordnungen
Handelt es sich urn eine mehrfache Attributzuordnung, dann ist dafur Sorge zu tragen, daB lihnlich wie in Programm 6-3 fUr einfache Attributzuordnungen gezeigt, durch Ubergeben von Kopien die Attribute nicht verlindert und auch nicht mehrfach referenziert werden konnen. Dies kann durch entsprechende Modifikation der Zugriffsmethoden erreicht werden. Man erkennt aus Programm 6-9, daB der Unterschied zwischen den Methoden Person»addVornameAlsAttribut: und Person»addVorname: nur darin liegt, daB beim Hinzufligen eines Attributes eine Kopie des Partnerobjektes angefertigt und in den Sammelbehlilter eingebracht wird. Ftir den ZugritT auf den Behlilter mit den Partnerattributen ist es notwendig, nieht nur eine Kopie des Behlilters herzustellen, sondem auch dessen Inhalt
216
6 Objektstrukturen
zu kopieren, weil fUr Behlilterobjekte keine postCopy-Methode vorgesehen ist, welehe den Kopiervorgang aueh auf den Inhalt erstreekt.
Person methodsFor: 'Attributzuordnung: Namen' addVornameAlsAttribut: einName
"Attributzuordnung vornamen (O..n): HinzufUgen eines Partnerobjektes." "vornamen add: einName copy
(1)
vornamenAlsAttribut
"Zuordnung vornamen (O.. n): Liefern einer Kopie des Behalters mit Kopien von allen Partnerobjekten."
I vncopy I vncopy := vornamen copy. 1 to: vncopy basicSize do: [:index I vncopy basicAt: index put: (vncopy basicAt: index) copy] "vncopy (1) Rier wird angenommen, daB der Instanzvariablen vorname bei der Initialisierung bereits ein leerer Behiilter zugeordnet wurde.
Programm 6-9
Zugriffsmethoden flir eine (O .. n) Attributzuordnung
Die in Programm 6-9 angegebene Methode Person»vornamenAlsAttribut solI nur dazu dienen, die notwendigen Kopieroperationen zu zeigen. EntsehlieBt man sieh, in einer Anwendung die Eigensehaften von Attributzuordnungen in den Zuordnungsmethoden explizit zu unterstUtzen, so empfiehlt sieh die Definition von Attributsammelbehliltern, die fUr die Einhaltung der Attributeigensehaft selbst Vorsorge treffen. Diese Mogliehkeit ist in Programm 6-10 an Hand eines Attributbehlilters der Art OrderedColiection angedeutet. Eine Instanz der neu hinzugeftigten Klasse OrderedAttributeCollection verhlilt sieh wie eine Instanz von OrderdColiection, ftigt dieser jedoeh eine postCopy-Methode hinzu und redefmiert die Zugriffsmethoden entspreehend der geforderten Kopiersemantik. In Programm 6-10 sind als Beispiel nur die Methoden OrderedAttributeColiection»addLast: und OrderedAttributeCollection>>first angeftihrt. Erstellt man naeh diesem Muster Klassen flir Attributsammelbehlilter, so geniigt es, flir eine Attributbeziehung die Instanzvariable statt mit einem "normalen" Behlilter mit einem Attributbehlilter zu initialisieren, urn die Attributeigensehaft in der erwlihnten Weise sieherzustellen. Methoden der in Programm 6-9 gezeigten Art sind dann nieht mehr erforderlieh.
6.6 Mehrfache Attributzuordnungen
217
OrderedCollection variableSubclass: #OrderedAttributeCollection instanceVariableNames: " classVariableNames: " poolDictionaries: " category: 'Attribute-Collection' OrderedAttributeCollection methodsFor: 'copying'
postCopy
"Ersetzen der Elemente des Attributbehalters durch Kopien." firstlndex to: lastlndex do: [:index I self basicAt: index put: (self basicAt: index) copy]
(1)
OrderedAttributeCollection methodsFor: 'adding'
add Last: newObject
"Einfiigen einer Kopie des Argumentes als letztes Element des Empfangers. Oas ROckgabeobjekt ist die Kopie des Argumentes." A
super add Last: newObject copy
OrderedAttributeCollection methodsFor: 'accessing' first
"Uefern einer Kopie des ersten Elementes. Wenn der Empfanger leer ist, wird ein Fehler gemeldet." A
super first copy
(1) In einer OrderedCollection liegen die Elemente in dem Indexbereich firstlndex..lastlndex, so daB es nicht notwendig ist, die Iteration tiber den gesamten Bereich 1..self basicSize zu erstrecken, wie dies in der allgemeineren Methode Person>>VornamenAlsAttribut (Programm 6-9) getan ist.
Programm 6-10 Ein Attributbehalter der Art OrderedAttributeCollection
In Programm 6-11 ist eine Initialisierungsmethode fUr Personenobjekte gegeben, durch welche die Instanzvariable vornamen mit einem Attributsammelbehalter initialisiert wird. Die Initialisierung mit einem "normalen" Behalter ist in Form eines Kommentares angefUhrt. Programm 6-12 zeigt an Hand eines Beispieles die unterschiedliche Wirkung dieser Behalterarten. Das mit (1) markierte Ergebnis ist false, wenn die Instanzvariable vornamen mit einem Attributsammelbehiilter initialisiert wurde, ansonsten true.
218
6 Objektstrukturen
'Person class methodsFor: 'instance creation' newMitNamen: einName "Erzeuge eine Person mit dem vorgegebenen Namensattribut" Asuper new initialize nameAlsAttribut: einName
(1)
'Person methodsFor: 'initializing' initialize "Initialisiere vornamen (O.. n) als (Attribut)zuordnung."
(2)
vornamen := OrderedAttributeColiection new "vornamen := OrderedCollection new"
(1) Durch diese Erzeugungsmethode wird die Modellforderung erfiillt, daB jeder Person genau ein Name zugeordnet sein muB.
Programm 6-11 Initiaiisierung einer mehrwertigen Attributzuordnung
Workspace
I person 1 person2 I "Person1: Rainer Maria Rilke" person1 := Testperson newMitNamen: 'Rilke'. person1 addVorname: 'Rainer'; addVorname: 'Maria'. "Person2: Wolfgang Amadeus Mozart" person2 := Testperson newMitNamen: 'Mozart'. person2 addVorname: 'Wolfgang'; addVorname: 'Amadeus'. "Person1 erhlilt als zuslitzlichen Vornamen den letzten von Person2" person1 addVorname: (person2 vornamen last). "Oberpriifen der Attributeigenschaft der Beziehung vornamen (O.. n) (A)" person 1 vornamen last = person2 vornamen last <printlt> false "true" (1) Das Ergebnis hangt von der Initiaiisierung der Variabien vornamen ab!
Programm 6-12 Beispiel fUr eine mehrwertige Attributzuordnung
(1)
6.7 Varietat einer Zuordnung
6.7
219
Varietat einer Zuordnung
Smalltalk sieht keine Typisierung von Variablen vor, daher konnen sie mit Auspragungen beliebiger Klassen belegt werden. Das bedeutet fUr Objektzuordnungen, daB die Zielobjekte ein und derselben Zuordnungsart nicht alle gleichartig sein mussen, sondem daB unterschiedliche Varianten vorkommen konnen. Eine Zuordnung ist nur dann sinnvoll, wenn das Tragerobjekt yom Zielobjekt erwarten kann, daB es ein bestimmtes Protokoll (eine Menge von Botschaften) versteht, uber das es mit seinem Partnerobjekt in Kommunikation treten kann . Fur den Fall, daB Objekte mit verschiedener KlassenzugehOrigkeit in einer Beziehung als Partnerobjekte in Betracht kommen, wird dieses Protokoll zumeist aus einer gemeinsamen Oberklasse geerbt. Dies kann besonders dann leicht erreicht werden, wenn die Klassenhierarchie fUr den Anwendungsfall speziell entworfen wird. In sol chen Fallen wird fUr eine Beziehung nur eine schwache Varietat vorliegen, well die Partnerobjekte zwar von unterschiedlicher Art sein konnen, jedoch unterscheiden sich diese Arten in dem Sinne nur schwach, als sie durch ihre gemeinsame Oberklasse artverwandt sind. Es sind aber auch Fiille moglich, bei denen auf eine vorgegebene Klassenhierarchie zUrUckgegriffen wird, so daB Objekte als Zielobjekte in einer Beziehung auftreten konnen, die keine gemeinsame Applikationsklasse als Oberklasse haben (technische Klassen wie Object, Model, ApplicationModel und andere seien hier ausgenommen). Dabei wird es notig sein, das in der Beziehung vorausgesetzte Protokoll entweder in die entsprechenden Klassen einzuftigen oder uber einen Adapter oder ein Rollenobjekt (Kapitel13.3.2) bereitzustellen. In solche Fallen kann eine Beziehung eine starke Varietat haben, weil sich die Partnerobjekte in dem Sinne stark unterscheiden konnen, als sich keine Gemeinsamkeiten aus ihren Klassen und deren Position in der Klassenhierarchie ableiten lassen. Ob eine Beziehung starke oder schwache Varietat besitzt, kann also nur im Kontext einer Klassenhierarchie festgestellt werden. Varietat kann in engem Zusammenhang mit Polymorphismus gesehen werden. Unter Polymorphismus ist die allgemeine Eigenschaft zu verstehen, daB ein Name verschiedenartige Dinge mit unterschiedlichen Formen bezeichnen kann [15]. Die Auspragungen einer Klasse weisen einen Strukturpolymorphismus auf, wenn sie Instanzvariable haben, die von Fall zu Fall mit Objekten verschiedener Klassenzugehorigkeit belegt sein konnen. Sind als Zielobjekte einer Zuordnung Auspragungen beliebiger Klassen zulassig, so daB im Objektraum eine unbeschrankte Varietat entstehen kann, dann kann die Instanzvariable als unbeschriinkt polymorph bezeichnet werden. Sind hingegen die Klassen der Zielobjekte eingeschriinkt, dann liegt ein begrenzter Polymorphismus (limited polymorphism) [23] vor.
220
6 Objektstrukturen
Polymorphismus kann aber auch als Eigenschaft des Verhaltensprotokolls betrachtet werden. Ein Methodenname ist polymorph, wenn er in Abhiingigkeit von der Klassenzugehorigkeit des Empfangers verschiedene Methoden bezeichnen kann. Haben die zulassigen Klassen der Zielobjekte eine gemeinsame Oberklasse, aus der sie das fUr die Beziehung relevante Verhalten erben, so liegt ein inhiirenter Polymorphismus (inherent polymorphism, inclusion polymorphism) vor, die Varietat im Objektraum ist schwach. Wird das fUr die Beziehung relevante Verhalten nicht durch Vererbung sichergestellt, so wird von ad-hoc-Polymorphismus gesprochen, der eine starke Varietat im Objektraum zulaBt. Die moglichen Arten der Varietatseinschrankung sollen an Hand eines Beispieles erlautert werden, in welchem die Beziehung zwischen einer Firma und ihren Kunden betrachtet wird. Eine ahnliche Situation tritt auch in der Fallstudie tiber den Betrieb von Banken (siehe Kapitel 10) auf. Als Kunden einer Firma mogen sowohl physische Personen als auch juristische Personen verschiedener Art in Frage kommen. Um dieser Gegebenheit Rechnung zu trag en, kann die in Abbildung 6-8 gezeigte Klassenhierarchie entworfen werden.
rPhysische Person
Abbildung 6-8
I
I
Firma
Ven~ln
Eine Klassenhierarchie von Rechtssubjekten
Der in Abbildung 6-9 gezeigte Ausschnitt aus einem Objektmodelllegt fest, daB sowohl (physische) Personen als auch juristische Personen wie Firmen und Vereine als Kunden einer Firma zugeordnet sein dtirfen.
221
6.7 Varietat einer Zuordnung
Firma L...-_ _ _....
Rechtssubjekt O.. n kunde - - . '--_ _ _ _.....
~ Modell I
Abbildung 6-9
Schwach variante Zuordnung von Kunden zu Firmen
Diese Beziehung erlaubt eine Varietat im Objektraum, well Auspragungen mehrerer Klassen (namlich der Klasse Rechtssubjekt und aller ihrer Unterklassen) als Kunden von Firmen zugelassen werden. Die Varietat ist schwach, weil alle m6glichen Kunden wegen ihrer gemeinsamen Eigenschaft, Rechtssubjekt zu sein, lihnlich sind. Setzt man die Begriffe Klassifikation und Typisierung gleich, dann ist die schwache Varietatseinschrankung aquivalent einer Typisierung der entsprechen den Instanzvariablen des Tragerobjektes. Es kann aber auch der Fall sein, daB die in Abbildung 6-8 angegebene Klassenhierarchie nicht speziell fUr die Formulierung von Kundenbeziehungen entworfen wurde, sondem daB die Klassen PhysischePerson und JuristischePerson samt ihren Unterklassen bereits in einem anderen Zusammenhang erstellt wurden, ohne daB eine gemeinsame Oberklasse Rechtssubjekt vorliegt. Auch sei es nicht einfach m6glich, die Oberklasse Rechtssubjekt einzufUhren, well die wiederzuverwendende Klassenhierarchie nach einem anderen Kriterium gebildet wurde. Eine solche Situation kann besonders dann auftreten, wenn in der Klassenhierarchie Mehrfachvererbung ausgeschlossen ist, was ja bei der Modellierung im Hinblickauf Smalltalk-Systeme der Fall ist.
Firma L...-_ _ _...I
O.. n
-
kunde - - . -
Lj
Physische Person
Juristische Person
Modell L
Abbildung 6-10 Stark variante Zuordnung von Kunden zu Firmen
222
6 Objektstrukturen
In diesem Fall muG der in Abbildung 6-9 gezeigte Modellausschnitt auf die in Abbildung 6-10 gezeigt Weise formuliert werden, urn eine aquivalente Aussage zu enthalten. Aus der graphischen Darstellung ist leicht zu entnehmen, daB eine Firma als Kunden entweder (physische) Personen oder juristische Personen, also Firmen oder Vereine, zugeordnet haben kann. Wegen des Fehlens einer gemeinsamen Oberklasse ist diese Beziehung stark variant und erlaubt somit das Auftreten einer starken Varietat im Objektraum. Eine ahnliche Modellkonstruktion ist in einer Erweiterung der OMTMethode [34] vorgeschlagen, wobei dort der Standpunkt eingenommen wird, daB die Klasse Firma an zwei Assoziationen beteiligt ist, wobei jedoch jede Auspragung nur eine Alternative aufweisen darf. Dies wird als eine "oder"Einschrlinkung der zwei Assoziationen formuliert. Firma methodsFor: 'Zuordnung: Kunden'
addKundeVarTest: einKunde "Zuordnung: kunden (O.. n) -> {PhysischePerson 1JuristischePerson}: Hinzufiigen eines Zielobjektes mit Kontrolle der (starken) Varietat" 1 varSet I varSet := Set with: PhysischePerson with: JuristischePerson. (einKunde isVarietyOf: varSet) ifFalse: [self error: 'VarieUUsverletzung']. A kunden add: einKunde
(1)
Object methodsFor: 'access-control'
isVarietyOf: aSetOfClasses "Stelle fest (truelfalse) ob der Empfanger einer der in aSetOfClasses enthaltenen Klassen oder einer Unterklasse davon angehtirt." A
aSetOfClasses inject: false into: [:ok :class I ok I (self isKindOf: class))
(2)
(1) Die zulassigen Klassen (PhysischePerson und JuristischePerson) sind hier wegen der besseren Dbersicht innerhalb der Methode direkt festgeschrieben.
(2) Hinweis: Das Zeichen "I" tritt hier in zwei verschiedenen Rollen auf: das erste Mal zur Abtrennung der vereinbarten Argumentvariablen von den Anweisungen des Blockes, das zweite Mal als Selektor der Methode Boolean»I, welche die ODER-Verkniipfung des Empflingers mit dem Argument vomimmt.
Programm 6-13 Zuordnung mit Varietatstest
6.7 Varietat einer Zuordnung
223
Wiihrend beim Arbeiten mit einer Entwicklungsumgebung mit statischer Typisierung der Variablen die Festlegung eines Typs fUr jede deklarierte Variable zwingend notwendig ist, stellt sie im FaIle eines Systems mit nicht typisierten Variablen eine Einschrankung dar, durch welche die technisch moglichen Partnerobjekte auf solche eingeschrankt werden, die fUr den zugrundeliegenden Anwendungsfall sinnvoll sind. Der allgemeinste Fallliegt dann vor, wenn eine Menge von nicht in Vererbungsbeziehung stehender Klassen vorgegeben wird, deren Auspragungen als Partnerobjekte einer Objektzuordnung in Frage kommen. Hier liegt zwar bereits eine Varietatseinschrankung vor, diese ist jedoch so gering, daB im Objektraum eine starke Varietat der Beziehung zugelassen ist. Programm 6-13 zeigt eine Zuordnungsmethode, welche eine Varietatstiberprtifung derart durchfUhrt, daB die im Modell (Abbildung 6-10) beschriebene starke Varietat eingehalten wird. Besteht die Menge der Klassen, deren Auspragungen als Partnerobjekte zugelassen werden, nur aus einer einzigen Klasse oder aus mehreren Klassen, die jedoch untereinander in Vererbungsbeziehung stehen, so laBt die Varietatseinschrankung bereits nur mehr artverwandte Partnerobjekte zu. In diesem Fall soIl von einer schwachen Varietiitseinschriinkung und einer dadurch entstehenden schwachen Varietiit im Objektraum gesprochen werden. In Programm 6-14 ist eine Zuordnungsmethode angegeben, in welcher eine Uberpriifung der schwachen Varietatseinschrankung durchgefUhrt wird, die durch das in Abbildung 6-9 gezeigte Modell gefordert wird. Firma methodsFor: 'Zuordnung: Kunden'
addKundeVarTest: einKunde "Zuordnung: kunden (O.n) -> Rechtssubjekt: Hinzufiigen eines Zielobjektes mit Kontrolle der (schwachen) Varietal" (einKunde isKindOf: Rechtssubjekt) ifFalse: [self error: 'Variet~tsverletzung'). "kunden add: einKunde
(1)
(1) Die zulllssige Klasse (Rechtssubjekt) ist hier wegen der besseren Ubersicht direkt festgeschrieben. Die Uberpriifung durch isKindOf: erlaubt auch Unter-
klassen von Rechtssubjekt als Zuordnungspartner.
Programm 6-14 Zuordnung mit Test auf schwache Varietat SchlieBlich ist noch eine starke Varietiitseinschriinkung denkbar, die dann vorliegt, wenn als Partnerobjekte einer Zuordnung nur mehr Instanzen genau
224
6 Objektstrukturen
einer Klasse auftreten durfen. Dies ist der Fall, wenn entweder die einzige angegebene Partnerklasse keine Unterklassen besitzt oder wenn Auspragungen eventueller Unterklassen durch eine Zusatzangabe explizit als Zielobjekte ausgeschlossen werden. Diese Vorgabe kann als starke Varietiitseinschriinkung bezeichnet werden, im Objektraum ist dann fUr die betreffende Beziehung keine Varietat mehr zulassig. In Abbildung 6-11 ist ein Beispiel fur eine Zuordnung mit starker Varietatseinschrankung gezeigt. Hier wird gefordert, daB die Kunden einer Firma genau nur Firmen sein durfen, also nur Auspragungen der Klasse Firma, nicht aber Auspragungen eventueller Unterklassen. Die starke Verietatseinschrankung ist durch die Angabe 'vr gekennzeichnet.
Firma ' - -_ _ _---I
O.. n kunde
V!
Firma
--+ '--___--'
~ Modell ' f - - - - - - - - - - - - - - - - - - - - - - '
Abbildung 6-11 Nicht variante Zuordnung von Kunden zu Firmen Starke Varietatseinschrankungen werden besonders dann vorkommen, wenn beim Entwurf der Klassenhierarchie nicht die Klassifikation als Ausdruck einer "is-a-kind-of'-Beziehung im Vordergrund steht (specialization inheritance), sondern die Wiederverwendung von Code (implementationinheritance). Wird in der in Programm 6-14 angefiihrten Zuordnungsmethode der KlassenzugehOrigkeitstest isKindOf: ersetzt durch isMemberOf:, so entspricht dies der Uberprufung einer starken Varietatseinschriinkung, durch welche fUr die jeweilige Zuordnung keine Varietat mehr im Objektraum zugelassen wird. Die Angaben der Varietatseinschrankungen dienen bei der Modellierung einer Applikation dazu, die sachlogischen Zusammenbange aufzuzeigen und Richtlinien fUr die Implementation vorzugeben. Wegen der dynamischen Typisierung ist eine Kontrolle des Einhaltens solcher Vorgaben durch statische Inspektion des Programmcodes nicht moglich. Wegen des zusatzlichen Aufwandes werden solche Methoden nur in kritischen Fallen einzusetzen sein. Es kann jedoch gunstig sein, Laufzeitkontrollen dieser Art wahrend des Testens und in der EinfUhrungsphase einer Applikation durchzufUhren und erst dann auszuschalten, wenn sich empirisch herausgestellt hat, daB die Programmlogik mit den Modellvorgaben konform zu sein scheint.
225
6.8 Heterogenitat einer Zuordnung
6.8
Heterogenitat einer Zuordnung
1m Falle einer varianten Mehrfachzuordnung kann man die Frage stellen, ob die zuliissige Varietat nur "zwischen" den Objekten oder auch "innerha1b" der Objekte auftreten darf. Das in Abbildung 6-10 gegebene Beispiel einer stark varianten Mehrfachzuordnung legt fest, daB Firmen beliebig viele Kunden haben durfen und daB a1s Kunden entweder physische Personen oder juristische Personen in Frage kommen. Werden keine weiteren Einschrankungen vorgegeben, so kann es Firmen geben, die gleichzeitig sowohl physische als auch juridische Personen zu ihren Kunden zah1en, so daB ihr Kundenstock bezuglich der Art der Kunden als heterogen bezeichnet werden kann. Moglicherweise werden einige Firmen aber nur Kunden der einen oder anderen Art haben, also einen weniger heterogenen oder gar homogenen Kundenstock besitzen. Es kann sinnvoll sein, derartige Heterogenitatsvorgaben bereits auf Entwurfsebene vorzugeben, wodurch eine von der Klassenhierarchie unabhiingige weitere Klassiftkationsmoglichkeit entsteht.
Firma
A
I
Physische Person
Einzelhandels firma O.. n kunde
Juristische Person
GroBhandels firma O.. n kunde
--+
--+
~ Modell'
Abbildung 6-12 Modellierung spezieller Firmen aufKlassenebene Als Beispiel sei angenommen, daB Firmen entweder GroBhandelsfirmen sind, die ausschlieBlich an andere Firmen als Wiederverkaufer liefem durfen oder aber Einze1handelsfirmen, als deren Kunden nur physische Personen als Letztverbraucher in Frage kommen. Selbstverstandlich konnte man dieser Situation dadurch Rechnung tragen, daB man spezialisierte Firmen auf Klas-
226
6 Objektstrukturen
senebene modelliert und fUr sie eine entsprechende Kundenzuordnung festlegt, wie dies in Abbildung 6-12 gezeigt ist. Eine solche Losung mag gerechtfertigt sein, wenn GroBhandelsflfDlen und Einzelhandelsfrrmen als spezialisierte Firmen zu betrachten sind, die sich in ihrem Verhalten und moglicherweise auch in ihrer Struktur von allgemeinen Firmen so stark unterscheiden, daB die Einrichtung eigener Klassen angebracht ist. Liegt der Unterschied jedoch nur in der Art der Kunden, so kann dies auch durch eine Einschrankung der zulassigen Heterogenitat im urspriinglichen Modell erreicht werden. In Abbildung 6-13 ist ein Modell gezeigt, welches das urspriingliche, in Abbildung 6-10 dargestellte Modell urn eine Heterogenitatseinschrankung erganzt, was durch die Angabe "H" symbolisiert wird. Die hier geforderte Restriktion soIl als schwache Heterogenitatseinschrankung bezeichnet werden, weil eine bestimmte Firma entweder physische Personen (Auspragungen von PhysischePerson oder einer Unterklasse) oder juristische Personen (Auspragungen von JuristischePerson oder einer Unterklasse) als Kunden haben darf.
Physische Person H I--";"';;'='::;';';"""'-j Firma '-------'
r-
O ..n kunde
---+
H ....-----.., '-- Juristische Person
LJ Modell '1--------------------' AbbiIdung 6-13 Stark variante Zuordnung mit Heterogenitatseinschrankung Eine Heterogenitatseinschrankung solI als stark bezeichnet werden, wenn die Zielobjekte der Zuordnung in ihrer Art homogen sein miissen, wenn also nur Auspragungen genau der angegebenen Klasse und nicht auch einer Unterklasse zulassig sein sollen. Eine starke Heterogenitatseinschrankung kann durch "H!" symbolisiert werden. Bei der in Abbildung 6-12 angenommenen Modellvariante ist die Art der Firma bereits durch die Instanzierung der jeweiligen Klasse gegeben. In der Modellvariante mit Heterogenitiitseinschriinkung wird die Festlegung des "Firmentyps" erst bei der Initialisierung, genauer bei der ersten Zuweisung eines Kunden, festgelegt.
6.8 Heterogenitat einer Zuordnung
227
Firma methodsFor: 'Zuordnung: Kunden'
addKundeHetTest: einKunde
"Zuordnung: kunden (O.n) --> H {PhysischePerson I JuristischePerson}: HinzufUgen eines Partnerobjektes mit schwacher Heterogenitatseinschrankung."
I prototype protoRoot varSet I varSet := Set with: PhysischePerson with: JuristischePerson. prototype := self irgendEinKunde. prototype isNii iffrue: [A self addKundeVarTest: einKunde]. protoRoot := varSet detect: [:root I prototype isKindOf: root]. (einKunde isKindOf: protoRoot) ifFalse: [Aself error: 'HeterogenitlUsverletzung']. Akunden add: einKunde
(1) (2) (3) (4)
irgendEinKunde
"Zeige irgendeinen Kunden, falls ein solcher vorhanden ist." Aself kunden detect: [:kunde I true] ifNone: []
(5)
(1) Die zullissigen Klassen (Person und Firma) sind hier wegen der besseren Obersicht innerhalb der Methode direkt festgeschrieben. Es wird angenommen, daB diese Klassen untereinander nicht in Vererbungsbeziehung stehen.
(2) Wenn noch kein Kunde zugeordnet ist, kann keine Heterogenitlitskontrolle erfolgen. (3) Hier wird festgestellt, welcher der vorgegebenen Klassen (oder einer deren Unterklassen) der "Prototypkunde" angehort. (4) Letztendlich wird geprtift, ob der neue Kunde mit dem "Prototypkunden" artverwandt ist. (5) Es wird der "erstbeste" der bereits vorhandenen Kunden ausgewlihlt, welcher das ist, hlingt von der Organisation des Behlilters abo
Programm 6-15 Zuordnung mit schwacher Heterogenitatseinschrankung Programm 6-15 zeigt eine Methode Firma»addKundeHetTest:, in welcher iiberpriift wird, ob die in Abbildung 6-13 vorgegebene Varietat mit schwacher Heterogenitatseinschrankung beim Hinzufugen eines neuen Kunden eingehalten wird . In dieser und in allen ahnlichen Methoden sind die Modellvorgaben direkt in der Methode festgeschrieben, urn die Vorgaben und deren Uberpriifung gemeinsam im Blickfeld zu haben. Eine allgemeinere Losung ware, die Modellinformationen entweder in den entsprechenden Klassen zu verwalten oder eigene "Modellobjekte" vorzusehen, welche die Metain-
228
6 Objektstrukturen
formationen einer Applikation verwalten und den uberpriifenden Methoden verftigbar machen. Fur den Fall, daB eine starke Heterogenitatseinschrankung, also eine Homogenitatsforderung, vorgegeben ist, genugt es sicherzustellen, daB jedes hinzuzuftigende Partnerobjekt derselben Klasse angehOrt wie die bereits vorhandenen Zielobjekte der Zuordnung. Dies wird durch die in Programm 6-16 angeftihrte Methode Firma»addKundeHomTest: gewahrleistet. Firma methodsFor: 'Zuordnung: Kunden' addKundeHomTest: einKunde "Zuordnung: kunden (O.. n) -> H! {Testperson I Testfirrna}: Hinzufiigen eines Partnerobjektes bei starker Heterogenitatseinschrankung."
I prototyp I
prototyp := self irgendEinKunde. prototyp isNii ifTrue: [Aself addKundeVarTest: einKunde). (einKunde isMemberOf: prototyp class) ifFalse: [A self error: 'Heterogenit~tsverletzung') . Akunden add: einKunde
(1)
(1) Hier geniigt es zu priifen, ob der neue Kunde derselben Klasse angehort wie der "Prototypkunde".
Programm 6-16 Zuordnung mit starker Heterogenitatseinschriinkung
6.9
Organisation von Mehrfachzuordnungen
Durch Organisationseigenscha/ten wird die Art des Anordnens und damit der Moglichkeiten des Auffmdens eines von mehreren Partnerobjekten geregelt. 1m Faile einer Mehrfachzuordnung werden die einem Tragerobjekt zugeordneten Partnerobjekte in einem Behiilterobjekt gesammelt. Je nach der Art dieses Behlilterobjektes sind verschiedene Zugriffsmoglichkeiten auf die Partnerobjekte gegeben. Fur Einfachzuordnungen sind die Organisationseigenschaften konzeptionell nicht relevant. Die Organisation einer mehrwertigen Zuordnung sollte durch Angabe der Art des Sammelbebalters in einem Modell bereits vorgegeben werden. Ein Beispiel daftir ist in Abbildung 6-14 gegeben.
6.9 Organisation von Mehrfachzuordnungen
229
Ftir die Verwaltung der mehrfachen Zuordnung, also fUr das HinzufUgen und Entfemen von Partnerobjekten sowie fUr die Navigation zu Partnerobjekten stehen alle von den Behalterobjekten verstandenen Methoden zur VerfUgung. Die wichtigsten dieser Methoden wurden bereits im Abschnitt tiber Objektsammlungen vorgestellt.
6.9.1
Mengen von Partnerobjekten
1m einfachsten Fall werden die Partnerobjekte einer Zuordnung als Elemente einer Menge (Auspragung der Klassen Set oder IdentitySet) verwaltet. Entsprechend den Eigenschaften einer Menge wird dadurch sichergestellt, daB aIle Partnerobjekte voneinander verschieden sind, weiterhin ist keine Ordnungsrelation auf den Elementen gegeben. Die Partnerobjekte konnen nicht einzeln und gezielt angesprochen werden, sondem nur mit Hilfe von Enumerationsmethoden, wobei die Iteration tiber die Elemente einer Menge in einer sachlogisch unbestimmten Reihenfolge erfolgt. Weiterhin ist es moglich, Teilmengen zu bilden, deren Elemente bestimmte Eigenschaften aufweisen, Partnerobjekte mit bestimmten Eigenschaften aufzufinden oder festzusteIlen , ob ein vorgegebenes Objekt als Partnerobjekt zugeordnet ist.
6.9.2 Anordnungen von Partnerobjekten Werden Partnerobjekte in Anordnungen gesammelt, so kann der Reihenfolge der Anordnung eine Bedeutung verliehen werden, auf die bei der Enumeration Bezug genommen wird. Ein direkter Zugriff auf ein Partnerobjekt tiber einen Positionsindex oder relativ zu einem anderen Partnerobjekt ist ebenso moglich wie die Auswahl von Partnerobjekten mit bestimmten Eigenschaften, wobei deren relative Anordnung beibehalten wird.
Geordnete Anordnungen (ordered collections) Auspragungen der Klasse OrderedColiection erlauben es, Objekte unmittelbar vor oder nach einem bereits enthaltenen Objekt einzufiigen, an einer bestimmten Indexposition zu positionieren oder auch als erstes oder letztes Element aufzunehmen. Die Methode OrderedColiection»add: greift zuriick aufOrderedCollection»addLast: und fUgt damit ein weiteres Objekt immer an das Ende der Ansammlung. Bei ausschlieBlicher Verwendung dieser Methode zum Hinzu-
230
6 Objektstrukturen
fUgen von Partnerobjekten einer Mehrfachzuordnung entspricht die Reihenfolge der Partnerobjekte somit der zeitlichen Reihenfolge ihrer Zuordnung. Die fur Mengen erwahnten Enumerations- und Testmethoden stehen mit gleichen Signaturen auch fUr geordnete Anordnungen zur VerfUgung.
Person
String O .•n
(A)
vornamen (OrdColI) ----. ~ Modell I
Abbildung 6-14 Anordnung der Vomamen einer Person In Abbildung 6-14 ist ein Modellausschnitt gezeigt, der angibt, daB die Mehrfachzuordnung von Vomamen zu einer Person als geordnete Anordnung (ordered collection) organisiert werden soli. Damit ist auch festgelegt, daB die Vomamen einer Person eine bestimmte Reihenfolge haben, so daB es sinnvoll ist, yom ersten, zweiten oder allgemein n-ten Vomamen zu sprechen.
Sortierte Anordnungen (sorted collections) Stehen fUr die Partnerobjekte einer Mehrfachzuordnung Vergleichsmethoden zur VerfUgung, die eine Sortierung erlauben, so kann die Zuordnung mit Hilfe eines Behalterobjektes der Klasse Sorted Collection als sortierte Anordnung organisiert werden.
6.9.3 Verzeichnisse von Partnerobjekten In vielen Flillen ist ein Objekt mit einem Attribut versehen, durch dessen Wert es innerhalb einer Applikation eindeutig identifiziert wird. Ein Attribut mit dieser Eigenschaft wird als Schltisselattribut bezeichnet. Treten Objekte mit einem Schltisselattribut als Zielobjekte einer mehrfachen Beziehung auf, so kann die Zuordnung so organisiert werden, daB ein Partnerobjekt tiber den Wert seines Schltissels direkt ausgewahlt und angesprochen werden kann. Dazu ist es notwendig, als Sammelbehalter fUr die zugeordneten Partnerobjekte ein Verzeichnis zu wahlen, also eine Auspragung der Klasse Dictionary. In Abbildung 6-15 ist ein Beispiel fUr eine solche Organisationsform gegeben. Eine Bank hat als assoziierte Objekte Konten, die irn Bankbetrieb durch
231
6.10 Indirekte Objektzuordnungen
eine eindeutige Kontonummer identiflZiert werden. Die Unterstreichung der Instanzvariablen nr solI auf die Schltisseleigenschaft hinweisen. Die Angabe Dict(nr) bei der Kontenzuordnung legt fast, daB die Mehrfachbeziehung durch ein Behalterobjekt der Klasse Dictionary organisiert werden solI und zwar derart, daB die zugeordneten Konten unter ihrer Kontonummer in das Verzeichnis eingetragen werden.
Bank ktolahler
Konto O. . n konten (Diet: nr)
YModell'
---.
Dr (A)
Abbildung 6-15 Verzeichnis der Konten einer Bank
6.10 Indirekte Objektzuordnungen Bei den bisher behandelten Objektzuordnungen wurde das Partnerobjekt tiber die Instanzvariable des Tragerobjektes direkt referenziert oder im Falle von Mehrfachzuordnungen direkt in den von der Instanzvariablen bezeichneten Sammelbehalter eingetragen. Wie zu Beginn dieses Kapitels bereits erlautert wurde, kann dabei die Kardinalitat der Erreichbarkeitsmenge des Tragerobjektes, also die Anzahl der yom Tragerobjekt tiber Referenzen erreichbaren Objekte, auch stark anwachsen, was besonders beim Einsatz von Objektbanken (objektorientierten Datenbanken) unerwiinscht sein kann. In solchen Fallen ist es gtinstig, an Stelle des konzeptionellen Partnerobjektes ein Stellvertreterobjekt zu setzen, mit dessen Hilfe das Zielobjekt eindeutig gefunden werden kann. Wenn das Partnerobjekt yom Stellvertreter nicht direkt erreicht werden kann, so soIl von einer indirekten Objektzuordnung gesprochen werden. Die Zugriffsmethode auf das konzeptionelle Partnerobjekt muB dann jene Information zur Verf'ligung haben, die notwendig ist, mit Hilfe des Stellvertreters das Partnerobjekt aufzusuchen. Abbildung 6-16 zeigt einen kleinen Ausschnitt aus einem Modell, das an einer anderen Stelle im Zusammenhang mit einer Fallstudie tiber Banken wesentlich ausfUhrlicher betrachtet wird. Hier wird das Augenmerk darauf gerichtet, daB jeder Bankkunde beliebig viele Konten zugeordnet haben kann, wobei eine direkte Zuordnung vorgegeben wird, bei der die einzelnen Konten direkt in den fUr die Mehrfachzuordnung notwendigen Behalter eingetragen
232
6 Objektstrukturen
werden. Da ein Konto ein komplexes Objekt ist, das unter anderen seine einzelnen Kontoumsatze zugeordnet hat, werden bei der direkten Zuordnung eines Kontos zu einem Bankkunden auch aIle Kontoumsatze vom Bankkunden durch Navigation erreichbar und damit zu Elementen seiner Erreichbarkeitsmenge, die somit bei jedem Buchungsvorgang auf einem seiner Konten vergroBert wird.
Konto
Bankkunde O.. n
or
name adresse
~
konten (OrdColI)
Kontoumsatz O.. n~
or
biz
umsAtze (OrdColI)
~ Modell I
Abbildung 6-16 Direkte Zuordnung von Konten zu einem Bankkunden
Bankkunde methodsFor: 'Zuordnung: Konten' erstesKonto
"Nenne das erste Konto des Kunden oder nil, falls kein Konto zugeordnet ist Direkte Zuordnung Bankkunde (O ..n)/OrdColl -> Konto." A
konten isEmpty ifTrue: [nil] if False: [konten first]
Programm 6-17 Direkter ZugritT auf das erste Konto eines Kunden Mochte man jenes Konto eines Bankkunden ansprechen, das an erster Stelle des Kontenverzeichnisses steht, so kann dies auf die in Programm 6-17 gezeigten Weise erfolgen. In Abbildung 6-17 ist der gleiche Modellausschnitt gezeigt, jedoch mit einer indirekten Zuordnung von Konten zu Bankkunden. Die Angaben in dem Diagramm bedeuten, daB in dem von der Instanzvariablen konten referenzierten Behalter (dieser ist von der Art OrderedCollection) nicht die Konten selbst eingetragen sind, sondern als Stellvertreter ganze Zahlen, welche den Kontonummern entsprechen. In der ZugritTsmethode auf die Konten muB ein sichtbarer Einstiegspunkt festgeschrieben sein, tiber den mit Hilfe der als Stellvertreter gespeicherten Kontonummer das Konto erreicht werden kann.
233
6.10 Indirekte Objektzuordnungen
Bankkunde
Konto
O.. n ~ Integer (nrt - •
or
name adresse
konten (OrdCol!)
or
biz
Kontoumsatz
O..n - ' umsAtze (Ordeoll)
Modell I
Abbildung 6-17 Indirekte Zuordnung von Konten zu einem Bankkunden
Bankkunde methodsFor: 'Zuordnung: Konten'
erstesKonto "Nenne das erste Konto des Kunden oder nil, falls kein Konto zugeordnet ist Indirekte Zuordnung Bankkunde (O .. n)/OrdCoil ->Integer (nr) - - >Konto."
I ktonr I ktonr := konten isEmpty ifTrue: [Anil] ifFalse: [konten first]. ABank testBank kontoMitNummer: ktonr
(1) (2) (3)
(1) Man beachte, daB hier nicht nur der Block, sondem die Methode beendet wird.
(2) Wegen der indirekten Zuordnung wird hier nicht das erste Konto sondern die erste Kontonummer erhalten. Die Methode first ist angebracht, weil die Nummern der zugeordneten Konten in anOrderedCollection organisiert sind. (3) Durch Bank testBank sei als Einstiegspunkt ein ZugrifT auf jene Bank gegeben,
welche der Applikation zugrunde liegt (siehe Fallstudie Banken).
Programm 6-18 Indirekter Zugriff auf das erste Konto eines Kunden Programm 6-18 zeigt eine Methode, welche das im Kontenverzeichnis eines Bankkunden an erster Stelle stehende Konto liefert, dabei allerdings auf die indirekte Zuordnung Riicksicht nimmt. Von der Wirkung her sind die in den Programmen 6-17 und 6-18 enthaltenen Methoden iiquivalent. In der Regel wird das Stellvertreterobjekt, iiber welches das Zielobjekt aufgefunden werden kann, wie im angegebenen Beispiel ein Schliisselattribut des Zielobjektes sein.
234
6 Objektstrukturen
6.11
Gekoppelte Objektzuordnungen
Objektzuordnungen wurden als einseitige Anbindungen eines oder mehrerer Zielobjekte an ein Trligerobjekt charakterisert. Diese Einseitigkeit liuBert sich darin, daB flir die Zuordnung nur eine Instanzvariable zustlindig ist, welche im Trligerobjekt definiert ist. Als Folge davon ist eine direkte Erreichbarkeit des Zielobjektes yom Quellobjekt aus m6glich, eine Navigation in umgekehrter Richtung hingegen nicht. Die meisten bisher gezeigten Beispiele haben sich auf eine einzige Zuordnung konzentriert, ein Blick in Abbildung 6-2 jedoch ergibt, daB ein Adressenobjekt Zielobjekt in der Adressenzuordnung einer Person ist und gleichzeitig Trligerobjekt der Zuordnungen flir den Ort, die StraBe und flir die Postleitzahl. Allgemein kann jedes Objekt in mehreren Zuordnungen die Trligerrolle und gleichzeitig auch in mehreren Zuordnungen die Partnerrolle spielen. Auf diese Weise k6nnen beliebig komplexe Objektstrukturen im Objektraum aufgebaut werden. Eine Ausnahme davon bilden nur die Attributzuordnungen, bei denen das Zielobjekt (Attribut) als solches nur einmal auftreten darf.
O.. n
Firma
. - (Set) Iieferanten
Physische Person
O.. n kunden (SortColI)--+
YModell I Abbildung 6-18 Unabhlingige gegenseitige Zuordnungen im Modell In Abbildung 6-18 ist ein Modellausschnitt gezeigt, der bechreibt, daB jede Firma belie big viele physische Personen zu ihren Kunden zlihlen kann und daB auch jede physische Person beliebig viele Firmen als Einkaufsquellen kennt. Hier handelt es sich urn zwei unabhlingige Beziehungen flir welche es auf Instanzebene ohne Bedeutung ist, daB eine Firma und eine Person in zwei Zuordnungen jeweils als Trligerobjekt und Zielobjekt vorkommen kann. Aus der Tatsache, daB eine bestimmte Firma eine Person als Kunden registriert hat folgt also nicht zwangslliufig, daB die Person auch diese Firma als ihren Lieferanten betrachten muB. Abbildung 6-19 zeigt eine Situation im Objektraum, die mit dieser Modellvorgabe konform ist. Firma 1 hat sowohl die Personen Person 1 und Person2 als ihre Kunden vermerkt, umgekehrt hat keine der beiden Personen diese Firma in ihrer Lieferantenevidenz. Person1 betrachtet Firma2 als ihren Lieferanten, Firma2 jedoch hat Person1 nicht in ihrem Kundenverzeichnis. Ledig-
235
6.11 Gekoppelte Objektzuordnungen
lich das Kunden-Lieferanten-Verhliltnis zwischen Firma2 und Person2 beruht auf einer gegenseitigen Kenntnisnahme.
'__
Ileteranten
/l.------------\illill~
Abbildung 6-19 Unabhiingige gegenseitige Zuordnungen im Objektraum
Bankkunde 1 - - - - - - I O.. n
M
name adresse
konten (OrdColI) +---+ inhaber
Konto
M
-i Modell I r - - - - - - - - - - - - - - - - - - - - ' Abbildung 6-20 Gekoppelte Zuordnung zwischen Bankkunden und Konten Ein anderer Fallliegt vor, wenn zwei Objekte durch gegenseitige Zuordnung miteinander gekoppelt werden sollen, so daB eine gegenseitige Erreichbarkeit sicherzustellen ist. Abbildung 6-20 gibt als Beispiel einen Modellausschnitt, der beschreibt, daB in einer Applikation aus dem Bankbereich Bankkunden und Konten in einer gegenseitigen,gekoppelten Beziehung stehen. Die Gegenseitigkeit dieser Beziehung besteht darin, daB dann, wenn ein Bankkunde ein Konto zugeordnet hat, das Konto genau diesen Bankkunden als Inhaber zugeordnet hat. Bei einer gekoppelte Zuordnung kann nicht mehr von einem Quellobjekt und einem Zielobjekt gesprochen werden, beide Objekte sind vielmehr gleichwertig und gegenseitige Partner. Strukturell entspricht eine gekoppelte Zuordnung zwei unabhiingigen Zuordnungen, in denen jedes Partnerobjekt einmal die Rolle eines Quellobjektes und einmal die eines Zielobjektes spielt. Die Koppelung dieser unabhiingigen Zuordnungen erfolgt durch jene Methoden,
236
6 Objektstrukturen
welche die gekoppelte Beziehung zwischen zwei Objekten einrichten und auflosen. Diese Verwaltungsmethoden mussen sicherstellen, daB gekoppelte Zuordnungen nur vollsHindig errichtet beziehungsweise nur voUstandig aufgelost werden konnen. Bankkunde methodsFor: 'Privat: Kunde-Konto-Beziehung' addKonto: einKonto "Fuge das Konto einKonto in den Kontenbestand eines Kunden ein, falls es dort noch nicht enthalten ist."
(self hatKonto: einKonto) ifFalse: [self konten add: einKontoj Bankkunde methodsFor: 'Kunde-Konto-Beziehung' hatKonto: einKonto "Priife (truelfalse), ob der Kunde das als Argument angegebene Konto zugeordnet hat." 1\
self konten includes: einKonto
Konto methodsFor: 'Konto-Kunde-Beziehung' hatlnhaber: einKunde "Prufe (truelfalse), ob das Argument einKunde der Inhaber des Kontos ist" 1\
self inhaber = einKunde
Programm 6-19 Private Hilfsmethoden fUr die Kunde-Konto-Beziehung Programm 6-19 enthllit Hilfsmethoden fUr die Kunde-Konto-Zuordnung des gewllhlten Beispieles. Die Methode Bankkunde»addKonto: fUgt ein weiteres Konto zum Kontenbestand eines Bankkunden hinzu, verhindert aber die mehrfache Zuordnung ein und desselben Kontos. Diese Uberprufung ist notwendig, da ein SammelbehllIter der Klasse OrderedCollection ein Objekt auch mehrfach aufnehmen kann. Die beiden anderen Methoden dienen zum Feststellen einer bereits vorliegenden einseitigen Zuordnung. Die Errichtung einer gekoppeIten Beziehung besteht aus zwei Teilschritten, nlimlich aus der Errichtung der beiden einseitigen Zuordnungen. In Programm 6-20 ist eine Methode Bankkunde» bekommtKonto: gezeigt, welche eine gekoppelte Zuordnung zwischen einem Bankkunden und einem Konto einrichtet (siehe auch Programm 10-14). Die dort vorgenommene Uberprufung, ob das zuzuordnende Konto bereits einen Inhaber hat, ist fUr die Aufrechterhaltung der Konsistenz der Kunde-Konto-Beziehungen wesentlich. Ein eventuell dem Konto zugeordneter Inhaber wiirde durch diese Methode zwar durch den neuen Bankkunden ersetzt werden, das Konto selbst wiirde jedoch nicht aus dem Kontenbestand des vorherigen Kontoinhabers entfemt werden.
6.11 Gekoppelte Objektzuordnungen
237
Bankkunde methodsFor: 'Kunde-Konto-Beziehung'
bekommtKonto: einKonto "Errichten einer Kunde-Konto-Zuordnung, das heiBt: (a) ordne dem Konto (einKonto) den Bankkunden als Inhaber zu und (b) ordne dem Bankkunden das Konto zu." (einKonto inhaber notNil) (1) ifTrue: [self error: 'Oem Konto ist bereits ein Inhaber zugeordnet!1. self addKonto: (einKonto inhaber: self) (2) (1) Es wird gepriift, ob das Konto bereits einen Inhaber hat. (2) Hier wird zuerst der Kunde dem Konto und unmittelbar darauf dem Kunden das Konto zugeordnet, wodurch die gegenseitige, gekoppeite Zuordnung sichergestellt wird. Die Methode Konto»inhaber: liefert als Riickgabeobjekt den Empfanger, also das Konto!
Programm 6-20 Erriehten einer gekoppelten Zuordnung SoU ein Konto von einem Inhaber auf einen anderen ubertragen werden, so ist zuerst die alte Kunde-Konto-Beziehung zu losen, wodureh das Konto intermediar keinen Inhaber hat, und erst dann die neue Beziehung aufzubauen. Bei der Auflosung einer gekoppelten Beziehung ist ebenfalls darauf zu aehten, daB beide Teilbeziehungen ordnungsgemaB gelost werden, wie dies in Programm 6-21 fur die Aufl6sung einer Kunde-Konto-Beziehung gezeigt ist. Aueh hier wird in einem ersten Sehritt uberpriift, ob die aufzul6sende Beziehung uberhaupt existiert, denn nur dann kann sie aueh aufgel6st werden. Aus der Sieht des Kunden bedeutet die L6sung der gekoppelten Zuordnung die Entfemung des Kontos aus seinem Kontenbestand, aus der Warte des Kontos wird dessen Inhaber dadureh entfemt, daB die Instanzvariable inhaber mit nil belegt wird. Bei der Implementation der Methoden zur Verwaltung (Erriehtung und Auflosung) von gekoppelten Zuordnungen ist zu beaehten, daB diese in dem Sinne einer Transaktion entspreehen mussen, daB entweder beide Teilzuordnungen voUstandig erriehtet werden oder keine von beiden. Es sind daher aUe Voraussetzungen reehtzeitig prufen, bevor die einseitigen Zuordnung aufgebaut oder gel6st werden. Eine andere M6gliehkeit ware, die Voraussetzungen fUr die einseitigen Zuordnungen in deren "privaten" Methoden lokal zu prufen, dafUr aber in der Applikationsmethode vorzusehen, daB im FaUe eines Fehlers bereits eingegangene Teilzuordnungen wieder ruckgangig gemaeht werden, damit im Objektraum die Integritat entsprechend den ModeUvorgaben gewabrleistet bleibt.
238
6 Objektstrukturen
Bankkunde methodsFor: 'Kunde-Konto-Beziehung'
verliertKonto: einKonto "Aufltisen einer Kunde-Konto-Beziehung, das heiSt: (a) Entfernen des Kontos aus dem Kontenbestand des Kunden und (b) Entfemen des Kunden als Inhaber des Kontos." (self hatKonto: einKonto) & (einKonto hatlnhaber: self) ifFalse: [self error: 'AufzulOsende Kunde-Konto-Beziehung ist nicht eingerichtet.'J. self removeKonto: (einKonto inhaber: nil)
Programm 6-21 Aufiosung einer gekoppelten Zuordnung In diesem Zusammenhang solI darauf hingewiesen werden, daB durch die Benennung der Methodenkategorien versucht wird, die Methoden entsprechend ihrer technischen Abstraktion zu klassifizieren. Die in die Kategorie 'Kunde-Konto-Beziehung' eingereihten Methoden stellen die Einhaltung der Modellvorgaben sicher, wiihrend die Methoden der Kategorie 'Privat: KundeKonto-Beziehung' nur Teilaspekte berucksichtigen und daher nur unter bestimmten Vorbedingungen eingesetzt werden durfen. Letztere greifen auf noch stiirker technisch orientierte Methoden zuruck, die auf einer tieferen Systemebene operieren und beispielsweise in Kategorien mit Namen der Art 'accessing' oder 'copying' eingereiht werden. Fur Methoden, welche im Rahmen einer Applikation die Einhaltung der Geschiiftslogik sieherstellen, soli ten ebenfalls entsprechend benannte Kategorien vorgesehen werden. Die Methoden Bankkunde»bekommtKonto: und Bankkunde»verliertKonto: wurden in der an anderer Stelle gezeigten Fallstudie (Kapitel 10) nicht in eine Kategorie 'Applikation: Kunde-Konto-Beziehung' eingereiht werden, da sie nieht gewabrleisten, daB Kunden und Konten nur dann gegenseitig zugeordnet werden durfen, wenn sie bereits im Kundenoder Kontenverzeichnis vermerkt sind.
6.12 Dynamische Einschrankungen Die bisher vorgestellten Eigenschaften von Objektzuordnungen waren statische Einschriinkungen, die wiihrend der Lebenszeit eines Objektes immer erftillt sein mussen. In diesem Abschnitt werden einige dynamische Integritiitsbedingungen behandelt, welche zusiitzliche Einschriinkungen festlegen, welche sieh auf
6.12 Dynamische Einschriinkungen
239
Veriinderungen von Zuordnungen beziehen, wobei selbstverstiindlich die vorgegebenen statischen Eigenschaften nicht verletzt werden durfen. Zuordnungen k6nnen einerseits durch Hinzuftigen oder Entfemen von Partnerobjekten veriindert werden, andererseits durch den Austausch eines bereits zugeordneten Partners durch ein anderes Partnerobjekt. Die Einhaltung dynamischer Einschriinkungen kann durch entsprechend gestaltete Zuordnungsmethoden kontrolliert werden, es werden jedoch solche Methoden nicht angegeben, weil ihr Aufbau einfach ist und zumeist in der Verhinderung des Hinzufiigens oder Entfernens eines Partnerobjektes besteht.
6.12.1 Initialisierung einer Zuordnung Die Existenz eines Objektes im Objektraum beginnt mit der Instanzierung seiner Klasse. Ein Objekt befmdet sich unmittelbar nach seiner Erzeugung in einem Rohzustand, der dadurch gekennzeichnet ist, daB aile Instanzvariablen mit nil belegt sind. Durch die Initialisierung der Objektzuordnungen werden dem Objekt im Einklang mit den statischen Einschriinkungen des Modelles Partnerobjekte zugeordnet. Das Objekt beginnt nun seine Lebenszeit im Objektraum in einem "giiltigen" Zustand, der bei laufender Applikation Anderungen unterworfen ist. Bei einem Geschiiftsobjekt spiegeln diese Anderungen die Aktionen des entsprechenden Objektes der Realitiit wider. Es kann a1s Charakteristikum der Initialisierung einer Zuordnung betrachtet werden, daB ihre Durchftihrung unabhiingig von der Lebensgeschichte und vom momentanen Zustand des Objektes erfolgt. Anderungen von Objektzuordnungen, die nicht im Rahmen der Initialisierung stattfmden, k6nnen dynamischen Einschriinkungen unterworfen werden. In der Folge werden Mutabilitiit und Flexibilitiit als dynamischen Einschriinkungen betrachtet. Es kann in man chen Fiillen auch sinnvoll sein, eine Objektbeziehung auch wiihrend der Lebenszeit eines Objektes durch "Wiederinitialisierung" erneut in einen Grundzustand zu versetzen. Widerspricht dieser Vorgang der Geschiiftslogik, so wird dies in den Klassendiagrammen der Modelle durch die Angabe "II" (Initialisierungseinschriinkung) gekennzeichnet.
6.12.2 Mutabilitat einer Objektzuordnung Die Eigenschaft der Mutabilitiit einer Zuordnung bezieht sich auf die Austauschbarkeit eines bereits zugeordneten Partnerobjektes.
240
6 Objektstrukturen
Uneingeschrankte Mutabilitiit Bei vollkommen uneingeschriinkter Mutabilitiit kann ein Partnerobjekt jederzeit durch ein beliebiges anderes Objekt ersetzt werden, sofem dies durch die statischen Einschriinkungen ermoglicht wird. Beispielsweise wird die Zuordnung eines Saldos zu einem Konto voll mutabel sein, weil im Sinne der Verwendung eines Kontos durch Ein- und Auszahlungsvorgiinge der Kontostand laufend veriindert wird. Selbstverstiindlich durfen in dieser Zuordnung nur Partnerobjekte auftreten, die einen Geldbetrag repriisentieren, was jedoch Gegenstand einer statischen Einschriinkung ist.
Eingeschrankte Mutabilitat Die Mutabilitiit einer Zuordnung kann als stark eingeschriinkt bezeichnet werden, wenn zwar der Austausch eines Partnerobjektes zuliissig ist, das neue Partnerobjekt jedoch derselben Klasse wie das abgeloste Partnerobjekt angehoren muB. In einem Klassendiagramm kann stark eingeschriinkte Mutabilitiit durch "M=" gekennzeichnet werden. Bei schwacher Mutabilitiitseinschriinkung (Kennzeichen "M - ") mussen die Klassen des neuen und des abgelosten Partnerobjektes zwar nicht identisch sein, aber der gleichen Teilhierarchie angehOren. Welche Klassen oder Klassenhierarchien dabei uberhaupt in Frage kommen, wird durch die Varietiitseinschriinkung bestimmt.
Immutabilitiit Ein Zuordnung ist immutabel, wenn es ausgeschlossen ist, daB ein Partnerobjekt durch ein anderes ersetzt werden darf. In diesem Falle ist das bei der Initialisierung zugewiesene Partnerobjekt wiihrend der gesamten Lebenszeit des Triigerobjektes mit diesem verbunden, die Objektbeziehung ist konstant. Fur diese Einschriinkung wird in Modelldiagrammen die Kennzeichnung "M!" verwendet. Zuordnungen werden besonders dann als immutabel zu erkliiren sein, wenn das Zielobjekt fUr das Triigerobjekt einen identifizierenden Charakter hat. Beispielsweise wird die Zuordnung einer Kontonummer zu einem Konto immutabel sein, weil ein Konto durch seine Nummer innerhalb einer Applikation identiftziert wird. In Kapitel 8 wird eine Klasse vorgestellt, deren Instanzen Geldobjekte darstellen, die einen Betrag und eine Wiihrung zugeordnet haben. Auch diese Zuordnungen sind immutabel, weil ein Geldobjekt weder in seinem Betrag noch in seiner Wiihrung abiinderbar ist. In Abbildung 6-21 ist ein Beispiel fUr Mutabilitiitseinschriinkungen in einem Modell gegeben.
241
6.12 Dynamische Einschrankungen
Person
nr (MI) Geld
O.. n
inhaber
t
1.MI.... betrag
1
1
1.M'....
Konto
nr (MI)
Betrag
(A)
1-+
(A)
I
wahrungl
O. . n Wahrung
buchSaldo
I
Modell ~
Abbildung 6-21 Mutabilitatseinschrankungen
Dieses Beispiel zeigt, daB einem Konto seine Kontonummer, einer Person ihre Personennummer und einem Geldobjekt sein Betrag und seine Wahrung immutabel zugeordnet sind. Die Zuordnung eines Geldobjektes als Saldo eines Kontos ist keiner Mutabilitatseinschrankung unterworfen, da bei einer Saldoanderung ein anderes Geldobjekt zugewiesen wird. Dieses Modell schlieBt somit auch aus, daB eine Saldoanderung dadurch vorgenommen werden kann, daB zwar das zugeordnete Geldobjekt beibehalten wird, dieses jedoch mit einem anderen Betragsobjekt versehen wird. Die Zuordnung einer Person als Inhaber eines Kontos ist in diesem Modell ohne Mutabilitatseinschrankung formuliert, wei! es moglich sein soU, ein Konto auf einen anderen Inhaber zu iibertragen. Da der Wechsel eines Kontoinhabers aber eher ein Vorgang ist, der nur in Ausnahmefallen durchgefiihrt wird, konnte man diese Beziehung auch als immutabel erklaren, aber eine Wiederinitialisierung zulassen.
6.12.3 Flexibilitiit einer Objektzuordnung Flexibilitat ist eine Eigenschaft einer Mehrfachzuordnung, die sich auf die Moglichkeit der Anderung der Kardinalitat der Partnermenge einer Zuordnung bezieht. Man kann die folgenden Arten der Flexibilitatseinschrlinkung unterscheiden.
6 Objektstrukturen
242
Uneingeschrinkte Flexibilitiit Eine Mehrfachbeziehung ist voll flexibel, wenn die Anzahl der Partnerobjekte innerhalb der durch die MultipliziHitsvorgabe gesetzten Grenzen beliebig zuund abnehmen kann. Beispielsweise wird die Beziehung zwischen einer Firma und ihren Kunden voll flexibel sein, da der Kundenstock einer Firma je nach Geschiiftserfolg wachsen und schrumpfen kann.
Beschrinkte Flexibilitiit Eine beschrankte Flexibilitat liegt dann vor, wenn die Anzahl der Partnerobjekte in einer Mehrfachbeziehung entweder nur zunehmen oder nur abnehmen kann. 1m ersten Fall ist die Flexibilitat nach un ten beschrankt (F-), im zweiten Fall nach oben beschrankt (F+). Ais Beispiel sei die mit der Multiplizitat O.. n versehene Beziehung zwischen einem Konto und seinen Kontoumsatzen (Buchungen) erwiihnt. Dieser Beziehung wird eine nach unten beschrankte Flexibilitat vorzugeben sein, weil bei einer ordnungsgemaBen Kontofiihrung keine Buchung entfernt werden darf. Ein eventueller Fehler ist durch eine weitere Buchung (Stornobuchung) zu beheben. Da eine Buchung auch nicht gegen eine andere ausgetauscht werden darf, ist flir diese Beziehung auch die Immutabilitat zu fordern. Ebenso ist das Zurucksetzen in einen Grundzustand zu vermeiden, was einer zusatzlichen Initialisierungseinschriinkung entspricht.
Inflexibilitiit Eine Zuordnung ist inflexibel, wenn Partnerobjekte weder hinzugefligt noch entfernt werden durfen, selbst dann nicht, wenn es durch die Multiplizitatseinschrankung noch einen Freiraum gabe. In Abbildung 6-22 ist ein Beispiel flir Flexibilitatseinschriinkungen gezeigt. In dem Modellausschnitt sind die oben erwiihnten Eigenschaften der Zuordnung von Umsatzen zu einem Konto dargestellt. Durch die dynamische Einschrankung (I!, M!, F-) bilden die Kontoumsatze ansammelbare, jedoch nicht austauschbare Partnerobjekte eines Kontos, die in keinem Fall verloren gehen durfen. Dieser Modellausschnitt enthalt zusatzlich ein Beispiel flir eine Beziehung mit nach oben beschrankter Flexibilitat. Einem Konto, uber das durch Telebanking verfugt werden kann, wird eine vorgegebene Anzahl von Transaktionsnummern zugeordnet, die dem Inhaber bekannt gegeben werden. Die Transaktionsnummern konnen einzeln verbraucht, jedoch nicht einzeln hinzugefiigt werden, deswegen liegt eine nach oben beschriinkte Flexibilitat vor.
243
6.13 Untersuchung von Struktureigenschaften
Nach dem Verbrauch eines Teiles der Transaktionsnummern werden iiblicherweise die restlichen fur ungiiltig erkiart und eine neue Menge von Transaktionsnummern zur Verfiigung gestellt, was einer Neuinitialisierung der Beziehung entspricht. Die dynamische Einschrlinkung (M!, F+) qualiflZiert die Transaktionsnummern als verbrauchbare Partnerobjekte, die aber nicht austauschbar sind.
TAN
0 ..30, M!, F+
Konto
...
y
Modell
I
tan (Set)
O•• n,II, M!, FumsAtze (OrdColI)
•
Kontoumsatz
AbbUdung 6-22 Flexibilitat von Zuordnungen
6.13 Untersuchung von Struktureigenschaften Eine Zuordnung erfiillt die Eigenschaft einer Attributbeziehung, wenn das Zielobjekt von keinem anderen Objekt als dem Tragerobjekt referenziert wird. Eine Mogiichkeit, diese Eigenschaft in eingeschrankter Form zu Testzwecken zu iiberpriifen, ist durch die in den Programmen 6-22 und 6-23 gezeigten Methoden gegeben. Object methodsFor: 'association control'
ownedBylnstancesOf: aCollectionOfClasses "Bestimmen jener Menge von Objekten, welche den Empfanger referenzieren und Instanzen einer in aColiectionOfClasses enthaltenen Klasse sind."
I result I
result := Set new. self allOwners do:[:obj I (aCollectionOfClasses includes: obj class) ifTrue: [result add: obj]). "result
Programm 6-22 Feststellen von Objekten, die ein Objekt referenzieren
244
6 Objektstrukturen
Die in Programm 6-22 verwendete Methode Object»aIlOwners liefert eine Menge von Objekten, die den Empfanger (vor der Aktivierung der Methode) referenzieren. Das Ergebnis dieser Methode istjedoch fUr den angestrebten Zweck deswegen nicht direkt brauchbar, weil darin auch aIle jene temporliren Objekte enthalten sind, die im Kontext der aufrufenden Methode liegen. Die Methode Object»ownedBylnstancesOf: filtert deswegen aus allen den Empfanger referenzierenden Objekten jene heraus, die Instanz einer der im Parameter angegebenen Klassen sind.
Object methodsFor: 'association control' countReferencesTo: anObject "Bestimmen der Anzahl der Instanzvariablen des Empfangers, welche das Argument, anObject, direkt referenzieren. Es werden nur benannte Instanzvariable betrachtet!"
I count I count:= O. 1 to: self class instSize do: [:index I ((self instVarAt: index) = anObject) ifTrue: [count := count + 1]]. 1\ count countReferencesFromlnstancesOf: aCollectionOfClasses "Bestimmen, wie oft der Empfanger von Instanzen der im Argument gesammelten Klassen referenziert wird."
I count I
count := O. (self ownedBylnstancesOf: aCollectionOfClasses) do: (1) [:owner I count := count + (owner countReferencesTo: self)]. 1\ count
isAttributeln: aCollectionOfClasses "FeststelIen, ob der Empfanger von Instanzen der im Argument gesammelten Klassen htichstens einmal referenziert wird." 1\
(self countReferencesFromlnstancesOf: aCollectionOfClasses) <= 1
(1) Es geniigt nicht, die referenzierenden Objekte zu zahlen, da mehrere Instanzvariable eines Objektes ein und dasselbe Objekt referenzieren konnen.
Programm 6-23 Uberpriifen der Attributeigenschaft eines Objektes
6.13 Untersuchung von Struktureigenschaften
245
Mit Hilfe der Methode Object»countReferencesTo: anObject kann festgestellt werden, von wieviel Instanzvariablen des Argumentes der Empfanger referenziert wird, wobei indizierte Instanzvariable nicht berucksichtigt werden. SchlieBlich kann durch die Methode Object»countReferencesFromlnstancesOf: aColiectionOfClasses festgestellt werden, wie oft der Empfanger insgesamt von Auspragungen ausgewahlter Klassen referenziert wird. Die Methode Object»isAttributeln: aColiectionOfClasses testet auf der Basis der erwahnten Referenzzahlmethoden die Attributeigenschaft des Empfangers beziiglich Auspragungen der im Argument gesammelten Klassen. Programm 6-24 zeigt an Hand von Beispielen die Anwendung dieser Methoden.
Workspace
I person1
person2 applikationsklassen I applikationsklassen := Set with: Person with: Bankkunde. person1 := Person new name: 'Maier'. person2 := Bankkunde new name: 'Maier'.
(1) 1st der Name von Person1 ein Attribut? person1 name isAttributeln: applikationsklassen.
<printlt> true
(2) Person1 bekommt denselben Namen wir Person2, ist dieser ein Attribut? person1 name: person2 name. person1 name isAttributeln: applikationsklassen.
<printlt> false
(3) Welche Objekte referenzieren diesen Namen? person 1 name ownedBylnstancesOf: applikationsklassen. <printlt> Set (Person 'Maier' Bankkunde 'Maier' (Knr. 12345»
(4) Person2 erhalt den gleichen Namen wie Person1, ist dieser ein Attribut? person1 name: person2 name copy. person1 name isAttributeln: applikationsklassen.
<printlt> true
(5) Person1 erhalt als Adresse ihren Namen, ist dieser ein Attribut? Welche Objekte referenzieren diesen Namen? person1 adresse: person1 name. person1 name isAttributeln: applikationsklassen <printlt> false person1 name ownedBylnstancesOf: applikationsklassen. <printlt> Set (Person 'Maier') Programm 6-24 Beispiele fUr die Uberpriifung der Attributeigenschaft
246
6 Objektstrukturen
6.14 Aufgaben Aufgabe 6.1
Attributeigenschaft und indizierte Instanzvariable
In den Programmen 6-23 und 6-24 sind Methoden skizziert, mit deren Hilfe die Attributeigenschaft eines Objektes iiberpriift werden kann. In diesen Methoden werden jedoch nur Referenzen von benannten Instanzvariablen beriicksichtigt. Man erweitere diese Methoden derart, daB auch indizierte Instanzvariable in die Uberpriifung einbezogen werden, so daB es moglich wird, Referenzen aus Sammelbehalterobjekten zu erkennen.
Aufgabe 6.2
Kontrolle der Mutabilitatseinschrankung
SolI ein Partnerobjekt einer Zuordnung durch ein anderes ersetzt werden, so ist die Einhaltung eventueller Mutabilitatseinschrankungen sicherzustellen. Man erstelle analog zu der in Programm 6-13 angegebenen Methode die Methoden Firma» ersetzeKunde: altKunde starkDurch: neuKunde "Ersetze altKunde durch neuKunde unter Einhaltung einer starken Mutabilitatseinschrankung." ersetzeKunde: altKunde schwachDurch: neuKunde "Ersetze altKunde durch neuKunde unter Einhaltung einer schwachen Mutabilitatseinschrankung."
7 Verwaltung von Metainformationen iiber Objektstrukturen
1m vorangehenden Abschnitt wurden Methoden fur die Verwaltung von einfachen oder gekoppelten Zuordnungen gezeigt, welche Entwurfsvorgaben beriicksichtigen und deren Einhaltung gewlUlrleisten. Diese Methoden sollten die jeweils diskutierten Modellierungseigenschaften an Hand eines speziellen Beispieles demonstrieren, so daB es angebracht war, die durch das Modell vorgegebenen Bedingungen und Einschrankungen direkt in den Methoden zu verankem. In diesem Abschnitt wird ein Konzept vorgestellt, das es erlaubt, die Metain/ormation des Modelles selbst zu verwalten und fUr die Integritatskontrolle zur VerfUgung zu steIlen. Auch hier wird nicht der Zweck verfolgt, einfertiges Geriist t fUr die Applikationsentwicklung zur VerfUgung zu steIlen, sondem vielmehr Moglichkeiten fUr dessen Realisierung aufzuzeigen. Urn die Art der DarsteIlung der Metainformation und deren Verwendung in den Methoden fUr die Verwaltung von Beziehungen verdeutlichen zu konnen, wird vorerst ein Beispiel angegeben, welches zur Veranschaulichung des Konzeptes dienen soIl.
7.1
Beispiel: Studienwesen
Es wird ein Ausschnitt der Realitat betrachtet, der sich auf das Angebot von Studienrichtungen an Universitaten und auf die Belegung von Studienrichtungen durch Studenten bezieht.
t
Entwicklungswerkzeuge der hier beschriebenen Art, aber mit wesentlich groBerem Funktionsumfang, sind kommerziell verfiigbar.
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
248
7 Verwaltung von Metainformationen tiber Objektstrukturen
Es sei angenommen, daB Universitiiten Studienriehtungen anbieten, die von Studenten belegt werden konnen. Weiterhin konnen Universitiiten aueh Kurse anbieten, die dazu dienen, Personen, die noeh keine Studienvoraussetzung besitzen, auf eine Studienbereehtigungsprtifung vorzubereiten. Ein Spezialfall einer Studienriehtung sei ein Ausbildungsprogramm, das zwar an einer Universitiit vorgesehen sein kann, jedoeh fur einen speziellen Teilnehmerkreis gedaeht ist und daher von Studenten nieht belegt werden kann. Jede Studienriehtung und jeder Kurs konnen an mehreren Universitiiten angeboten werden, umgekehrt kann eine Universitiit mehrere Studienriehtungen und Kurse in ihrem Programm haben. Studenten konnen gleiehzeitig hoehstens zwei Studienriehtungen oder Kurse belegen. Da Kurse nur fUr Personen ohne Studienbereehtigung und Studienriehtungen nur fUr Personen mit Studienbereehtigung vorgesehen sind, darf ein Student nieht gleiehzeitig eine Studienriehtung und einen Kurs beiegen. Studienriehtungen und Kurse mogen von beliebig vielen Studenten beiegt werden konnen. Ein Modell, das diesen Vorgaben und Annahmen entsprieht, ist in Abbildung 7-1 angegeben.
Universit4t
Student Ausbildungsprogramm
studien (0 ..2), homo ~
belegung
~
kurse (O •.n) I~
.--_....loL..._---, veranstalter closed Studien(O .. n) ... ~f----I-' rrichtung I-----'---i studienangebot
- . teilnehmer (O •• n)
studien (O •.n)
Kurs
veranstalter (O .• n) .......1-------4--1
kursangebot
~
Modell
Abbildung 7-1
Modell fur das Studienwesen
In diesem Modell sind insgesamt drei Objektbeziehungen formuliert und mit den Beziehungsnamen belegung, studienangebot und kursangebot
7.2 Die Klasse AssociableObject
249
bezeichnet. Die Beziehung mit Namen studienangebot ist zwischen Universitaten und Studienrichtungen festgelegt, sie koppelt die Mehrfachzuordnung von Studienrichtungen zu einer Universitat mit der Mehrfachzuordnung von Universitaten zu einer Studienrichtung. Die Zuordnungsnamen studien und veranstalter charakterisieren die jeweilige Rolle der Partnerobjekte. Analoges gilt fur die Beziehung kursangebot. Mit dem Beziehungsnamen belegung wird eine Beziehung zwischen Studenten und Studienrichtungen beziehungsweise Kursen bezeichnet. Diese Beziehung ist variant, weil als Zuordnungspartner fUr die studien-Zuordnung von Studenten sowohl Studienrichtungen als auch Kurse in Frage kommen, die in dies em Beispiel untereinander nicht in Vererbungsbeziehung stehen. Durch die Angabe homo wird eine Homogenitatsforderung (Heterogenitatseinschrankung) symbolisiert, die festiegt, daB ein und derselbe Student nicht gemischt Studienrichtungen und Kurse belegen darf. Die Angabe closed bedeutet, daB die Teilnehmerzuordnung nicht aufUnterklassen vererbt wird, so daB Auspragungen der Unterklassen von Studienrichtung nicht als Zielobjekte der studien-Zuordnung eines Studenten zulassig sind, mit anderen Worten, daB Ausbildungsprogramme von Studenten nicht belegt werden konnen.t Wiirde man eine diesen Modellvorgaben entsprechende Implementation auf die im vorangehenden Abschnitt gezeigte Art durchfUhren, so miiBte man fUr jeden im Modell vorkommenden Rollennamen in der entsprechenden Klasse eine Instanzvariable vorsehen, diese mit einem Behlilterobjekt initialisieren und die Zuordnungsmethoden individuell so gestalten, daB die Integritatsregeln eingehaiten werden. 1m folgenden wird eine abstrakte Klasse AssociableObject entworfen, die ihren Unterklassen eriaubt, Modellinformationen deskriptiv festzulegen und die Beziehungen zwischen ihren Auspragungen zu kontrollieren.
7.2
Die Klasse AssociableObject
Es wird vorausgesetzt, daB die Beziehungsnamen in einem Modell eindeutig sind und daB auch fUr jeden Beziehungsnamen genau zwei Rollennamen festgelegt sind. Rollen mit gleichen Namen in verschiedenen Beziehungen sind jedoch zulassig. 1m angegebenen Modell kommt beispielsweise der Rollenname veranstalter in den zwei verschiedenen Beziehungen studienangebot und kursangebot vor, nicht zullissig ware jedoch, in der Beziehung belegung
t
Durch eine Kombination von homo/closed-Angaben konnen schwache und starke Heteroge· nitatseinschriinlrungen formuliert werden.
250
7 Verwaltung von Metainformationen tiber Objektstrukturen
die Rolle teilnehmer bei Kursen und Studienrichtungen anders zu benennen. Dadurch wird gewahrleistet, daB die Information tiber eine Beziehung in zwei Teile zerlegt werden kann, die jeweils einer der beteiligten Klassen zuzuschreiben ist und somit auch in dieser Klasse verwaltet werden kann. Die Beziehung zwischen zwei Objekten kann dann durch "Zusammenstecken" der gegenseitigen Zuordnungen aufgebaut werden, wobei zwei Zuordnungen dann zusammenpassen, wenn sie gleichen Beziehungsnamen und unterschiedliche Rollennamen tragen. Ob eine konkrete Beziehung tatsachlich errichtet werden kann, hiingt aber noch von den im Modell festgelegten Einschriinkungen abo Auf einer hoheren Abstraktionsebene werden Assoziationen als semantische Zuordnung zwischen Objekten betrachtet, die eigenstandige Modellkonzepte bilden und prinzipiell zweiseitig und symmetrisch sind [35]. Solche sachlogischen Zusammenhiinge stehen in der Analysephase einer Entwicklung im Vordergrund. Auf dieser Ebene ist es sinnvoll, Uberlegungen tiber die Multiplizitat einer Beziehung anzustellen, nicht aber nach technischen Moglichkeiten der Navigation zu fragen und zwischen unidirektionalen Objektzuordnungen und bidirektionalen, gekoppelten Objektbeziehungen zu unterscheiden. Ebenso sind Uberlegungen tiber die Organisation von Mehrfachzuordnungen noch verfrtiht. In einer Entwurfsphase wird bereits die Struktur und das Verhalten von Komponenten einer Applikation festgelegt. Dabei ist es notwendig, Beziehungen auf Klassenebene zu entwerfen und bereits ihre Einschrankungen und Organisationsformen zu festzulegen . Dazu gehOrt auch, Uberlegungen tiber Varietat und Heterogenitat von Mehrfachbeziehungen, tiber ihr dynamisches Verhalten sowie tiber ihre Organisationsform anzustellen. Die im folgenden eingeschlagene Vorgangsweise, eine Beziehung nicht als eigenstandiges Konzept zu sehen, sondern als Eigenschaft der Klassen ihrer Partnerobjekte, entspricht einer Realisierungsmoglichkeit auf Implementationsebene und steht nicht im Widerspruch zu einer abstrakten Sicht von Assoziationen.
l2.1
Die Struktur der Klasse AssociableObject
Wie aus der in Programm 7-1 angegebenen Defmition ersichtlich ist, werden fUr die Klasse AssociableObject die Klasseninstanzvariablen designedAssociations und aliDesignedAssociations festgelegt. Diese sind dazu gedacht, die Informationen tiber die irn Modell festgelegten Beziehungen zu tragen. Wahrend die Variable designedAssociations die der Klasse zugeordnete Metainformation tragt, halt die Variable allDesignedAssociations ein Verzeichnis mit samtlichen fUr die Auspragungen relevanten Beziehungs-
7.2 Die Klasse AssociableObject
251
informationen, also auch jenen, die in Oberklassen festgelegt sind. Dieses Verzeichnis wird im folgenden als Modellverzeichnis bezeichnet. Es sei daran erinnert, daB Klasseninstanzvariable im Unterschied zu Klassenvariablen private Variable der Klassenobjekte sind, so daB fur jede Unterklasse von AssociableObject individuelle Informationen festgelegt werden konnen. Object subclass: #AssociableObject instanceVariableNames: 'name partner' classVariableNames: " poolDictionaries: " category: 'Associations-Controlled' AssociableObject class instanceVariableNames: 'designedAssociations aliDesignedAssociations ' AssociableObject class methodsFor: 'class initialization'
initClassDesign "self subclassResponsibility AssociableObject methodsFor: 'testing'
isAssociable
"Auspragungen der Subklassen von AssociableObject sind assoziierbar." "true Object methodsFor: 'testing'
isAssociable
"Nur Auspragungen der Subklassen von AssociableObject sind assoziierbar." "false
printOn: aStream aStream nextPutAlI: self class name, '(" self name, ')'
Programm 7-1
Defmition der Klasse AssociableObject
Die Beziehungen zwischen Auspragungen samtlicher Unterklassen von AssociableObject (sie werden in der Folge als assoziierbare Objekte bezeichnet) werden tiber die Instanzvariable partner realisiert. Diese wird bei der Erzeugung eines (assoziierbaren) Objektes mit einem Verzeichnis (Dictionary)
initialisiert, in dem fur jede vom Modell zuliissige Beziehung eine Eintragung vorgesehen ist, die tiber die Beziehungskennzeichnung den Behii.lter der Partnerobjekte anzusprechen erlaubt. Ftir assoziierbare Objekte mtissen daher nur mehr Instanzvariable fUr Attribute und Aggregatobjekte vorgesehen werden,
252
7 Verwaltung von Metainformationen iiber Objektstrukturen
nieht aber Instanzvariable fUr die Realisierung von gekoppelten Objektbeziehungen. Das von der Instanzvariablen partner referenzierte Objekt wird in der Folge als Beziehungsverzeichnis bezeichnet, es enthlilt die Orthoin/ormationen tiber die aktuellen Beziehungen eines assoziierbaren Objektes. Das Beziehungsverzeichnis ist yom Modellverzeichnis zu unterscheiden, das dem Klassenobjekt zugeordnet ist und die Metainformationen der Modellvorgaben enthiilt. 1m Programm 7-1 wurde eine weitere Instanzvariable name festgelegt, diese dient nur fUr Testzwecke dazu, den Objekten eine Bezeichnung geben zu konnen und damit die Testergebnisse tiber die Methode printOn: besser verstiindlich zu machen. Urn feststellen zu konnen, ob ein Objekt assoziierbar ist, sind die im Programm 7-1 angegebenen Methoden Object»isAssociable und AssociableObject»isAssociable eingerichtet.
7.2.2
Die Metainformation einer Klasse
Der Instanzvariablen designedAssociations wird durch die Klassenmethode initClassDesign ein Feld (Array) zugeordnet, dessen Elemente je eine Beziehung beschreiben, die fUr Auspriigungen der Klasse vorgesehen sind und die auch an die Unterklassen vererbt werden, soweit dies nicht durch die Angabe closed ausgeschlossen wird. Diese Elemente sind selbst wieder Felder mit folgendem Aufbau:
1. Rollenname (bezeichnet die Rolle des Partnerobjektes) 2. Beziehungsname 3. minimale Multiplizitiit min >= 0, 4. maximale Multiplizitiit max >= min, oder "n" fur beliebig 5. Vererbungskennzeichen (4fclosed, 4fopen) 4Fopen: die Beziehungsinformation wird an Unterklassen vererbt 4Fclosed: die Vererbung der Beziehungsinformation wird unterbunden 6. Heterogenitiitskennzeichen (4Fhetero, 4Fhomo) 4Fhetero: keine Heterogenitiitseinschriinkung 4fhomo: starke Heterogenitiitseinschriinkung Die Modellinformationen des Beispiels (Abbildung 7-1) sind in Programm 7-2 in der beschriebenen Form festgelegt.
253
7.2 Die Klasse AssociableObject
(1)
AssociableObject subclass: :H=Studienrichtung instanceVariableNames: " classVariableNames: " poolDictionaries: " category: 'Beispiel-UniversiUitsstudien' Studienrichtung class>>initClassDesign
"Eine Studienrichtung a) kann beliebig viele Teilnehmer haben b) kann an beliebig vielen Universitaten eingerichtet sein." designedAssociations := :H=((belegung teilnehmer 0 n closed (studienangebot veranstalter 0 n open )
hetero) hetero)
(2)
Student class>>initClassDesign
"Ein Student kann hOchstens zwei Studienrichtungen belegen." designedAssociations := :H=((belegung studien
0 2 open
homo)
)
Universitat class>>initClassDesign
"Eine Universitat a) kann beliebig viele Studienrichtungen anbieten b) kann beliebig viele Kurse anbieten." designedAssociations := :H=((studienangebot studien (kursangebot kurse )
o o
n open n open
hetero) hetero)
(1) Auf gleiche Weise sind die Klassen Kurs, Student und UniversitAt als Subklassen von AssociableObject eingerichtet. (2) Eine gleich1autende Methode muB fliT die Klasse Kurs gelten.
Programm 7-2
Metainformation der Beispielklassen
Beispielsweise haben in der Methode Studienrichtung class»initClassDesign die Eintragungen in das Feld, das der Variablen designedAssociations zugeordnet wird, folgende Bedeutung:
254
7 Verwaltung von Metainformationen iiber Objektstrukturen
a) In der Belegungsbeziehung spielen die beliebig vielen Partnerobjekte einer Studienrichtung die Teilnehmerrolle, diese Beziehung wird nicht auf Unterklassen der Klasse Studienrichtung weitergegeben und b) in der Studienangebotsbeziehung spielen die beliebig vielen Partnerobjekte einer Studienrichtung die Veranstalterrolle. Die Angaben hetero und open bedeuten, daB beziiglich der Heterogenitiit und der Vererbung der Beziehungseigenschaft keine Einschriinkungen vorgegeben sind.
7.2.3
Das Modellverzeichnis der Klassen
Die gesamte fUr die Steuerung des Einrichtens und Losens von Beziehungen zwischen assoziierbaren Objekte notwendige Information wird in ein Verzeichnis (eine Auspriigung der Klasse Dictionary) eingetragen, das iiber die Klasseninstanzvariable aliDesignedAssociations angesprochen werden kann. Die "Vererbung" der Beziehungsinformation einer Klasse an ihre Unterklassen wird dadurch realisiert, daB bei der Klasseninitialisierung nicht nur die Beziehungsinformation der Klasse selbst (Klasseninstanzvariable designedAssociations) in das Verzeichnis der Modellvorgaben (Klasseninstanzvariable aliDesignedAssociations) eingetragen wird, sondern auch die Beziehungsinformationen aus der Oberklasse, sofern diese nicht als closed gekennzeiehnet sind. Somit enthiilt jede Klasse in ihrem ModeIlverzeichnis aIle fUr ihre Auspriigungen relevanten Beziehungsinformationen, sodaB bei der Kontrolle der Zuliissigkeit einer Beziehung nur dieses Verzeichnis konsultiert werden muB. Durch die Veriinderung der Beziehungsinformationen einer Klasse sind im Allgemeinen auch ihre Unterklassen betroffen, so daB auch eine neue Initialisierung des ModeIlverzeichnisses der Unterklassen notwendig ist. In Programm 7-3 ist die Methode AssociableObject class»initialize angegeben, welche diese Forderung dadurch beriicksichtigt, daB sie die Botschaft initAssociationDesign zuerst an sieh selbst und schlieBlich an alle ihre Unterklassen sendet. Dadurch wird sichergestellt, daB vor der Ubemahme der Beziehungsinformation aus der Oberklasse diese auf den aktuellen Stand gebracht wird. Werden bei laufender Applikation Beziehungsinformationen geiindert und durch Initialisierung die betroffenen Verzeichnisse mit den Modellinformationen aktualisiert, so entspricht dies einem Vorgang, der bei Anwendungen im Datenbankbereieh als Schemaevolution bezeichnet wird. In der Klasse AssociableObject ist jedoch nieht fUr den Fall Vorsorge getroffen, daB durch eine Schemaiinderung bisher zugelassene Beziehungen ihre Giiltigkeit verlieren.
7.2 Die Klasse AssociableObject
255
AssociableObject class methodsFor: 'class initialization'
initialize "Filhre aile notwendigen Initialisierungen durch." self initAssociationDesign. self aliSubclasses do: [:sub I sub initAssociationDesign)
initAssociationDesign "Initialisiere die Entwurfsinformationen." aliDesignedAssociations := Dictionary new. self initClassDesign; registerAII
registerAiI "Registriere aile in der Superklasse mit #open gekennzeichneten sowie die in der Klasse selbst vorgegebenen Assoziationsinformationen." (self superclass inheritsFrom: AssociableObject) ifTrue: [self registerAssociations: (self superclass openAssociations)). (1) self registerAssociations (1) Es wird vorausgesetzt, daB die Oberklasse ordnungsgemaB initialisiert ist!
Programm 7-3
Initialisierung der Modellinformation
Die Methode AssociableObject class»initAssociationDesign stellt der aktivierenden Klasse in einem ersten Schritt ein neues, noch leeres Modellverzeichnis zur VerfUgung, aktualisiert die fUr die Klasse festgelegten Beziehungen und erstellt mit Hilfe der Klassenmethode registerAII die Eintragungen in das Verzeichnis. Dies geschieht derart, daB zuerst die aus dem als aktuell vorausgesetzten Modellverzeichnis der Oberklasse durch open gekennzeichneten Beziehungsinformationen in das eigene Verzeichnis kopiert werden und sodann die in der Klasse selbst mit Hilfe der Klassenmethode initClassDesign festgehaltene Beziehungsinformation interpretiert und ebenfalls in das Verzeichnis eingetragen wird, wofUr die in Programm 7-4 gezeigte Klassenmethode registerAssociations zustiindig ist. Die Methode AssociableObject class» registerAssociations ersetzt die durch "n" gekennzeichnete unbeschrankte Multiplizitat durch die groBtmogliche Zahl der Klasse Smalllnteger, bildet ein aus dem Beziehungsnamen und dem Rollennamen bestehendes Feld als Schliissel fUr das Modellverzeichnis und tragt die Angaben iiber Multiplizitat, Varietiit und Homogenitat unter diesem Schliissel in das Verzeichnis ein.
256
7 Verwaltung von Metainformationen tiber Objektstrukturen
AssociableObject class methodsFor: 'registration'
registerAssociations: aDesignDictionary "Registriere die in dem Verzeichnis aDesignDictionary enthaltenen Assoziationen" aDesignDictionary associationsDo: [:assoc I aliDesignedAssociations at: assoc key put: assoc value]
registerAssociations "Trage die Modellbeziehungen der Klasse in das Gesamtverzeichnis ein"
In I
n := Smallinteger maxVal. designedAssociations do: [:assoc lassoc replaceAII: #n with: n from: 3 to: 4. allDesignedAssociations at: (assoc copyFrom: 1 to: 2) put: (assoc copyFrom: 3 to: 6)]
Programm 7-4
Registrierung der Modellinformationen
Nach ordnungsgema13er Initialisierung der Klassen entstehen aus den in Abbildung 7-1 und Programm 7-2 gezeigten Modellinformationen Modellverzeichnisse mit folgendem Inhalt: Klasse Studienrichtung: #(#belegung #teilnehmer) -> #(#studienangebot#veranstalter) ->
#(0536870911 #closed#hetero) #(0536870911 #open #hetero)
Klasse Ausbildungsprogramm: (#(#studienangebot#veranstalter)-> #(0536870911 #open #hetero) Klasse Student: (#(#belegung
#studien)
->
#(0
2 #open #homo)
Da die Modellinformation in den Methoden initClassDesign in Form von Literalen angegeben wurde, sind die Beziehungs- und Rollennamen sowie die Varietats- und Heterogenitatskennzeichen als Symbole interpretiert worden.
257
7.2 Die Klasse AssociableObject
7.2.4
Das Beziehungsverzeichnis der Instanzen
Wenn im Rahmen der AktiviHiten einer Applikation eine Beziehung zwischen zwei assoziierbaren Objekten eingerichtet werden soIl, so wird zuerst iiberpriift, ob die gewiinschte Beziehung im Entwurfsmodell vorgesehen ist, was dann der Fall ist, wenn in den Modellverzeichnissen der zustlindigen Klassen entsprechende Eintragungen unter den Zuordnungsnamen vorliegen. Weiterhin wird iiberpriift, ob die zu assoziierenden Objekte die Modellvorgaben fUr eine giiltige Beziehung erftillen. Die Beziehung wird schlieBlich dadurch errichtet, daB in den Beziehungsverzeichnissen der zu assoziierenden Objekten unter den jeweiligen Zuordnungsnamen die Partnerobjekte vermerkt werden, genauer gesagt, daB die Partnerobjekte in die dort vorgesehenen Behlilterobjekte eingefUgt werden. Zuordnungsnamen sind dabei Beziehungsnamen, die durch einen Rollennamen erglinzt sind.
aDictionary
61nStudent
'Meier'
#b #s
-> 0
1 - - - --10
partner \J---j----iI>\
'Blo!ogie' 'UniWlen'
aDictiooary '!nformaUkl
#b #t ->
partner
#s #v -> \J-f--- --
AbbUdung 7-2
Ausschnitt aus dem Objektraum
-BIi>
258
7 Verwaltung von Metainformationen iiber Objektstrukturen
In Abbildung 7-2 ist ein Ausschnitt des Objektraumes mit einer Situation gezeigt, die dem Beispiel des Studienwesens entnommen ist und den Modellvorgaben aus Abbildung 7-1 entspricht. Er veranschaulicht die Realisierung der Beziehung belegung zwischen dem Studenten "Meier" und der Studienrichtung "Informatik", was bedeutet, daB der Student Meier (unter anderen) Informatik studiert und daB umgekehrt die Studienrichtung Informatik (unter anderen) den Studenten Meier als Teilnehmer hat. 1m Objektraum sind die beiden Geschliftsobjekte "Student Meier" und "Studienrichtung Informatik" gezeigt, die als Ausprligungen von Subklassen der Klasse AssociableObject iiber ihre Instanzvariable partner je ein Beziehungsverzeichnis zugeordnet haben. Das Beziehungsverzeichnis des "Studenten Meier" hat (wie die Beziehungsverzeichnisse aller Studenten) nur eine Eintragung unter dem Zuordnungsnamen #(#belegung #studien) (in der Abbildung durch #b #s abgekiirzt), weil fUr Studenten keine anderen Beziehungen modelliert sind. Der Eintrag unter dies em Zuordnungsnamen als Schliissel ist ein Behlilterobjekt der Art OrderedColiection, in welchem die zugeordneten Partnerobjekte eingetragen sind, namlich die "Studienrichtung Informatik" und die "Studienrichtung Biologie". Dem "Studenten Meier" konnte keine weitere Studienrichtung mehr zugeordnet werden, da dies eine Verletzung der im Modell geforderten Maximalkardinalitlit bedeuten wiirde. Das Beziehungsverzeichnis der "Studienrichtung Informatik" enthlilt zwei Behlilterobjekte, jeweils eines unter den Zuordnunsnamen #(#belegung #teilnehmer) und #(studienangebot #veranstalter), was in Ubereinstimmung mit dem Modell steht. In der in Abbildung 7-2 gezeigten Situation gibt es genau den "Studenten Meier", der an der "Studienrichtung Informatik" teilnimmt, womit die gegenseitige, gekoppelte Beziehung zwischen den beiden Geschliftsobjekten ordnungsgemliB realisiert ist. Programm 7-5 zeigt eine Methode, welche den Empfanger mit einem als Parameter anzugebenden Partnerobjekt in eine ebenfalls als Parameter anzugebende Beziehung setzt, sofern dies nach den Modellvorgaben moglich ist. Durch die in diese Methode eingeftigten Kommentare wird auf die einzelnen Priifschritte hingewiesen, die durchlaufen werden, bevor die Assoziation der Objekte hergestellt wird. 1m FaIle der Verletzung einer Bedingung wird die Methode mit einer Fehlermeldung abgebrochen, wobei durch einen erkllirenden Text auf die Ursache des Fehlers hingewiesen wird. Diese Vorgangsweise ist nur fUr Test- und Demonstrationszwecke geeignet. Fiir den Einsatz irn Produktionsbetrieb einer Applikation wliren Methoden zu realisieren, die ein entsprechendes Fehlermanagement durchftihren.
7.2 Die Klasse AssociableObject
259
AssociableObject methodsFor: 'association'
associateNamed: associationName role: selfRole with: anAssociableObject role: partnerRole
"Errichten einer Beziehung mit der Bezeichnung association Name und den Rollen selfRole und partnerRole zwischen dem Empfanger und dem Argument anAssociableObject in Obereinstimmung mit den Entwurfsvorgaben."
I forward Name reverseName I forwardName := Array with: association Name with: selfRole. reverseName := Array with: association Name with: partnerRole. "Pruten der GUltigkeit des Assoziationspartners." anAssociableObject isAssociable ifFalse: [self error: 'Assoziation nicht mOglich'].
"PrUfen, ob die angesprochene Beziehung modelliert ist." ((self class hasDesignFor: forwardName) and: [anAssociableObject class hasDesignFor: reverseName]) ifFalse: [self error: 'Beziehung nicht model\iert'].
"PrUfen, ob die Assoziation bereits besteht." (self isAssociatedAt: forwardName with: anAssociableObject) ifTrue: [self error: 'Die Assoziation besteht bereits.'].
"Prufen, ob die Errichtung der Beziehung ohne Oberschreitung der maximalen Kardinamaten moglich ist." ((self isMaxCardinalityAt: forwardName) or: [anAssociableObject isMaxCardinalityAt: reverseName]) ifTrue: [self error: 'KardinaIiUitsuberschreitung1.
"PrUfen, ob die Errichtung der Beziehung ohne Verletzung der Heterogenitatseinschrankungen moglich ist." ((self isHeteroConformAt: forwardName with: anAssociableObject) and: [anAssociableObject isHeteroConformAt: reverseName with: self]) ifFalse: [self error: 'Homogenit~tsbedingung verletzt'].
"Errichten der Beziehung." (self partner at: forwardName) add: anAssociableObject. (anAssociableObject partner at: reverseName) add: self
Programm 7-5
Kontrolliertes Errichten einer Beziehung
260
7 Verwaltung von Metainformationen iiber Objektstrukturen
Es ist wichtig darauf hinzuweisen, daB vor der Errichtung der beiden gegenseitigen Zuordnungen aIle Bedingungen gepriifi werden miissen. Wiirde eine Zuordnung durchgeflihrt werden, bevor sichergestellt ist, daB auch die zweite Zuordnung durchflihrbar ist, so konnte im FaIle des Scheiterns der zweiten Zuordnung eine inkonsistente Situation im Objektraum entstehen. Beispielsweise konnte in der belegung-Beziehung zwischen einem Studenten und einer Studienrichtung ein Student der Studienrichtung als Teilnehmer erfolgreich zugeordnet werden, die umgekehrte Zuordnung der Studienrichtung zum Studenten jedoch konnte an einer Kardinalitats- oder einer Homogenitatsverletzung scheitern. Wird jetzt die Zuordnung des Studenten zur Studienrichtung nieht riickgangig gemacht, befmdet sich die Beziehungsstruktur der Objekte im Objektraum in einem nicht modeIlkonformen und daher inkonsistenten Zustand. Programm 7-6 enthlilt einige Klassenmethoden, mit deren Hilfe gezielte Informationen aus dem Modellverzeichnis erhalten werden konnen. AssociableObject class methodsFor: 'design-accessing' hasOesignFor: assocRoleName
"PrUte, ob die Beziehung assocRoleName im Beziehungsmodell vorliegt" A
self assocRoleNames includes: assocRoleName
minMuHiplicityAt: assocRoleName
"Zeige die dem Beziehungsnamen (assocRoleName) zugehorende minimale Kardinalitlit (mmin)" A
(self multiplicityAt: assocRoleName) at: 1
maxMuHiplicityAt: assocRoleName A
(self multiplicityAt: assocRoleName) at: 2
varietyAt: assocRoleName A
(self designlnfoAt: assocRoleName) at: 3
homogenityAt: assocRoleName A
(self designlnfoAt: assocRoleName) at: 4
Programm 7-6
Zugriff auf Modellinformationen
Einige fur das Verstandnis erforderliche Hilfsmethoden flir den Zugriff auf das Modellverzeichnis sind in Programm 7-7 zusammengestellt. Programm 7-8 zeigt Methoden flir den Zugriff auf das Beziehungsverzeichnis. In diesen Methoden bezeichnet assocRoleName den aus dem Assoziationsnamen und dem Rollennamen gebildeten Schliissel der Verzeiehnisse.
7.2 Die Klasse AssociableObject
261
AssociableObject class methodsFor: 'private-design' assocRoleNames
"Uefern aller vorliegenden Beziehungsnamen." 1\
aliDesignedAssociations keys
designlnfoAt: assocRoleName
"Uefern der unter dem Namen assocRoleName vorliegende Entwurfsinformation. Melden eines Fehlers, wenn diese nicht vorliegt." 1\
aliDesignedAssociations at: assocRoleName ifAbsent: [self error: 'unbekannte Beziehung'].
Programm 7-7
Privater Zugriff auf das Modellverzeichnis
AssociableObject methodsFor: 'association-accessing' associationsNamed: association Name role: selfRole
"Uefern eines Behalters mit den Partnern, die via associationName/selfRole mit dem Empfanger assoziiert sind."
I assocRoleName I
assocRoleName := Array with: associationName with: selfRole. 1\ (self partnerAt: assocRoleName) copy
cardinalityAt: assocRoleName
"Bestimmen der Anzahl der Partner, die unter dem Beziehungsnamen assocRoleName bereits mit dem Empfanger verbunden sind." 1\
(self partnerAt: assocRoleName) size
partnerAt: assocRoleName
"Zugriff auf die Assoziationspartner." (partner includesKey: assocRoleName) ifFalse: [self error: 'Beziehung " assocRoleName printString, 'nicht definiert.']. 1\ partner at: assocRoleName
Programm 7-8
Zugriff auf das Beziehungsverzeichnis
262
7 Verwaltung von Metainformationen iiber Objektstrukturen
In Programm 7-9 ist schlieBlich noch eine Methode angefiihrt, welche eine bestehende Beziehung zwischen zwei Objekten aufiost.
AssociableObject methodsFor: 'association'
deAssociateNamed: associationName role: selfRole from: anAssociableObject role: partnerRole "Uisen einer Beziehung mit der Bezeichnung asociationName/seltRole zwischen dem Empfanger und dem Argument anAssociableObject."
I forward Name reverseName I torwardName := Array with: associationName with: selfRole. reverseName := Array with: associationName with: partnerRole. "PrOten, ob die Assoziation besteht." (self isAssociatedAt: forwardName with: anAssociableObject) itFalse: [selt error: 'Die aufzulOsende Assoziation besteht nicht.']. "PrOten, ob die Uisung der Beziehung ohne Unterschreitung der minimalen Kardinalitliten moglich ist." ((self isMinCardinalityAt: forwardName) or: [anAssociableObject isMinCardinalityAt: reverseName]) ifTrue: [self error: 'Kardinalitiitsunterschreitung']. "Lose die Beziehung" (self partner at: forwardName) remove: anAssociableObject. (anAssociableObject partner at: reverseName) remove: selt Programm 7-9
7.3
Kontrolliertes Losen einer bestehenden Beziehung
Anwendung: Studienwesen
In dem angegebenen Beispiel fur das Studienwesen sind die Geschiiftsklassen Student, Studienrichtung, Ausbildungsprogramm, Kurs und Universitiit als Unterklasse von AssociableObject positioniert. Die Eintragungen in ihren Modellverzeichnissen entsprechen dem in Abbildung 7-1 gezeigten Modell, sodaB zwischen ihren Auspriigungen auf die gezeigte Art Beziehungen errichtet und auch wieder aufgelost werden konnen.
263
7.3 Anwendung: Studienwesen
UniversiUit methodsFor: studienwesen bietetStudium: eineStudienrichtung
"Eine Universitat bietet eine Studienrichtung an." self
associateNamed: #:studienangebot with: eineStudienrichtung
role: #:studien role: :#veranstalter
veranstaltetKurs: einenKurs
"Eine Universitat veranstaltet einen Kurs." self
associateNamed: #:kursangebot with: einenKurs
role: #:kurse role: :#veranstalter
studienangebot
"Bestimmen aller Studienrichtungen, die an der Universitat eingerichtet sind." Aself associationsNamed: #:studienangebot role: #:studien kursangebot
"Bestimmen aller Kurse, die an der Universitat angeboten werden." Aself associationsNamed: #:kursangebot role: #:kurse Programm 7-10 Beziehungsmethoden: Studienwesen einer Universitiit
Student methodsFor: studienwesen belegt: eineStudienrichtungOderKurs
"Ein Student belegt ein Studienrichtung oder einen Kurs." self
associateNamed: #:belegung with: eineStudienrichtungOderKurs
role: #:studien role: #:teilnehmer
beendet: eineStudienrichtungOderKurs
"Ein Student belegt ein Studienrichtung oder einen Kurs." self
deAssociateNamed: #:belegung from: eineStudienrichtungOderKurs
role: #:studien role: #:teilnehmer
studien
''Bestimmen aller Studien des Studenten." Aself associationsNamed: #:belegung role: #:studien Programm 7-11 Beziehungsmethoden: Studien eines Studenten
264
7 Verwaltung von Metainformationen tiber Objektstrukturen
Die Programme 7-10 und 7-11 zeigen Methoden, die auf solche der Klasse AssociableObject zurtickgreifen, diese aber mit dem Anwendungsgebiet entsprechenden Methodennamen versehen und dabei die detaillierte Modellinformation, die in den Methodenparametern zum Ausdruck kommt, verbergen. Um die entwickelten Beziehungsmethoden an Hand des Beispieles demonstrieren zu konnen, werden in einem Arbeitsbereich (Programm 7-12) voriibergehend globale Variable angelegt und mit Auspragungen der Klassen des Anwendungsgebietes belegt. Diese fUr die Zeit der Demonstration persistent gehaltenen Objekte sollen dazu dienen, in einem Arbeitsbereich Aktionen des Anwendungsgebietes zu simulieren. Workspace "Anlegen von globalen Variablen zum Testen." #(Uni Stud1 Stud2 Kurs1 Kurs2 Str1 Str2 Str3 Ab1) do: [:globVar Smalltalk at: globVar put: nil]. <dolt>
I
"Studienrichtungen, Ausbildungsprogramme und Kurse." Str1:= Str2:= Str3:= Ab1:= Kurs1 := Kurs2 :=
Studienrichtung new name: 'Informatik'. Studienrichtung new name: 'Statistik'. Studienrichtung new name: 'Biologie'. Ausbildungsprogramm new name: 'Didaktik'. Kurs new name: 'Mathematik'. Kurs new name: 'Deutsch'.
<dolt>
"Studenten." Stud1 := Student new name: 'Meier'. Stud2 := Student new name: 'Huber'.
<dolt>
"Eine Universitat und ihr Studienangebot" Uni := Universitaet new name: 'Uni Wien'. Uni bietetStudium: Str1; bietetStudium: Str2; bietetStudium: Str3; bietetStudium: Ab1; veranstaltetKurs: Kurs1.
<dolt>
Programm 7-12 Beispiel: Eine Universitat mit Studien und Studenten Durch die von Programm 7-12 gesetzten MaBnahmen werden weiterhin Methoden aktiviert, welche Beziehungen zwischen Universitaten und Studienrichtungen beziehungsweise Kursen einrichten.
265
7.3 Anwendung: Studienwesen
Programm 7-13 demonstriert schlieBlich Aktionen aus dem Anwendungsgebiet, die teilweise zu Integritiitsverletzungen flihren.
Workspace "Aktionen Stud1 belegt: Str1 Stud1 belegt: Stv1. Stud1 belegt: Kurs1. Stud1 belegt: Str2. Stud1 belegt: Str2. Stud1 belegt: Str3. Stud1 beendet: Str3 Stud1 beendet: Str2. Stud1 belegt: Str3. Stud2 belegt: Kurs1. Stud2 belegt: Kurs2.
Meldung eventueller Integritatsverletzungen" (1)
Beziehung niehl mode//iert Homogenilalsbedingung vertetzl Die Assozialion beslehl bereits Kardina/ilalsiibersehreilung Die aufzu/iisende Assozialion beslehl niehl
(2) (3) (4) (5) (6) (7)
(8) (9)
(10)
(11)
(1) Diese und aile weiteren Ausdriicke sind durch <dolt> durchzufiihren.
Programm 7-13 Kontrollierte Verwaltung von Beziehungen In Zeile (2) wird versucht, einen Studenten ein Ausbildungsprogramm belegen zulassen, was nicht moglich ist, da eine solche Beziehung im Modell nicht vorgesehen ist. Die Aktion in Zeile (3) verursacht eine Homogenitatsverletzung, well der Student Stud1 bereits in Zelle (1) eine Studienrichtung belegt hat und daher wegen der Homogenitatsforderung des Modelles keinen Kurs belegen kann. Da eine Beziehung zwischen zwei Objekten (unter gleichem Beziehungs- und Rollennamen) nur einmal eingerichtet werden kann, wird die Aktion in Zeile (5) zurUckgewiesen. In Zeile (6) wird versucht, dem Studenten Stud1, der bereits zwei Studienrichtungen belegt hat, noch eine dritte Studienrichtung zuzuordnen, was eine Uberschreitung der Maximalkardinalitat zur Folge hlitte und somit abgewiesen wird. SchlieBlich muB auch der Versuch in Zeile (7) scheitern, eine nicht eingerichtete Belegung rUckgangig zu machen. Aile anderen in Programm 7-13 angegebenen Aktionen konnen erfolgreich durchgeflihrt werden, was auch aus den in Programm 7-14 gezeigten Abfragen hervorgeht. Beispielsweise erkennt man, daB der Student Stud1 die Studienrichtungen "Informatik" und "Biologie" belegt hat, welche ibm in den Zeilen (1) und (9) zugeordnet wurden. Ebenso sieht man, daB die Kurse "Mathematik" und "Deutsch" von Stud2 belegt sind.
266
7 Verwaltung von Metainformationen tiber Objektstrukturen
Der Ordnung halber ist in Programm 7-14 am Ende noch angegeben, daB die vortibergehend angelegten globalen Variablen aus dem Systemverzeichnis Smalltalk wieder entfernt werden sollten. "Oberpriifung einiger Beziehungen."
<printlt> OrderedColiection (
Stud1 studien
Studienrichtung(lnformatik) Studienrichtung(Biologie»
<printlt> OrderedColiection
Stud2 studien
(Kurs(Mathematik) Kurs(Deutsch))
Uni studienangebot<printlt> OrderedColiection ( Studienrichtung(lnformatik) Studienrichtung(Statistik) Studienrichtung(Biologie) AusbiidungsprogrammDidaktik» Uni kursangebot
<printlt> OrderedColiection
(Kurs(Mathematik»)
"Entfernen der globalen Variablen nach dem Testen."
#(Uni Stud1 Stud2 Kurs1 Kurs2 Str1 Str2 Str3 Ab1) do: [:globVar I Smalltalk removeKey: globVar). <dolt> Programm 7-14 Oberpriifung von Beziehungen
l4
Aufgaben
Aufgabe l1
Oberpriifen einer Heterogenitiitsbedingung
In Programm 7-5 wird zur Oberpriifung, ob eine Beziehung ohne Verletzung von Heterogenitatseinschrlinkungen errichtet werden kann, eine Methode isHeteroConformAt: assocRoleName with: anAssociableObject verwendet.
7.4 Aufgaben
267
Man verfasse diese Methode, wobei vorausgesetzt werden kann, daB aile in Programm 7-5 vor dem Senden dieser Methode durchgefiihrten Prlifungen erfolgreich waren und daher nicht mehr durchgefUhrt werden mussen.
Losung von Aufgabe l1 Die Methode AssociableObject»isHeteroConformAt:with: ist in Programm 7-15 gezeigt, die Abfolge der einzelnen Prlifungen kann aus den eingefiigten Kommentaren entnommen werden.
AssociableObject methodsFor: 'private-association
isHeteroConformAt: assocRoleName with: anAssociableObject
"Testen (true I false), ob das Argument anAssociableObject ohne Verletzung der Homogenitatsbedingung als Partner des Empfangers eingesetzt werden kann."
I myClass oneOfMyPartners I "PrUfen, ob Uberhaupt eine Homogenitatseinschrankung vorliegt" myClass := self class. (((myClass maxMultiplicityAt: assocRoleName) <= 1) or: [(myClass homogenityAt: assocRoleName) = :fI:hetero]) iITrue: ["true].
"PrOfen, ob Assoziatonspartner vorhanden sind, wenn ja, ob diese der gleichen Klasse angehOren wie der zu assoziierende Partner." oneOfMyPartners := self somePartnerAt: assocRoleName. (oneOfMyPartners isNii or: [oneOfMyPartners class = anAssociableObject class]) iITrue: ["true]. "false
somePartnerAt: assocRoleName
"Nennen irgendeines Partners, der unter dem Beziehungsnamen assocRoleName bereits mit dem Empfanger verbunden sind." "(self partnerAt: assocRoleName) detect: [:elem I true] ifNone: []
Programm 7-15 Test auf HeterogeniUitskonformitat
268
Aufgabe l2
7 Verwaltung von Metainformationen tiber Objektstrukturen
Metainformation iiber die Organisationsform
In der gezeigten Form werden die Partnerobjekte der gekoppelten Zuordnungen einer Beziehung in einem BehiHterobjekt gesammelt, das der Klasse OrderedColiection angehort. Man erweitere den Formalismus derart, daB auch die Organisationsform der Beziehungen als Metainformation vorgegeben werden kann.
8
Fallstudie: Geld
In den vorangehenden Kapiteln lag der Schwerpunkt auf der Darstellung der Sprache und jener Klassen, die eng mit der Funktionalitiit der Sprache zusammenhiingen, ebenso wurden Vorgangsweisen vorgestellt, die es edauben, auf kontrollierte Weise Objektstrukturen aufzubauen. In einigen der folgenden Kapitel werden aufeinander autbauende Anwendungsbeispiele gegeben. Diese als Fallstudien bezeichneten Beispiele sollen einerseits den Entwurf und die Realisierung von Anwendungsklassen zeigen, sie sind andererseits auch so gewiihlt, daB durch sie ein weiterer Einblick in ausgewiihlte Bereiche der Klassenhierarchie geboten wird und daB jeweils einzelne Charakteristika von Smalltalk in den Vordergrund geruckt werden. Die Beispiele befassen sich mit der Realitiit des Geld- und Bankwesens. Dieses Anwendungsgebiet wird aus zwei Grunden gewiihlt. Erstens deswegen, weil es sich dabei urn einen Bereich handelt, der aus dem tiiglichen Leben allgemein bekannt ist, sodaB ein Verstiindnis der Realitat vorausgesetzt werden kann und daher keiner besonderen Erkliirung bedarf. Ein zweiter Grund liegt auch darin, daB einige der angesprochenen Objektarten in der Literatur bereits wiederholt diskutiert wurden, so daB dem Leser ein Vergleich unterschiedlicher Sichten und Implementierungen moglich ist [27]. In diesem Kapitel wird eine Klasse entworfen, deren Auspriigungen Geldobjekte sind. Die Einrichtung dieser Klasse ist der AnlaB fUr einen Einblick in die in der Klassenhierarchie bereits bestehende abstrakte Klasse Magnitude.
8.1
Geldobjekte
Geldbetriige sind quantitative GroBen, die jeweils in einer bestimmten Wiihrung ausgedriickt sind, sie charakterisieren einen okonomischen Wert. Es ist daher naheliegend, ein Geldobjekt aus zwei Komponenten aufgebaut zu
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
270
8 Fallstudie: Geld
sehen: aus einem durch eine Zahl ausgedriickten Betrag und aus einer Angabe der Wlihrung. Beide Komponenten sind Restriktionen unterworfen. Geldbetrage mussen unabhiingig von ihrer GroBe stets ein Vielfaches einer kleinsten Wlihrungseinheit sein. Es ist daher wichtig, auf diese Voraussetzung bei der Wahl ihrer zahlenmaBigen Darstellung zu achten. In der Praxis werden Geldbetrage durch eine Kombination von "groBen" und "kleinen" Wlihrungseinheiten ausgedriickt, wobei in fast allen Wahrungen eine groBe Einheit 100 kleinen Einheiten entspricht. Eine kurze Aufmerksamkeit ist auch der Frage zu widmen, ob Geldbetrage an sich negativ sein konnen. Es ist sicher nicht moglich, jemanden "minus funf Schilling" zu uberreichen, wohl aber kann man jemandem diesen Betrag schulden. Bei einer Untersuchung der Realitat, wie sie im Rahmen der konzeptionelIen Modellierung durchgefUhrt wird, kann man zu der Auffassung gelangen, daB Geldobjekte prinzipiell einen positiven Betrag haben und daB sich SolI- und Habenbetrage erst durch die Zuordnung von Geld zu Wirtschaftssubjekten im Rahmen des Besitzverhaltnisses ergeben. 1m gezeigten Entwurf der Klasse Money werden jedoch auch Geldobjekte mit negativem Betrag zugelassen. Geldobjekte konnen im Zahlungsverkehr nur dann verwendet werden, wenn sie einer allgemein akzeptierten Wahrung angehoren. Aus diesem Grund soIl ein Register der in einem Wirtschaftsbereich giiltigen Wlihrungen verwaltet werden, welches bei jeder Erzeugung eines Geldobjektes konsultiert wird, ob die angegebene Wahrung in diesem Register tatsachlich eingetragen ist. Abbildung 8-1 zeigt ein konzeptionelles Modell fur Geld. Dieses Modell legt fest, daB ein Geldobjekt aus zwei Komponenten besteht, einem Betrag und einer Wlihrung. Die Multiplizitatsvorgaben verlangen, daB beide Komponenten vorhanden sein muss en, ein Geldobjekt darf also nur dann in Umlauf gebracht werden, wenn es einen Betrag und eine Wahrung zugeordnet hat. Das Wahrungsregister kann beliebig viele Wlihrungen enthalten, eine einem Geldobjekt zugeordnete Wahrung muB jedoch in dem Register eingetragen sein. Zusatzlich zu diesem strukturellen Entwurf sind noch einige Uberlegungen zum "Verhalten" von Geldobjekten erforderlich, um einen Anhaltspunkt uber die notwendigen Methoden dieser Klasse zu gewinnen. Diese Uberlegung ist auch fUr die Einordnung der Klasse in die bestehende Klassenhierarchie von Bedeutung, da es wunschenswert ist, einen betrachtlichen Tell des Verhaltens von einer bereits bestehenden Klasse zu erben und dadurch deren Code wiederverwenden zu konnen. Geldbetrage konnen als quantitative GroBen untereinander nach ihrem Betrag direkt verglichen werden, sofem sie der gleichen Wlihrung angehoren. Unter der gleichen Bedingung konnen sie auch zueinander addiert und voneinander subtrahiert werden. Weiterhin sinnvoll sind die Division zweier
271
8.2 Klassenhierarchie: Magnitude
Geldbetriige gleicher Wlihrung zur Bestimmung ihres (skalaren) GroBenverhliltnisses und die Multiplikation eines Geldbetrages mit (skalaren) Zahlen, um Vielfache oder Teile eines Geldbetrages zu erhalten. Hingegen stellt die Verkniipfung zweier Geldbetrlige durch Multiplikation keine sinnvolle Operation dar.
Betrag (A)
r---G-el-d--~ 1 --.~~------~ 1---------1 betrag L -_ _ _
1 --. ~wahrung
I ~
Wahrung Kennzeichen
Register (1)
t-___O_.._n-l
Bezeichnung
y Modell :t------------------------Abbildung 8-1
8.2
Ein Modell fUr Geld
Klassenhierarchie: Magnitude
In der Smalltalk-Klassenhierarchie existiert bereits die abstrakte Klasse Magnitude, die das allgemeine Verhalten von GroBen beschreibt, die in einer
linearen Dimension verglichen werden konnen. Ausprligungen von konkreten Subklassen der Klasse Magnitude haben zumindest das Verhalten ordinalskalierter GroBen. Programm 8-1 zeigt einen Ausschnitt aus jenem Tell der Klassenhierarchie, an deren Wurzel die Klasse Magnitude steht. Sie enthlilt die Klassen aller arithmetischen GroBen und damit aller Zahlen und auch Klassen fUr Datumsund Zeitobjekte. Die im nlichsten Abschnitt beschriebene Klasse Money ist in dieser Hierarchie ebenfalls bereits eingetragen. Die gewlihlte Darstellung entspricht der Hierarchie-Ansicht des Klassenbrowsers, sie driickt die hierarchische Anordnung der Klassen durch Einriikkung aus, auf die Klassennamen folgt in Klammern eine Aufzlihlung der in dieser Klasse defmierten benannten Instanzvariablen.
272
8 Fallstudie: Geld
KlassenBrowser
Object
0
Magnitude
0
ArithmeticValue () Number () FixedPoint ('numerator' 'denominator' 'scale') Fraction ('numerator' 'denominator') Integer 0 Largeinteger 0 LargeNegativelnteger () LargePositivelnteger () Smalllnteger () LimitedPrecisionReal () Double () Float 0 Point ('x' 'y') Character () Date(,day' 'year') Money ('amount'
'currency~
Time ('hours' 'minutes' 'seconds') Programm 8-1
Die Klasse Magnitude in der Klassenhierarchie
Die Klasse Magnitude legt ihren Unterklassen die Verpflichtung auf, die Vergleichsmethoden mit den Selektoren
<
=
"Feststellen, ob der Empfanger kleiner als das Argument ist" "Feststellent, ob der Empfanger gleich dem Argument ist"
zu implementieren,t bietet jedoch auf dem Wege der Verhaltensvererbung auf diese aufbauende Vergleichsmethoden an, von denen zwei als Beispiel in Programm 8-2 wiedergegeben sind. t
Zusatzlich wird erwartet, daB Unterklassen von Magnitude eine Methode mit Selektor hash implementieren, deren Riickgabeobjekt den Wert einer Hashfunktion darstellt, der fUr das EinfUgen in Mengen und iihnIich implementierte Behiilterobjekte notwendig ist. Man vergleiche dazu Abschnitt 4.5.
8.2 Klassenhierarchie: Magnitude
273
Auf Zahlenobjekte, sie sind alle Auspragungen der Unterklassen von Number, wurde bereits im Zusammenhang mit ihrer Literaldarstellung hingewiesen. Einige ihrer Eigenschaften werden bei Bedarf erlautert, sie werden jedoch als so selbstverstandlich angenommen, daB ihnen kein eigenes Kapitel gewidmet ist. KlassenBrowser
Magnitude methodsFor: 'comparing'
<= aMagnitude "Feststellen, ob der Empfanger kleiner oder gleich dem Argument ist." "(self> aMagnitude) not between: min and: max
"Feststellen, ob der Empfanger seiner GroBe nach zwischen den Argumenten min und max eingeordnet werden kann." "self>= min and: [self <= max] Programm 8-2
Vergleichsmethoden der Klasse Magnitude (Auswahl)
Workspace
Ix I x := 1.25s / 3. (x truncatedToScale) * 3. (x roundedToScale) * 3. x * 3. x scale 1.25/3 (5/4) 13 1.25 1 3 asFixedPoint: 2
<print't> <print't> <print't> <printlt> <print't> <printlt> <printlt> <printlt>
(1)
0.42s 1.23s 1.26s 1.25s
(2)
2 0.416667 (5/12) 0.42s
"Instanz von Float." "Instanz von Fraction." (3)
(1) 1.25s ist die Literaldarstellung einer auf zwei Nachkommastellen genauen, skalierten Zahl. (2) Man erkennt, daB die interne Genauigkeit beim Rechnen nicht begrenzt ist. (3) Umwandlung einer beliebigen Zahl in eine skalierte Zahl.
Programm 8-3
Instanzen der Klasse FixedPoint
274
8 Fallstudie: Geld
An dieser Stelle wird aber die Aufmerksamkeit auf die Klasse FixedPoint gelenkt, deren Auspragungen Zahlen sind, die genau jene vorher erwahnten Eigenschaften besitzen, die fur Geldbetrage veriangt werden. Instanzen dieser Klasse sind Zahlen, die eine beliebige Genauigkeit in ihrem ganzzahligen Anteil aufweisen, ihre Genauigkeit aber auf eine vorzugebende Anzahl von Stellen nach dem Dezimalpunkt beschranken. Eigenschaften von Auspragungen der Klasse FixedPoint werden durch einige in Programm 8-3 evaluierte und kommentierte freie Methoden veranschaulicht.
8.3
Die Klasse Money
Geldobjekte besitzen unter anderen auch die von der Klasse Magnitude gebotenen allgemeinen Eigenschaften, aus diesem Grunde wird die Klasse Money als Unterklasse von Magnitude eingerichtet. Sie wird mit den Instanzvariablen amount und currency versehen.
Magnitude subclass: #Money instanceVariableNames: 'amount currency' classVariableNames: 'Currencies DefaultCurrency , poolDictionaries: " category: 'Wirtschaft' Money methodsFor: 'comparing'
"Feststellen (true I false), ob der Empfanger kleiner als das Argument ist" (self isSameCurrencyAs: aMoney) ifFalse: [self error: 'currency mismatch']. 1\ self amount < aMoney amount Money methodsFor: 'testing'
isSameCurrencyAs: aMoney
"Feststellen (true I false), ob die Wahrungsangaben des Empfangers und des Argumentes gleich sind." 1\
self currency = aMoney currency
Programm 8-4
Basismethoden fUr den Vergleich von Geldobjekten
8.3 Die Klasse Money
275
Die Definition dieser Klasse und die Realisierung einer Basismethode fUr den GroBenvergleieh ist aus Programm 8-4 zu entnehmen, wo aueh eine Methode angefUhrt ist, die es erlaubt festzuste11en, ob zwei Geldobjekte in ihrer Wiihrung iibereinstimmen. Man erkennt aus der Defmition dieser Klasse, daB aueh zwei Klassenvariable Currencies und DefaultCurrency vereinbart sind. Die Klassenvariable Currencies so11 das Verzeiehnis der zuliissigen Wiihrungen tragen, eine Vorgabewlihrung so11 iiber die Klassenvariable DefaultCurrency verfiigbar gemaeht werden. In diesem und in allen folgenden Beispielen wird vorausgesetzt, daB namenskonforme Methoden fUr den ZugrifT auf Instanzvariable eingeriehtet sind. Programm 8-5 zeigt eine spezielle Methode fUr den sehreibenden ZugrifT auf die Instanzvariable currency, in welcher iiberpriift wird, ob das zuzuordnende Wlihrungssymbol im Wlihrungsverzeiehnis eingetragen ist. Money methodsFor: 'private' currency: aCurrency
"Kontrollierte Zuordnung eines Wlihrungssymbols." (self class registeredCurrency: aCurrency) ifFalse: (1) [ self error: 'currency not registered: " (aCurrency printString) ]. currency := aCurrency (1) Die Methode Money class>>registeredCurrency: stellt fest (true I false), ob das Argument eine im Verzeichnis eingetragene Wlihrung bezeichnet.
Programm 8-5
Kontrolliertes Zuordnen eines Wlihrungssymhols
Money methodsFor: 'private-accessing' amount 1\ amount copy amount: aFixedPointWrthScale2 amount := aFixedPointWithScale2 copy
Programm 8-6
AttributzugrifT auf den Betrag eines Geldobjektes
Die ZugrifTsmethoden auf die Instanzvariable amount (Programm 8-6) sehreiben und Hefern das den Betrag repriisentierende Objekt nieht selbst, son-
276
8 Fallstudie: Geld
dern jeweils eine Kopie. Dies entsprieht der Modellforderung, daB der Betrag als Attribut eines Geldobjektes gesehen wird, eine Eigensehaft, die an einer friiheren Stelle bereits ausftihrlieh diskutiert wurde. Money class methodsFor: 'instance creation'
newAmount: aFixedPoint2 andCurrency: aRegisteredCurrency
"Erzeugen eines Geldobjektes." 1\
super new amount: (aFixedPoint2 asFixedPoint: 2); currency: aRegisteredCurrency
(1)
newAmount: aFixedPoint2
"Erzeugen eines Geldobjektes mit Vorgabewahrung." I\self newAmount: aFixedPoint2 andCurrency: (self defaultCurrency)
new
"Erzeugen eines Geldobjektes mit Vorgabewahrung und Betrag 0." 1\
self newAmount: 0
Integer methodsFor: 'instance creation'
asMoney
"Erzeugen eines Geldobjektes mit Vorgabewahrung mit dem Empfanger als Betrag." 1\
Money newAmount: self
(1) Der Betrag wird injedem Fall in eine aufzwei Nachkommastellen skalierte Zahl umgewandelt.
Programm 8-7
Erzeugung von Geldobjekten
Eine Familie von Methoden fUr die Erzeugung von Auspdigungen der Klasse Money ist in Programm 8-7 zusammengefaBt. Die allgemeinste dieser Methoden, Money class»newAmount:andCurrency: erzeugt intermediar ein nieht initialisiertes Geldobjekt und ordnet diesem einen Betrag in Form einer auf zwei Naehkommastellen skalierten Zahl und eine Wiihrung zu. Die spezielleren Methoden dieser Familie erzeugen Geldobjekte mit beliebigem Betrag oder mit dem festen Betrag von null, jedoeh jeweils in Vorgabewahrung. Zusatzlieh ist eine Methode Integer»asMoney angegeben, die ein Geldobjekt mit Vorgabewahrung und einem entspreehenden ganzzahligen Betrag erzeugt.
8.3 Die Klasse Money
277
Urn erste Tests mit Auspragungen einer neu entworfenen Klasse in einem Arbeitsbereich durchfiihren zu konnen, empfiehlt es sich, die Methode Object»printOn: in der neuen Klasse zu redefmieren, urn eine aussagekrliftige Form der »Druckdarstellung" von Auspragungen dieser Klasse zu ermog1ichen. Diese Methode wird aktiviert, wenn in einem Arbeitsbereich mittels <printlt> ein Ausdruck evaluiert und sein Ergebnis »angeschrieben" wird, auf diese Methode wird auch zuriickgegriffen, wenn ein Objekt die Botschaft printString empfcingt, die eine Zeichenkette liefert, welche das Objekt in lesbarer Form charakterisiert. Wird eine solche Methode nicht eingerichtet, so wird die allgemeine Methode Object»printOn: aktiviert, welche den Klassennamen mit einem vorangestellten, unbestimmten Artikel (»a" oder »an", abhangig davon, ob der Klassenname mit einem Konsonanten oder einem Vokal beginnt) erzeugt. t Programm 8-8 zeigt die Methode Money»printOn: fur die Druckausgabe von Geldobjekten. Diese Methode fligt an das Argument (im Arbeitsbereich: an die durch den Cursor markierte aktuelle Position) zuerst das Wahrungssymbol ein, sodann den Absolutbetrag des Geldbetrages, aus welchem der Buchstabe »s" (das Exponentenzeichen der Literaldarstellung von FixedPointZahlen) entfernt wurde, urn schlieBlich, falls der Betrag negativ ist, die Zeichenkette ' CR' anzufligen. Aile diese Bestandteile der Druckdarstellung werden in Zeichenketten umgewandelt und untereinander verkettet. Money methodsFor: 'printing' printOn: aStream
"AnfUgen einer Zeichenkette an das Argumen~ welche den Empfanger charakterisiert."
I temp I temp := self amount. aStream nextPutAII: (self currency asString), ' " (temp abs printString copyWithout: (temp class exponentCharacter)). (self isNegative) ifTrue: [aStream nextPutAlI: 'CR'] Programm 8-8
Druckdarstellung eines Geldobjektes
Zum besseren Verstandnis dieser Methode sei daraufhingewiesen, daB das Argument aStream der Klasse WriteStream, einer Unterklasse von t
In Kapitel 5 wurden mehrfach Auspriigungen der dort entworfenen K1asse Relation in Arbeitsbereichen durch <printIt> dargestellt. Allerdings war es nicht notwendig, eine entsprechende Methode zu verfassen, wei! die geerbte Methode Coliection>>printOn: ausreichend ist.
278
8 Fallstudie: Geld
PositionableStream, angehOren muB und daher ein Objekt ist, welches eine
indizierbare Datenstruktur (Zeichenkette) und einen Zeiger auf deren aktuelle Position enthalt. DasProtokoll unterstiitzt unter anderem das sequentielle Schreiben von einzelnen Zeichen (aStream nextPut: aCharacter) und von Zeichenketten (aStream nextPutAlI: aByteString) an die aktuelle Position, die wahrend des Schreibvorganges aktualisiert wird. Workspace
I s1
s2 m1
I
"Instanzierung der Klasse Money nach verschiedenen Methoden." s1 := 1000 asMoney.
<printlf> ATS 1000.00 s2 := Money newAmount: -120.50 andCurrency: #ATS.
<printlf> ATS 120.50 CR
m1 := Money newAmount: 125.1 andCurrency: #OEM.
<printlf> OEM 125.10
Money newAmount: 200000 andCurrency: #LlT.
<printl!> Unhandled exception: currency not registerd: #UT
Programm 8-9
Erzeugung und Druckdarstellung von Geldobjekten
In Programm 8-9 sind Beispiele fUr die Erzeugung von Geldobjekten und fUr deren Druckausgabe gegeben. Es wird dabei angenommen, daB die Wahrungen mit den Kennzeichnungen #ATS (Vorgabewahrung) und #OEM im Wahrungsverzeichnis eingetragen sind, nicht aber #LlT. Diese Wahrungskennzeichnungen sind Auspragungen der Klasse ByteSymbol. Durch die in Programm 8-10 gezeigten Ausdriicke werden Geldbetrage untereinander verglichen. Die angewendeten Vergleichsmethoden werden von der Klasse Magnitude geerbt. Workspace
"Fortsetzung von Programm 8-9: Vergleich von Geldobjekten." s1 > s2. Money new between: s2 and: s1.
<printl!> true <printlf> true
Programm 8-10 Vergleich von Geldbetragen
279
8.3 Die Klasse Money
Money methodsFor: 'arithmetic' +aMoney
"Erzeugen eines neuen Geldobjektes, welches der Summe aus dem Empfanger und dem Argument entspricht." (self isSameCurrencyAs: aMoney) ifFalse: [self error: 'currency mismatch1. 1\ self class newAmount: (self amount + aMoney amount) andCurrency: (seH currency) -aMoney
"Erzeugen eines neuen Geldobjektes, welches der Differenz zwischen dem Empfanger und dem Argument entspricht." 1\
self + aMoney negated
scaleBy: aN umber
"Erzeugen eines neuen Geldobjektes, das aus dem Empfanger durch Betragsmultiplikation mit dem skalaren Argument entsteht" 1\
self class newAmount: (self amount * aNumber) andCurrency: (self currency)
Programm 8-11 Rechenoperationen mit Geldobjekten
Workspace
"Fortsetzung von Programm 8-9: Arithmetische Operationen mit Geldobjekten." 81 + 82. 81 - 82. 81 8caleBy: 100. s1 scaleBy: (1/3). s1 8caleBy: (-1/3). (81 scaleBy: (1/3)) scaleBy: 3.
<printlf> <printlf> <printlf> <printlf> <printlf> <printlf>
ATS 879.50 ATS 1120.50 ATS 100000.00 ATS 333.33 ATS 333.33 CR ATS 1000.00
"Ein Versuch, Betrage verschiedener Wahrungen zu addieren. s1 + m1.
<printtt> Unhand/eel exception: currency mismatch
Programm 8-U Arithmetische Verkniipfung von Geldobjekten
280
8 Fallstudie: Geld
Methoden fUr die Addition und Subtraktion von Geldobjekten sowie fUr deren Multiplikation mit skalaren GraBen sind in Programm 8-11 zusammengestellt, ihre Wirkungsweise wird durch die Beispiele in Programm 8-12 demonstriert. Man beachte, daB keine der Methoden den Empfanger veriindert, sondem immer eine neue Auspriigung der Klasse Money liefert.
8.4
Aufgaben
Aufgabe 8.1
Wahrungsumrechnung
Man ergiinze die entworfene Klasse Money derart, daB die Umrechnung zwischen Geldbetriigen verschiedener registrierter Wiihrungen maglich sind. Man gehe davon aus, daB die zur Umrechnung heranzuziehenden Kurstabellen jeweils nur einen Tag giiltig sind. Urn Umrechnungen im Nachhinein durchfiihren zu kannen, mussen auch Kurstabellen vergangener Tage verfiigbar sein. Eine Methode zur Wiihrungsumrechnung kannte folgende Signatur besitzen: Money»asCurrency: aCurrency fromdate: aDate
"Erzeugen eines Geldobjektes mit der Wahrung aCurrency, das dem Wert des Empfangers entspricht, gemessen an den am Tage aDate giiltigen Umrechnungskurs."
Aufgabe 8.2
Physikalisch dimensionierte GroBen
Geldobjekte sind Sonderfalle von GroBen, die eine physikalische Dimension tragen. Auf iihnliche Weise kannten Klassen festgelegt werden, deren Auspriigungen GraBen mit anderen physikalische Dimensionen sind. Man entwerfe eine Klasse, deren Auspriigungen eine beliebige physikalische Dimension haben, die sich aus Multiplikation von GraBen mit den Grunddimensionen: Liinge (Meter), Masse (Kilogramm), Zeitdauer (Stunde), Anzahl (Stuck) und akonomischer Wert (Geld) ergeben. Beispiele fUr soiche dimensionierte GraBen sind: Preisangaben wie ,,3000 Schilling pro Quadratmeter", Angaben einer Produktionsleistung wie ,,500 Stuck pro Stunde", Geschwindigkeitsangaben wie ,,150000 Meter pro Stunde" oder Dichteangaben wie "Kilogramm pro Kubikmeter".
9
Fallstudie: Konten
Im Geschiiftslebenwerden Konten zur Verrechnung von Leistungen herangezogen, im Bankwesen stellen sie auch eigene Produkte dar, die Banken ihren Kunden anbieten. Entsprechend den verschiedenen Produkten und Dienstleitungen von Banken werden Konten mit unterschiedlichen Merkmalen und Konditionen versehen. In diesem Kapitel wird eine Hierarchie von Kontoklassen entworfen. Dabei wird auf die im vorangehenden Kapitel betrachteten Geldobjekte zurtickgegritTen und eine Voraussetzung fUr die Fallstudien tiber den Bankbetrieb und die Abwicklung des Zahlungsverkehrs geschatTen. Aus der Sicht des konzeptionellen Entwurfes bietet sich dabei die Gelegenheit, die Gestaltung einer Hierarchie von Anwendungsklassen zu diskutieren, aus der Sicht von SmalItalk kann die Verwendung verschiedener Arten von Variablen demonstriert werden.
9.1
Konten
Konten werden innerhalb ihres Einsatzgebietes durch Kontonummern identifiziert, welche ihnen bei der ErotTnung zugewiesen werden, sie tragen einen Hinweis auf den Kontoinhaber, eine Bezeichnung des Kontozweckes und einen Kommentar, der es der kontoftihrenden Stelle ermoglicht, Anmerkungen tiber die Benutzung des Kontos zu machen. Der Buchsaldo eines Kontos vermerkt den jeweils aktuelIen Geldbetrag, der sich aus der Summe alIer Kontobewegungen ergibt. Jede Kontobewegung bewirkt einen Umsatz auf dem Konto, der fortlaufend festgehalten wird, sodaB jederzeit Informationen auch tiber vergangene Kontobewegungen zur Verfiigung stehen. Ein Kontoumsatz vermerkt den umgesetzten Geldbetrag, das Buchungsdatum, das Valutadatum und einen
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
9 Fallstudie: Konten
282
den Zweck des Umsatzes erklarenden Text. Eingehende und ausgehende GeIdtransaktionen mogen durch das Vorzeichen des Geldbetrages gekennzeichnet sein. Ein diesen Vorgaben entsprechendes Strukturmodell von Konten ist in Abbildung 9-1 gezeigt. Teile dieses ModeUes wurden bereits in den Abbildungen 6-17, 6-21 und 6-22 vorweggenommen, wo auch Details uber die Eigenschaften der Beziehungen erlautert sind.
Konto
nr M! inhaber bezeichnung kommentar
O ..n, I!, M!, F-
Kontoumsatz
•
buchungsDatum 1 - - - - - - - - - ; valutaDatum umsAtze (Ordeoll) buchungsText
betrag
buchSaldo
~
Geld L -_ _ _ _-I
betrag wAhrung
(A)
y
Modell
Abbildung 9-1
1, M!
(A)
II----------------------..J Strukturmodell eines Kontos
Konten unterscheiden sich einerseits durch die Moglichkeit ihrer Nutzung und andererseits durch die Konditionen der Verzinsung. Fur eine Art von Konten seien nur Einzahlungen erlaubt, jedoch keine Auszahlungen. Solche Konten konnen zum Ansparen von Kapital oder zum Tilgen von Krediten verwendet werden. Auf anderen Konten sind sowohl Einals auch Auszahlungen moglich, wie es etwa bei Geschaftskonten oder Gehaltskonten der Fall ist. SoIche Konten mogen zur Unterscheidung von ersteren als Vollkonten bezeichnet werden. Weiterhin moge zwischen Standardkonten und Sonderkonten unterschieden werden. Standardkonten haben durch die Bankpolitik vorgegebene Zinskonditionen, die sich einerseits nach der Art der Konten und andererseits nach den wirtschaftlichen Gegebenheiten richten, etwa nach der aktuellen Bankrate und Inflationsrate. Als Sonderkonten sollen soIche Vollkonten bezeichnet werden, fUr die individuelle Zinsvereinbarungen vorgesehen sind. Fur aIle
9.2 Eine Hierarchie von Kontoklassen
283
Vollkonten kann ein individueller Uberziehungsrahmen festgelegt werden, der einen durch die Bankpolitik vorgegebenen und von der Kontoart abhiingigen Maximalrahmen nicht iiberschreiten darf.
9.2
Eine Hierarchie von Kontoklassen
Bei der Einrichtung einer Hierarchie von Klassen, die wiederverwendbare Komponenten verschiedener Anwendungen bilden sollen, muB das Augenmerk darauf gerichtet werden, daB in der Vererbungshierarchie nicht eine Impiementierungsvererbung, sondern eine Spezijikationsvererbung realisiert wird [26], [38], [43], [44]. Die Klassen sollen also derart in einer Hierarchie angeordnet werden, daB Auspragungen einer Unterklasse stets an die Stelle von Auspragungen einer ihrer Oberklassen treten kannen, ohne daB es dabei zu Fehlern kommt. Die geerbte Struktur und das geerbte Verhalten darf also nur so abgeandert werden, daB diese Kompatibiltat gewabrleistet ist.
9.2.1
Die abstralden Klassen Konto und Vollkonto
Aus diesen Richtlinien folgt, daB die Klasse Konto als Superklasse der Klasse Vollkonto einzurichten ist, da Vollkonten die Funktionalitat von Konten aufweisen und dariiber hinaus noch Auszahlungsvorgiinge ermoglichen. Beide Klassen sind als abstrakte Klassen geplant, die selbst nicht instanziert werden, sondern dazu dienen, ihren konkreten Unterklassen Struktur und charakteristisches Verhalten zu vererben. In Programm 9-1 ist die Defmition der Klasse Konto gezeigt. Die Instanzvariablen entsprechen den Angaben des Modelles in Abbildung 9-1. Der Variablenpool Wirtschaftsdaten wird allen Kontoklassen t (sowie weiteren, spater einzufUhrenden Klassen) zugeordnet, er enthalt die Poolvariablen bankrate und inflationsrate. Zusatzlich sind die Klasseninstanzvariablen zinsDekrement und zinslnkrement ereinbart, mit deren Hilfe die aktuellen Haben- und SolIzinssatze aller Auspragungen der jeweiligen Kontoklasse bestimmt werden konnen. Es wird vorausgesetzt, daB fUr alle Instanzvariablen namenskonforme Zugriffsmethoden festgelegt sind. Programm 9-1 enthalt auch die Methode Konto class»initialize fUr die Klasseninitialisierung, in welcher ein Vorgabewert fUr die Klasseninstanzt
Seit der Version 2.5 von VisualWorks\Smalltalk4t werden in Obereinstimmung mit dem Standardisierungsentwurf [47] Datenpoois nicht mehr an Unterkiassen vererbt.
284
9 Fallstudie: Konten
variablen gesetzt wird. Man beachte, daB in jeder Kontoklasse durch die jeweilige Klassenmethode initialize klassenspezifische Konditionen vorgegeben werden konnen. Object subclass: #Konto instanceVariableNames 'nr buchSaldo inhaber umsatze bezeichnung kommentar ' classVariableNames: " poolDictionaries: 'Wirtschaftdaten' category: 'Konten' Konto class instanceVariableNames: 'zinsDekrement zinslnkrement' Konto class methodsFor: 'class initialization'
initialize "Initialisieren einer Kontoklasse: Festlegen der Standardkonditionen." self zinsDekrement: (7/5); zinslnkrement: (9/5)
initializeAIiClasses "Initialisiere die gesamte Konten-Klassenhierarchie." self withAIISubclasses do: [:class I class initialize]
(1)
Konto methodsFor: 'printing'
printOn: aStream "Darstellen des Empfangers durch eine erklarende Zeichenkette." aStream nextPutAlI: self class name, ' (Nummer: " self kontoNummer printString, , Saldo: " self buchSaldo printString, , Inhaber: " self inhaber printString, ')'
(2)
(1) Durch Konto»initializeAIiClasses werden aIle SubkIassen initialisiert. (2) Hier wird indirekt auf die Methode Money»printOn: (Programm 8-8) zuriickgegriffen.
Programm 9-1
Die abstrakte Klasse Konto
Programm 9-2 zeigt die Definition der Klasse Vollkonto als Subklasse von Konto. Hier wird die zusatzliche Instanzvariable rahmen deklariert, welche den individuellen Uberziehungrahmen von Vollkonten halt. AuBerdem werden die zusatzlichen Klasseninstanzvariablen normal Rahmen und maximalRahmen vereinbart und durch die Methode Vollkonto class»initialize mit
9.2 Eine Hierarchie von Kontoklassen
285
Vorgabewerten belegt. Diese konnen durch Vererbung der Methode Konto class»initialize in den konkreten Subklassen iibernommen oder durch Redefmition dieser Methode klassenspezifisch gesetzt werden. Konto subclass: #Vo"konto instanceVariableNames: 'rahmen' classVariableNames: " pool Dictionaries: 'Wirtschaftsdaten' category: 'Konten' Vo"konto class instanceVariableNames: 'normalRahmen maximalRahmen ' Vo"konto class methodsFor: 'initialize' initialize
"Initialisieren einer Kontoklasse: Festlegen der Standardkonditionen." self normalRahmen: maximalRahmen: zinslnkremenl: zinsDekrement:
Programm 9-2
(10000 asMoney); (50000 asMoney); (25/10); (9/5)
Die abstrakte Klasse Vo"konto
Konto class methodsFor: 'instance creation' newMitNummer: eineNummer
"Erzeuge ein neues Konto mit der angegebenen Kontonummer." 1\
super new initialize kontoNummer: eineNummer
Konto methodsFor: 'initialize' initialize
"Initialisieren eines Kontos." self buchSaldo: Money new; "Buchungssaldo := 0.0 ATS" bezeichnung: 'Verrechnungskonto'; kommentar: 'Kein Kommentar'.
"Modell: Vorbereitung der Zuordnung Konto (O..n) -> Kontoumsatz." umsatze := OrderedColiection new
Programm 9-3
Konstruktormethode fUr Konten
286
9 Fallstudie: Konten
Konstruktormethoden flir die Erzeugung von initialisierten Konten sind in Programm 9-3 gezeigt. Diese Methoden werden von der Klasse Konto ihren konkreten Subklassen zur VerfUgung gestellt, sie sind jedoch nicht flir die Instanzierung der abstrakten Klasse Konto selbst vorgesehen. Vollkonto methodsFor: 'initialize'
initialize
"Initialisieren eines Vollkontos." super initialize. self rahmen: (self class normalRahmen copy).
Programm 9-4
Initialisieren eines Vollkontos
Programm 9-4 legt fest, daB Subklassen von Vollkonto bei der Instanzierung ihren Auspragungen den in der Klasseninstanzvariablen normalRahmen vorgegebenen Oberziehungsrahmen zuordnen. Die Bedeutung der Klasseninstanzvariablen zinsDekrement und zinsInkrement geht aus den in Programm 9-5 gezeigten Methoden flir die Bestimmung der aktuellen Haben- und Sollzinssatze hervor. Der Habenzinssatz von Standardkonten berechnet sich als Differenz zwischen der im Poolerzeichnis Wirtschaftsdaten enthaltenen Bankrate (Poolvariable bankrate) und dem bei der Klasseninitialisierung festgelegten Dekrement (Klasseninstanzvariable zinsDekrement). Ahnliches gilt fUr den Sollzinssatz. Auf diese Weise wird simuliert, daB die Zinskonditionen eines Kontos sowohl "von Au Ben" durch die Wirtschaftdaten als auch "von Innen" durch die Zinspolitik des Bankinstitutes, das die Kontoklassen initialisiert, beeinfluBt werden. Die Verzinsung von Konten wird jedoch in der Folge nicht weiter betrachtet. Konto methodsFor: 'zinsberechnung'
zinsSatzHaben
"Bestimmen des aktuellen Habenzinssatzes." 1\
bankrate - self class zinsDekrement
zinsSatzSoll
"Bestimmen des aktuellen Sollzinssatzes." 1\
bankrate
Programm 9-5
+ self class zinslnkrement
Bestimmen der Zinssatze von Standardkonten
9.2 Eine Hierarchie von Kontoklassen
287
9.2.2 Kontoumsatze Entsprechend den Modellvorgaben (Abbildung 9-1) wird eine Klasse Kontoumsatz eingerichtet. Die Defmition dieser Klasse sowie eine Instanzierungsmethode sind in Programm 9-6 zusammengefaBt. Auch hier wird wieder vorausgesetzt, daB zum Lesen und Schreiben der Instanzvariablen entsprechend benannte Zugriffsmethoden eingerichtet sind.
Object subclass: :f#:Kontoumsatz instanceVariableNames: 'be1rag buchungsDatum valutaDatum buchungsText' classVariableNames: " poolDictionaries: " category: 'Konten' Kontoumsatz class methodsFor: 'instance creation' newBetrag: einBetrag buchungsText: einString valutaDatum: einDatum
"Erzeugen eines Kontoumsatzobjektes."
"self new betrag: einBetrag; valutaDatum: einDatum; buchungsText: einString Programm 9-6
Kontoumsiitze
9.2.3 Kontobewegungen Nach diesen Vorbereitungen konnen die in den Programmen 9-7 und 9-8 enthaltenen Methoden fUr Einzahlungen und Auszahlungen auf Konten formuHert werden. Fur jede Kontobewegung wird vorausgesetzt, daB der zu buchende Betrag als positiver Geldbetrag vorgegeben wird. In der Methode Konto»einzahlung:mitText:undValutaDatum: wird vorerst gepruft, ob der einzuzahlende Betrag positiv ist, sodann wird der Buchungssaldo um diesen Betrag erhoht, ein neues Kontoumsatzobjekt erzeugt und mit Hilfe der Methode Konto>>vermerkeUmsatz: in die geordneten Sammlung der bisherigen Umsiitze hinzugefUgt, wobei auch das Buchungsdatum auf das aktuelle Tagesdatum gesetzt wird. Auf iihnliche Weise wird durch die Methode Vollkonto>>auszahlung:mitText:undValutaDatum eine Auszahlung von dem Konto vorgenommen. Vor
288
9 Fallstudie: Konten
der Durchfiihrung des Auszahlungsvorganges wird allerdings iiberpriift, ob durch die Auszahlung der vorgegebene Uberziehungrahmen iiberschritten wird. SoUte dies der Fall sein, wird durch eine Fehlermeldung darauf hingewiesen, daB die Auszahlung nicht durchgeflihrt werden kann. Konto methodsFor: 'buchen'
vermerkeUmsatz: einUmsatz "Vermerken eines Kontoumsatzes." umsatze add: (einUmsatz buchungsDatum: Date today). 1\ einUmsatz
einzahlung: einBetrag mitText: einString undValutaDatum: einDatum "Eingangsbuchung." einBetrag isNegative ifTrue: [self error: 'Negativer Buchungsbetrag!']. self buchSaldo: (self buchSaldo + einBetrag). self vermerkeUmsatz: (Kontoumsatz newBetrag: einBetrag buchungsText: einString copy valutaDatum: einDatum copy)
Programm 9-7
Eingangsbuchung auf Konten
Vollkonto methodsFor: 'buchen'
auszahlung: einBetrag mitText: einString undValutaDatum: einDatum "Ausgangsbuchung."
I neuSaldo I
einBetrag isNegative ifTrue: [self error: 'Negativer Buchungsbetrag!']. ((neuSaldo := self buchSaldo - einBetrag) < self rahmen negated) ifTrue: [self error: 'RahmenOberziehung!']. self buchSaldo: neuSaldo. self vermerkeUmsatz: (Kontoumsatz newBetrag: einBetrag negated buchungsText: einString valutaDatum: einDatum)
Programm 9-8
Ausgangsbuchung aufVollkonten
9.2 Eine Hierarchie von Kontoklassen
289
9.2.4 Einige konkrete Kontoklassen Folgende Zusammenstellung gibt einen Uberblick iiber eine mogliche Hierarchie von Kontoklassen. Object ()
Konto ('nr' 'buchSaldo' 'inhaber' 'umsatze' 'bezeichnung' 'kommentar') Sparkonto () Jugendsparkonto () Kreditkonto Vollkonto ('rahmen') Sonderkonto ('zinsSatzHaben' 'zinsSatzSoll') Girokonto ()
Die Klassen Sparkonto und Jugendsparkonto sind konkrete Klassen, deren Auspragungen Konten sind, die fUr bestimmte Sparprogramme vorgesehen sein konnen. Beispielsweise konnte es der Zinspolitik einer Bank entsprechen, die Verzinsung von Guthaben auf Jugendsparkonten wie bei allen Standardkonten von der Bankrate abhlingig zu machen, allerdings den Zinssatz nicht unter die Inflationsrate fallen zu lassen. Dieser Vorgangsweise entspricht die in Programm 9-9 gezeigte Methode. Jugendsparkonto class methodsFor: 'initialize'
initialize
"Vorgabe von Standardkonditionen der Kontoklasse." self zinsDekrement: (1/5); zinslnkrement: (4/5) Jugendsparkonto methodsFor: 'zinsberechnung'
zinsSatzHaben
"Bestimmen des aktuellen Habenzinssatzes." A
(super zinsSatzHaben) max: inflationsrate
(1)
(1) Die Methode Magnitude max: aMagnitude Iiefert als Ergebnis den Empfanger oder das Argument, je nachdem welches groBer ist.
Programm 9-9
Die Konditionen fUr Jugendsparkonten
Fiir Sonderkonten sind die Instanzvariablen zinsSatzhaben und zinsSatzSoli deklariert, sodaB jedem Sonderkonto individuelle Zinssatze zugeordnet werden konnen. In diesem Fall miissen die geerbten Methoden fUr die
290
9 Pallstudie: Konten
Bestimmung der Zinssatze (Programm 9-5) durch Zugriffsmethoden auf die Instanzvariablen (Programm 9-10) redefmiert werden. Sonderkonto methodsFor: 'zinsberechnung' zinsSatzHaben "Bestimmen des aktuellen Habenzinssatzes." 1\
zinsSatzHaben
Programm 9-10 Zinssatzbestimmung durch Zugriff auf die Instanzvariable In der oben als Beispiel angeflihrten Hierarchie von Kontoklassen wird davon ausgegangen, daB Sparkonten nur generelle, flir die jeweilige Klasse spezifische Zinskonditionen aufweisen. Ware jedoch verlangt, Sparkonten mit individuellen Zinssatzen anlegen zu konnen, so muBte eine Klasse Sondersparkonto als Unterklasse von Sparkonto eingerichtet werden, welche ihre Oberklasse auf die gleiche Weise spezialisiert wie die Klasse Sonderkonto. Das wurde bedeuten, daB samtliche der Klasse Sonderkonto zugeordneten Methoden kopiert und auch in der Klasse Sondersparkonto einzurichten waren. Die Tatsache, daB gleiche Instanzvariable und gleiche Methoden in verschiedenen Klassen deklariert werden, kann auf einen Entwurfsehler hindeuten, der durch Herausheben der gemeinsamen Eigenschaften in eine gemeinsame Oberklasse zu behen ware, eine Vorgangsweise, die als Faktorisierung bezeichnet wird. 1m vorliegenden Pall istjedoch die Einrichtung einer gemeinsamen Oberklasse nicht moglich, wenn die bisherige Unterscheidung zwischen Konten und Vollkonten beibehalten werden solI. Dies ist eine Polge davon, daB in Smalltalk nur Ein/achvererbung vorgesehen ist.
9.2.5 Beispiele fur den Einsatz yon Konten Die Punktionalitat von Kontoklassen wird an Hand einiger in einem Arbeitsbereich durchgeflihrter Beispiele demonstriert. Fur die in der Polge gezeigten Aktionen mit Konten sei vorausgesetzt, daB der Variablenpool Wirtschaftsdaten in der in Programm 9-11 gezeigten Porm vorliegt. Dieser Variablenpool muB bereits vor der Defmtion der teilnehmenden Klassen angelegt worden sein. AuBerdem wird vorausgesetzt, daB aIle Kontoklassen ordnungsgemaB initialisiert wurden, was durch Ausflihren des Ausdruckes Konto initializeAIiClasses (Programm 9-1) erreicht werden kann.
9.2 Eine Hierarchie von Kontoklassen
291
Workspace
"Erzeugen des Variablenpools Wirtschaftsdaten." Smalltalk at: #Wirtschaftsdaten put: PoolDictionary new. Wirtschaftsdaten at: #inflationsrate put:(19/10). Wirtschaftsdaten at: #bankrate put: (11/2) <dolf> "Initialisieren der Kontoklassen" Konto initializeAIiClasses <dolt>
Programm 9-11 Der Variablenpool Wirtschaftsdaten
Workspace
"(1) Erzeugen von Konten."
I gk jspk I
gk := Girokonto newMitNummer: 1. <printlt> Girokonto (Nummer: 1 Saldo: ATS 0.00 Inhaber: nil) jspk := Jugendsparkonto newMitNummer: 2. <printlf> Jugendsparkonto (Nummer: 2 Saldo: ATS 0.00 Inhaber: nil) sk := (Sonderkonto newMitNummer: 3) zinsSatzHaben: 6. <dolt>
"(2) Oberpriifen der Zinskonditionen." gk zinsSatzHaben. jspk zinsSatzHaben. sk zinsSatzHaben
<printlt> (37110) <printlt> (53110) <printlt> 6
(1)
gk zinsSatzSoli. jspk zinsSatzSoli
<printlt> 8 <printlt> (63110)
(2)
(1) Der Habenzinssatz ergibt sich zu (1112)-(9/5) = 37/10 bei Girokonten und zu(11I2) - (115) = 53/10 bei Jugendsparkonten, fUr das Sonderkonto wurde er individuell mit 6 Prozent festgelegt. (2) Den Sollzinssatz erMIt man durch (1112)+(25/10) = (80110) = 8 bei Girokonten und (1112)+(415) = 63/10 bei Jugendsparkonten. Auspriigungen der Klasse Fraction werden stets gekiirzt.
Programm 9-12 Anlegen von Konten und Oberpriifen ihrer Konditionen
292
9 Fallstudie: Konten
Durch die in Programm 9-12 unter Punkt (1) angeftihrten Aktionen wird zuerst je ein Girokonto, ein Jugendsparkonto und ein Sonderkonto angelegt. Durch die unter Punkt (2) zusammengefaBten Uberpriifungen der Zinssatze ist zu erkennen, daB die Konditionen entsprechend den Vorgaben in den jeweiligen Klassen unterschiedlich sind. 1m FaIle des Sonderkontos wurde der Zinssatz individuell unmittelbar nach der Erzeugung des Kontos festgelegt. Programm 9-13 zeigt eine Fortsetzung des Beispieles. Unter Punkt (3) erfolgt auf dem Girokonto eine Einzahlung von ATS 100,-- und eine Auszahlung von ATS 200,--. Nach dies en Kontobewegungen weist das Konto einen Negativsaldo von ATS 100,-- auf. Die Kontoiiberziehung ist moglich, weil dem Girokonto bei der Initialisierung (Programm 9-4) als Uberziehungsrahmen der Normalrahmen der Klasse (das ist gemaB Programm 9-2 ein Betrag von Schilling 10.000,-- ) zugeordnet wurde. SchlieBlich werden unter Punkt (4) der Uberziehungsrahmen des Girokontos und die bisher auf diesem Konto getatigten Umsatze festgestellt. Punkt (5) zeigt, daB der Versuch fehlschlagt, von diesem Konto 10.000,-Schilling abzuheben, weil damit der eingeraumte Uberziehungrahmen iiberschritten wird. Eine letzte Uberpriifung des Kontostandes ergibt, daB die Abbuchung nicht durchgeftihrt wurde und der Buchsaldo unverandert einen Betrag von 100 Schilling im Minus aufweist. Workspace "Fortsetzung von Programm 9-12." "(3) Kontobewegungen auf dem Girokonto." gk einzahlung: (100 asMoney) mitText: " undValutaDatum: (Date today). gk auszahlung: (200 asMoney) mitText:" undValutaDatum: (Date today).
<dolt> gk <printlt>
Girokonto (Nummer: 1 Saldo: ATS 100.00 CR Inhaber: nil) "(4) Oberprilfen des Oberziehungsrahmens und der Kontoumsatze."
<printlt> ATS 10000.00 gk umsatze <printlt> OrderedColiection gk rahmen
(Kontoumsatz: ATS 100.00 Kontoumsatz: ATS 200.00 CR)
"(5) Abbuchung von ATS 10.000,- von dem Girokonto." gk auszahlung: (10000 asMoney) mitText:" undValutaDatum: (Date today).
<dolt>
Rahmeniiberziehung
gk buchSaldo <printlt> ATS 100.00 CR
Programm 9-13 Kontobewegungen
10 Fallstudie: Banken
In frtiheren Abschnitten wurde bereits gezeigt, wie die Klassenhierarchie von Smalltalk durch Klassen erganzt werden kann, deren Auspragungen allgemein verwendbare Geschaftsobjekte sind, die als Bausteine in verschiedenen Anwendungsgebieten eingesetzt werden konnen. Ein Beispiel dafUr ist die Klasse Money, welche vorerst nicht fUr eine bestimmte Anwendung entworfen wurde, sondern als allgemeine Geschaftsklasse fur kommerzielle Anwendungsgebiete gedacht ist. Die Klasse Konto mit allen ihren Unterklassen wurde zwar in Hinblick auf eine Anwendung im Bereich von Banken entworfen, sie kann aber ebenfalls fUr viele Einsatzgebiete nutzlich sein, bei denen Buchhaltungsaktionen notwendig sind. In diesem Kapitelliegt der Schwerpunkt auf der Entwicklung einer einfachen Anwendung, in der auf bereits vorliegenden Geschliftsklassen zurtickgegriffen wird. Diese Anwendung befaBt sicb mit einer sehr vereinfachten Form des Betriebes einer Bank. Nach einer informellen Analyse des in Betracbt gezogenen Bankbetriebes erfolgt der Entwurf eines Modells, das die Objektstruktur der Anwendung zeigt. Wegen der Einfachheit des Beispieles erscheint es ausreichend, ein Objektmodell festzulegen und auf eine modellhafte Darstellung der Dynamik der Anwendung zu verzicbten. Auf Grund dieses Entwurfes werden sodann die zusatzlicben Gescbliftsklassen festgelegt und die notwendigen Methoden zugeordnet. Fur jede Klasse werden vorerst grundlegende Methoden festgelegt, darunter sollen einerseits Konstruktormethoden verstanden werden, die fUr die Erzeugung initialisierter Auspragungen zustandig sind und andererseits Methoden fUr den Zugriff auf die Instanzvariablen und Methode fUr die Druckdarstellung in einem Arbeitsbereich. Die durch solche Methoden erzeugten und bearbeiteten Objekte werden nicht die yom Modell der Anwendung geforderten Integritatsbedingungen erfullen, so daB sie nur den Charakter von privaten Hilfsmethoden fUr die eigentlichen Geschaftsmethoden baben. Solche grundlegende Methoden konnen bereits zu Testzwecken ver-
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
294
10 Fallstudie: Banken
wendet werden, sie decken jedoch nicht aile Aktionen ab, die zu einem vollstandigen GeschiiftsfaIl gehOren. Die fUr die DurchfUhrung der Geschliftsfalle vorgesehen Methoden, welche die vorgegebenen Integritatsbedingungen einhaIten, werden als solche in den Methodenkommentaren gekennzeichnet. Die Durchfiihrung von Geschaftsaktionen werden als Anwendungsfall (use case) [23] bezeichnet, sie werden in einem Arbeitsbereich demonstriert. Wie bei den anderen Beispielen wird auch hier angenommen, daB die fUr den Anwendungsbereich wesentlichen Objekte, ihre Funktionalitat und ihre Kollaboration bekannt sind, so daB sofort die Realisierung in Small talk betrachtet werden kann. Diese hier bereits als bekannt vorausgesetzte Informationen konnen durch Analyse- und Designtechniken gewonnen werden. Bekannte Techniken beruhen auf der Extraktion von Konzepten aus Anforderungsbeschreibungen zum Auffinden von Objekten, auf der Festlegung von Verpflichtungen und Kollaborationen zur Organisation von Objekten (ClassResponsibilities-Collaborators (CRC) [5], Responsibility Driven Design (ROD) [45], [46]) und auf der Beschreibung von Szenarien zum Charakterisieren von anwendungsspezifischem Verhalten (Object Behavior Analysis (OBA) [32], Objectory [23]). Ein Beispiel fUr eine Entwicklungmethode, die aile Phasen des Software-Entwicklungszyklus abdeckt, ist Object Modeling Technique (OMT) [33].
10.1
Die Realitiit des Bankbetriebes
Banken bieten ihren Kunden Produkte und Dienstleistungen an. Es ist daher naheliegend, Kunden und Produkte aIs zentrale Entitaten des Geschiiftsbereiches einer Bank zu betrachten. Produkte einer Bank sind unter anderen Kredite, Darlehen, Sparvertrage oder Kapitalmarktdienste. Konten sind einerseits eine Voraussetzung fUr die Abwicklung solcher Geschafte, andererseits ist die Fiihrung verschiedener Arten von Konten und die DurchfUhrung des Zahlungsverkehrs selbst ein wesentliches Bankprodukt. In dieser Fallstudie werden als Produkte nur Konten und der iiber diese abgewickelte Zahlungsverkehr betrachtet. Die Kunden einer Bank sind ebenfalls von unterschiedlicher Art. Kunden konnen einzelne Personen ebenso sein wie Firmen mit verschiedener Rechtsform, Vereine, Korperschaften offentlichen Rechtes, internationale Institutionen oder auch Banken selbst. Vorliiufig werdender Einfachheit wegen als Kunden nur physische Personen betrachtet, an einer spateren Stelle (siehe Abschnitt 14.3.2) wird jedoch eine Ausweitung des Kundenbegriffes vorgenommen und die damit zusammenhangenden Modellierungsmoglichkeiten diskutiert.
10.2 Strukturmodell eines Bankbetriebes
295
Der Geschiiftsbetrieb eines Bankinstitutes so11 aus einer stark "kundenorientierten" Sieht betrachtet werden. Banken benotigen fUr die Beratung ihrer Kunden und fUr das Anbieten weiterer Produkte explizite Kenntnisse tiber bereits bestehende Geschliftsbeziehungen mit ihren Kunden. Es gentigt daher nicht, daB jedes verkaufte Produkt, etwa jedes Konto, 1egitimiert ist in dem Sinne, daB bekannt ist, wem es gehort, vie1mehr ist es fUr die Bank auch wesentlich zu wissen, welche Produkte ein Kunde jeweils besitzt. Es wird vereinfachend angenommen, daB jedes Produkt (Konto) genau einem Kunden zugeordnet ist. Aile Kunden werden innerhalb der Bank durch eine eindeutige Kundennummer identifiziert und unter dieser im Kundenregister eingetragen. Auch potentielle Kunden, die noch kein Produkt der Bank besitzen, konnen in diesem Register eingetragen sein. Ebenso werden Konten innerhalb der Bank durch eine eindeutige Kontonummer identiflZiert und unter dieser in einem Kontenregister verwaltet. Konten konnen jedoch nicht als vorgefertigte Produkte im Kontenregister eingetragen sein, sie werden erst angelegt, wenn sie einem Kunden zugeordnet werden konnen. In dem betrachteten Bankbetrieb muB also der Kunde bereits existieren und identiflZiert sein, wenn ein neues Konto angelegt wird.
10.2 Strukturmodell eines Bankbetriebes Abbildung 10-1 zeigt ein Strukturmodell, das der beschriebenen RealiHit des Bankbetriebes entspricht und die Grundlage fUr die Realisierung der Applikation bildet. 1m Zentrum der Betrachtung stehen die Klassen Bank, Bankkunde und Konto. Die Multiplizitatsangaben der Zuordnung von Kunden zu einer Bank sagt aus, daB eine Bank belie big viele Kunden haben kann. Ein Kunde muB genau dieser Bank zugeordnet, also in ihrem Kundenregister vermerkt sein. Die Bank kann ihre Kunden durch Navigation im Objektraum direkt ansprechen, einem Kunden ist es nicht moglich, auf direktem Wege das Bankobjekt zu erreichen. Ahnliches gilt fUr die Zuordnung der Konten zur Bank. Eine Bank kann beliebig viele Konten eroffnen, jedes Konto gehOrt zu genau einer Bank. Die Bank kennt ihre Konten und kann auf diese durch Navigation direkt zugreifen, eine Navigation in umgekehrte Richtung ist nicht moglich. Die Eigenschaft daB jedes Konto und jeder Kunde genau zu einer Bank gehort, ist somit keine Eigenschaft des Kontos oder Kunden selbst, sondem eine Charakteristikum des Bankmodelles.
296
10 Fallstudie: Banken
Konto
nr Bank
llJz
name adresse
inhaber
O.. n
konten O•. n
-+
kunden
-+
,--o_..n......l._k_on_t..,en (OrdColI) Bankkunde -
nr
name adresse
Modellj
Abbildung 10-1 Strukturmodell fur den Bankbetrieb
Die gegenseitige Beziehung zwischen einem Konto und einem Bankkunden entspricht einer gekoppelten Zuordnung: wenn ein Bankkunde ein Konto besitzt, dann muB es genau diesen Kunden als Inhaber vermerkt haben. Durch die M ultiplizitiitsangaben wird festgelegt, daB ein Kunde (bei dieser Bank) beliebig viele Konten besitzen kann, jedes Konto jedoch genau einen Inhaber haben muB. Dabei ist die im Bankwesen iibliche Moglichkeit, daB ein Konto mehreren Inhabem zugeordnet sein kann, der Einfachheit wegen nicht in das Modell aufgenommen worden. Durch die Multiplizitiitsforderungen der Beziehungen wird die anfangs erwiihnte "kundenorientierte" Sicht unterstiitzt. Da ein Konto einen Kunden als Inhaber zugeordnet haben muB, also nicht ohne einen Inhaber im Objektraum existieren darf, muB der Kunde bereits existieren, urn unmittelbar nach der Erzeugung eines Kontoobjektes im Rahmen der Initialisierung diesem zugeordnet werden zu konnen. Der Bankkunde selbst darf nicht ohne Eintragung in das Kundenverzeichnis der Bank existieren. Der Geschiiftsfall "ErotTnen eines Kontos", genauer "ErotTnen eines Kontos fUr eine Person" kann also nur so ablaufen, daB zuerst sichergestellt wird, daB die in Frage kommende Person als Kunde registriert ist, notigenfalls ist sie als neuer Kunde aufzunehmen. Erst dann ist es moglich, ein neues Konto anzulegen.
10.3 Bankkunden
297
10.3 Bankkunden Wie aus der bisherigen Beschreibung hervorgeht, stehen die Begriffe »Kunde" und "Produkt" im Zentrum der konzeptionellen Sicht eines Bankbetriebes. Fur Konten, die stellvertretend fUr beliebige Bankprodukte stehen, wurden bereits Klassen entworfen, fUr Kunden soll das in einfacher Form nachgeholt werden. In der Foige werden die Defmition der Klasse Bankkunde und die wichtigsten grundlegenden Methoden angefuhrt. Die Klasse Bankkunde wird als Subklasse von Person eingerichtet, wie dies in Programm 10-1 gezeigt ist. Bei der Initialisierung eines Kunden wird der Instanzvariablen konten ein leerer Behlilter der Klasse OrderedCollection zugewiesen, in welchen die Konten eines Kunden der Reihe nach eingetragen werden konnen.
Object subclass: #Person instanceVariableNames: 'name adresse ' classVariableNames: " poolDictionaries: "category: 'Kunden'
(1)
Person subclass: #Bankkunde instanceVariableNames: 'nr konten ' classVariableNames: " poolDictionaries: " category: 'Banken' Bankkunde methodsFor: 'initialize' initialize "Initialisieren eines Bankkunden. Modell: Vorbereitung der Zuordnung Bankkunde (O..n) -> Konten."
super initialize. konten := OrderedColiection new (1) Fur das Weitere wird vorausgesetzt, daB die entsprechenden Zugriffsmethoden impiementiert sind.
Programm 10-1 Defmition und Initiaiisierung von Bankkunden
Die Zuordnung eines vorzugebenden Kontos zu einem Kunden, also die Aufnahme des Kontos in dessen Kontenbestand, wird durch die Methode Bankkunde»addKonto: (Programm 10-2) veranlaBt.
298
10 Fallstudie: Banken
Bankkunde methodsFor: 'private' addKonto: einKonto
"Aufnehmen eines Kontos (einKonto) in die Kontensammlung eines Kunden. Modell: 8ankkunde O..n -> Konten." self konten add: einKonto
Programm 10-2 Zuordnung eines Kontos zu einem Kunden
Programm 10-3 zeigt die Erzeugung einer Druckausgabe von Bankkunden, die fUr das Testen in einem Arbeitsbereich benotigt wird. Person methodsFor: 'printing' printOn: aStream
"Charakterisieren des Empflingers durch eine Zeichenkette." aStream nextPutAlI: self class name, ' " self name printString Bankkunde methodsFor: 'printing' printOn: aStream super printOn: aStream. aStream nextPutAlI: ' (Knr. " self kundenNummer printString, ')'
Programm 10-3 "Druckausgabe" von Personen und Bankkunden Programm 10-4 enthaIt eine Familie von Erzeugungsmethoden fUr Personen, die es erlauben, Person en und Bankkunden mit oder ohne Namen zu generieren. Mit Hilfe dieser Methoden konnen bereits Bankkunden erzeugt und ausgegeben werden, etwa durch: Bankkunde new
<print/t> Bankkunde 'keinName' (Knr. nil)
Bankkunde newMitNamen: 'Maier Franz' <printlt> Bankkunde 'Maier Franz' (Knr. nil)
Ebenso ist es moglich, durch einen Ausdruck der Art: (Bankkunde newMitNamen: 'Maier Franz') konten <printlt> OrderedColiection ()
auf die noch leere Sammlung der Konten eines Bankkunden zuzugreifen.
lOA Banken
299
Person class methodsFor: 'instance creation'
new
"Erzeugen und Initialisieren einer Person." "super new initialize
newMitNamen: einName "self new name: einName
newMitNamen: einName undAdresse: eineAdresse "(self newMitNamen: einName) adresse: eineAdresse
Programm 10-4 Instanzierungsmethoden der Klasse Person
Aus der in Programm 10-3 gezeigten Methode Bankkunde»printOn: geht auch hervor, daB eine Methode Bankkunde»kundenNummer vorausgesetzt wird, welche die dem Bankkunden zugeordnete Kundennummer liefert. Die Zuordnung einer Kundennummer kann allerdings erst im Zusammenhang mit dem Einrichten eines Kunden im Rahmen des Bankbetriebes erfolgen. Aus diesem Grunde wurde auch die Initialisierung der Instanzvariablen kunde in der Methode Bankkunde»initialize nicht vorgenommen, was auch aus den T estergebnissen zu ersehen ist.
10.4 Banken 10.4.1 Das Strukturmodell einer Bank Eine Bank solI durch eine Bankleitzahl (biz) identifIziert werden konnen, sie besitzt auBerdem einen Namen und eine Adresse. In einer Erweiterung der Fallstudie auf die Kommunikation zwischen verschiedenen Banken wird verlangt, daB jede Bank in einem »zentralen Bankenservice" registriert sein muG, von welchem auch die Bankleitzahlen vergeben werden. Aus diesem Grunde ist bereits in dem in Abbildung 10-1 gezeigten Modell angegeben, daB die Klasse Bank als Subklasse von RegistrierteBank positioniert wird, deren Definition und Eigenschaften erst spater festgelegt werden. Fur die Betrachtung des internen Betriebes einer Bank genugt es vorerst anzunehmen, daB jede Bank tiber eine entsprechende ZugrifTsmethode ihre Bank-
300
10 Fallstudie: Banken
leitzahl, ihren N amen und ihre Adresse feststellen kann. Die Bedeutung der im Modell ebenfalls angefuhrte Klasse BankRegistrierung wird erst in einem anderen Zusammenhang erlliutert. Bereits beim Entwurf von Konten wurde festgestellt, daB es Aufgabe der kontoftihrenden Institution ist, ftir die eindeutige Vergabe von Kontonummern Sorge zu tragen. Es gehort daher zu den Aufgaben einer Bank, die von ihr eroiTneten Konten mit einer Kontonummer zu versehen. Zur Durchfiihrung dieser Aufgabe wird einer Bank ein Zlihlwerk fiir Kontonummern (eine Ausprligung der bereits frtiher erwlihnten Klasse Zahlwerk) zugeordnet, welches bei der Errichtung der Bank initialisiert wird und welches bei jeder KontoeroiTnung die nlichste freie Kontonummer liefert. Der Einfachheit hatber wird dabei vorausgesetzt, daB die Bank ihre Konten von eins beginnend der Reihe nach durchnumeriert. Eine analoge Vorgangsweise wird fur die Vergabe der Kundennummern gewlihlt.
Bank Registrierung biz name adresse
Uhlwerk register Uhlwerk register
y
Registrierte Bank
+--1 registrierung
+--
Dictionary
1, M!
Bank
1, M! --. 1
ktoUhler
konten
+--
1, M! --. 1
1, M!
kndUhler
kunden
Dictionary
Modell 11--_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _---'
Abbildung 10-2 Strukturmodell einer Bank
Aus dem Strukturmodell ist auch zu erkennen, daB die Mehrfachbeziehungen der Bank zu den Kunden und zu den Konten durch Verzeichnisse realisiert werden. In den Verzeichnissen werden die Kunden beziehungsweise Konten unter ihrer Nummer eingetragen. Die Beziehungen einer Bank zu den Verzeichnissen fur die Kunden und Konten und auch zu den Zlihlwerken sind als immutabel gekennzeichnet.
10.4 Banken
301
10.4.2 Grundlegende Methoden einer Bank Programm 10-5 zeigt die Definition der Klasse Bank und ihre Initialisierung. Man erkennt, daB fUr die Klasse Bank zwei Klasseninstanzvariable vereinbart sind. Die Variable bankenService wird bei der spater gezeigten Einfuhrung eines zentralen "Bankenservice" dazu dienen, dieses zu referenzieren. Die Klasseninstanzvariable testBank erhalt bei der Initialisierung der Klasse eine Auspragungen der Klasse (also eine Bank), zugewiesen, die dadurch permanent gehalten wird und fUr Testzwecke zur Verfugung steht. Dadurch ist es moglich, Geschaftsaktionen in einem Arbeitsbereich auszufUhren, ohne ein Bankobjekt jeweils neu erzeugen oder uber eine globale Variable festhalten zu mussen. Die hier angegebene Initialisierungsmethode wird an spaterer Stelle bei der eben erwahnten Erweiterung abgeandert, diese vorlaufige Form solI es ermoglichen, bereits jetzt einige Tests durchzufuhren. Object subclass: #RegistrierteBank instanceVariableNames: 'registrierung , classVariableNames: " poolDictionaries: 'Wirtschaftsdaten' category: 'Banken' RegistrierteBank subclass: #Bank instanceVariableNames: 'konten ktoUhler kunden kndUhler ' classVariableNames: " poolDictionaries: " category: 'Banken' Bank class instanceVariableNames: 'bankenService testBank ' Bank class methodsFor: 'initialize'
initializeNoReg "Initialisieren der Klasse: Erzeugen einer nicht registrierten Testbank."
I noreg I
noreg := BankRegistrierung new name: 'Testbank ohne Registrierung'; adresse: 'Testadresse'; leitzahl: 9999. testBank := self new registrierung: noreg; initialize
Programm 10-5 Defmition und vorlaufige Initialisierung der Klasse Bank Programm 10-6 enthalt die Methoden zur Initialisierung eines neu erzeugten Bankobjektes. Die auch fUr das Anlegen der Testbank bereits verwendete
302
10 Fallstudie: Banken
Methode Bank»initiaJize delegiert ihre Aufgaben an Methoden der Art Bank»initialisiereKunden und Bank»starteKundennummern, die sowohl fUr die Kunden als auch fUr die Konten jeweils ein Verzeichnis und ein Zlihlwerk fUr die Generierung der Nummern anlegen. Diese Methoden werden ausschlieBlich bei der Initialisierung einer Bank angewendet und in keiner Geschliftsmethode direkt oder indirekt aktiviert, wodurch der Forderung nach Immutabilitat dieser Beziehungen entsprochen wird.
Bank methodsFor: 'initialize' initialize "Initialisieren einer Bank."
self starteKundennummern; initialisiereKunden starteKontonummern; initialisiereKonten initialisiereKunden "Modell: Vorbereitung der Zuordnung Bank (O..n) ->Bankkunde."
kunden := Dictionary new starteKundennummem "Initialisieren des Kundennummernkreises."
kndZahler := Zahlwerk new Programm 10-6 Initialisierung einer Bank
Bank methodsFor: 'printing' printOn: aStream "Erzeugen einer Zeichenkette zur Charakterisierung einer Bank."
aStream nextPutAlI: self class name, '(" self leitzahl printString, ') " self name Programm 10-7 "Druckdarstellung" einer Bank fUr Testzwecke Ein erster Test fUr die erwahnten Methoden ist in Programm 10-8 vorgenommen. Die dort erhaltene Druckausgabe fUr eine Bank (die Testbank) wurde durch die in Programm 10-7 angegebene Methode erzeugt. Man erkennt aus der Evaluation der in Programm 10-8 gezeigten Ausdriicke, daB durch Bank testBank eine Bank angesprochen werden kann, der
303
lOA Banken
die Bankleitzahl 9999 zugeordnet ist. Diese Bank besitzt vorUiufig ein leeres Kontenregister und ein leeres Kundenregister. Workspace "Initialisieren der Klasse Bank durch die VORLAUFIGE Methode initializeNoReg." Bank initializeNoReg.
"Oberpriifen der erzeugten Testbank."
<printn> Bank(9999) Testbank ohne Registrierung Bank testBank konten <printlt> Dictionary 0 Bank testBank kunden <printlt> Dictionary 0 Bank testBank
Programm 10-8 Erzeugen einer "Testbank"
10.4.3 Geschiiftsfall: Anlegen eines Kunden Auspragungen der Klasse Bankkunde mussen nach den Vorgaben des Modelles einer Bank zugeordnet sein, sie durfen daher nicht im Objektraum existieren, ohne daB sie mit einer Kundennummer versehen und im Kundenverzeichnis einer Bank eingetragen sind. Zusatzlich sei zu den Vorgaben des in Abbildung 10-1 gezeigten Modells angenommen, daB Kunden unbedingt einen Namen und einer Adresse haben mussen, da anonyme Kunden von Banken nicht geftihrt werden soDen. Bankkunde class methodsFor: 'Bankapplikation: instance creation'
newBeiBank: eineBank mitNamen: einName undAdresse: eineAdresse "Geschiiftsmethode: Erzeugen eines neuen Kunden bei der vorgegebenen Bank."
I kunde I kunde := self newMitNamen: einName undAdresse: eineAdresse. eineBank registriereKunde: kunde. (1) "kunde (1) Durch die Methode Bank»registriereKunde: wird gemiiB den Modellvoraussetzungen die Beziehung: Bank (O .. n) <--> (1) Bankkunde hergestellt (siehe Programm 10-10).
Programm 10-9 Erzeugung eines Bankkunden in der Bankapplikation
304
10 Fallstudie: Banken
Aus diesen Grunden kann als Applikationsmethode fUr die Erzeugung eines neuen Kundenobjektes nur eine Methode vorgesehen werden, welche diese Bedingungen erfdllt, was fUr die in Programm 10-9 angefUhrte Methode Bankkunde class »newBeiBank:mitNamen:undAdresse: zutrifft. Diese Methode greift auf eine Instanzierungsmethode der Klasse Bankkunde zUrUck, entllH3t das Kundenobjekt jedoch nicht, bevor es eine Kundennummer zugeordnet hat und in das Kundenregister einer Bank eingetragen ist.
Bank methodsFor: 'Kundenverwaltung' registriereKunde: einKunde
"Registrieren eines Kunden: Erteilen einer Kundennummer und Eintragen des Kunden in das Kundenregister."
I knr I
knr := self neueKundennummer. '(self kunden at: knr put: (einKunde kundenNummer: knr))
(1)
neueKundennummer
"Anfordern einer neuen Kundennummer." 1\
kndZahler zahle liesZahlerstand
(2)
(1) Zuordnung der Kundennummer und Eintragung des Kunden in das Kunden-
verzeichnis. (2) Die hier angewendeten Methoden wurden im Zusammenhang mit Zahlwerken erlautert.
Programm 10-10 Herstellung der Beziehung zwischen Bank und Kunden
Bank methodsFor: 'Kundenverwaltung' kundeMitNummer: eineNummer
"Geschiiftsmethode: Nennen des Kunden mit der Nummer eineNummer." 1\
self kunden at: eineNummer ifAbsent: [self error: 'Kunde mit Nummer " eineNummer printString, ' existiert nichtl']
Programm 10-11 Zugriff auf einen Kunden uber die Kundennummer
lOA Banken
305
Die Einrichtung der Beziehung zwischen einer Bank und einem Kunden erfolgt durch die in Programm 10-10 vorgestellte Methode Bank»registriereKunde: . In dieser Methode wird zuerst eine neue Kundennummer angefordert, diese dem Kundenobjekt zugeordnet und der nunmehr mit einer Kundennummer versehene Kunde unter dieser Nummer in das Kundenverzeichnis der Bank eingetragen. Der ZugritT auf einen Kunden erfolgt tiber dessen Kundennummer, er wird durch die Methode Bank»kundeMitNummer: eineNummer (Programm 10-11) erm6glicht. Workspace
"Geschiiftsfall: Die Testbank erhalt zwei Kunden." "(1) Zuordnen der ersten zwei Kunden." Bankkunde newBeiBank: (Bank testBank) mitNamen: 'Maier Franz' undAdresse: 'Wien 1., Dr. Karl Lueger-Ring 1'; newBeiBank: (Bank testBank) mitNamen: 'Oberhuber Alois' undAdresse: 'St. POlten, Hauptplatz 37'.
<dolt>
(2) Ausgabe des Kundenverzeichnisses der Testbank." Bank testBank kunden <print't> Dictionary ( 1->Bankkunde 'Maier Franz' (Knr. 1) 2->Bankkunde 'Oberhuber Alois' (Knr. 2) )
"(3) Feststellen des unter der Kundennummer 1 eingetragenen Bankkunden." Bank testBank kundeMitNummer: 1 <print't> Bankkunde 'Maier Franz' (Knr. 1)
"(4) Feststellen der Konten des Kunden mit der Kundennummer 1." (Bank testBank kundeMitNummer: 1) konten OrderedColiection ()
<printlt>
Programm 10-12 Geschiiftsfall: Aufnahme neuer Kunden Programm 10-12 zeigt die Durchfiihrung eines Geschiiftsfalles in einem Arbeitsbereich. Die unter Punkt (1) durchgefdhrten Methoden veranlassen die Aufnahme der ersten zwei Kunden der Testbank. Punkt (2) zeigt das Lesen des Kundenverzeichnisses, in dem nunmehr die neuen Kunden unter den Kundennummern 1 und 2 abgelegt sind. Der Zugriff auf einen Kunden, dessen Kundenummer bekannt ist, wird unter Punkt (3) gezeigt, der Zugriff auf
306
10 Fallstudie: Banken
des sen Kontenbestand geht aus Punkt (4) hervor, das Ergebnis ist ein leerer Kontenbestand. Urn feststellen zu konnen, ob ein Person bereits Kunde der Bank ist, werden Methoden benotigt, die das Kundenverzeichnis nach verschiedenen Kriterien durchsuchen. Ais Beispiel sind in Programm 10-13 zwei Methoden gezeigt, welche das Kundenregister nach Kunden mit einem vorgegebenen Namen durchsuchen und als Ergebnis die in einem BehiHter gesammelten Kunden oder Kundennummem liefem. Bank methodsFor: 'kunden-zugriff'
kundenMitNamen: einName "Suchen aller Kunden mit einem vorgegebenen Namen." 1\
(self kunden select: [:kunde I kunde name = einName)) values
kundenNummernMitNamen: einName "Suchen aile Nummern von Kunden mit einem vorgegebenen Namen." 1\
(self kundenMitNamen: einName) collect: [:kunde I kunde kundenNummer]
Programm 10-13 Suchen aller Kunden mit vorgegebenem Namen 1m folgenden Abschnitt wird die Integration von Konten in die Bankapplikation beschrieben.
10.4.4 Registrieren und Zuordnen von Konten Die Modellvorgaben verlangen, daB ein Konto genau einen Bankkunden als Inhaber zugeordnet hat und daB dieses Konto auch im Produktverzeichnis seines Inhabers vermerkt ist. Das Konto muB zusatzlich noch im Kontenverzeichnis der Bank registriert sein. Programm 10-14 zeigt eine Methode, welche die gegenseitige, gekoppelte Zuordnung zwischen einem Konto und einem Kunden vomimmt, wobei sie auf die zwei "einseitigen" Zuordnungmethoden Konto»inhaber: einKunde und Bankkunde»addKonto: einKonto zuriickgreift. Die Methode Bankkunde»bekommtKonto: einKonto istjedoch keine Geschaftsmethode, da sie ein beliebiges Kontoobjekt mit einem beliebigen Kundenobjekt verkniipft, ohne auf die Forderung Riicksicht zu nehmen, daB sowohl das Konto als auch der Kunde bei der Bank registriert sein miissen.
lOA Banken
307
Bankkunde methodsFor: 'private'
bekommtKonto: einKonto
"Vermerken, daB (a) das vorgegebene Konto dem Kunden zugeordnet wird und (b) der Inhaber dieses Kontos der Kunde ist Modell: Einrichten der Bez;ehung: Bankkunde (O..n) <-> (1) Konto (siehe Abbildung 10-1)." self addKonto: (einKonto inhaber: self)
Programm 10-14 Einrichten der Zuordnung zwischen Konto und Kunden
Bank methodsFor: 'konten-private'
registriereKonto: einKonto
"Vergabe einer Kontonummer und Eintragen des Kontos in das Kontenregister. Modell: Herstellung der Beziehung Bank (O..n) <-> (1) Konto."
I knr I
knr := self neueKontonummer. (self konten at: knr put: (einKonto kontoNummer: knr))
Bank methodsFor: 'konten-registrierung'
registriereKonto: einKonto fiirKundenMitNummer: eineKundenNummer
"Registrieren eines vorgegebenen Kontos und Herstellen der Beziehung zwischen diesem und dem unter der vorgegebenen Nummer bereits registrierten Kunden. Modell: Einrichten der Beziehung: Bank (O..n) <-> (1) Konto (1) <-> (O..n) Kunde."
I kunde I
kunde := self kundeMitNummer: eineKundenNummer. self registriereKonto: einKonto. kunde bekommtKonto: einKonto
Programm 10-15 Registrierung eines Kontos Die Registrierung eines Kontos wird durch Bank»registrierekonto: einKonto (Programm 10-15) vorgenommen. Diese Methode erwartet als Parameter ein (neues) Kontoobjekt, versieht es mit einer neu angeforderten Kontonummer und auch mit der Bankleitzahl des Empfangers, also jener Bank, bei
308
10 Fallstudie: Banken
der das Konto registriert wird, und trligt das Konto unter der Kontonummer in das Kontenverzeichnis der Bank ein. Die ebenfalls in Programm 10-15 vorgestellte Methode Bank»registriereKonto: einKonto fOrKundeMitNummer: eineKundennummer greift auf die eben erwlihnte Methode zurtick und ftihrt nunmehr slimtliche im Modell verlangten Zuordnungen durch. Da der Kunde, dem das Konto zuzuordnen ist, tiber seine Kundennummer angesprochen wird, ist sichergestellt, daB er bereits im Kundenverzeichnis existiert, da anderenfalls die ZugritTsmethode auf das Kundenverzeichnis (Programm 10-11) einen Fehler signalisieren wtirde. Nicht sichergestellt wird jedoch, daB das Konto noch nicht im Kundenverzeichnis unter einer anderen Nummer verzeichnet ist und bereits einem Kunden gehOrt. Aus diesem Grunde kann diese Methode nur dann sicher angewendet werden, wenn ihr aIs Argument ein unmittelbar vorher erzeugtes, neues Konto tibergeben wird.
10.4.5 Geschaftsfall: Eroffnen von Konten Der Geschliftsfall des ErotTnen eines neuen Kontos fur einen bereits bestehenden (oder unmittelbar vor der KontoerotTnung angelegten neuen) Kunden wird durch die in Programm 10-16 gezeigte Methode abgedeckt. Konto class methodsFor: 'instance creation-application' newBeiBank: eineBank fiirKundenMitNummer: eineNummer
"Geschiiftsmethode: Erzeugen eines neuen Kontos bei der vorgegebenen Bank fUr einen Kunden mit vorgegebener Kundennummer."
I konto I
konto := self new. eineBank registriereKonto: konto fOrKundenMitNummer: eineNummer. I\konto
(1)
(1) Durch die Methode Bank»registriereKonto:fOrKundenMitNummer: werden die Beziehungen Bank (O .. n) <--> (1) Konto (1) <-->(O.. n) Kunde hergestellt
(siehe Programm 10-15).
Programm 10-16 Geschliftsmethode: Anlegen eines Kontos Die Wirkungsweise dieser Methoden wird an Hand eines Anwendungsfalles (Programm 10-17) demonstriert. Nachdem unter Punkt (1) zwei Konten
309
10.4 Banken
fUr den Kunden mit der Kundennummer 1 angelegt wurden, wird unter Punkt (2) das Kontenverzeichnis der Testbank ausgedruckt, es enthiilt genau diese zwei Konten, aus deren Druckdarstellung man auch erkennt, welchem Kunden sie zugeordnet sind. Workspace
"Geschaftsfall: Die Testbank eroffnet ein Girokonto und ein Sparkonto fUr Kunden 1." "(1) Eroffnen der zwei Konten." Girokonto Sparkonto <dolt>
newBeiBank: Bank testBank fOrKundenMitNummer: 1. newBeiBank: Bank testBank fOrKundenMitNummer: 1.
"(2) Feststellen der Konten des Kunden 1." (Bank testBank kundeMitNummer: 1) konten <printlt> OrderedColiection (
Girokonto (Nummer: 1 Saldo: ATS 0.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1)) Sparkonto (Nummer: 2Saldo: ATS 0.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1))) Programm 10-17 Geschaftsfall: Eroffnen von zwei Konten
Workspace
"Geschaftsfall: Die Testbank eroffnet je ein Girokonto fUr die Kunden 2 und 3." "(1) Eroffnen der zwei Konten." Girokonto newBeiBank: Bank testBank fOrKundenMitNummer: 2. Girokonto newBeiBank: Bank testBank fOrKundenMitNummer: 3. <dolt> Kunde mit Nummer 3 existiert nicht
"(2) Feststellen der Konten der Bank." Bank testBank konten
<printlt>
Dictionary ( 1->Girokonto (Nummer: 1 Saldo: ATS 0.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1)) 2->Sparkonto (Nummer: 2 Saldo: ATS 0.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1)) 3->Girokonto (Nummer: 3 Saldo: ATS 0.00 Inhaber: Bankkunde 'Oberhuber Alois' (Knr. 2» )
Programm 10-18 Geschliftsfall: Eroffnen weiterer Konten
310
10 Fallstudie: Banken
Programm 10-18 zeigt weitere Geschliftsfalle. Zuerst wird versucht, je ein Girokonto fur die Kunden mit den Nummem 2 und 3 anzulegen. Da die Kundennummer 3 nicht vorkommt, wird der Versuch, fUr einen nichtexistierenden Kunden ein Konto anzulegen, mit einer Fehlermeldung abgebrochen, welche durch die in Programm 10-11 angefUhrte Methode verursacht wird. Die unter Punkt (2) verlangte Ausgabe des Kontenregisters der Bank zeigt, daB das fUr den nichtexistierenden Kunden gedachte Girokonto nicht angelegt wurde, so daB keine Verletzung der Integritatsbedingung eingetreten ist.
10.4.6 Geschaftsfall: Buchung auf einem Konto 1m Rahmen der Geschaftstatigkeit einer Bank werden Einzahlungen und Auszahlungen von Geldbetragen auf den Konten dieser Bank vorgenommen. Die eigentlichen Buchungsvorgange werden durch Methoden der Klasse Konto beschrieben und wurden dort bereits behandelt. Ftir den Bankbetrieb selbst sind noch Geschliftsmethoden zu formulieren, welche Konten fiber Kontonummem identifizieren und die Buchungsanforderungen an diese Konten weiterleiten. Zu diesem Zweck ist eine Familie von Methoden angelegt und in Programm 10-19 gezeigt. Die erste und allgemeinste dieser Methoden spricht ein Konto tiber seine Kontonummer an, veranlaBt die Einzahlung eines vorzugebenden Geldbetrages und erwartet auch die Angabe eines Buchungstextes und eines Valutadatums. Die zweite Methoden verzichtet auf die Vorgabe eines Valutadatums und setzt daflir den dritten Tag nach dem aktuellen Buchungstag ein, die dritte Methode verzichtet auch auf die Angabe eines Buchungstextes und begntigt sich somit mit den Parametem, die flir die Durchflihrung der Einzahlung unerHiBlich sind. Analoge Methoden flir die Auszahlung von Konten sind ebenfalls einzurichten. Der in Programm 10-20 vorgefuhrte Geschaftsfall wendet diese Methoden an. In einem ersten Schritt werden auf dem Konto mit der Nummer 1 zwei Einzahlungen und eine Auszahlung durchgeflihrt. Der in Punkt (2) untersuchte Zustand des Kontos la13t erkennen, daB der Saldo nunmehr einen Kontostand von ATS 10000.-- ausweist. Unter Punkt (3) wird die Druckausgabe der einzelnen Kontoumsatze angefordert, aus der die einzelnen Kontobewegungen nachvollzogen werden konnen.
lOA Banken
Bank methodsFor: 'konten-buchungen'
311
(1)
kontoMitNummer: knr einzahlung: einBetrag mitText: einString undValutaDatum: einDatum
"Geschiiftsmethode: Buchen eines vorgegebenen Betrages auf ein Konto mit vorgegebener Kontonummer samt Angabe eines Buchungstextes (Zahlungsgrund) und eines Valutadatums." "(self kontoMitNummer: knr) einzahlung: einBetrag mitText: einString undValutaDatum: einDatum
(2)
kontoMitNummer: knr einzahlung: einBetrag mitText: einString
"Geschiiftsmethode: Buchen eines Betrages auf ein Konto mit festgelegtem Valutadatum." "self kontoMitNummer: knr einzahlung: einBetrag mitText: einString undValutaDatum: (Date today addDays: 3)
kontoMitNummer: knr einzahlung: einBetrag
"Geschiiftsmethode: Buchen eines Betrages auf ein Konto mit festgelegtem Text und Valutadatum." "self kontoMitNummer: knr einzahlung: einBetrag mitText: '?' (1) Hier sind nur Einzahlungsmethoden angefiihrt, Auszahlungsmethoden sind analog zu formulieren.
(2) Die Methode Bank»kontoMitNummer: ist analog der Methode Bank»kundeMitNummer: (Programm 10-11) aufgebaut.
Programm 10-19 Eine Familie von Buchungsmethoden
Man beachte, daB an der Druckdarstellung mehrere Methoden beteiligt sind, die aIle den stark iiberladenen Methodennamen printOn: tragen. Beispielsweise wird das unter Punkt (3) erhaltene Ergebnis aus den Ergebnissen der Methoden Money»printOn: (durch Fettdruck hervorgehoben), Kontoumsatz»printOn: und Collection»printOn: zusammengesetzt.
312
10 Fallstudie: Banken
"Geschiiflsfall: Ein- und Auszahlungen auf ein Konto mit Kontonummer 1." ,,(1) DurchfOhrung von zwei Einzahlungen und einer Auszahlung." Bank testBank kontoMitNummer: 1 einzahlung: 1500 asMoney. Bank testBank kontoMitNummer: 1 einzahlung: 9000 asMoney. Bank testBank kontoMitNummer: 1 auszahlung: 500 asMoney.
"(2) Feststellen des Zustandes von Konto 1." Bank testBank kontoMitNummer: 1 <printlt> Girokonto (Nummer: 1 Saldo: ATS 10000.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1»
"(3) Untersuchen der Umsatze von Konto 1." (Bank testBank kontoMitNummer: 1) umsatze <printlt> OrderedColiection ( Kontoumsatz: ATS 1500.00 Kontoumsatz: ATS 9000.00 Kontoumsatz: ATS 500.00 CR )
"(4) Versuch. von einem Sparkonto eine Auszahlung durchzufOhren." Bank testBank kontoMitNummer: 2 auszahlung: 500 asMoney <printlt> Unhandled exception: Message not understood: #auszahlung:mitText:undValutaDatum
(1)
(1) Meldungen dieser Art erlauben es, den Ursprung eines Fehlers zu lokalisieren, in einer fertigen Applikation ist ein Fehlerbehandlung zu realisieren. Programm 10-20 Gescbaftsfall: Ein- und Auszahlungen auf einem Konto
10.4.7 Geschaftsfall: Kontoliberweisungen Ein im Bankbetrieb haufig vorkommender Geschaftsfall ist die Transferierung eines Geldbetrages zwischen zwei Konten innerhalb der Bank. Eine Methode, die einen solchen Gescbaftsfall durchfUhrt, ist in Programm 10-21 angegeben. Diese Methode beruht auf den im vorangehenden Abschnitt verwendeten Methoden fUr die Ein- und Auszahlung auf Konten. Es ist wichtig, daB vor der Abbuchung des Betrages yom Auszahlungskonto iiberpriift wird, ob das Einzahlungskonto registriert ist, damit es nicht zu einer Buchung ohne der zugeh6rigen Gegenbuchung kommt. Bei einem eventuell nicht registrierten Auszahlungskonto kann es zu keiner Buchung kommen.
lOA Banken
313
Bank methodsFor: 'konten-buchungen' transferiereBetrag: einBetrag vonKontoMitNummer: knrVon nachKontoMitNummer: knrNach
"Geschaftsmethode: Transferieren eines Betrages von einem Konto auf ein anderes Konto innerhalb derselben Bank." (self hatKontoMitNummer: knrNach) ifFalse:[self error: 'Empfangerkonto existiert nicht'J. self kontoMitNummer: knrVon auszahlung: einBetrag mitText: ('Transfer auf Konto " knrNach printString). self kontoMitNummer: knrNach einzahlung: einBetrag mitText: (,Transfer von Konto " knrVon printString) (1) Uberpriifung, ob unter der Nummer knrNach ein Konto registriert ist.
Programm 10-21 Geschiiftsmethode: Kontoiiberweisung
Workspace
"Geschaftsfall: Oberweisen von ATS 100.- von Konto 1 auf Konto 3." "(1) Durchfiihrung der Oberweisung." Bank testBank transferiereBetrag: 100 asMoney vonKontoMitNummer: 1 nachKontoMitNummer: 3 <dolt>
"(2) OberprUfen der letzten Umsatze der Konten 1 und 3." (Bank testBank kontoMitNummer: 1) umsatze last <printlt> Kontoumsatz: ATS 100.00 CR (Bank testBank kontoMitNummer: 3) umsatze last <printlt> Kontoumsatz: ATS 100.00
"(3) Drucken des Buchungstextes des letzten Umsatzes von Konto 3." (Bank testBank kontoMitNummer: 3) umsatze last buchungsText <printlt> 'Transfer von Konto l'
Programm 10-22 Geschiiftsfall: Uberweisung zwischen Konten
(1)
314
10 Fallstudie: Banken
Ein Beispiel fiir eine Kontoiiberweisung ist in Programm 10-22 gegeben. Nach der Uberweisung von ATS 100.-- von Konto 1 auf Konto 3 werden unter Punkt (2) die letzten Umsatze der betroffenen Konten ausgedruckt, woraus die ordnungsgemaBe Uberweisung erkenntlich ist. Weiterhin wird noch unter Punkt (3) der Buchungstext des einen der beiden Umsatze kontrolliert.
10.4.8 Informationen iiber Kunden Bei der DurchfUhrung von Bankgeschaften ist es notwendig, Informationen iiber einzelne Kunden oder auch summarisch iiber den gesamten Kundenbestand zur Verftigung zu haben. Bank methodsFor: 'kunden-informationen' kontonummernVonKundenMitNummer: eineNummer "Erzeugen eines Feldes mit den Nummern aller Konten eines Kunden."
I knrArray I
knrArray :=Array new. (self kundeMitNummer: eineNummer) konten do: [:konto I knrArray := knrArray copyWith: konto kontoNummer). AknrArray
saldenSummeVonKundeMitNummer: knr "Feststellen der Summe der Salden aller Konten des Kunden mit der Nummer knr." A(self kundeMitNummer: knr) saldenSumme Bankkunde methodsFor: 'konto-informationen' saldenSumme "Feststellen der Summe aller Salden jener Konten, deren Inhaber der Bankkunde ist" Aself konten inject: (0 asMoney) into: [:summe :konto I summe + konto buchSaldo) Programm 10-23 Informationen iiber Konten von Kunden Stellvertretend fUr viele andere Methoden sind in Programm 10-23 zwei Methoden zur Gewinnung von Informationen iiber Kunden angeftihrt. Mit Hilfe der Methode Bank»kontoNummernVonKundenMitNummer: ist es moglich, fUr einen durch seine Kundennummer identiflZierten Kunden festzustellen, welche Konten in seinem Besitz sind.
315
10.4 Banken
Die Methode Bank»saldenSummeVonKundenMitNummer: liefert die Summe der Buchsalden alier Konten des Kunden mit der vorgegebenen Kundennummer. Methoden dieser Art kannen dazu dienen, einen Uberblick tiber die verfUgbaren Mittel eines Kunden zu erhalten, was eine Grundlage fur Entscheidungen des Kundenbetreuers der Bank sein kann. Einige Beispiele fUr den Einsatz solcher Methoden sind in Programm 10-24 zusammengefaBt.
Workspace
"Informationen fiber den Kunden mit der Kundennummer 1." Bank testBank kontonummernVonKundenMitNummer: 1 <printlt> #(1 2) Bank testBank saldenSummeVonKundeMitNummer: 1 <printlt> ATS 10400.00
"Zur Kontro"e: Informationen fiber die zugeordneten Konten." Bank testBank kontoMitNummer: 1 <printlt> Girokonto (Nummer: 1 Saldo: ATS 9900.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1» Bank testBank kontoMitNummer: 2 <printlt> Sparkonto (Nummer: 2 Saldo: ATS 500.00 Inhaber: Bankkunde 'Maier Franz' (Knr. 1»
Programm 10-24 Beispiele fUr Informationen tiber Kunden
10.4.9 Aufgaben Aufgabe 10.1 Uste mit Kundeninformationen Man erstelle eine Methode, welche eine nach Kundennummern sortierte Liste (SortedCo"ection) aller Kunden ausgibt. Jede Eintragung solI drei Elemente haben: die Nummer des Kunden, seinen Namen und die Summe der Salden aller seiner Konten.
316
10 Fallstudie: Banken
Losung von Aufgabe 10.1 Die in Programm 10-25 gezeigte Methode Bank»kundenListeMitSaldoSortiert erzeugt eine Auspragung der Klasse Sorted Collection, deren Elemente Felder sind, welche die in der Aufgabe geforderten Elemente enthalten.
Bank methodsFor: 'kunden-informationen' kundenlisteMitSaldoSortiert
"Erstellen einer nach Kundennummern sortierten Liste aller Kunden, diese enthiilt die Nummern, Namen und Saldensummen aller Konten des Kunden."
I kundenliste I kundenliste := SortedCollection sortBlock: [:x :y I (x at: 1) <= (yat: 1)]. self kunden do: [ :kunde I kundenliste := kundenliste copyWith: (Array with: kunde kundenNummer with: (kunde name copy) with: kunde saldenSumme)]. 1\ kundenliste Programm 10-25 Erstellen einer Kundenliste
Workspace
"Erstellen einer Kundenliste der Testbank." Bank testBank kundenlisteMitSaldoSortiert <printlt> SortedCollection ( *(1 'Maier Franz' ATS 10400.00) *(2 'Oberhuber Alois' ATS 100.00) )
Programm 10-26 Beispiel fUr eine Kundenliste
lOA Banken
317
Aufgabe 10.2 Kontoinformationen In einem vorangehenden Abschnitt wurden einige Methode gezeigt, die es ermoglichen, Informationen tiber Kunden zu erhalten. Ftir den Bankbetrieb ist es auch notwendig, Informationen tiber Konten zu erhalten. Man erstelle Methoden fur folgende Zwecke: a) Bank»saldoVonKontoMitNummer: eineNummer
"Feststellen des Buchsaldos (Kopie) des Kontos mit der vorgegebenen Nummer." b) Bank»kundennummerVonKontoMitNummer: eineNummer
"Feststellen der Kundennummer jenes Kunden, der Inhaber des Kontos mit der vorgegebenen Kontonummer ist." c) Bank>>kontenlisteNachSaldenSortiert
"Erstellen einer absteigend nach Salden sortierten Liste (SortedCollection) aller Konten. Die Elemente der Eintragungen sind: Nummer des Kontos, Nummer und Name des Kunden und Kontosaldo."
Losung von Aufgabe 10.2 Methoden, welche den Saldo eines Kontos und die Nummer des zugeordneten Kunden Hefern, sind in Programm 10-27 angefUhrt. Programm 10-28 zeigt die Methode Bank»kontenlisteNachSaldenSortiert, ein Beispiel fUr eine nach Salden absteigend sortierte Kontenliste ist in Programm 10-29 enthalten.
Bank methodsFor: 'konten-informationen'
saldoVonKontoMitNummer: eineNummer "Feststellen des Buchsaldos (Kopie) des Kontos mit der vorgegebenen Nummer." "(self kontoMitNummer: eineNummer) buchSaldo
kundennummerVonKontoMitNummer: eineNummer "Feststellen der Kundennummer jenes Kunden, der Inhaber des Kontos mit der vorgegebenen Kontonummer ist." "(self kontoMitNummer: eineNummer) inhaber kundenNummer
Programm 10-27 Informationen tiber Konten
318
10 Fallstudie: Banken
Bank methodsFor: 'konten-informationen' kontenliste
"Erstellen einer Liste (Array) aller Konten. Jedes Element der Liste enthillt die in der Aufgabe verlangten Elemente."
I kontenliste I kontenliste := Array new. self konten do: [:konto I kontenliste := kontenliste copyWith: (Array with: konto kontoNummer with: (konto inhaber kundenNummer) with: (konto inhaber name) with: (konto buchSaldo))]. 1\ kontenliste
(1)
kontenlisteNachSalden
"Erstellen einer sortierten Liste (SortedCollection) aller Konten. Die Elemente der Liste entsprechen der Methode 'kontenliste', sie werden nach den Buchsalden sortiert." 1\
self kontenliste asSortedCollection: [:x :y I (x at: 4) >= (y at: 4)]
(2)
(1) Man beachte: sofern es sich urn Attributbeziehungen handelt, werden durch die Zugriffsrnethoden Kopien geliefert. (2) Durch den Pararneterblock wird die Sortieranordnung festgelegt.
Programm 10-28 Erzeugung von Kontenlisten
Workspace
"Erzeugen einer nach Salden absteigend sortierten Kontenliste der Testbank." Bank testBank kontenlisteNachSaldenSortiert <printlt> SortedCollection ( #(1 1 'Maier Franz' ATS 9900.00) #(2 1 'Maier Franz' ATS 500.00) #(3 2 'Oberhuber Alois' ATS 100.00) )
Programm 10-29 Beispiel fUr eine nach SaIden sortierte Kontenliste
11 Fallstudie: Bankwesen
1m vorangehenden Absehnitt wurde bereits angedeutet, daB Banken nieht voneinander isoliert existieren, sondern innerhalb eines geregelten Bankwesens ihrer Tiitigkeit naehgehen, wodureh es ihnen aueh ermoglieht wird, untereinander in Kommunikation zu treten und einen banktibergreifenden Zahlungsverkehr abzuwiekeln.
11.1
Die Realitiit des Bankwesens
In diesem Absehnitt wird eine Situation besehrieben, welche die Grundlage fUr eine Fallstudie des Bankwesens bildet. Eine Bank solI erst ihre Gesehiiftstiitigkeit aufnehmen konnen, wenn sie von einer zentralen Stelle registriert und autorisiert wurde. Diese zentrale Stelle, sie solI als Bankenserviee bezeiehnet werden, fUhrt ein Register alIer zugelassenen Banken. Das Bankenserviee erlaubt allen registrierten Banken den Zugriff auf das Bankenregister und stellt diesen zusiitzlieh weitere, zentral gewartete Informationen zur VerfUgung: ein Verzeiehnis der fUr die Gesehaftstiitigkeit zuliissigen Wahrungen und einen Informationspool mit allgemeinen Wirtsehaftsdaten. Das Bankenregister solI es ermogliehen, tiber die bei der Registrierung einer Bank vergebene eindeutige Bankleitzahl jede Bank zu identifizieren sowie deren Namen und Adresse zu liefern. Den registrierten Banken solI es erlaubt sein, den Inhalt des Registers zu lesen, nieht jedoeh zu modiflzieren. 1m Wiihrungregister werden die gehandelten Wiihrungen unter ihrem internationalen Wiihrungeode (beispielsweise: ATS, DEM, USD usw.) eingetragen. Das Wiihrungregister solI dartiber hinaus in seiner jeweils aktuellen Form aueh allgemein veroffentlieht, das heiBt, aueh fUr andere Applikationen
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
320
11 Fallstudie: Bankwesen
verftigbar gemacht werden, ohne daB daftir ein Kontakt mit dem Bankenservice erforderlich ist. Es wurde bereits in der Klasse Money eine Klassenvariable (Currencies) vereinbart, die ein Verzeichnis der zulassigen Wahrungen referenziert. Dieses Wahrungsverzeichnis entspricht dem yom Bankenservice bereitgestellten Wahrungsregister. Eine entsprechende Anderungen ist also in der Klasse Money durchzufiihren. Der Pool der Wirtschaftsdaten moge zumindest die jeweils aktuellen Werte der Bankrate und Inflationsrate enthalten, er solI ahnlich wie die Wahrungsinformationen allgemein benutzbar sein. Die Bankinstitute sollen jedoch auf jede Anderung dieser Werte aufmerksam gemacht werden, urn beispielsweise ihre Zinskonditionen an eine geanderte Bankrate oder Inflationsrate anpassen zu konnen. In einigen Methoden der Klasse Konto wurde bereits auf das Verzeichnis der Wirtschaftsdaten Bezug genommen.
11.2 Ein Modell des Bankwesens Der beschriebene Realitatsausschnitt legt nahe, die in Abbildung 11-1 gezeigten Objektarten zu betrachten.
Banken Service (1) 1, M!
name
~
Wirtschafts Register
tL
bkreg wgreg 1, M!
~
1
Bank Registrierung name adresse biz
1, M!
wdreg
1
"-(global)
~
i
1
Wahrungs Register
Banken Register
,.
,.
Dict(blz)
1
1
I---
i
registrierung 1
Registrierte Bank
O. . n
lesen) _ _ _ .-J _ _ _ _ 1_ _ _(nur __ _ _ _ _ ...J
YModell : Abbildung 11-1 Modell des Bankwesens
11.3 Ein Blick in den konzeptione11en Objektraum
321
Das Mode111egt fest, daB genau ein Bankenservice existeren so11, welches seinerseits genau ein Bankenregister, ein Wlihrungsregister und ein Register der allgemeinen Wirtschaftsdaten enthlilt. Jedes dieser Register ist genau einem (und damit dem einzigen) Bankenservice zugeordnet. Das Bankenservice soll global erreichbar sein und somit eine Wurzel der Applikation darstellen, von der aus die anderen zugehorigen Objekte entsprechend den Modellangaben erreichbar sind. Das Bankenregister kann beliebig viele Bankregistrierungen enthalten, die auf direktem Wege tiber ihre Bankleitzahl auffindbar sind. Jede Bank muB durch genau eine Eintragung im Bankenregister beim Bankenservice registriert. Daraus folgt auch, daB es keine registrierte Bank geben darf, die nicht auf diese Weise im Bankenregister eingetragen ist. Es ist zu beachten, daB in dieser Konstruktion zwischen einer "registrierten Bank" und deren "Bankregistrierung" unterschieden wird. Bankobjekte sind jene Geschliftsobjekte des Anwendungsgebietes (business objects, domain objects), deren Aufgabe es ist, Bankgeschlifte abzuwickeln, also Bankprodukte an ihre Kunden zu verkaufen. Ihr Aufbau wurde bereits an einer frtiheren Stelle in einer Fallstudie tiber den Bankbetrieb betrachtet. Demgegegentiber sind Bankregistrierungen artifizielle Objekte, welche durch ihre Existenz die Tatsache der Eintragung einer Bank in das Bankenregister dokumentieren. Diese Trennung ist nicht zwingend notwendig, es konnte vielmehr auch eine Bank direkt in das Bankregister eingetragen sein. Der hier gewlihlte Entwurf soH einerseits darauf hinweisen, daB durch das "zentrale" Bankenservice kein direkter Zugriff auf die Banken moglich sein soll, andererseits bringt er Vorteile bei der Speicherung des Bankenservices in einer objektorientierten Datenbank, weil im Objektnetz die direkte Verbindung vom Bankenservice tiber das Bankenregister zu den eigentlichen Banken unterbrochen wird. Der im Modell von einer registrierten Bank zu den Registern weisende strichlierte Pfeil soll anzeigen, daB eine Bankregistrierung diese Register nur lesen, nicht aber verlindern konnen solI. Damit ist eine Einschrlinkung beztiglich der Zugriffsart festgelegt, nieht aber ein zuslitzlicher Navigationspfad. Diese Register konnen von der Bankenregistrierung aus nicht direkt, sondern nur tiber das Bankenservice erreicht werden.
11.3 Ein Blick in den konzeptionellen
Objektraum Abbildung 11-2 zeigt einen Ausschnitt aus dem Objektraum einer laufenden Applikation fUr das Bankwesen. Die hier gezeigt Struktur wird im Detail erst
322
11 Fallstudie: Bankwesen
durch die in den folgenden Abschnitten gegebene Implementation klar, an dieser Stelle soll jedoch einerseits nochmals auf den Unterschied zwischen der Darstellung im Modell und im Objektraum hingewiesen und andererseits eine Vorschau auf die Realisierung gegeben werden. 1m Objektraum ist die Klasse BankenService enthalten, die ihre (einzige) Auspragung in der Variablen AktivesBankenService halt. Von dies em (aktiven) Bankenservice ist nur jener Teil gezeigt, der sich auf das Bankenregister bezieht, welches selbst durch eine Instanz der Klasse Zentralregister dargestellt ist. Ein Zentralregister enthalt ein Verzeichnis (Dictionary), welches im gezeigten Fall zwei Eintragungen hat, namlich zwei Bankregistrierungen, die durch ihre Bankleitzahlen angesprochen werden konnen. Die Bankobjekte selbst besitzen fiber ihre von der Klasse RegistrierteBank geerbte Instanzvariable registrierung ebenfalls einen Zugang zu ihrem Registrierungsobjekt, von welchem sie ihre Bankleitzahl und ihren offiziellen Namen beziehen konnen.
Banken Service Ak!BServ
einBanken Service
I+-------+..... bkreg eineBankregistrierun
eineRegistrierteBank
100
regis!rierung
Testbank eineRegistrierteBank Creditbank
regis!rierung
Abbildung 11-2 Ausschnitt aus dem Objektraum: zwei registrierte Banken
11.4 Zentralregister Um die erwahnten Register zu realisieren, wird eine Klasse Zentralregister festgelegt, die in ihrer einzigen Instanzvariablen inhalt das entsprechende Ver-
11.4 Zentralregister
323
zeichnis (Dictionary) halt. Es werden keine ZugrifTsmethoden auf die Instanzvariable definiert, so daB das Verzeichnis nicht direkt manipulierbar ist, sondern nur indirekt tiber die Methoden eines Zentrairegisters angesprochen werden kann. Object subclass: #Zentralregister instanceVariableNames: 'inhalt ' classVariableNames: .. poolDictionaries: .. category: 'OrgHilfe' Zentralregister methodsFor: 'privat-initialisieren' initialisiere
"Initialisieren des Registers mit einem leeren Verzeichnis." inhalt := Dictionary new
(1)
Zentralregister methodsFor: 'privat-Schreibzugriff' setzeBei: einSchlussel denEintrag: einEintrag
"Eintragen von einEintrag unter einSchlUssel in das Zentralregister." inhalt at: einSchlOssel put: einEintrag loscheEintragBei: einSchlUssel
"Uischen des unter einSchlOssel gespeicherten Registereintrags." inhalt removeKey: einSchlOssel ifAbsent: [nil] (1) Man beachte, daB in allen Methoden die Instanzvariable inhalt direkt gelesen und geschrieben wird, urn sie nicht durch Zugriffsmethoden erreichbar zu machen.
Programm 11-1 NichtotTentliche Methoden fUr ein Zentralregister Die Definition der Klasse Zentralregister und ihre wichtigsten Methoden sind in den Programmen 11-1 und 11-2 zusammengestellt. Diese Methoden sind als otTentlich oder privat kategorisiert, was in Smalltalk jedoch mit keiner Wirkung verbunden ist, sondern nur den Charakter einer Empfehlung hat. Diese Empfehlung soIl hier bedeuten, daB die nichtotTentlichen Methoden, mit deren Hilfe der Registerinhalt verandert werden kann, nur vom Bankenservice selbst verwendet werden sollen, wahrend die otTentlichen Lesemethoden allen Bankregistrierungen (und damit, wie spater gezeigt wird, allen Banken) zur Verfligung stehen.
11 Fallstudie: Bankwesen
324
Zentralregister methodsFor: 'Offentlich-Lesezugriff'
eintragBei: einSchlUssel
"Zugriff auf das unter einSchlUssel eingetragene Objekt." "inhalt at: einSchlOssel ifAbsent: [nil]
kenntEintragBei: einSchUissel
"Feststellen, ob unter einSchlUssel ein Registereintrag vorliegt" "(self eintragBei: einSchlOssel) notNU
Programm 11-2 Offentliche Methoden zum Lesen eines Zentralregisters
Die Unterscheidung zwischen Methoden, die fUr den offentlichen und nichtOffentlichen Gebrauch gedacht sind, wird auch deswegen besonders betont, da in einer spateren Stelle (Abschnitt 14.2) eine Unterklasse GeschOtztesRegister mit der Moglichkeit der Realisierung eines starkeren Schutzmechanismus eingerichtet wird. Programm 11-3 zeigt eine Methode zur "Druckausgabe" eines Zentralregisters, die auch seinen Inhalt darstellt. Zentralregister methodsFor: 'printing'
printOn: aStream
"Schreiben einer das Zentralregister samt seinem Inhalt charakterisierenden Zeichenkette." aStream nextPutAlI: self class name, ((inhalt notNU) ifTrue: [inhalt printString copyReplaceAII: 'Dictionary' with: "] (1)
''FOr den Fall, daB der Debugger benotigt wird~'
(2)
ifFalse: [' (nicht initialisiert)'J) (1) Hier wird auf die Druckdarstellung eines Dictionary zuriickgegriffen, aus der die Zeichenkette 'Dictionary' entfemt wurde.
(2) 1m Normaifall wird die Instanzvariable inhalt unmittelbar nach der Erzeugung des Registers mit einem Dictionary initialisiert, dieser Teil der Methode soli jedoch Sonderfalle beim Testen beriicksichtigen.
Programm 11-3 Zentralregister» printOn:
325
11.5 Erzeugen des Bankenservice
Zentralregister methodsFor: 'printing' wihleAus: auswahlBlock
"Auswahlen jener Eintragungen, fur welche der auswahlBlock zu true evaluiert wird." 1\
inhalt select: auswahlBlock
alsSortierteUste: sortBlock
"Erstellen einer sortierten Liste der Eintragungen, wobei das Sortierkriterium durch sortBlock festgelegt ist." I\inhalt asSortedCollection: sortBlock
Programm 11-4 Erstellen von Ausziigen aus einem Zentrairegister
SchlieBlich sind in Programm 11-4 einige Hilfsmethoden zusammengestellt, auf die an spiiterer Stelle noch zUrUckgegrifTen werden wird.
11.5 Erzeugen des Bankenservice Bei der Definition der Klasse BankenService wird zusiitzlich zu den im Modell bereits angefUhrten Instanzvariablen noch die Variable bkZahler festgelegt, welche mit einem Ziihlwerkobjekt belegt wird, das bei der Registrierung einer Bank, also beim Eintragen einer Bankregistrierung, die jeweils niichste zu vergebende Bankleitzahlliefem soll. Dieses Ziihlwerk hat fUr die Vergabe der Bankleitzahlen eine iihnliche Funktion wie die Ziihlwerke in einer Bank fUr die Vergabe der Kunden- und Kontonummem. Somit sind fUr die Klasse Bankenservice insgesamt folgende Variable festgelegt: a) Instanzvariable bkreg wgreg wdreg name <String> bkZahler
Bankenregister Wahrungsregister Wirtschaftsdatenregister Name des Bankenservice Generator fOr Bankleitzahlen
b) Kasseninstanzvariable AktivesBankenService
326
11 Fallstudie: Bankwesen
Die Klasseninstanzvariable AktivesBankenService halt das aktive Bankenservice als einzige Auspragung dieser Klasse. Dadurch ist sichergesteHt, daB dieses Objekt global tiber sein Klassenobjekt erreichbar ist, ohne daB eine globale Variable angelegt werden muB. Die Definition der Klasse BankenService ist in Programm 11-5 gezeigt. Wie daraus auch ersichtlich ist, wird die Methode BankenService class»new derart redefiniert, daB ein neues Bankenserviceobjekt sofort initialisiert und an die Klassenvariable AktivesBankenService gebunden wird. SoUte bereits ein derartiges Objekt existieren, wird die Erzeugung unterbunden. Auf diese Weise wird die Modellforderung erf1.illt, daB jeweils nur eine einzige Instanz der Klasse BankenService existieren kann. SoH aus irgendeinem Grunde ein Bankenservice neu erzeugt werden, so ist dies nur moglich, wenn ein bereits existierendes Bankenservice vorher mit Hilfe der Methode BankenService class>>IOscheAktivesService entfemt wurde. Object subclass: #BankenService instanceVariableNames: 'bkreg bkZ~hler name wgreg wdreg , classVariableNames: " poolDictionaries: 'Wirtschaftsdaten' category: 'Banken' BankenService class instanceVariableNames: 'AktivesBankenService ' BankenService class methodsFor: 'instance creation'
new "Erzeugen des aktiven BankenService. jedoch nur dann. wenn es noch nicht existiert."
(self aktivService notNiI) ifTrue: [self error: 'Es ist bereits ein Bankenservice aktivl']. AktivesBankenService := super new initialisiereAlies
(1)
(1) Dadurch wird sichergestellt, daB nur eine Auspragung existieren kann, diese wird an die Klasseninstanzvariable AktivesBankenService gebunden und fiber die Klassenmethode mit dem Selektor aktivService angespochen. Die Methode BankenService class>>aktivService moge das aktive Bankenservice liefem.
Programm 11-5 Erzeugung des (aktiven) Bankenservice Bei der Initialisierung des aktiven Bankenservices (Programm 11-6) werden entsprechend den ModeHanforderungen die Register erzeugt und zugeordnet, der Name vergeben und ein neues Zahlwerk fUr die Generierung der Bankleitzahlen eingesetzt
327
11.5 Erzeugen des Bankenservice
BankenService methodsFor: 'initialize'
initialisiereAlles "Initialisieren des Bankenservice." bkreg := Zentralregister new. wdreg := Zentralregister new. wgreg := Zentralregister new. name := 'Bankaufsicht'. bkZahier := Zahlwerk new Programm 11-6 Initialisierung des Bankenservice
BankenService methodsFor: 'initialize'
ladeBasisWirtschaftsdaten "Setzen von Vorgabewerten, diese sollten aktualisiert werden." self
setzeBankrate: (11/2); setzelnflationsrate: (19/10).
ladeBasisWihrungen "Setzen von Vorgabewerten, diese sollten aktualisiert werden." self
registriereWahrung: #EUR registriereWahrung: #ATS "usw."
mitNamen: 'Euro'; mitNamen: 'Schilling';
Programm 11-7 Laden der Wirtschafts- und Wlihrungsdaten Mit Hilfe der Methoden ladeBasisWirtschaftsdaten und ladeBasisWahrungen (Programm 11-7) werden die Register der Wirtschaftsdaten und der Wahrungen mit einigen Eintragungen versehen, die eine Voraussetzung fUr die DurchfUhrung der vorzustellenden Beispiele sind. Die Eintragungen in diesen Registem konnen jederzeit erganzt oder abgeandert werden. In der Klasse Money wurde eine Klassenvariable deklariert, die ein Verzeichnis der giiltigen Wahrungen tragt. Es ware sinnvoll, dem Wlihrungsregister des aktiven Bankenservice diese Funktion zu iibertragen. Programm 11-8 fasst einige zusatzliche Methoden zusammen, welche Hilfsfunktionen erfUllen und fUr das Verstandnis der in Programm 11-6 angegebenen Methoden wesentlich sind.
328
11 Fallstudie: Bankwesen
BankenService methodsFor: 'wirtschaftsdaten'
registriereWiihrung: einWiihrungssymbol mitNamen: aString "Registrieren einer Wahrung." wgreg setzeBei: einWahrungssymbol asSymbol denEintrag: aString
(1)
setzeBankrate: eineBruchzahl "Festlegen einer neuen Bankrate und deren Veroffentlichung." wdreg setzeBei: #bankrate denEintrag: eineBruchzahl. self publiziereBankrate
publiziereBankrate "Eintragen der Bankrate in den Datenpool Wirtschaftsdaten." bankrate := (wdreg eintragBei: #bankrate) copy (1) Zwar wird a1s Parameter einWAhrungssymbol eine Instanz der Klasse Symbol erwartet, falls jedoch eine Zeichenkette als Wiihrungssymbol iibergeben wird, erfolgt hier die Umwandlung in ein Symbol.
Programm 11-8 Hilfsmethoden fur das Bankenservice
BankenService methodsFor: 'printing'
printOn: aStream "Schreiben einer das Bankenservice charakterisierenden Zeichenkette." aStream nextPutAlI: self class name, «self registrierteBanken notNil) ifTrue: [' mit " self anzahlBanken printString, , registrierten Banken'] ifFalse: [' ohne Bankenregister'])
(1)
(2)
(1) Bin ordnungsgemiiB erzeugtes Bankenservice besitzt immer ein Bankenregister, dieser Code istjedoch fUr Testzwecke niitzlich. (2) Die Methode BankenService»anzahIBanken soli dieAnzahl der registrierten Banken liefern.
Programm 11-9 BankenService» printOn:
11.5 Erzeugen des Bankenservice
329
Um die Ergebnisse der Einrichtung eines Bankenservice in einem Arbeitsbereich veranschaulichen zu k6nnen, wird noch die in Programm 11-9 gezeigte Methode printOn: festgelegt, die ein Bankenservice durch eine Zeichenkette charakterisiert. t Workspace BankenService new.
<dolt>
BankenService aktivService <printlt> BankenService mit 0 registrierten Banken BankenService new. <dolt> Es ist bereits ein Bankenservice aldivl
(1)
BankenService aktivService wirtschaftsdaten <printlt> Zentralregister () BankenService aktivService ladeBasisWahrungen; ladeBasisWirtschaftsdaten. BankenService aktivService wirtschaftsdaten <printlt> Zentralregister (#inflationsrate->{1911 0) #bankrate->(11/2) )
(2)
Wirtschaftsdaten <printlt> PoolDictionary ({VariableBinding key: #inflationsrate) (VariableBinding key: #bankrate) )
(3)
(1) Es ist nicht moglich, ein weiteres Bankenservice zu erzeugen.
(2) Nach dem Laden von Basisdaten enth1i.lt das Wirtschaftdatenregister die notwendigen Eintragungen. (3) Man erkennt, daB die Wirtschaftsdaten offentlich (als Datenpool) zur Verfugung stehen!
Programm 11-10 Erzeugung und Ausgabe eines Bankenservice In Programm 11-10 sind die Vorgangsweise fUr das Einrichten eines aktiven Bankenservice in einem Workspace sowie einige Tests gezeigt. Fiir die weite-
t
Die in allen gezeigten Klassen eingerichtete Methode mit dem Selektor prinlOn: wird deshalb immer angefiihrt, well sie das Verstiindnis der in Arbeitsbereichen demonstrierten Geschiiftsrille erleichtert.
330
11 Fallstudie: Bankwesen
ren Demonstrationsbeispiele kann nun davon ausgegangen werden, daB das zentrale Bankenservice eingerichtet ist und daB daher die Voraussetzungen fUr die Registrierung neu einzurichtender Banken vorliegen. Allerdings sind noch kurze Blicke auf die Klasse Bankregistrierung und auf die Registrierungseigenschaften von Banken zu werfen, urn das Zusammenwirken solcher Objekte zu verdeutlichen.
11.6 Bankregistrierungen Die Auspragungen der in Programm 11-11 defmierten Klasse BankRegistrierung sind jene Objekte, die bei der Registrierung einer Bank in das Bankenregister des zentralen Bankenservices eingetragen werden. Object subclass: #BankRegistrierung instanceVariableNames: 'name adresse leitzahl' classVariableNames: " poolDictionaries: " category: 'Banken' BankRegistrierung class methodsFor: 'instance creation'
newMitNamen: einName undAdresse: eineAdresse "Erzeugen einer neuen Bankregistrierung mit Namen und Adresse." Aself new name: einName; adresse: eineAdresse BankRegistrierung methodsFor: 'printing'
printOn: aStream "Schreibe auf aStream eine Zeichenkette, welche den Empfanger charakterisiert." aStream nextPutAlI: self class name,' Name: " self name printString, , BLZ: " self leitzahl printString
Programm 11-11 Einige Methoden fUr Bankregistrierungen Urn die Aufgaben der Verwaltung des Bankenregisters wahrnehmen zu konnen, muss en entsprechende Methoden bereitgestellt werden. Dazu gehoren Methoden fUr das Eintragen einer neuen Bank in das Bankenregister, flir das Loschen einer bereits registrierten Bank aus dem Register sowie fUr die Beantwortung der Frage nach dem Namen und der Adresse der zu einer Bankleitzahl gehOrenden Bank. Fur diese Zwecke verfaBte Methoden sind in Programm 11-12 zusammengestellt.
11.7 Registrierte Banken
331
BankenService methodsFor: 'bankwesen'
bankMitLeitzahl: eineBankleitzahl "Zugriff auf die unter der Bankleitzahl eingetragenen Bankregistrierung." 1\
bkreg eintragBei: eineBankleitzahl
entferneBankMitLeitzahl: eineBankLeitzahl "Entfernen der unter der Bankleitzahl eingetragenen Bankregistrierung aus dem Register der zugelassenen Banken." bkreg 16scheEintragBei: eineBankLeitzahl
Programm 11-12 Verwaltung des Bankenregisters
Bevor die Methode fUr die Registrierung einer Bank vorgestellt werden kann, ist noch eine kurze Betrachtung der Bankregistrierung aus der Warte von Banken notwendig.
11.7 Registrierte Banken Die Klasse Bank wurde als Subklasse von RegistrierteBank eingerichtet, welche die fUr die Registrierung von Banken notwendige Funktionalitiit beisteuert. Die Defmition dieser Klasse wurde bereits an einer friiheren Stelle angegeben, so daB es geniigt, in Prograrnm 11-13 auf zwei Methoden aufmerksarn zu machen, deren Bedeutung aus ihren Kommentaren klar hervorgeht. RegistrierteBank methodsFor: 'accessing - private'
registrierung: eineBankRegistrierung "Zuordnen der Bankregistrierung." registrierung := eineBankRegistrierung RegistrierteBank methodsFor: 'testing'
istRegistriert "Stelle fest ob die Bank bereits registriert ist" 1\
self registrierung notNil
Programm 11-13 Registrierte Banken
332
11 Fallstudie: Bankwesen
Zusatzlich muB die fruher als vorlaufig deklarierte Initialisierungsmethode der Klasse Bank (Programm 10-5) revidiert werden, was in Programm 11-14 gezeigt ist. Die nunmehrige Methode Bank class»initialize besetzt vorerst die Klasseninstanzvariable bankenService mit dem fur das Bankenservice zustandigen Klassenobjekt und ordnet dann ihrer Klasseninstanzvariablen testBank eine Bank zu, die im Bankenservice durch die in Programm 11-15 gezeigte Methode registriert wurde.
Bank class methodsFor: 'initialize' initialize
"Initialisiere die Klasse: erzeuge eine Testbank." "Bank bankenService initialize" "Bank initialize" bankenService := BankenService. testBank := self bankenService aktivService registriereBank: (self new) mitNamen: 'Testbank' undAdresse: 'Europlatz l'
Programm 11-14 Initialisierung der Klasse Bank fUr die Registrierung
11.8 Geschaftsfall: Registrierung einer Bank Programm 11-15 enthalt jene Geschaftsmethode, durch welche die Registrierung einr Bank vorgenommen wird, wobei fUr die Einhaltung alIer durch das Modell verlangten Vorgaben Sorge getragen wird. Diese Methode erwartet als Argumente die (neue) zu registrierende Bank sowie den ihr zuzuteilenden Namen und die Adresse. In einem nachsten Schritt wird die nachste verfugbare Bankleitzahl angefordert und eine Instanz der Klasse BankRegistrierung erzeugt, welche mit dem Namen, der Adresse und der Bankleitzahl versehen wird. Diese Bankregistrierung wird sodann unter der Bankleitzahl in das Bankenregister eingetragen. SchlieBlich wird der Bank ihr Bankregistereintrag bekanntgemacht und die Bank initialisiert. Die nunmehr ordnungsgema13 registrierte und initialisierte Bank wird als Riickgabeobjekt geliefert, was beim Testen von Vorteil sein kann.
333
H.8 Geschaftsfall: Registrierung einer Bank
BankenService methodsFor: 'bankwesen'
registriereBank: eineBank mitNamen: einName undAdresse: eineAdresse "Geschiiftsmethode: Registrieren einer Bank unter der nachsten zu vergebenden Bankleitzahl."
I biz bankRegisterEintrag I
eineBank istRegistriert iffrue: [self error: 'Die Bank ist bereits registriert!']. biz := self naechsteBLZ. bankRegisterEintrag := BankRegistrierung newMitNamen: einName undAdresse: eineAdresse. bkreg setzeBei: biz denEintrag: (bankRegisterEintrag leitzahl: biz). eineBank registrierung: bankRegisterEintrag. eineBank initialisiereAlles. "zvreg setzeBei: biz denEintrag: (OrderedCollection new)." (1) l\eineBank
(1) Dieser Ausdruck ist absichtIich nauskommentiert", er soli erst bei einer Erweiterung wirksam werden, siehe Programm 12-2.
Programm 11-15 Registrierung einer Bank
Workspace "(0) Oberpriifen des aktiven BankenService." BankenService aktivService <printlt>
BankenService mit 0 registrierten Banken "(1) Initialisieren der Klasse Bank, dabei wird eine Testbank registriert." Bank initialize. BankenService aktivService.
<dolt>
<printlt>
BankenService mit 1 registrierten Banken BankenService aktivService registrierteBanken.
<printlt>
Zentralregister (
100->BankRegistrierung Name: 'Testbank' BU: 100 ) Programm 11-16 Erzeugen und Registrieren der Testbank
334
11 Fallstudie: Bankwesen
Workspace
"Fortsetzung von Programm 11-16." "(1) Registrieren einer Bank." BankenService aktivService registriereBank: Bank new mitNamen: 'CreditBank' undAdresse: 'Finanzplatz l' Bank(200)CredHBank
<printlt>
(1)
BankenService aktivService <printlt> BankenService mH 2 registrierten Banken
"(2) Ausdrucken des Bankenregisters." BankenService aktivService registrierteBanken Zentralregister ( 100->BankRegistrierung Name: 'Testbank' BLZ: 100 200->BankRegistrierung Name: 'CredHBank' BLZ: 200)
"(3) Feststellen der Bankregistrierung mit Bankleitzahl 200." BankenService aktivService bankMitLeitzahl: 200 <printlt> BankRegistrierung Name: 'CredHBank' BLZ: 200 (1) An dieser Stelle ist im Objektraum genau die in Abbildung 11-2 gezeigte
Konstellation erreicht.
Programm 11-17 Geschliftsfall: Registrieren einer Bank
Zur Uberprtifung der Funktion dieser Methoden sind in den Programmen 11-16 und 11-17 einige Anweisungen samt den Ergebnissen ihrer Evaluation in einem Workspace angegeben. t An einer spateren Stelle wird noch gezeigt, wie (irn Sinne einer inkrementellen Entwicklung) die Funktionalitat eines Bankenservice derart ausgebaut werden kann, daB es fUr die registrierten Banken Postracher verwaltet, tiber welche die Banken Inforrnationen austauschen und dadurch den Zahlungsverkehr abwickeln konnen.
t In den gezeigten Beispielen werden die Banldeitzahlen nicht fortlaufend, sondern in Schritten von 100 vergeben.
11.9 Aufgaben
335
11.9 Aufgaben Aufgabe 11.1 Verhinderung von Mehrfacheintragungen in ein Register Naeh den bisher entworfenen Methoden ist es moglieh, daB in ein Zentralregister unter versehiedenen Sehliisseln gleiehe oder aueh identisehe Eintragungen vorgenommen werden konnen. Beispielsweise kann in das Bankenregister eine Bank unter mehreren Bankleitzahlen eingetragen werden. Um solche Situationen zu vermeiden, verandere man die Zugriffsmethoden derart, daB a) eine bereits unter einer Bankleitzahl registrierte Bank nieht noehmals unter einer anderen Bankleitzahl registriert werden kann und daB b) es nieht moglieh ist, mehrere Banken zu registrieren, die einen gleiehen Namen tragen
Losung von Aufgabe 11.1 Um Eintragungen identiseher Objekte in ein Zentralregister zu verhindem, ist die in Programm 11-1 angegebene Methode Zentralregister»setzeBei:denEintrag dureh dureh die im Programm 11-18 angegebene zu ersetzen oder entspreehend abzuiindem. Moehte man sicherstellen, daB Eintragungen gleicher Objekte in einem Zentralregister nieht moglich sein soIlen, so ist wie in Programm 11-19 gezeigt vorzugehen. Man beaehte, daB der Untersehied zwischen den beiden Eintragungsmethoden (abgesehen von der Adaptierung des Textes der Fehlermeldung) nur in der Methode fUr den Vergleieh von Eintragungen liegt. In einem Fall wird auf Identitiit, im anderen Fall auf Gleiehheit gepriift. 1m Falle der Priifung auf Gleiehheit ist fUr die einzutragenden Objekte sieherzusteIlen, daB eine Methode existiert, dureh welche die der Anwendung entspreehende Gleiehheit festgestellt wird. Die in Programm 11-19 gezeigte Methode erfUllt fUr die gestellte Forderung, daB registrierte Banken dann als gleieh betraehtet werden sollen, wenn sie einen gleiehen Namen haben. SoU gewiihrleistet sein, daB die in einem Wiihrungsregister eingetragenen Wiihrungen sieh nieht nur in ihrem Wiihrungssysmbol, sondem aueh in ihrem Namen unterseheiden, miiBte man die in Programm 11-19 gezeigte Eintragungsmethode verwenden, eine neue Vergleiehsmethode ist nieht mehr vorzusehen, da die Eintragungen Zeiehenketten (String) sind, fUr die bereits eine solche Methode existiert.
336
11 Fallstudie: Bankwesen
Zentralregister methodsFor: 'privat-Schreibzugriff'
setzeldKontrolliertBei: einSchlUssel denEintrag: einEintrag "l(isung Aufgabe 1a: Trage einEintrag unter einSchllissel in das Zentralregister ein." inhalt keysAndValuesDo: (1) [:schIOssel :eintrag I (eintrag = einEintrag) (2) ifTrue: [self error: 'ein identischer Eintrag liegt bereits unter dem SchlOssel', schlOssel printString, , vorl'] ]. inhalt at: einSchlOssel put: einEintrag (1) Diese flir Verzeichnisse (Dictionary) definierte Enumerationsmethode erwartet als Argument einen Block mit zwei Argumenten, den Schliissel und den Wert der Assoziation.
(2) Es wird iiberpriift, ob das einzutragende Objekt bereits eingetragen ist.
Programm 11-18 Zentralregister mit verschiedenen Objekten
Zentralregister methodsFor: 'privat-Schreibzugriff'
setzeEquKontrolliertBei: einSchlUssel denEintrag: einEintrag "Liisung Aufgabe 1b: Trage einEintrag unter einSchllissel in das Zentralregister ein." inhalt keysAndValuesDo: [:schlOssel :eintrag I (eintrag = einEintrag) ifTrue: [self error: 'ein gleicher Eintrag liegt bereits unter dem SchlOssel', schlOssel printString, ' vorl'] ]. inhalt at: einSchlOssel put: einEintrag
(1)
(1) Es wird iiberpriift, ob ein gleiches Objekt bereits eingetragen ist. Dabei wird vorausgesetzt, daB flir die Eintragungen die Operation = definiert ist!
Programm 11-19 Zentralregister mit ungleichen Objekten Wenn in einer Anwendung gleichzeitig Register mit verschiedenen Varianten der Eintragungskontrolle notwendig sind, ware es auch zu iiberlegen, Subklassen von Zentralregister zu definieren, welche spezielle Arten der Eintragungskontrolle vorsehen.
12 Fallstudie: Zahlungsverkehr zwischen Banken
In einer Fallstudie tiber den Betrieb von Banken wurde bereits gezeigt, wie ein stark vereinfachtes Modell eines Bankininstitutes aussehen kann und welche Methoden vorgesehen werden konnen, um die fUr den Bankbetrieb notwendige Funktionalitat zu bieten. Dabei wurde das Augenmerk vorerst auf interne Geschaftsablaufe einer Bank gerichtet, wie die Verwaltung des Kunden- und Kontenbestandes und den Zahlungsverkehr zwischen Kunden ein und desselben Bankinstitutes. In einer Fortsetzung durch die Fallstudie tiber das Bankwesen wurde angedeutet, wie mehrere Banken eines Landes in einer als Bankenservice bezeichneten zentralen Stelle registriert werden konnen und wie dieses zentrale Bankenservice Informationen fUr aIle registrierten Banken sammeln und verftigbar machen kann. Dadurch wurde die Grundlage fUr die Kommunikation zwischen verschiedenen Banken gelegt, sodaB nun die Abwicklung des Zahlungsverkehrs zwischen Bankinstituten in Betracht gezogen werden kann. Um Auftrage von einer Banken an eine andere Bank tibermitteln zu konnen, werden nun die Aufgaben des zentralen Bankenservice derart erweitert, daB fUr jede registrierte Bank eine Art von Postfach gefUhrt wird, in dem Auftrage fUr diese Bank hinterlegt werden konnen. Die Empfangerbank kann die in ihrem Postfach eingelangten Auftrage entgegennehmen und nach entsprechender Priifung bearbeiten und erledigen. Zu diesem Zwecke ist es notwendig, Erweiterungen hinsichtlich der Struktur und des Verhaltens in den Klassen BankenService und Bank vorzunehmen. Weiterhin ist zu tiberlegen, durch welche Art von Objekten Bankauftrage dargestellt werden konnen und welches Verhalten diesen zuzumessen ist. Dieses Vorhaben solI auch als ein Beispiel fUr die iterative und inkrementelle Systementwicklung dienen, die von einer objektorientierten Vorgangsweise ausdriicklich untersttitzt wird. G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
338
12 Fallstudie: Zahlungsverkehr zwischen Banken
12.1
Ein erweitertes Modell des Bankwesens
In Abbildung 12-1 sind die Erweiterungen des bisher erstellten Modelles fUr das Bankwesen hervorgehoben. Das Bankenservice erhlilt zuslitzlich zu den bereits eingerichteten Registem (Wirtschafts- Wlihrungs- und Bankenregister) ein Postfachregister, welches fUr jede registrierte Bank unter deren Bankleitzahl ein Postfach unterhlilt, in das Bankauftrlige in der Reihenfolge ihres Einlangens abgelegt werden konnen.
Banken Service (1)
Bank auftrag
name wdreg wgreg bkreg pfreg
banr text status datum
t
1, M!
+
1
Ordeoll O. n •
1 Postfach Register
Postfach Dict(blz)--'
' - -_ _....I
-1
Modell
O.. n
1
I
Abbildung 12-1 Ein erweitertes Modell des Bankwesens Der Aufbau eines Bankauftrages ist in Abbildung 12-2 modelliert. Bankauftrage besitzen zuslitzlich zu einem Identifikationsmerkmal einen Text, der den Auftrag beschreibt sowie ein Datum ihrer Erstellung. AuBerdem sollen sie mit einer Statusinformation versehen sein, um ihren jeweiligen Bearbeitungszustand dokumentieren zu konnen. Eine spezielle Art eines Bankauftrages, die in dieser Fallstudie ausschlieBlich beriicksichtigt werden soli, ist die Inlandsiiberweisung. Eine Inlandsiiberweisung wird von einer auftraggebenden Bank an eine auftragnehmende Bank iibermittelt, wobei als Voraussetzung angenommen wird, daB beide Banken bei demselben Bankenservice registriert sind und somit dessen Kommunikationsdienste in Anspruch nehmen konnen. Diese Voraussetzung soli durch die Bezeichnung "Inlandsiiberweisung" verdeutlicht werden.
339
12.1 Ein erweitertes Modell des Bankwesens
Bankauftrag
Kontoinformation
banr text status datum
biz knr name status
InlandskontoVon --+ Oberweisung t - - - - - - - - - - - ' betrag valutaDatum
kontoNach
---+
Modell,
Abbildung 12-2 Bankauftrage
Eine Inlandsfiberweisung soll die Transferierung eines Geldbetrages zwischen zwei bei verschiedenen Banken geftihrten Konten bewirken. Sie verzeichnet zusatzlich zu den bereits erwahnten Informationen den zu transferierenden Betrag, das Datum der Uberweisung sowie je eine »Kontoinformation" fiber das QueIlkonto und das Zielkonto. Eine Kontoinformation wird als eigene Entitat gesehen, die es erlaubt, ein Konto zu identifizieren. Sie enthalt die Bankleitzahl der kontofiihrenden Bank, optional die Nummer des angesprochenen Kontos, den Namen des Kontoinhabers sowie eine Angabe fiber den Bearbeitungsstatus. Wird beispielsweise bei einer Uberweisung an eine Bank das Zielkonto durch Angabe seiner Nummer spezifiziert, so ist der Betrag auf genau dieses Konto zu buchen, falls dieses von der Empfangerbank erkannt wird. 1st keine Kontonummer angegeben, so liegt es im Ermessen der Bank, ein dem bezeichneten Empfanger zugehorendes Konto auszuwahlen. Die Kontoinformation fiber das Quellkonto wird zwar den Namen des Auftraggebers und die Bankleitzahl der sendenden Bank enthalten, nichtjedoch die Kontonummer. In jedem Fall ist vorgesehen, daB sowohl in der Auftraggeberbank als auch in der Empfangerbank eine Entscheidung fiber die Durchfiihrbarkeit der Uberweisung moglich ist, was durch die Vergabe der Statusinformationen fUr den Bankauftrag ausgedruckt werden solI.
340
12 Fallstudie: Zahiungsverkehr zwischen Banken
12.2 Erweiterung der Klasse Bankenservice Fur die Anderung einer bestehenden Applikation, die uber das Hinzufligen von Methoden zu einer bestehenden Klasse hinausgeht und auch die Struktur der Auspragungen dieser Klasse erweitert, bieten sich prinzipiell zwei Moglichkeiten an. Einerseits kann eine Subkiasse der zu erweitemden Klasse eingerichtet werden, welche die notwendigen Zusatze realisiert, andererseits konnen die Erweiterungen in der bestehenden Klasse selbst vorgenommen werden. Die Bildung einer Subkiasse erscheint nur dann gerechtfertigt, wenn sowohl Auspragungen der bisherigen Klasse ais auch der neuen Klasse eine Existenzberechtigung haben und im Objektraum koexistieren sollen. 1st dies nicht der Fall, dann sollte die bisherige Klasse nur dann ais abstrakte Klasse beibehalten werden, wenn andere konkrete Subklassen dieser Klasse sinnvoll erscheinen. In der Fallstudie wird die bisher festgeIegte Klasse BankenService direkt verandert, wobei durch die Veranderung die bereits bestehenden Funktionalitat nicht beeintrachtigt wird. Dies erscheint im vorliegenden Fall besonders auch deswegen geboten, wei! die Klasse BankenService ais Singleton-Klasse konzipiert ist, von der nur genau eine Auspragung im Objektraum existieren solI. Die notwendigen Veranderungen in der Klassendefinition und in der Initialisierung der Instanzen sind in Programm 12-1 zusammengestellt und durch Unterstreichung gekennzeichnet. Es wird eine zusatzliche Instanzvariable zvreg festgeIegt, die bei der Initialisierung mit einem Ieeren Zentralregister beIegt wird. Model subclass: #BankenService instanceVariableNames: 'bkreg bkZi:l.hler name wgreg wdreg classVariableNames: " pool Dictionaries: " category: 'Banken' BankenService methodsFor: 'initialize'
initialisiereAlies
"Modell: Einrichtung der BeziehungBankenService (1) -> PostfachRegister." zvreg '- Zentralregister new
Programm 12-1 Erweiterung der Klasse BankenService
~
,
12.2 Erweiterung der Klasse Bankenservice
341
Das neu eingefiihrte Zahlungsverkehrsregister solI in Ubereinstimmung mit den Eintrligen in das Bankenregister (Instanzvariable bkreg) bei der Registrierung einer Bank unter der vergebenen Bankleitzahl einen Behlilter (Ordered Collection) eingetragen bekommen, welcher die an die entsprechende Bank adressierten Auftrlige aufnimmt. Die daflir notwendige Adaptierung der Methode flir die Registrierung von Banken ist in Programm 12-2 gezeigt.
BankenService methodsFor: 'bankwesen'
registriereBank: eineBank mitNamen: einName undAdresse: eineAdresse "Modell: Einrichtung der Beziehung Postfachregister (O..n) -> Postfach." zvreg setzeBej' biz denEjntrag' (OrderedCollectjon new). "eineBank
Programm 12-2 Adaption der Registrierung einer Bank Jetzt bleibt noch die Notwendigkeit, jene in Programm 12-3 gezeigten Methoden zu verfassen, welche Auftrage flir eine bestimmte Bank entgegennehmen und den Zugriff auf die hinteriegten Auftrage gestatten.
BankenService methodsFor: 'auftragsevidenz'
registriereAuftrag: einAuftrag fiirBLZ: eineBankleitzahl "Senden des Auftrages in das Postfach der Bank mit der vorgegebenen Bankleitzahl." (zvreg eintragBei: eineBankleitzahl) add: einAuftrag
auftrageFUrBLZ: eineBankleitzahl "Antworte mit der Sammlung der Auftriige. die fur die Bank mit der vorgegebenen Leitzahl vorliegen." "zvreg eintragBei: eineBankleitzahl
Programm 12-3 Lesen und Schreiben des Zahlungsverkehrsregisters
Selbstverstandlich mussen auch Methoden flir das Verwalten der Postfacher eingerichtet werden, beispielsweise zum Entfemen eriedigter Bankauftrlige, jedoch wird diese Funktionalitlit hier nicht naher behandelt.
342
12 Fallstudie: Zahlungsverkehr zwischen Banken
12.3 Kontoinformationen
1m Zusammenhang mit der Ubermittlung von Auftragen an Banken ist es meistens notwendig, eine Information tiber ein Konto zu erstellen, das mit der Abwicklung des Auftrages in Zusammenhang steht. Eine Kontoinformation soli dazu dienen, einer Bank die Identiftzierung eines Kontos zu ermoglichen, sie enthliltjedoch keine direkt Referenz auf ein Konto. Kontoinformationen treten als Kotnponenten von Inlandstiberweisungen auf. Sie sind ebenso wie diese Entitliten, die durch die Erweiterung des Modelles zusatzlich zu den bisherigen Entitaten betrachtet werden, ihre Einrichtung bedeutet jedoch keine Anderung bestehender Objektarten und daher keine Redefmition bestehender Klassen.
Object subclass: #Kontolnfo instanceVariableNames: 'biz ktonr name status' classVariableNames: " poolDictionaries: " category: 'Konten'
Programm 12-4 Die Klasse Kontolnfo
Aus Programm 12-4 ist ersichtlich, daB eine Auspragung der Klasse KontoInfo eine Bankleitzahl, eine Kontonummer und einen Namen sowie eine Statusangabe zugeordnet hat. Wenn ein Bankkunde seiner Bank den Auftrag gibt, von einem seiner Konten auf ein Konto bei einer anderen Bank eine Uberweisung durchzufUhren, so muB er der Bank jene Informationen zur VerfUgung stellen, die notwendig sind, urn je eine Kontoinformation tiber das Auftraggeberkonto und tiber das Konto des Begtinstigten zu erstellen. Diese Kontoinformationen sind aus der Warte der jeweiligen Bank vorerst ungeprtift. Kann die Bank aufgrund der Kontoinformation ein Konto identiflZieren, so soli die Kontoinformation als gepriift bezeichnet werden. Programm 12-5 zeigt Methoden fur die direkte Erzeugung von Kontoinformationen und fUr die Ableitung einer Kontoinformation aus einem bestehenden Konto. Der Status der Kontoinformation wird abhlingig von der Qualitlit der Daten auf »gepruft" odeT »ungepriift" gesetzt.
12.4 Bankauftrage
343
Kontolnfo class methodsFor: 'instance creation'
newBLZ: eineBankleitzahl mitKontonummer: eineKontonummer undName: einName "Erzeugen einer vollstandigen Kontoinformation." "'self new biz: eineBankleitzahl; ktonr: eineKontonummer; name: einName; ungeprOft
(1)
newVonKonto: einKonto beiBank: eineBank "Erzeugen einer Kontoinformation iiber das angegebene Konto." ... (self newBLZ: eineBank leitzahl mitKontonummer: einKonto kontoNummer undName: einKonto inhaber name copy) geprOft
(2)
(1) Eine direkt erzeugte Kontoinformation ist ungepriift.Die Methode Kontoinfo»ungeprOft setzt den Status der Kontoinformation auf#ungeprOft. (2) Eine von einem Konto abgeieitete Kontoinformation ist gepriift. Die Methode Kontolnfo>>geprOft setzt den Status der Kontoinformation auf #geprOft.
Programm 12-5 Erzeugung einer Kontoinformation
12.4 Bankauftrige 1m Geschaftsverkehr zwischen Banken werden Bankauftrage verschiedenster Art auftreten, von denen Inlandsiiberweisungen nur eine spezielle Form sind. Aus diesem Grunde wird eine abstrakte Klasse Bankauftrag und eine konkrete Subklasse InlandsOberweisung eingerichtet, wie das bereits durch den Entwurf (Abbildung 12-2) vorgegeben ist. Aus Programm 12-6 ist zu entnehmen, daB eine neu erzeugte Auspragung der Klasse Bankauftrag in Obereinstimmung mit den Angaben in Abbildung 12-3 den Zustand #erstellt aufweist. Zustandsanderungen eines Bankauftrages werden durch Methoden vermerkt, die der Methode Bankauftrag»erstellt (Programm 12-7) entsprechen.
344
12 Fallstudie: Zahlungsverkehr zwischen Banken
Object subclass: #Bankauftrag instanceVariableNames: 'banr text status datum' classVariableNames: " poolDictionaries: " category: 'Banken' Bankauftrag class methodsFor: 'instance creation'
new 1\
super new initialize
Bankauftrag methodsFor: 'initialize'
initialize "Ein neu erzeugter Bankauftrag befindet sich im Status #erstellt" self datum: (Date today). self erstellt
Programm 12-6 Defmition und Erzeugung von Bankauftragen
Bankauftrag methodsFor: 'status'
erstellt "Vermerken, daB der Bankauftrag erstellt ist." self status: #erstellt
(1)
(1) Analoge Methoden sind fUr die anderen Zustiinde einer InlandsiibelWeisung
einzurichten.
Programm 12-7 Zustandsiinderungen von Bankauftragen
12.4.1 Inlandsuberweisungen Die Definition der Klasse InlandsOberweisung sowie eine Methode zur Erzeugung von initialisierten Auspragungen ist in Programm 12-8 enthalten. Es sei darauf hingewiesen, daB bei der Erzeugung einer initialisierten Inlandsuberweisung nicht nur die in der Klasse definierten Instanzvariablen initialisiert werden, sondern daB auch die Initialisierungsmethode der Superklasse (Programm 12-6) aktiviert wird, sodaB die Inlandsuberweisung in den Zustand #erstellt versetzt wird und durch Belegung der Instanzvariablen datum einen "Eingangsdatumsstempel" erhalt.
12.4 Bankauftrage
345
Bankauftrag subclass: #lnlandOberweisung instanceVariableNames: 'kontoVon kontoNach betrag valutaDatum ' classVariableNames: " poolDictionaries: " category: 'Banken' InlandsOberweisung class methodsFor: 'instance creation'
newBetrag: einBetrag vonKonto: vonKontolnfo nachKonto: nachKontolnfo mitDatum: einDatum undText: einText "Erzeugen einer Inlandsiiberweisung mit aktuellem Datum." "super new betrag: einBetrag; valutaDatum: einDatum; text: ein Text.
"Einrichtung der Beziehungen gemaB Abbildung 12-2." kontoVon: vonKontolnfo; kontoNach: nachKontolnfo;
Programm 12-8 Defmition und Erzeugung von Inlandsiiberweisungen
12.4.2 Der Lebenszyklus einer Inlandsiiberweisung Diese Fa11studie soll zum AniaB genommen werden, das Augenmerk auf den den Lebenszyklus eines Objektes zu richten. Zu diesem Zwecke werden die einzeIn en Bearbeitungsschritte und die daraus resultierenden Zustande eines Uberweisungsauftrages genauer betrachtet. Abbildung 12-3 zeigt ein Zustandsdiagramm fUr eine Iniandsiiberweisung, dessen Darstellungsform der in der OMT-Methode [33] verwendeten Notation entspricht. Ein Zustandsdiagramm ist ein gerichteter Graph, dessen Knoten die moglichen Zustande von Objekten einer bestimmten Art reprasentieren und dessen Kanten die zulassigen Zustandsiibergange angeben. Die Beschriftung der Kanten entspricht den Ereignissen, welche die Zustandsanderungen ausiosen. Jeder Weg durch den Zustandsgraphen von einem Anfangszustand zu einem Endzustand enspricht einem zulassigen Lebensweg eines Objektes. Die Zustandsgeschichte des Objektes wird durch die Foige der auf dem Lebensweg durchIaufenen Knoten beschrieben, wobei es moglich ist, daB ein Objekt mehrmais ein und denselben Zustand einnimmt. Die Foige der im Laufe des Lebens durchquerten Kanten gibt die Foige der (zustandsverandernden) Operationen an, die auf das Objekt angewendet wurden.
346
12 Fallstudie: Zahlungsverkehr zwischen Banken
Start kontrolliereA [Quellkonto existiert nicht]
korrigiere [mOglich] korrigiere [unmOglich]
prOfeA [Auftrag ungedecktl korrigiere [mOglich]
korrigiere [unmOglich]
kontrolliereE [Zielkonto existiert nicht]
korrigiere [unmOglich]
Stop2 '-------II~.
Abbildung 12-3 Zustandsdiagramm fur eine Inlandsiiberweisung
Wie aus dem Modell (Abbildung 12-3) zu entnehmen ist, befindet sich ein bei der Auftraggeberbank eingegangener Oberweisungsauftrag vorerst in einer unkontrollierten Form, die durch den Zustand #erstellt charakterisiert sein solI. Die Auftraggeberbank kontrolliert den Auftrag zuerst formal, das heiBt sie ste11t fest, ob das angesprochene Auftraggeberkonto existiert und ob die Bankleitzahl der Empfangerbank giiltig ist. Dieser Kontrollvorgang wird durch die Operation "kontrolliereA" bewirkt. Abhangig yom Ergebnis der Oberpriifung wird der Bankauftrag in den Zustand #kontrolliertA oder #undurchfOhrbarA
12.4 Bankauftriige
347
versetzt. (In den Bezeichnungen der Art #kontrolliertA oder #undurchfOhrbarA soIl der Buchstabe ,,~' daraufhinweisen, daB der Status sich auf das Auftraggeberkonto bezieht, analog weist "E" auf das Empfangerkonto hin.) Fur einen Bankauftrag, dessen Auftraggeberkonto nunmehr sichergestellt ist, wird in einem niichsten Schritt durch die Aktion "priifeA" festgestellt, ob die Uberweisung durch das Konto gedeckt ist (und selbstverstandlich auch, ob es sich im eine berechtigte Disposition handelt). Je nach dem Ergebnis dieser Uberpriifung gelangt der Bankauftrag in einen der beiden Zustande #geprOftA oder #nichtgedecktA. Bank methodsFor: 'auftragsprOfung-ausgang'
kontrolliereAus: einelnlandsuberweisung "Geschaftsmethode: Operation "kontrolliereA:' (Abbildung 12-3)."
I kontoNummer biz I
(einelnlandsOberweisung status = #erstellt) ifFalse: ["Dialog warn: 'Auftrag nicht kontrollierbar']. (1) kontoNummer := einelnlandsOberweisung kontoVon ktonr. biz := einelnlandsOberweisung kontoNach biz. (self hatKontoMitNummer: kontoNummer) & (self bankenService aktivService hatBankMitleitzahl: biz) (2) iITrue: [einelnlandsOberweisung kontoVon: (Kontolnfo newVonKonto: (self kontoMitNummer: kontoNummer) beiBank: self). (3) einelnlandsOberweisung kontrolliertAus] ifFalse: [einelnlandsOberweisung undurchfOhrbarAus] (4)
(1) Priifung der Vorbedingung: der Bankauftrag (einelnlandsOberweisung) muB sich im Zustand #erstellt befinden. (2) Formale Priifung des Bankauftrages. (3) Nachdem die ungepriifte Kontoinforrnation durch eine vom Auftraggeberkonto abgeleitete und daher iiberpriifte ersetzt wurde, wechselt der Bankauftrag in den Zustand #kontrolliertAus. (4) Der Bankauftrag wechselt in den Zustand #undurchfOhrbarAus.
Programm 12-9 Formale Kontrolle eines Bankauftrages Jeder im Zustand #geprOftA befmdliche Bankauftrag kann nun durch die Operation "beauftrage" weiterverarbeitet werden, wobei einerseits der zu uberweisende Betrag vom Auftraggeberkonto abgebucht und andererseits der Bankauftrag an die Empfangerbank ubermittelt wird. Ein Bankauftrag im
348
12 Fallstudie: Zahlungsverkehr zwischen Banken
Zustand #undurchfOhrbarA oder #nichtgedecktA kann durch eine Korrektur entweder in einen weiterverarbeitbaren Zustand iiberflihrt oder unerledigt ad acta gelegt werden. Diese Korrekturaktionen werden jedoch im Beispiel nicht weiter verfolgt. Der nunmehr bei der Empfangerbank eingelangte Bankauftrag wird durch diese mit Hilfe der Operation "kontrolliereE" beziiglich des Empfangerkontos iiberpriift und gelangt dadurch entweder in den Zustand #erledigt (die Gutschrift auf das Empfangerkonto muG also erfolgt sein) oder in den Zustand #undurchfOhrbarE, flir den wieder eine Korrekturmoglichkeit bestehen soIl. Die im Zustandsdiagramm geforderten Operation en "kontrolliereA" und "priifeA" werden durch die in den Programmen 12-9 und 12-10 angegeben Methoden realsiert. Der jeweilige Zustand einer Auspragung der Klasse InlandOberweisung spiegelt sich in der Belegung der Instanzvariablen status wider. Da in Smalltalk Zustande bevorzugt durch Symbole dargestellt werden, wurde deren Literalform bereits zur Benennung der Zustande im Zustandsdiagramm verwendet. Bank methodsFor: 'auftragsprOfung-ausgang'
priifeOeckungFiir: einelnlandsiiberweisung "Geschiflsmethode: Operation ..prOteI!:' {Abbildung 12-3)."
I konto I
=
(einelnlandsOberweisung status #kontrolliertAus) ifFalse: [ADialog warn: 'Auftrag nicht auf Deckung prOfbar']. (1) konto := self kontoMitNummer: (einelnlandsOberweisung kontoVon ktonr). (konto hatDeckungFOr: einelnlandsOberweisung betrag) (2) ifTrue: [konto auszahlung: einelnlandsOberweisung betrag mitText: 'Oberweisung' undValutaDatum: einelnlandsOberweisung valutaDatum. einelnlandsOberweisung geprOftAus] (3) ifFalse: [einelnlandsOberweisung nichtgedecktAus] (4)
(1) Prtifung der Vorbedingung des Bankauftrages (einelnlandsOberweisung).
(2) Inhaitliche Prtifung des Bankauftrages (3) Nach der Abbuchung des Betrages yom Konto geiangt der Bankauftrag in den Zustand #geprOftAus. (4) Der Bankauftrag wechselt in den Zustand #nichtgedecktAus.
Programm 12-10 Inhalt1iche Kontrolle eines Bankauftrages
349
12.5 Erweiterung der Klasse Bank
12.5 Erweiterung der Klasse Bank Banken miissen nunmehr die Fahigkeit haben, Bankauftrage entgegenzunehmen, diese zu iiberpriifen und an andere Banken weiterzuleiten. Aus diesem Grunde ist es notwendig, im Modell einer Bank und in der bisherigen Implementierung Erweiterungen vorzunehmen, welche die Verwaltung und Bearbeitung von Bankauftragen ermoglichen. In Abbildung 12-4 ist gezeigt, daB eine zusatzliche Mehrfachbeziehung zwischen einem Bankobjekt und Bankauftragen vorgesehen wird und zwar derart, daB eine Bank beliebig viele Bankauftrage verwalten kann, jeder Bankauftrag jedoch genau einer Bank zugeordnet ist.
Bank
biz name adresse konten kunden
Bankauftrag
O.. n auftrage (OrdColI)
-+
Modell 1 1 - - - - - - - - - - - - - - - - - - - - - - '
Abbildung 12-4 Erweiterung des Modelles einer Bank
RegistrierteBank subclass: #Bank instanceVariableNames: 'konten ktoZahler kunden kndZahler auftrage' classVariableNames: " poolDictionaries: " category: 'Banken' Bank methodsFor: 'initialize' initialize
"Modell: Vorbereitung der Beziehung Bank (O..n) -> Bankauftrag."
auftrage .- OrderedCollectjon new
Programm 12-11 Erweiterung der Klasse Bank
350
12 Fallstudie: Zahlungsverkehr zwischen Banken
Programm 12-11 faBt jene Anderungen der Defmition der Klasse Bank und der Initialisierung von Bankkobjekten zusammen, die sich aus dieser Modellerweiterung ergeben. Bank methodsFor: 'auftragsverwaltung' "Entgegennehmen eines 8ankauftrages." auftr~ge
add: (einBankauftrag banr: (self
n~chsteBanr))
(1)
(1) Die Vergabe der Nummern (Benutzeridentifikation) von Bankauftragen wird hier nicht nilier betrachtet.
Programm 12-12 EinfUgen eines Auftrages in den Auftragsbestand Programm 12-12 zeigt die Methode Bank»akzeptiereAuftrag, welche einen weiteren Bankauftrag in den Auftragsbestand aufnimmt und dies em dabei gleichzeitig eine Kennzeichnung zuordnet.
12.6 Bearbeitung von Bankauftragen Geschaftsmethoden fUr das formale Kontrollieren und inhalt1iche Priifen von Inlandsiiberweisungen wurden bereits in den Programmen 12-9 und 12-10 vorgestellt. In den folgenden Programmen werden noch exemplarisch einige Methoden gezeigt, welche mehrere Bankauftrage einer Bearbeitung unterziehen. Programm 12-13 zeigt zwei Geschaftsmethoden zur Bearbeitung von Bankauftragen innerhalb der Auftraggeberbank. Die Methode Bank»kontrolliereAlieKundenlnlandsOberweisungen extrahiert aus dem Bestand der Bankauftriige jene Inlandsiiberweisungen, die sich im Zustand #erstellt befinden und fUhrt fUr diese die formale Kontrolle durch, indem sie die in Programm 12-9 angegebene Methode Bank»kontrolliereAus: mit jedem der extrahierten Bankauftriige als Argument aktiviert. Die ebenfalls in Programm 12-13 angefUhrte Methode Bank»ObermittleAlieKundenlnlandsOberweisungen erledigt in iihnlicher Weise die Ubermittlung aller bereits gepriiften Bankauftrage an die jeweils angesprochenen Bank. Zu dies em Zwecke werden zuerst aIle gepriiften Auftriige ausgewahlt und sodann mit Hilfe der Methode BankenService>>registriereAuftrag:fUrBLZ: (Programm 12-3) in das entsprechende Postfach einfUgt.
12.6 Bearbeitung von Bankauftrligen
351
Einige Methoden zur Auswahl von Bankauftrligen sind exemplarisch in den Progammen 12-14 und 12-15 zusammengestellt. Bank methodsFor: 'auftragsabwicklung-ausgang'
kontrolliereAlleKundenlnlandsiiberweisungen "Geschiftsmethode: Kontrollieren aller erstellten InlandsOberweisungen von Kunden." self alleErstelltenKundenlnlandsOberweisungen do: [:auftrag I self kontrolliereAus: auftrag ]
(1)
beauftrageUndObermittleAlieKundenlnlandsiiberweisungen "Geschiftsmethode: Obermitteln aller gepruften InlandsOberweisungen von Kunden."
I bks I bks := self bankenService aktivService. self alieGeprOftenKundenlnlandsOberweisungen do: [:auftrag I bks registriereAuftrag: (auftrag beauftragt) copy fOrBLZ: (auftrag kontoNach biz) ]
(2)
(1) Auswahl jener Inlandsiiberweisungsauftrage, die im Zustand #erstellt sind.
(2) Aile Inlandsiiberweisungsauftrage, die sich im Zustand #geprOftAus befinden, wechseln in den Zustand #beauftragt, sodann wird eine Kopie davon in das Postfach der jeweiligen Empfangerbank geschrieben.
Programm 12-13 Beispiele fur Methoden des Geschliftsbetriebes
Bank methodsFor: 'zahlungsverkehr-extern'
alieKundenAuftriigeDerArt: eineKiasse "Antworte mit allen vorliegenden Kundenauftragen. die von der angegebenen Art sind." A
self
auftr~ge
select: [:auftrag I (auftrag isMemberOf: eineKlasse))
aliePartnerAuftriigeDerArt: eineKIasse "Einholen aller Auftrage. die im Posteingang des Bankenservice vorliegen und von der angegebenen Art (eineKlasse) sind." A
(self bankenService aktivService auftr~geFOrBLZ: (self leitzahl)) select: [:auftrag I (auftrag isMemberOf: eineKlasse))
Programm 12-14 Zugriff auf Kunden- und Partnerauftriige
352
12 Fallstudie: Zahlungsverkehr zwischen Banken
Bank methodsFor: 'zahlungsverkehr-extern'
alleErstelltenKundenlnlandsuberweisungen "Einholen aller vorliegenden Inlandsuberweisungen, die noch nicht bearbeitet sind." 1\
self alleKundenlnlandsOberweisungenMitStatus: #erstellt
alieKundenlnlandsuberweisungenMitStatus: aSymbol "Einholen aller Inlandsuberweisungen mit vorgegebenem Status." 1\
self alleKundenlnlandsOberweisungen select: [:auftrag I auftrag status =
aSymbol]
alieKundenlnlandsuberweisungen "Antworte mit einer Sammlung (OrderedCollection) aller vorliegender Kunden Inlandsanweisungen" 1\
self alleKundenAuftrageDerArt: InlandOberweisung
Programm 12-15 Eine Methodenfamilie zur Auswahl von Kundenauftragen
Das Zusammenwirken dieser Methoden solI an Hand eines Beispieles demonstriert werden, welches in seiner Wirkung dem im Programm 10-22 gezeigten Geschaftsfall aquivalent ist. In beiden Fallen wird ein Betrag von ATS 100,-- von dem Konto Nummer 1 auf das Konto Nummer 3 der Testbank iiberwiesen. Wahrend es sich im vorher gezeigten Fall urn eine bankinterne Uberweisung gehandelt hat, wird nunmehr die Uberweisung auf dem Wege eines Bankauftrages zwischen Bankinstituten durchgefUhrt. Der Einfachheit halber wird jedoch angenommen, daB die Testbank mit der Bankleitzahl 100 sowohl die Rolle der Auftraggeberbank als auch die Rolle der Empflingerbank spielt. Programm 12-16 zeigt die Ausfiihrung des erwahnten Geschaftsfalles in einem Arbeitsbereich. Nach der AusfUhrung des angegebenen Ausdruckes hat die Bank hat nun in ihrem Auftragsbestand eine Inlandsiiberweisung, die sich im Zustand #erstellt befmdet. Die Vorgange zur Kontrolle und Beabeitung dieses Auftrages sind in Programm 12-17 angegeben. Durch die dort gezeigten Aktionen nimmt der Bankauftrag entsprechend den Vorgaben in Abbildung 12-3 hintereinander die Zustande #kontrolliertA, #geprQftA und schlieBlich #beauftragt an, sodann wird eine Kopie des Auftrages in das Postfach der Empfangerbank abgelegt. Man erkennt, daB der zu iiberweisende Betrag bereits vom Auftraggeberkonto abgebucht wurde t.
353
12.6 Bearbeitung von Bankauftriigen
Workspace
"Geschiftsfall: Eingang einer Inlandiiberweisung." Bank testBank erstellelnlandAuftrag: 100 asMoney vonKtoNr: 1 anEmpf~nger: 'Meier' nachKtoNr: 3 beiBank: 100 mitText: 'Zahlung' undDatum: Date today. <dolt>
"Feststellen der vorliegenden Inlandsiiberweisungen von eigenen Kunden." Bank testBank alleKundenlnlandsOberweisungen
<printlt> OrderedCollection (InlandOberweisung (erstellt» Programm 12-16 Eingang einer Inlandsiiberweisung
Workspace
"Geschiftsfall: Bearbeiten aller hier: (der einzigen) ausgehenden Inlandsiiberweisungen (vergleiche Abbildung 12-3)."
Bank testBank kontrolliereAlleKundenlnlandsOberweisungen; prOfeAlleKundenlnlandsOberweisungen; beauftrageUndObermittleAlleKundenlnlandsOberweisungen
<dolt>
"Oberpriifen der Bankauftrage im Auftragsbestand." Bank testBank alleKundenlnlandsOberweisungen
<printlt> OrderedColiection (InlandOberweisung (beauftragt»
"Feststellen des letzten Umsatzes des Auftraggeberkontos." (Bank testBank kontoMitNummer: 1)
ums~tze
last
<printlt> Kontoumsatz: ATS 100.00 CR Programm 12-17 Kontrolle und Weiterleitung einer Inlandsiiberweisung t In der Fallstudie wird darauf verzichtet, eine Gegenbuchung auf einem Sammeikonto zu berucksichtigen.
354
12 Falistudie: Zahlungsverkehr zwischen Banken
Programm 12-18 zeigt die Geschliftsaktionen der Testbank in der Rolle der Empfangerbank. Sie findet den Auftrag in ihrem Postfach vor und fiihrt die Kontrolle und Erledigung durch, ebenfalls in Ubereinstimmung mit den in Abbildung 12-3 beschriebenen Zustandsfolgen. Eine Endiiberpriifung ergibt, daB die Inlandsiiberweisung erledigt ist und der Betrag von ATS 100.-- auf dem Empfangerkonto mit dem Zahlungsgrund nZahlung von Maier Franz" gutgeschrieben ist.
Workspace
"OberprOfen der Inlandsuberweisungen im Postfach." Bank testBank alleBeauftragtenPartnerlnlandsOberweisungen
<printlt>
OrderedColiection (InlandOberweisung (beauftragt»
"Geschiftsfall: Bearbeiten aller (hier: des einzigen) im Postfach eingegengenen Bankauftrage (vergleiche Abbildung 12-3)." Bank testBank kontrolliereAllePartnerlnlandsOberweisungen; erledigeAllePartnerlnlandsOberweisungen <dolt>
"Oberprufen der Inlandsuberweisungen im Postfach." Bank testBank aliePartnerlnlandsOberweisungen
<printlt> OrderedColiection (InlandOberweisung (erledigt» "Feststellen des letzten Umsatzes des Empfangerkontos."
(Bank testBank kontoMitNummer: 3)
ums~tze
<printlt> Kontoumsatz: ATS 100.00
last
(Bank testBank kontoMitNummer: 3) ums~tze last buchungsText
<printlt> 'Zahlung yon Maier Franz'
Programm 12-18 Kontrolle und Erledigung einer Inlandsiiberweisung
13 Persistenz von Objekten
Es wurde bereits mehrfach daraufhingewiesen, daB die Existenz von Objekten an einen Objektraum gebunden ist. In einem laufenden Smalltalk-System wird der aktive Objektraum von der virtuellen Maschine in dem yom Betriebssystem zur Verftigung gestellten Arbeitsspeicher verwaltet. Dabei ist es jederzeit moglich, ein Abbild (image) des momentanen Zustandes des Objektraumes in einer Datei abzulegen. Eine solche Image-Datei kann als "eingefrorener" Objektraum angesehen werden, der wieder "aufgetaut" und zum Leben erweckt werden kann. Durch das Laden einer Image-Datei wird der Objektraum rekonstruiert, sodaB aBe Objekte in genau demselben Zustand existieren, den sie beim Speichern des Abbildes innehatten. Objekte werden wahrend der Ausftihrung einer Methode in den aktiven Objektraum hineingeboren, ihre Existenz ist so lange sichergestellt, wie sie von der Wurzel des Objektnetzes aus erreicht werden konnen. SoU die Existenz eines Objekts den Zeitraum der Ausflihrung jener Methode iiberdauern, in der es erzeugt wurde, so muB es noch innerhalb dieser Methode durch Zuweisung an eine nichttemporare Variable von einem anderen Objekt aus erreichbar gemacht werden. Seine Existenz ist dann von der Existenz jenes Objektes abhiingig, dem es durch eine Referenz zugeordnet ist. Die einzigen Objekte, deren Existenz auf jeden Fall sichergestellt ist, sind die a-priori im Objektraum existierenden Objekte. Von diesen ist das Systemverzeichnis narnens Smalltalk wieder das einzige, das andere Objekte referenzieren kann, es bildet somit die Wurzel des Objektnetzes aller nicht a-priori existierender Objekte. SoU ein Objekt unabhangig von der Existenz anderer Objekte im Objektraum verankert sein, so rouB es in das Systemverzeichnis eingetragen, mit anderen Worten, an eine glob ale Variable gebunden werden. Betrachtet man den ProzeB, der durch das Starten der virtuellen Maschine und das Laden einer Image-Datei entsteht, nicht als eigenen ProzeB irn Sinne des Betriebssystems, sondern als Fortsetzung eines nur temporar unterbrochenen Vorganges, so haben alle bisher betrachteten Objekte die Eigenschaft, daB
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
356
13 Persistenz von Objekten
ihre Existenz nur innerhalb jenes Prozesses giiltig ist, in welchem sie erzeugt wurden. Objekte mit dieser Eigenschaft werden transiente Objekte genannt. Objekte mit der Fahigkeit, ihre Existenz auch auBerhalb des sie erzeugenden Prozesses beizubehalten, werden als persistente Objekte bezeichnet. Die Persistenz von Objekten kann im wesentlichen auf zwei Arten realisiert werden: durch Kodierung von Objekten oder durch Erweiterung des Objektraumes. Durch Kodierung von Objekten werden Daten erzeugt, welche die Objekte vollstandig beschreiben. Diese Daten konnen auBerhalb des Objektraumes aufbewahrt und dazu verwendet werden, die kodierten Objekte in einem (moglicherweise anderen) Objektraum zu rekonstruieren. Die rekonstruierten Objekte sind Kopien ihrer Originale. Bei der Erweiterung des Objektraumes werden diesem temporar zusatzliche Bereiche angekoppelt, welche die Eigenschaft haben, die in ihnen befindlichen Objekte unabhiingig von ihrem ErzeugungsprozeB persistent zu verwalten. Diese Erweiterungsbereiche werden durch objektorientierte Datenbanken (Objektbanken) realisiert, die An- und Abkopplung wird durch einen Transaktionsmechanismus gesteuert. Urn diese Techniken an einfachen Beispielen demonstrieren zu konnen, wird eine Klasse PersistDemo festgelegt, deren Auspragungen die Instanzvariablen name und partner tragen, fUr die namenskonforme Zugriffsmethoden vereinbart sind. Zusatzlich ist eine Klasseninstanzvariable persistState vereinbart, welche dazu vorgesehen ist, in den Beispielen die persistente Form von Objekten zu referenzieren.
Workspace "(1) Vereinbaren von globalen Variablen." #(PD1 PD2 PD3) do: [:ell Smalltalk at: el put: nil]. <dolt>
"(2) Erzeugen von transienten Objekten." PD1 := PersistDemo new name: 'pd1'. PD2 := PersistDemo new name: 'pd2'. PD1 partner: PD2.
<dolt>
"(*) Testen persistenter Objekte, siehe Programme 13-3, 13-4 und 13-7 bis 13-10."
"(n) Aufraumen." #(PD1 PD2 PD3) do: [:ell Smalltalk removeKey: el].<dolt>
Programm 13-1 Testumgebung fUr persistente Objekte
357
13.1 Kodierung von Objekten durch Ausdriicke
Programm 13-1 enthiilt einen Arbeitsbereich, in dem Vorbereitungen fUr das Untersuchen von persistenten Objekten getrotfen sind. Hier werden unter Punkt (1) globale Variable vereinbart und unter Punkt (2) derart mit Objekten belegt, daB die in Abbildung 13-1 veranschaulichte Situation hergestellt wird, welche jeweils die Ausgangssituation fUr die folgenden Beispiele bildet. Die fUr die einzelnen Verfahren spezifischen Methoden werden unter Punkt (*) eingefUgt.
PD10
•
'pd1' partnerQ
PD2
'pd2'
..
... partnerO
PD30
I KOR ~
AbbUdung 13-1 Transiente Objekte im Objektraum
13.1
Kodierung von Objekten durch Ausdrlicke
In der Klasse Object ist eine Methode Object>>storeOn: aStream definiert, welche mit Hilfe systemnaher Methoden einen Smalltalk-Ausdruck erzeugt und auf das Argument aStream schreibt, der bei seiner Evaluierung eine Rekonstruktion des Empflingers liefert. Die Methode Object»storeString greift auf Object»storeOn: zuriick und liefert als Ergebnis den Kodierungsausdruck in Form einer Zeichenkette. Diese Methoden sind in ihrem Aufbau und in ihrem Zusammenwirken lihnlich den "Druckausgabemethoden" Object»printOn: und Object»printString. In vielen Klassen wird die Methode Object»storeOn: redefiniert und durch eine spezifische Methode ersetzt. Dies ist fUr die Klasse PersistDemo in Programm 13-2 gezeigt. Man erkennt, daB diese Methode eine Zeichenkette auf das Argument schreibt, die einen in Klammern gesetzten Smalltalk-Ausdruck der Form: (PersistDemo new name: ; partner: <partner»
enthlilt, wobei an Stelle von und <partner> Ausdriicke gesetzt sind, welche den entsprechenden Namen und den entsprechenden Partner erzeu-
358
13 Persistenz von Objekten
gen. Diese Komponenten werden durch PersistDemo(Object»>store: gebildet, sodaB die Methode PersistDemo»storeOn: indirekt rekursiv aktiviert wird.
PersistDemo methodFor: 'printing' storeOn: aStream "Erzeugen eines Ausdruckes fUr die Rekonstruktion des Empfangers."
aStream nextPutAlI: '(" self class storeString, 'new', , name: " self name storeString, '; partner: ' self partner storeString, ')' Programm 13-2 Die Methode PersistDemo»storeOn: Programm 13-3 zeigt das Ergebnis der Kodierung einer einfachen Objektstruktur durch einen Smalltalk-Ausdruck, der bei seiner Evaluation das urspriingliche Objekt rekonstruiert.
Workspace "Position (*) von Programm 13-1."
PD1 storeString <printlf> '(PersistDemo new name: "pd1 "; partner: (PersistDemo new name: "pd2"; partner: nil»' Programm 13-3 Ein Smalltalk-Ausdruck zur Reprasentation eines Objektes Programm 13-4 gibt ein Beispiel fUr die Vorgangsweise, ein Objekt in kodierter Form in eine Datei zu schreiben und aus dieser wieder zu rekonstruieren. Zu dies em Zweck wird unter Punkt (3) der Klasseninstanzvariablen persistState eine Auspragung der Klasse ExternalReadWriteStream zugewiesen, welche mit einer Datei verbunden ist. Unter Punkt (4) wird die Zeichenkette, welche Ergebnis der Evaluation des Ausdruckes PD1 storeString ist (vergleiche Programm 13-3), auf die Datei geschrieben. Unter Punkt (5) wird diese Datei zuriickgesetzt, die gespeicherte Zeichenkette wird durch die Botschaft contents ausgelesen und dem Kompiler zur Evaluation iibergeben. Das durch die Evaluation erzeugte Objekt wird sodann an die globale Variable PD3 gebunden.
359
13.1 Kodierung von Objekten durch Ausdriicke
SchlieBt man nach Punkt (4) die Datei und fiihrt die folgenden Schritte nach dem Offnen der Datei mit einem anderen Smalltalk-Image durch, so entspricht dies einem Transport der in der Datei "abgelegten" Objekte in einen anderen Objektraum.
Workspace "Position (*) von Programm 13-1." "(3) Initialisieren des persistent kodierten Objektes." PersistDemo persistState: (Filename named: 'c:\temp\perstest.str') newReadWriteStream.
"(4) Speich ern der kodierten Form von PDt" PersistDemo persistState nextPutAlI: PD1 storeString.
"(5) Zuweisung der Rekonstruktion von PD1 an PD3." PersistDemo persistState reset. PD3 := Compiler evaluate: (PersistDemo persistState contents).
"(6) Untersuchen von PD1 und PD3." PD1 = PD3. PD1 partner =
PD3 partner.
<printlt> false <printlt> false
Programm 13-4 Beispiel zur Kodierung durch Smalltalk-Ausdriicke Die Evaluation der unter Punkt (6) angefUhrten Ausdriicke bestiitigt, daB im Objektraum nunmehr die in Abbildung 13-2 gezeigte Situation vorliegt.
PD10 PD2 PD3
•
'pd1' partner
0
'pd2'
...... partner 0
7
'pd2'
'pd1' partner
.. partner 0
0 I
KOR
~
AbbUdung 13-2 Situation nach der Rekonstruktion eines kodierten Objektes
360
13 Persistenz von Objekten
13.2 Kodierung von Objekten durch literale Felder Eine andere, allerdings nicht fUr alle Objektarten anwendbare Form der Kodierung ist die Repriisentation von Objekten durch Felder mit literalen Elementen. Urn ein Objekt als Literalfeld reprasentieren und aus diesem wieder rekonstruieren zu konnen, miissen folgende Methoden vorgesehen werden: 1. eine Methode IiteralArrayEncoding, welche ein gegebenes Objekt in Form
eines Literalfeldes darstellt und 2. eine Klassenmethode decodeFromLiteralArray: anArray, welche aus der Literalfelddarstellung ein entsprechendes Objekt rekonstruiert. In Programm 13-5 ist die bereits im System vorgesehene Methode decodeAsLiteralArray gezeigt, welche ein Feld als Literalarray interpretiert, das ein Objekt reprasentiert. Dabei wird vorausgesetzt, daB dieses Feld bestimmte Voraussetzungen erfUllt, auf welche in Programm 13-5 durch Kommentare hingewiesen wird.
KlassenBrowser
Array methodsFor: 'converting' decodeAsUteralArray
"Erzeugen eines Objektes auf der Basis jener Informationen, die durch den Empfanger gegeben sind."
I theClass I theClass := self at: 1. 1\ (Smalltalk at: theClass) decodeFromLiteralArray: self
(1) (2)
(1) Hier wird vorausgesetzt, daB die erste Komponente des zu interpretierenden Feid die zu instanzierende Klasse ist. Die anderen Komponenten des Empfangers beinhalten Informationen, die zur Rekonstruktion des kodierten Objektes notwendig sind.
(2) Zuslitziich wird vorausgesetzt, daB diese Kiasse die Methode decodeFromLiteralArray: impiementiert hat
Programm 13-5 Rekonstruktion eines Objektes aus einem Literalfeld
13.2 Kodierung von Objekten durch literale Felder
361
Die Vorgangsweise solI wieder an Hand des gewlihlten Beispieles demonstriert werden. Die in der Klasse PersistDemo notwendigen Erganzungen sind in Programm 13-6 zusammengefaBt.
PersistDemo methodsFor: 'converting'
literalArrayEncoding
"Erzeugen eines den Empfanger charakterisierenden literalen Feldes." "Array with: #PersistDemo with: self name IiteralArrayEncoding with: self partner IiteralArrayEncoding PersistDemo class methodsFor: 'instance creation'
decodeFromUteralArray: anArray
"Erzeugen einer Auspragung nach der Beschreibung durch das Argument." "self new name: (anArray at: 2) decodeAsLiteralArray; partner: (anArray at: 3) decodeAsLiteralArray
Programm 13-6 Vorbereitung fUr die Literalfeld-Kodierung
Programm 13-7 zeigt das Ergebnis der Literalfeldkodierung der bereits im vorangehenden Beispiel verwendeten Objektstruktur.
Workspace
"Position (*) von Programm 13-1." PD1 IiteralArrayEncoding
<print/t>
#{#PersistDemo 'pd1' #(#PersistDemo 'pd2' nil»
Programm 13-7 Ein Literalfeld zur Reprlisentation eines Objektes In Programm 13-8 wird die Wirkung der Literalfeldkodierung an demselben Beispiel demonstriert, das bereits im vorangehenden Abschnitt verwendet wurde, jedoch wurde auf eine Zwischenspeicherung in einer Datei verzichtet. Wie man aus dem Vergleich des urspriinglichen Objektes mit dem Ergebnis
362
13 Persistenz von Objekten
der Rekonstruktion erkennen kann, sind beide Vorgangsweisen in ihrer Wirkung gleich, in beiden Hillen wird die in Abbildung 13-2 gezeigte Situation im Objektraum erhalten.
Workspace "Position (*) yon Programm 13-1." "(3) Kodieren yon POt" PersistDemo persistState: PD1 IiteralArrayEncoding. "(4) Zuweisung der Rekonstruktion yon PD1 an PD3 .. "
PD3 := PersistDemo persistState decodeAsLiteralArray. "(5) Untersuchen yon PD1 und PD3."
PD1 = PD3. PD1 partner =
PD3 partner.
<printlt> false <printlt> false
Programm 13-8 Beispiel zur Literalfeld-Kodierung Das Verfahren der Kodierung von Objekten durch literale Felder unterscheidet sich von dem Verfahren der Kodierung durch Ausdriicke vor aHem dadurch, daB zur Dekodierung kein Kompiler benotigt wird. Es kann daher auch in Applikationen angewendet werden kann, deren Klassenhierarchie die Kompilerklassen nicht mehr enthalten. Die Darstellung von Objekten durch literale Felder ist besonders im Falle groBer Objekte kurzer. Es konnen jedoch nur solche Objekte durch literale Felder spezifiziert werden, die direkt oder indirekt aus Objekten mit einer Literaldarstellung aufgebaut sind. Mit Hilfe des VisualWorks-Werkzeuges »Canvas Tool" gestaltete BenutzerschnittsteHen werden inklusive der Fenster, in denen sie dargestellt werden, durch literalfeldkodierte Objekte spezifiziert, welche bei Bedarf durch einen »user interface builder" dekodiert werden. Bei beiden Verfahren ist die kodierte Form eine Zeichenkette, die auf Dateien abgelegt und auch editiert werden kann.
13.3 Das Binary Object Streaming Service Die in den vorangehenden Abschnitten vorgesteHten Verfahren zur Kodierung von Objekten durch Zeichenketten, aus denen diese Objekte wieder rekonstruiert werden konnen, haben einige gravierende Nachteile.
13.3 Das Binary Object Streaming Service
363
Die wesentlichsten Nachteile resultieren aus der Tatsache, daB bei der Kodierung und nachfolgenden Rekonstruktion die Objektidentitiit nicht erhalten bleibt, die rekonstruierten Objekte sind nur Kopien der Originale. Objektkomponenten, die von dem zu kodierenden Objekt auf mehreren Wegen zu erreichen sind, werden mehrfach kodiert und daher auch mehrfach rekonstruiert, wobei charakteristische Merkmale der Objektstruktur veriorengehen. Zirkulare Strukturen konnen diesen Verfahren iiberhaupt nicht unterworfen werden, da bereits der Kodierungsvorgang immer wieder ein und dasselbe Objekt kodiert und daher nicht abbricht T. AuBerdem ist es nicht moglich, die Tiefe des Kodierungs- und Reproduktionsvorganges durch gezieltes Abschneiden von Teilstrukturen zu beeinfiussen, was besonders bei groBen und komplexen Objekten ein Nachteil ist. Diese Nachteile werden von einem Verfahren zum Speichem und Transportieren von Objekten vermieden, das als binary object streaming service (BOSS) bezeichnet wird.
Workspace "Position (*) von Programm 13-1." "(3) Initialisieren des BOSS-Files." PersistDemo persistState: BinaryObjectStorage onNew: (Filename named: 'c:\temp\perstest.bos') readWriteStream. "(4) Kodieren von PDt"
PersistDemo persistState nextPut: PD1. "(5) Lesen des geschriebenen PD1 in PD3."
PersistDemo persistState reset. PD3 := PersistDemo persistState next. "(6) Untersuchen von PD1 und PD3."
PD1 = PD3. PD1 partner = PD2
<printlt> true <printlt> true
Programm 13-9 Beispiel zur BOSS-Kodierung Von diesem Verfahren sei nur erwahnt, daB es bei der Kodierung von Objekten die Identitat bereits behandelter Teilobjekte registriert und fUr den t Dieser Fall tritt beispielsweise ein, wenn in Programm 13-1 am Ende von Punk! (2) die Anweisung PD2 partner: PD1 hinzugefdgt wird, sodaS POI und PD2 gegenseitig gekoppelt sind und eine zirkulare Struktur bilden.
364
13 Persistenz von Objekten
Fall, daB bei der Durchquerung des Objektnetzes ein bereits besuchtes Objekt nochmals angetroffen wird, dieses nicht mehr kodiert, sondern durch einen Verweis auf die friihere Kodierung ersetzt. Auf diese Weise konnen auch . Objektnetze mit wiederkehrenden Komponenten und zirkulare Strukturen bearbeitet werden, die Objektidentitaten bleiben innerhalb des kodierten Objektnetzes und auch hinsichtlich der im Objektraum verbleibenden transienten Origin ale erhalten. Die Wirkungsweise von BOSS wird in Programm 13-9 an Hand desselben Beispieles demonstriert, das auch fUr die anderen Verfahren herangezogen wurde. Aus den unter Punkt (6) erhaltenen Ergebnissen wird deutlich, daB das urspriingliche, durch die glob ale Variable PD1 bezeichnete Objekt und das an die Variable PD3 gebundene rekonstruierte Objekt identisch sind, dasselbe gilt fUr die jeweiligen Partnerobjekte. Die nunmehr im Objektraum vorhandene Situation ist in Abbildung 13-3 veranschaulicht.
PD1 Or----I~~( 'pd1'
'pd2' )!----ttpartner
0
PD2 PD3
Abbildung 13-3 Situation nach der Rekonstruktion eines "gebossten" Objektes
13.4 Kodierung von Objekten durch Tupel relationaler Datenbanken Die Anbindung eines Smalltalk-Objektraumes an eine relationale Datenbank ist ebenfalls als ein Verfahren zur Persistenthaltung von Objekten durch Kodierung zu sehen. Bei diesem Verfahren wird eine Abbildung zwischen Smalltalk-Klassen und Relationenschemata einer relationalen Datenbank verwaltet, sodaB es moglich wird, eine Zuordnung zwischen Objekten im Objektraum und Tupeln von Relationen der Datenbank herzustellen. Durch Fremdschliissel realisierte Beziehungen zwischen Datenbankobjekten konnen dabei in entsprechende
13.5 Objektraumerweiterung durch objektorientierte Datenbanken
365
Objektreferenzen im Objektraum iiberfUhrt werden, wodurch eine weitgehende Korrespondenz zwischen der relationalen Struktur einer Datenbank und der Objektstruktur in einem Smalltalk-Objektraum erreicht werden kann. Da oft der Fall vorliegt, daB groBe Datenmengen bereits in einer Datenbank verwaltet werden, kommt der Anbindung eines Smalltalk-Systems an relationale Datenbanken in der Praxis eine besondere Bedeutung zu. Ein zuslitzlicher Vorteil der Persistenthaltung von Objekten in Datenbanken gegeniiber der kodierter Speicherung in Dateien ist auch darin zu sehen, daB die von einem Datenbanksystem gebotenen Mechanismen fUr die Erhaltung der Datenkonsistenz und fUr die Kontrolle des Zugriffsberechtigung genutzt werden konnen. In Visualworks\Smalltalk® sind unter dem Begriff "ObjectLens" zahlreiche Klassen und vielfliltige Werkzeuge vorgesehen, welche die Anbindung von relationalen Datenbanken unterstiitzen.
13.5 Objektraumerweiterung durch objektorientierte Datenbanken Durch die bisher erlliuterten Verfahren konnen Objekte dadurch persistent gehalten werden, daB sie in Zeichenketten oder Binlirdaten abgebildet und in dieser Form auf Dateien geschrieben werden, urn zu einem spliteren Zeitpunkt in dem selben oder einem anderen Objektraum rekonstruiert werden zu konnen. Diese Verfahren leiden aus einer konzeptionellen Sicht darunter, das sie den "Paradigmenbruch" zwischen einer datenorientierten und einer objektorientierten Denkweise aufrechterhalten, sie eignen sich in erster Linie zum Archivieren von Objekten, nicht aber fUr eine persistente Verwaltung von Objekten, die im Rahmen einer Applikation standigen Anderungen unterworfen sind. Zur Verwaltung von persistenten Objekten, die in dynamischen Umgebungen konsistent gehalten und mehreren Benutzem zur Verfugung stehen sollen, ist es notwendig, objektorientierte Datenbanken einzusetzen. Objektorientierte Datenbanken vereinigen Konzepte objektorientierter Systeme mit Konzepten von Datenbanksystemen wie Sekundlirspeicherverwaltung, Transaktionskontrolle, Abfragesprachen und Sicherung der Daten vor Zerstorung und Schutz vor unberechtigtem Zugriff [20). Objektorientierte Datenbanken konnen sowohl als Erweiterung eines Datenbanksystems urn objektorientierte Konzepte oder auch als Erweiterung eines objektortientierten Systems urn Datenbankfunktionalitlit betrachtet werden.
366
13 Persistenz von Objekten
Von dieser Sichtweise ausgehend kann man annehmen, daB ein objektorientiertes Datenbanksystem einen oder mehrere persistente konzeptionelle Objektriiume zur VerfUgung stellt, die dynamisch an transiente Objektriiume an- und abgekoppelt werden konnen. 1m angekoppelten Zustand, der wiihrend einer Datenbank-Transaktion aufrecht erhalten wird, verschwindet der Unterschied zwischen dem transienten und dem persistenten Objektraum, so daB die Navigation ungehindert moglich ist. AuBerhalb einer Transaktion sind die im persistenten Objektraum befindlichen Objekte unsichtbar. Ein persistenter Objektraum kann zu jedem Zeitpunkt mit hochstens einem transienten Objektraum gekoppelt sein, umgekehrt konnen gleichzeitig mehrere persistente Objektriiume durch offene Transaktionen an ein und denselben transienten Objektraum gebunden werden. Um die Verwendung einer objektorientierten Datenbank und die Handhabung persistenter Objekte an einem konkreten Beispiel demonstrieren zu konnen, wird ObjectStore® Smalltalk t verwendet [8], [31]. Das Ziel ist dabei, einen Eindruck von der Funktionsweise eines objektorientierten Datenbanksystems zu vermitteln, nicht aber, die Eigenschaften und Anwedungsmoglichkeiten von ObjectS tore Smalltalk im Detail zu beschreiben. ObjectStore Smalltalk fUgt sich nahtlos in Visualworks\Smalltalk® ein und erweitert dieses um die Fiihigkeiten, Objekte persistent zu halten und durch einen Transaktionsmechanismus geschiitzt anzusprechen. Es erlaubt, in einer verteilten Umgebung mehrere Datenbank-Server einzurichten und mehrere Anwendungs-Klienten mit ihren Dienstieistungen zu versorgen. Die persistenten technischen Objektriiume werden in Form von ObjectStore-Dateien auf Sekundiirspeichern verwaltet, ihre Kopplung an einen von einer virtuellen Smalltalk-Maschine kontrollierten transienten Objektraum erfolgt automatisch und fUr den Benutzer voIlkommen transparent. Die zu einer Datenbanktransaktion zusammengefaBten Anweisungen bilden den Inhalt eines Blockes. Bei der Aktivierung eines Blockes durch die Methode OSTransaction class»transact: aBlockO wird die Transaktion gestartet. Wird der Block durch AusfUhrung seiner letzten Anweisung vollstiindig abgearbeitet, so werden aIle innerhalb der Transaktion durchgefUhrten Anderungen persistenter Objekte endgiiltig permanent gemacht, die Transaktion wird erfolgreich abgeschlossen (commit). Wird der Blocke veriassen, bevor alle Anweisungen abgearbeitet sind, so werden aIle bereits durchgeftihrten Anderungen persistenter Objekte riickgiingig gemacht, die Transaktion wird abgebrochen (abort). Es ist also sichergesteIlt, daB die zu einer Transaktion zusammengefaBten Aktionen entweder vollstiindig oder gar nicht durchgeftihrt werden.
t
Die in diesem Kapitel enthaltenen Beispiele wurden mit Hilfe von ObjectStore® Smalltalk, Release 1.0 (Juli 1995) in Verbindung mit VisualWorks\Smalltalk® Release 2.0 erstellt.
13.5 Objektraumerweiterung durch objektorientierte Datenbanken
367
In der Folge wird durch Weiterfiihrung des laufenden Beispieles das Zusammenwirken zwischen transienten und in einer ObjektStore-Datenbank persistenten Objekten gezeigt. Programm 13-10 ruft den Zustand im Objektraum nochmals in Erinnerung, der im laufenden Beispiel bereits unter Punkt (*) von Programm 13-1 erreicht wurde und den Ausgangszustand fUr die FortfUhrung des Beispieles bildet.
Workspace "Position (*) von Programm 13-1, jedoch seien die Variablen PD1 bis PD6 erklart." "(3) Ansprechen der Objekte PD1 und PD2 im transienten Objektraum." P01
P02 PO 1 partner P01 class
<printlt> <printlt> <printlt> <printlt>
PersistDemo pd1 PersistDemo pd2 PersistDemo pd2
(1)
PersistDemo
(1) Die Merthode PersistDemo»printOn: Iiefert den Klassennamen und den Namen (name) des Empflingers.
Programm 13-10 Beispiel zur Speicherung in ObjectS tore
Dieser Zustand ist in Abbildung 13-1 und in Abbildung 13-9 links oben wiedergegeben. Fast UberflUssig erscheint die Feststellung, daB die Objekte, welche von den globalen Variablen P01 und P02 referenziert werden, Ausprligungen der Klasse PersistDemo sind und durch die Methode Behavior (PersistOemo class»>new im transienten Objektraum erzeugt wurden. Programm 13-11 zeigt eine Fortsetzung des Beispieles, in der unter Punkt (3) der persistente Objektraum durch Erzeugen einer ObjectStore-Datenbank eingerichtet wird. Unter Punkt (4) wird eine Transaktion gestartet, wodurch der persistente Objektraum an den tranisienten Objektraum angekoppelt wird. Innerhalb der Transaktion werden zwei weitere Ausprligungen der Klasse PersistOemo erzeugt und den globalen Variablen P03 und P04 zugewiesen. Allerdings werden diese beiden Instanzen durch die Methode Behavior (PersistOemo class»>basicNewln: anObjectMemoryManager direkt im persistenten Objektraum erzeugt. Das Argument dieser Methode ist die durch den Ausdruck PersistDemo persistState ansprechbare ObjectS tore-
368
13 Persistenz von Objekten
Datenbank, eine Auspriigung der Klasse OSDatabase, die selbst eine Subklasse von ObjectMemoryManager ist. Die Erzeugung der neuen Objekte und ihre Positionierung im persistenten Objektraum erfolgt letztendlich durch die ObjectStore-Primitivmethode OSDatabase»new: aClass.
Workspace
"Fortsetzung von Programm 13·10." "(3) Erzeugen einer ObjectStore·Datenbank." PersistDemo persistState: (OSDataBase create: 'c:\temp\perstest.ost' overWrite: true).
"(4) Erzeugen zweier Instanzen der Klasse PersistDemo in der Datenbank." OSTransaction transact: [PD3 := PersistDemo basicNewln : PersistDemo persistState. PD3 name: 'pd3'. PD4 := PersistDemo basicNewln: PersistDemo persistState. PD4 name: 'pd4'. PD3 partner: PD4] . <dolt>
"(5) Ansprechen von PD3 auBerhalb einer Transaktion." <printlf> Unhandled exception: There is no transaction in progress.
PD3
PD3 class
<printlf> OSGeneratedReference
"(6) Inspektion von PD3 bei offengehaltener Transaktion." OSTransaction transact: [PD3 inspect. PD3 halt].
<dolt> "Siehe."
Programm 13-11 Erzeugen von Objekten im persistenten Objektraum
Abbildung 13·4 zeigt die Situation im Objektraum, wie sie unmittelbar vor dem AbschlieBen der unter Punkt (4) angefiihrten Datenbanktransaktion besteht. Wiihrend einer begonnenen und noch nicht abgeschlossenen Transaktion ist die "Schleuse" zwischen dem transienten und dem persistenten Objektraum ge6ffnet, die beiden Teile bilden hinsichtlich der Sichtbarkeit und der Erreichbarkeit der Objekte einen einzigen Objektraum. Man erkennt das zum Beispiel daran, daB die globalen Variablen PD3 und PD4, welche als Eintragungen im Systemverzeichnis Sma"talk im transienten Objektraum existieren, die eben neu erzeugten und im persistenten Objekt-
13.5 Objektraumerweiterung durch objektorientierte Datenbanken
369
raum befmdlichen Objekte mit den Namen 'pd3' und 'pd4' referenzieren. DaB diese Objekte tatsachlich tiber diese globalen Varoablen ansprechbar sind, zeigt sich auch darin, daB die Zuordnung von Objekt PD4 als Partner von PD3 durchgefUhrt wurde, was auch aus der in Abbildung 13-6 gezeigten Inspektion des Objektes PD3 deutlich wird.
PD1 PD2
PD3 PD4 PersistDemo persistState
~
O-------~.LCJ
KOR (transient)
~----I.-'"
KOR (persistent)
Abbildung 13-4 Situation im Objektraum wiihrend einer Transaktion
Wird die Transaktion beendet, so entsteht die in Abbildung 13-5 skizzierte Situation im Objektraum. Die Schleuse zwischen dem transienten und persistenten Objektraum ist geschlossen und die im persistenten Objektraum befindlichen Objekte sind nicht mehr ansprechbar. Der in Programm 13-11 unter Punkt (5) gezeigte Versuch, das an die Variable PD3 gebundene Objekt anzusprechen und seine Druckdarstellung anzufordern, endet mit der Fehlermeldung: Unhandled exception: There is no transaction in progress. Dieser Meldung ist zu entnehmen, daB zwar eine Referenz auf ein Objekt besteht, daB das Objekt allerdings auBerhalb einer Transaktion nicht erreichbar ist.
13 Persistenz von Objekten
370
PDi C't-'-
-II>
PD2(), .....,.
'",'-'-,
'
PD3C~~R@) ' PD4C}
.. ~"
PersistDemo llnOSGDS':} persfstState (J~~ "-.,,,./ '......... '
...".,
KOR (transient) ,~~~~~~~~~~~~~~~~~"~,~"""''''~'''~, .." .. ,, .........................................................,
Abbildung 13-5 Situation im Objektraum auBerhalb einer Transaktion
Abbildung 13-6 Inspektion eines persistenten Objektes
.... .
13.5 Objektraumerweiterung durch objektorientierte Datenbanken
371
Ein Test auf die Klassenzugehorigkeit des durch P03 bezeichneten Objektes ergibt, daB es sich urn eine Auspragung der Klasse OSGeneratedReference handelt, also urn einen im transienten Objektraum befindlichen Stellvertreter fUr das im persistenten Objektraum existierende Objekt. Diese Situation ist in Abbildung 13-5 veranschaulicht. Wird eine Transaktion fur diesen persistenten Objektraum gestartet, wie das unter Punkt (6) fUr die bereits erwahnte Inspektion des Objektes 'pd3' geschehen ist, so werden die Objektraume wieder gekoppeit und alle Referenzen verfUgbar gemacht. Die Durchftihrung der Inspektion des im persistenten Objektraum befmdlichen Objektes bedarf einer Erlauterung. Wie man aus dem unter Punkt (6) von Programm 13-11 gezeigten Code erkennen kann, wird durch OSTransaction»transact: eine Transaktion gestartet, die genau zwei Ausdrucke enthiilt. Der erste Ausdruck veranlaBt das Offnen eines Inspektors fUr das zu untersuchende persistente Objekt, der zweite Ausdruck setzt einen Haltepunkt, durch den der laufende ProzeB so lange angehalten wird, bis durch eine Interaktion (Proceed oder Terminate im Meldungsfenster) seine Sperre aufgehoben wird.
Workspace "Fortsetzung von Programm 13-11." "(7) Erzeugen von PD5und PD6 im transienten Objektraum."
P05 := PersistOemo new name: 'pd5'. P06 := PersistOemo new name: 'pd6'.
<dolt> <dolt>
"(8) Einbringen von PD5 unter seinem Namen ('pd5') in den persistenten Objektraum."
PersistOemo makePersistentNamed: P05.
<dolt>
"(9) Ansprechen von PD5 auBerhalb einer Transaktion."
P05 <printlt> Unhand/ed exception: A message was sent to an object that has been migrated to a database P06
<printlt> PersistDemo pel6
"(10) Ansprechen von PD5 innerhalb einer Transaktion."
PersistOemo printPersistentNamed: 'pd5' <printlt> 'PersistDemo pd5 (persistent)' P05 class
<printlt> OSMigrationTombstone
Programm 13-12 Benannte persistente Objekte
372
13 Persistenz von Objekten
In Abbildung 13-6 ist gezeigt, daB die Inspektion des persistenten Objektes bei angehaltenem ProzeB und damit vor AbschluB der Transaktion durchgeftihrt werden kann. In der Abbildung des Inspektors ist auf der linken Seite die Instanzvariable partner angewahlt, im rechten Teil ist die Druckdarstellung des Partnerobjektes ersichtlich. So lange die Transaktion nicht durch Fortsetzen des angehaltenen Prozesses abgeschlossen wird, konnen alle yom inspizierten Objekt aus erreichbaren Objekte im persistenten Objektraum untersucht werden. Werden nach Beendigung der Transaktion im Inspektorfenster Instanzvariable des zu untersuchenden Objekes angewahlt, so kommt es wieder zu der bereits erwahnten Fehlermeldung: Unhandled exception: There is no transaction in progress. Das Beispiel wird in Programm 13-12 unter Punkt (7) mit der Erzeugung von zwei weiteren Auspragungen der Klasse PersistDemo fortgesetzt. Da diese Objekte im transienten Objektraum erzeugt werden, bedarf es keiner Datenbanktransaktion. Die nunmehr im Objektraum vorliegende Situation ist in Abbildung 13-7 veranschaulicht.
PD1(
'poi'
1
PD2{ /
/ /
partner
"
~//~--. PD3 ()~anbSGanRei) /
partnarO
PD4 ()-+C~OSG-;~~ '-' . '. .' ~ /""
....--~, 'pdo'
PDSO
~/
partner
C)
PD60~--~// PersistDemo
persistState
O-+C anO~Goe ). -
Abbildung 13-7 Situation im transienten und permanenten Objektraum In einem nachsten Schritt solI das Objekt PD5 in den permanenten Objektraum eingebracht werden und zwar so, daB es in dessen "Inhaltsverzeichnis" eingetragen wird und tiber dieses wieder aufgefunden werden kann.
13.5 Objektraumerweiterung durch objektorientierte Datenbanken
373
Das Inhaltsverzeichnis einer ObjectStore-Datenbank versteht das Protokoll eines Verzeichnisses (Dictionary) und kann wlillrend einer Transaktion unter dem Namen der Datenbank erreicht werden. Es ermoglicht das direkte Ansprechen von Objekten im persistenten Objektraum tiber ihnen zugeordnete (persistente) Namen. Die in Programm 13-13 angegebene Methode PersistDemo»makePersistentNamed: anObject otTnet eine Transaktion auf die dieser Klasse fUr Testzwecke zugeordnete Datenbank (PersistDemo persistState), tragt das als Argument vorgegebene Objekt unter seinem Namen (anObject name) in das Inhaltsverzeichnis der Datenbank ein und transferiert dieses damit in den persistenten Objektraum, falls es sich dort noch nicht befindet. PersistDemo class methodeFor: 'persistence' makePersistentNamed: anObject "Eintragen des Argumentes unter seinem Namen in die Datenbank."
OSTransaction transact: [PersistDemo persistState at: anObject name put: anObject] printPersistentNamed: aNa me "Eroffnen eine Transaktion und liefern die Druckdarstellung des persistenten Objektes. welches uber seinen Namen erreichbar sein muB."
I resultl
OSTransaction transact: [result := (PersistDemo persistState at: aName) printString]. Aresult, ' (persistent)'
Programm 13-13 Ansprechen von persistenten Objekten tiber Namen Die Transferierung des Objektes PD5 in den permanenten Objektraum als durch seinen Namen 'pd5' benanntes Datenbankobjekt erfolgt unter Punkt (8) des Beispieles (Programm 13-12). Die im Objektraum unmittelbar vor dem AbschluB der Transaktion vorliegende Situation ist in Abbildung 13-8 gezeigt. Man erkennt daraus, daB das Objekt PD5 unter seinem Namen 'pd5' in das Inhaltsverzeichnis des permanenten Objektraumes eingetragen ist, es kann also innerhalb einer Transaktion indirekt durch den Ausdruck PersistDemo persistState at: 'pd5' erreicht werden. 1m Unterschied dazu konnen die Objekte mit den namen 'pd3' und 'pd4' tiber die globalen Variablen PD3 und PD4 direkt angesprochen werden. Diese aus dem transienten in den persistenten Objektraum weisenden Referenzen werden durch eine Instanz von OSReference realisiert und sind ebenfalls nur innerhalb einer Transaktion benutzbar.
374
13 Persistenz von Objekten
Das Objekt mit dem Namen 'pd5' ist nach seiner Transferierung (migration) in den persistenten Objektraum nieht mehr tiber die Variable PD5 ansprechbar, was aus der in Punkt (9) gezeigten Fehlermeldung hervorgeht. Ein Beispiel fUr das Ansprechen dieses Objektes innerhalb einer Transaktion tiber seinen Datenbanknamen ist unter Punkt (10) gezeigt, in welchem die Methode PersistentDemo»printPersistentNamed: (Programm 13-13) aktiviert wird. Hier wird auch dureh einen Test auf KIassenzugehorigkeit festgestellt, daB das von PD5 nunmehr referenzierte Objekt eine Instanz der KIasse OSMigrationTombstone ist. Tritt eine Ausprligung dieser Klasse als Zielobjekt einer Zuordnung auf, dann ist das ein Zeiehen daflir, daB ein friiheres Zielobjekt in einen persistenten Objektraum tibersiedelt wurde, wlihrend das Quellobjekt im transienten Objektraum verblieben ist. Instanzen einer Unterklasse von OSTombstone haben kein Protokoll und reagieren mit einer Fehlermeldung, wenn sie in irgendeiner Weise angesprochen werden.
PDi
Or-----4
i'---
--i
partner PD2 ~I o
t
.
'p02'
~artnerq
PDS (j
'-
/"
/'
/ //"
'i!i¢~$i;R&C/ 'po6.' '-~ --~
PD4~r--~~.~
••
parlnerQ
/
PD50 ~_I
Of-------I
PDS PerslstDemo
persistState
KOR (transient)
KOR (persistent)
Abbildung 13-8 Situation im Objektraum wlihrend einer Transaktion Wird in einer im transient en Objektraum bestehenden Zuordnung eines Zielobjektes zu einem Trligerobjekt das Zielobjekt persistent gemacht, nieht jedoch das Trligerobjekt, so bedarf es einer Regelung, durch was fUr ein Objekt
13.5 Objektraumerweiterung durch objektorientierte Datenbanken
375
das nunmehr im transienten Objektraum abhanden gekommene Zielobjekt in dieser Zuordnung zu ersetzen ist. Diese Regelung erfolgt durch Vorgabe einer Verhaltensweise (migration policy), die entweder fUr aile Instanzen einer Klasse oder auch fur ein einzelnes Objekt gel ten kann. Die allgemein vorgegebene Verhaltensweise (gekennzeichnet durch 4I'migrateTombstone) ist das Ersetzen eines persistent gewordenen Objektes durch eine Instanz von OSTombstone. Eine andere von mehreren Moglichkeiten ware, als Verhaltensweise festzulegen, daB Zielobjekte durch Referenzen in den persistenten Objektraum, also durch Auspragungen der Klasse OSGeneratedReference, zu ersetzen sind um damit die direkte Erreichbarkeit des Zielobjektes innerhalb einer Transaktion zu gewahrieisten. Hatte man im gegebenen Beispiel vor der Durchfuhrung von Punkt (8) die Anweisung PersistOemo migrationPolicy: #migrateReference ausgeftihrt, so ware das Objekt mit dem Namen 'pd5' nach der Transferierung in den persistenten Objektraum auf die gleiche Weise innerhalb einer Transaktion direkt erreichbar wie die Objekte mit Namen 'pd3' und 'pd4'. Workspace "Fortsetzung von Programm 13-12." "(11) pd5 wird innerhalb einer Transaktion angesprochen und erhiilt pd6 als Partner zugeordnet."
OSTransaction transact: [(PersistDemo persistState at: 'pd5') partner: P06] "(12) pd6 ist durch Migration persistent geworden und kann nicht mehr durch den Namen PD6 angesprochen werden."
P06 <printlt> Unhand/eel exception: A message was sent to an object that has been migrateel to a database P06 class
<printlt> OSMigrationTombstone
Programm 13-14 Migration von Objekten in den persistenten Objektraum Nunmehr wird in dem laufenden Beispiel ein Schritt we iter gegangen und dem persistenten Objekt mit Namen 'pd5' als Partner das transiente Objekt P06 zugeordnet, was selbstverstandlich nur innerhalb einer Transaktion moglich ist. Der daftir auszuftihrende Code ist in Programm 13-14 unter Punkt (11) angegeben. Innerhalb der Transaktion wird das Objekt fiber seinen Datenbanknamen 'pd5' im Inhaltsverzeichnis des persistenten Objektraumes aufgesucht und diesem das durch die globale Variable P06 referenzierte Objekt als
376
13 Persistenz von Objekten
Partner zugewiesen. Der dadurch entstandene Zustand im Objektraum ist in Abbildung 13-9 veranschaulicht. Man erkennt, daB das Objekt mit Namen 'pd6' in den persistenten Objektraum "gezogen" wurde und daB die Variable PD6 nunmehr ebenso wie PD5 eine Instanz der Klasse OSMigrationTombstone referenziert. Wahrend also die bisher im persistenten Objektraum angesiedelten Objekte bewuBt in dies en eingebracht wurden, sei es, daB sie direkt dort erzeugt wurden ('pd3' und 'pd4') oder durch eine Eintragung in das Inhaltsverzeichnis in dies en transferiert wurden (,pd5'), ist das Objekt namens 'pd6' implizit dadurch persistent geworden, daB es als Zielobjekt einem bereits persistenten Tragerobjekt zugeordnet wurde. Auch diese Vorgangsweise ist nicht unabanderlich vorgegeben, sondern hangt ebenfalls von der gewahlten Regelung fUr die Objektmigration abo Die bisher erwahnten Strategien (#migrateTombstone und #migrateReference) der Objektmigration verlangen beide, daB ein einem persistenten Tragerobjekt zugeordnetes transientes Zielobjekt bei der Beendigung der Transaktion in den persistenten Objektraum nachfolgen muB.
/ /
PD3 PD4 PD5C~%I'''' PD6C~llml
Abbildung 13-9 Objekte im Objektraum auBerhalb einer Transaktion
13.5 Objektraumerweiterung dureh objektorientierte Datenbanken
377
Beispielsweise bewirkt die Strategie #migrateClone, daB eine Kopie des transienten Zielobjektes persistent gemaeht wird, wahrend das Original im transienten Objektraum verbleibt. Diese Vorgangsweise ist besonders im Falle von Attributzuordnungen angebraeht, da dabei nur der "Wert" des Objektes, nieht aber seine Identitat von Bedeutung ist. Als weiteres Beispiel sei die Strategie #nilReference erwahnt. Ein Objekt, das einzeln oder fUr alle Auspragungen seiner Klasse dieser Vorgangsweise unterworfen ist, wird als Zielobjekt einer Zuordnung nieht persistent gemaeht, wenn sein Tragerobjekt persistent wird, es verbleibt vielmehr im transienten Objektraum und wird in der Datenbank dureh nil ersetzt. Ais AbsehluB des laufenden Beispieles ist in Abbildung 13-10 die nunmehr erreiehte Situation im Objektraum gezeigt, wie sie sieh bei einer geoffneten Transaktion darstellt. Ein Vergieieh der Abbildungen 13-9 und 13-10 verdeutlieht den Unterschied zwischen getrennten Objektraumen auBerhalb einer Transaktion und gekoppelten Objektraumen innerhalb einer Transaktion.
PD2\.. partner
0
PD3 PD4 PD5
PersistDemo odb
- ~
KOR (transient)
---"
KOR (persistent)
Abbildung 13-10 Objekte im Objektraum wiihrend einer Transaktion
378
13 Persistenz von Objekten
13.6 Aufgaben Aufgabe 13.1 Kunden und Konten als persistente Objekte Man andere die Fallstudie fiber den Betrieb von Banken derart ab, daB sowohl das Kundenverzeichnis als auch das Kontenverzeichnis in je einer ObjektStore-Datenbank persistent gehalten wird.
14 Erweiterte Konzepte und Mechanismen
Die in den bisherigen Kapiteln gezeigten Vorgangsweisen und behandelten Beispiele haben fast ausschlieBlich direkt auf grundlegenden Strukturen und Mechanismen von Smalltalk zuruckgegriffen. Zwar wurden ZusHinde und Verhalten von Objekten in mehreren Ebenen des konzeptionellen Objektraumes mit unterschiedlicher Granularitat betrachtet, jedoch bedeuten diese Ebenen nur verschieden starke Abstraktionen, auf denen im wesentlichen dieselben Basismechanismen wirken. Als Beispiel sei auf die in Kapitel 4 behandelte Realisierung von Sammelobjekten erinnert. Auf einer tieferen Ebene erkennt man die Details der einem Behalterobjekt zugrundeliegenden Struktur und der entsprechenden Zugriffsmethod en, wiihrend auf Basisebene das Protokoll fur das Einfiigen, Aufsuchen und Entfernen von Elementen im Blickpunkt steht. Auf jeder Ebene manifestiert sich aber derselbe Mechanismus: urn ein Element in den Behalter einzufUgen, ist dieser als Empfanger anzusprechen und ihm das einzufUgende Objekt als Parameter einer entsprechenden Botschaft bekanntzugeben. Falls der Empfanger die Botschaft versteht, wird er diese ausfuhren und ein Ruckgabeobjekt an den Sender ubermitteln. In einer anderen Hinsicht zeigt das Beispiel allerdings bereits eine Lockerung eines grundlegenden Konzeptes, niimlich des Konzeptes, daB die interne Struktur eines Objektes eindeutig und unabanderlich bei dessen Erzeugung festgelegt wird. 1m Falle von Behliltern mit variablen Fassungsvermogen wird der Eindruck vermittelt, daB die innere Struktur eines Objektes, die sich durch die Anzahl seiner Instanzvariablen ausdruckt, wiihrend der Objektlebenszeit verlindert werden kann. In diesem Abschnitt sollen nun einige abgeleitete Konzepte gezeigt werden, die auf den Basiskonzepten aufbauen, jedoch auf einer hoheren Betrachtungsebene zuslitzliche Sichtweisen anbieten. Die erste dieser Konzepterweiterungen bezieht sich auf einen Mechanismus der Benachrichtigung von Objekten uber eingetretene Ereignisse. Dieser als Abhiing;gkeitsmechan;smus (dependency mechanism) bezeichnete und im Smalltalk-System intensiv eingesetzte Kommunikationsmechanismus durch-
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
380
14 Erweiterte Konzepte und Mechanismen
bricht scheinbar die Notwendigkeit, die Empflinger einer Botschaft direkt anzusprechen. Eine andere Erweiterung solI die Moglichkeit bieten, die Beziehung zwischen dem Sender und dem Empfanger einer Methode selektiv zu gestalten. Wahrend der Basismechanismus vorsieht, daB ein Objekt auf eine empfangene Botschaft unbedingt reagiert, falls es dazu iiberhaupt in der Lage ist, solI es bei der selektiven Sender-Empfanger-Beziehung moglich sein, daB der Empfanger seine Reaktion vom Sender abhangig macht. SchlieBlich werden noch Konzepte diskutiert, die es auf einer hoheren Ebene eriauben, die Struktur und das Verhalten von Objekten dynamisch zu verandern, sodaB Objekte wahrend ihrer Lebenszeit zusatzlich zu ihrer Basisfunktionalitat wechselnde Rollen annehmen konnen. Die systematische Einrichtung solcher und vieler anderer erweiterter Strukturen und Mechanismen fUhrt zu Entwurfsmustem (patterns) und Geriisten (frameworks) fUr Anwendungen, welche wiederverwendbare Architekturen und generelle Losungen fUr wiederholt auftretende Anforderungen und allgemein benotigte Dienste anbieten. Sie stellen Applikationsskelette dar, die noch durch anwendungsspezifische Details erganzt werden miissen [7], [16], [23], [29], [46].
14.1
Kommunikationsmechanismen
In der Realitat konnen Objekte auf verschiedene Weise untereinander in Kontakt treten, um sich gegenseitig Informationen zu iibermitteln. In den meisten Fallen liegt die Verantwortung fUr die Auswahl der anzusprechenden Objekte bei jenem Objekt, das Informationen an andere Objekte iibermitteln mochte. Dazu ist es notwendig, daB die Adressaten der zu iibermittelnden Information direkt bekannt sind oder auf einfache Weise festgestellt werden konnen, damit eine gezielte Kommunikation erfolgen kann. Ais Beispiel sei an die DurchfUhrung einer Oberweisung im Rahmen des Zahlungsverkehrs zwischen Banken erinnert. SoIl ein Geldbetrag von einer Bank auf ein Konto einer anderen Bank iiberwiesen werden, so ist es fUr die iiberweisende Bank notwendig, die empfangende Bank zu identifizieren und die Mitteilung iiber die Oberweisung an diese zu adressieren. Es gehort zu den Aufgaben einer Bank, die Partnerbank bei der DurchfUhrung des Geschaftsfalles gezielt zu kontaktieren. Ein anderer Fallliegt vor, wenn ein Objekt Informationen bereitstellt, an der andere Objekte moglicherweise interessiert sind, wobei es aber nicht zu den Aufgaben dieses Objektes gehOrt, eventuelle Informationsempfanger direkt zu kontaktieren. Es liegt somit in der Verantwortung der an der Infor-
14.1 Kommunikationsmechanismen
381
mation interessierten Objekte, sich urn die Information zu kiimmern, jedoch muB ein Verfahren vereinbart sein, das es einem Objekt erlaubt, auf eine veroffentlichte Information aufmerksam zu werden. In solchen Hillen soIl von ungezielter Kommunikation gesprochen werden. Fiir die Zwecke dieses Abschnittes werden Objekte, die andere Objekte iiber das Eintreten eines Ereignisses informieren, In/ormatoren und jene Objekte, die an dieser Information Interesse haben, In/ormanden genannt.
14.1.1 Gezielte Kommunikation zwischen Objekten Ein Objekt kann aile jene Objekte gezielt ansprechen, die in seinem Horizont liegen und daher namentlich bekannt sind. Weiterhin kann in der Logik der Methoden verankert sein, wie durch Befragen namentlich bekannter Objekte weitere Objekte lokalisiert werden konnen, sodaB diese ebenfalls gezielt ansprechbar werden. Bei der gezieiten Kommunikation erfolgt die Information eines Objektes iiber das Eintreten eines Ereignisses durch direkte Ubermittlung einer Nachricht, wobei der Informator Absender der Nachricht und der Informand deren Adressat ist. 1m einfachsten Fail wird die Benachrichtigung durch eine direkte Botschaftsiibermittlung von einem Sender an einen Empfanger reaIisiert, doch stehen Informatoren und Informanden in einer allgemeineren Beziehung als Sender und Empfanger. 1m erwahnten Beispiel der Ubermittlung eines Bankauftrages spielt die Auftraggeberbank die Rolle des Informators und die Auftragnehmerbank die des Informanden, ohne daB diese Objekte jemals in einer Sender-Empfanger-Beziehung stehen. Auf einer niedrigen Systemebene betrachtet ist die gezielte Kommunikation die einzige Mogiichkeit, Objekte anzusprechen, urn mit ihnen in Kommunikation treten zu konnen.
14.1.2 Ungezielte Kommunikation zwischen Objekten: der Abhangigkeitsmechanismus 1m Smalltalk-System ist ein Mechanismus integriert, der zwar auf der gezielten Kommunikation zwischen Objekten basiert, der jedoch bereits auf der Basisebene das Arbeiten mit ungezielter Kommunikation erlaubt. In der Folge wird dieses als Abhiingigkeitsmechanismus (dependency mechanism) bezeichnete Verfahren vorgestellt.
382
14 Erweiterte Konzepte und Mechanismen
Die Abhingigkeitsbeziehung Abbildung 14-1 enthalt eine symbolische Darstellung der Abhangigkeitsbeziehung zwischen zwei Objekten und zeigt deren Eigenschaften. Nach der in Smalltalk gebrauchlichen Ausducksweise ist der Informand das yom Informator abhiingige Objekt, es ist beim Informator als solches registriert. "Abhangigkeit" ist dabei so zu verstehen, daB der Informand die Moglichkeit hat, auf allgemeine Mitteilungen des Informators zu reagieren und sein Verhalten davon abhangig zu machen. In der Smalltalk-Literatur werden Informatoren meist als Model bezeichnet, weil der Abhangigkeitsmechanismus im Rahmen der Model-View-Controller-Architektur besondere Bedeutung hat.
O.. n > 0 .. ....iOj.~. Informator ................................................""".....n... dep Abbildung 14-1 Die Abhangigkeitsbeziehung Ein Informator kann beliebig viele Informanden zugeordnet haben, umgekehrt kann ein Informand bei belie big vielen Informatoren registriert sein. Jedes Objekt kann seine abhlingigen Objekte erreichen, diese kennen jedoch nicht die Objekte, von denen sie abhangig sind. Informanden, die tiber die Abhangigkeitsbeziehung mit einem Informator verbunden sind, werden in der Folge als abhangige Informanden bezeichnet.
Verwaltung der Abhingigkeitsbeziehung Prinzipiell kann jedes Objekt die Rolle eines Informators und eines Informanden spielen, da das entsprechende Verhalten in der Klasse Object eingerichtet ist und daher auf aIle Klassen vererbt wird. Ftir die Klasse Object ist eine Klassenvariable DependentsFields vereinbart, die ein Verzeichnis (eine Ausprligung von IdentityDictionary) verwaltet, welches fUr jeden Informator einen Eintrag enthlilt, tiber den ein Feld (Array) erreichbar ist, das die zugehorigen abhiingigen Informanden enthlilt. Diese Implementierung ist fUr einen gelegentliche Anwendung des Abhangigkeitsmechanismus ausreichend, nicht jedoch fUr einen intensiven Einsatz, etwa bei der Propagierung von A.nderungsinformationen zwischen Geschliftsobjekten (Domainobjekten, Models) und Applikationsobjekten (ApplicationModels), sowie den Objekten fUr deren visuelle Darstellung (Views). Eine effizientere Implementierung ist in der Klasse Model gegeben, so daB es gtinstig ist, Klassen, deren Ausprligungen als Informatoren im Sinne des
14.1 Kommunikationsmechanismen
383
Abhangigkeitsmeschnismus auftreten sollen, in der Klassenhierarchie unter Model zu positionieren. Auspragungen der Klasse Model und aller ihrer Unterklassen besitzen eine Instanzvariable dependents, welche die Sammlung der Informanden (eine Auspragung von DependentsColiection) referenziert. Der Zugriff auf diese Instanzvariable erfolgt durch die (nieht namenskonformen) Selektoren myDependents: und myDependents. In der Folge wird immer davon ausgegangen, daB Informatoren der Klasse Model oder einer ihrer Subklassen angehoren. Die Implementierung des Abhangigkeitsmechanismus in der Klasse Model bietet den besonderen Vorteil, daB mit dem Ende der Existenz des Informators auch seine abhangigen Informanden ihre Existenz veriieren, falls sie nicht noch von anderen Objekten referenziert werden. Abhangige Objekte eines Objektes, das nicht von Model erbt, sind tiber die Klassenvariable DependentsFields der Klasse Object stets erreichbar und mtissen daher explizit aus ihrer Abhangigkeit entlassen werden. Die Einrichtung einerAbhangigkeitsbeziehung zwischen zwei Objekten wird durch Ubermittlung der Botschaft add Dependent: anObject an den Informator vorgenommen, sie kann durch removeDependent: anObject wieder rtickgangig gemacht werden. KlassenBrowser
Object methodsFor: 'dependents access' add Dependent: anObject
"Festlegen der Abhangigkeitsbeziehung zwischen dem Empfanger als Informator und dem Argument (anObject) als Informand."
self myDependents: (self myDependents asDependentsWIth: anObject). l\anObject removeDependent: anObject
"Uisen der Abhangigkeitsbeziehung zwischen dem Empfanger als Informator und dem Argument (anObject) als Informand."
seH myDependents: (self myDependents asOependentsWrthout: anObject). l\anObject Programm 14-1 Administration der abhangigen Informanden Folgende Erlauterung moge zum leichteren Verstandnis der Vorgangsweise bei der Registrierung eines abhangigen Informanden fUr einen Informator dienen. In jedem Fall wird durch die Methode Object»addDependent: (vergleiche Programm 14-1) vorerst durch die Evaluation des Ausdruckes self
384
14 Erweiterte Konzepte und Meehanismen
myDependents die "Sammlung" der momentan registrierten Informanden festgestellt. Diese Sammlung kann jedoeh von untersehiedlieher Art sein, je naehdem, ob der Informator keinen, nur einen oder bereits mehrere Infomanden zugeordnet hat. KlassenBrowser
UndefinedObject methodsFor: 'dependents collection' asDependentsWith: aFirstlnfonnand
"Liefern des Argumentes als ersten zu registrierenden Informanden." A
aFirstlnformand
Object methodsFor: 'dependents collection' asDependentsWith: aSecondlnformand
"Erzeugen und Liefern einer Sammlung von Informanden. die genau den Empfanger und das Argument enthalt bei der Registrierung eines zweiten Informanden." A
DependentsCollection with: self with: aSecondlnformand
(1)
DependentsCollection methodsFor: 'accessing' asDependentsWith: aFurtherlnformand
"Erweitern der Informandensammlung urn das Argument bei der Registrierung eines n-ten Informanden. n > 2)." A
self copyWith: aFurtherlnformand
(1) DependentsColiection ist eine Subklasse von Array.
Programm 14-2 Die polymorphe Methode asDependentsWith: Wird ein Informator neu erzeugt, so ist seine Instanzvariable dependents nieht initialisiert, also mit nil belegt, was bedeutet, daB noeh kein Informand registriert ist. Beim ersten Registrierungsvorgang wird die Botsehaft asDependentsWith: einErsterlnformand von nil empfangen t, welches gem liB Programm 14-2 den Informanden zuriiekgibt, der sehlieBlieh bei der Evaluation des Ausdruekes self myDependents: der Instanzvariablen dependents zugewiesen wird. In diesem Zustand besteht die "Sammlung" der abhllngigen Objekte aus dem t
Da nil (die einzige) Auspriigung der Klasse UndefinedObject ist, wird die Methode UndefinedObject»asDependentsWith: ausgefiihrt.
14.1 Kommunikationsmechanismen
385
einzigen Informanden, der allerdings fUr sich selbst steht und nicht in einem Behlilterobjekt (etwa einer Ausprligung der Klasse DependentsCollection) eingesperrt ist. Die Registrierung eines zweiten Informanden erfolgt lihnlich, jedoch ist jetzt der Empfanger von asDependentsWith: einZweiterlnformand genau der erste Informand, der (falls er nicht nil ist) diese Methode von Object erbt, wodurch gemliB Programm 14-2 erstmals eine Ausprligung der Klasse DependentsColiection erzeugt und sowohl mit dem bereits registrierten ersten als auch mit dem zu registrierenden zweiten Informanden gefUllt wird, urn sodann der Instanzvariablen dependents zugeordnet zu werden. Erst beim HinzufUgen von zuslitzlichen abhlingigen Objekten wird die Methode DependentsColiection»asDependentsWith: einWeitererlnformand von einem Objekt der Klasse DependentsColiection ausgefUhrt, was bewirkt, daB die Sammlung der abhlingigen Objekte urn einen zuslitzlichen Informanden erweitert wird. t Die Kenntnis dieses hier im Detail erlliuterten Vorganges ist fUr die Verwendung der Abhlingigkeitsbeziehung nicht von Bedeutung, sie gibt jedoch einen Einblick in eine oft eingeschlagene Vorgangsweise. Eine Instanzvariable, durch die eine mehrwertige Zuordnung realisiert werden solI, wird im al1gemeinen Fall ein BehlHterobjekt tragen, welches die Partnerobjekte enthlilt. Diese Instanzvariable wird jedoch sehr verzogert initialisiert und erst dann mit einem Behlilterobjekt belegt, wenn mehrere Partnerobjekte vorliegen.
Wirkung der Abhangigkeitsbeziehung 1st zwischen zwei Objekten eine Abhlingigkeitsbeziehung eingerichtet, so kann der Informator seine abhlingigen Informanden auf folgende Weise tiber das Eintreten von Ereignissen informieren. Die Benachrichtigung von Informanden eines Informators tiber das Eintreten eines Ereignisses erfolgt dadurch, daB an den Informator die Botschaft changed:with: gesandt wird. Die Benennung dieser Botschaft und ihre Einordnung in die Methodenkategorie "changing" rtihrt daher, daB als Ereignisse meistens Zustandslinderungen des Informatorobjektes betrachtet werden, welches bei der Verlinderung seines Zustandes die Verlinderungsbotschaft an sich selbst schickt. Der erste Parameter (anAspectSymbol) solI eine Information tiber die Art des Ereignisses geben, etwa einen Hinweis auf den Aspekt des Informators, der sich gelindert hat. Durch den zweiten Parameter (aParameter) kann eine Zusatzinformation tibermittelt werden.
t
Man beachte jedoch, daB durch DependentsColfection(SequenceableColfection»>CopyWith: anObject nicht das bestehende Behiilterobjekt aufgefiillt wird, sondem ein neues Behiilterobjekt mit vergroBertem Fassungsvermogen erzeugt und entsprechend gefiillt wird.
386
14 Erweiterte Konzepte und Mechanismen
In Fiillen, in denen die Parameter irrelevant sind, konnen die in Programm 14-3 angefUhrten verkiirzten Methoden (convenience methods) mit den Selektoren changed: oder auch nur changed verwendet werden. Aus Programm 14-3 ist auch zu erkennen, daB diese Methoden dadurch reagieren, daB sie an die Sammlung der registrierten Informanden die Botschaft update: with : from: iibermitteln. Die ersten zwei Parameter (anAspectSymbol und aParameter) werden von der changed-Botschaft iibernommen und weitergeleitet, mit Hilfe des dritten Parameters gibt sich er Informator selbst zu erkennen und bietet dadurch den Informanden die Moglichkeit einer direkten Riickfrage. KlassenBrowser
Object methodsFor: 'changing' changed: anAspectSymbol with: aParameter
"Benachrichtigung der Informanden Ober das Eintreten eines durch die Argumente niiher charakterisierten Ereignisses."
self myDependents update: anAspectSymbol with: aParameter from: self changed: anAspectSymbol
self changed: anAspectSymbol with: nil changed
self changed: nil Programm 14-3 Benachrichtigung der Informanden (abhangigen Objekte) Programm 14-4 zeigt, daB Instanzen der Klasse DependentsCollection diese Methoden an aile ihre Elemente weiterleiten, welche sodann ihrerseits eine gleichnamige Methode ausfiihren. Durch die Festlegung einer solchen Methode in Object ist sichergestellt, daB sie von allen Objekten verstanden wird. Allerdings ist diese geerbte Methode wirkungslos und muB in den Unterklassen derart redefiniert werden, daB die gewiinschte Wirkung eintritt. Urn insgesamt eine Abhiingigkeitsbeziehung einzurichten und den damit verbundenen Kommunikationsmechanismus zur Wirkung zu bringen, sind folgende Aktionen notwendig:
1. In der Informatorklasse muB sichergestellt sein, daB beim Eintreten eines Ereignisses eine changed-Botschaft an das Informatorobjekt gesandt wird. 2. Fiir die abhangigen Informanden muB gewiihrleistet sein, daB sie die update-Botschaft verstehen und darauf entsprechend reagieren. 3. Die Abhangigkeitsbezienung zwischen den Informator- und Informandenobjekten muB etabliert werden.
14.1 Kommunikationsmechanismen
387
KlassenBrowser
Object methodsFor: 'updating' update: anAspectSymbol with: aParameter from: aSender
"self update: anAspectSymbol with: aParameter update: anAspectSymbol with: aParameter
"self update: anAspectSymbol update: anAspectSymbol
"1m allgemeinen wird nichts unternommen, Subklassen konnen das and ern."
DependentsCollection methodsFor: 'updating' update: anAspect with: aParameter from: anObject
"Direkte Verbreitung der Benachrichtigung an aile Informanden."
1 to: self size do: [:i
I
(self at: i) update: anAspect with: aParameter from: anObject] Programm 14-4 Die Methodenfamilie Object>>Update:with:from:
Es ist also wesentlich, daB beim Entwurf der Informatorklasse bereits klar ist, welche Aktionen Ereignisse auslosen, die fUr die abhlingigen Informanden von Interesse sind. Ebenso muB beim Entwurf der Informandenklasse klar sein, daB die Ausprligungen dieser Klasse die Rolle von abhlingigen Informanden spielen werden, also von anderen Objekten im Sinne des Abhlingigkeitsmechanismus abhangig sein werden, denn nur dann ist die Implementation von changed-Methoden erforderlich. Diese beiden Uberlegungen sind nicht voneinander unabhlingig, denn in den changed-Methoden der Informanden muB im allgemeinen auf die von den Informatorobjekten ausgesandten Symbole Riicksicht genommen werden. An einer spliteren Stelle wird gezeigt werden, welche Moglichkeiten es gibt, eine starkere Unabhlingigkeit zwischen Informatoren und Informanden zu erreichen.
Geschaftsobjekte als Informatoren Urn die Abhangigkeitsbeziehung an einem Beispiel zu demonstrieren, wird auf die bereits friiher entworfenen Klassen Konto und ZAhlwerk zuriickgegriffen und gezeigt, welche Aktionen notwendig sind, urn die Haufigkeit der Buchungsvorglinge auf einem oder mehreren Konten durch ein Zahlwerk zu erfassen.
388
14 Erweiterte Konzepte und Mechanismen
Konten als Geschliftsobjekte eines Anwendungsgebietes sollen also in die Rolle von Informatoren versetzt werden, welche als abhlingige Informanden zugeordnete Zlihlwerke tiber erfolgte Ereignisse benachrichtigen. Die im Beispiel interessierenden Ereignisse sind Zustandslinderungen des Buchsaldos. Das dem Beispiel zugrundeliegende Modell ist in Abbildung 14-2 dargestellt.
I
Abbildung 14-2 Ein Geschliftsobjekt als direkter Informator Damit Konten als Informatoren wirksam werden konnen, mtissen aIle jene Methoden der Klasse Konto, welche zu registrierende Ereignisse auslosen, durch eine Benachrichtigungsaktion erglinzt werden. In Programm 14-5 ist dies fur die Einzahlungsmethode gezeigt, auf analoge Weise ware auch die Auszahlungsmethode zu adaptieren. Die Anderung besteht aus dem Senden der Botschaft changed: #saldo an den Empfanger selbst, also an dasjeweilige Konto. Konto methodsFor: 'buchen' einzahlung: einBetrag mitText: einString undValutaDatum: einDatum
"Eingangsbuchung." self changed: :ltsaldo
(1)
(1) Aktivierung der Verstiindigung eventueller Informanden.
Programm 14-5 Adaption der Klasse Konto als Informatorklasse Um Zlihlwerke auf die Rolle als abhangige Informanden vorzubereiten, ist in der Klasse Zahlwerk lediglich die in Programm 14-6 angegebene Methode Zahlwerk»update: hinzuzufiigen. Diese Methode lost einen Zlihlvorgang aus, falls das mit der Benachrichtigung tibersandte Objekt das Symbol #saldo ist. Der Zlihlvorgang ist also selektiv, so daB es moglich ware, unterschiedliche Ereignisse durch verschiedene Informanden registrieren zu lassen.
389
14.1 Kommunikationsmechanismen
zahlwerk methodsFor: 'updating' update: aSymbol
"Selektives Reagieren auf die Verstandigung durch einen Informator." aSymbol =
#saldo ifTrue: [self ztihle]
Programm 14-6 Adaption dec Klasse Zahlwerk als Informandenklasse
Dec in Programm 14-7 wiedergegebene Arbeitsbereich enthiHt ein Anwendungsbeispiel, aus dem ersichtlich ist, wie die Informator-Informand-Beziehung zwischen einem Konto und einem Ziihlwerk hergestellt wird und wie sich diese bei der Durchfiihrung von Kontoeinzahlungen auf das Ziihlwerk auswirkt.
Workspace
"(1) Erzeugen eines Zahlwerkes und eines Kontos. Beide Objekte werden durch globale Variable permanent gehalten." Smalltalk at:#ZW put: Zahlwerk new; at:#GK put: (Girokonto newMitNummer: 12345). <dolt>
"(2) Herstellen der direkten Infarmator -Infarmand-Beziehung." GK addDependent: ZW.
"(3) OberprOfen des Zahlwerkes." ZW.
<printlt> Zihlwerk (0)
"(4) Durchfilhrung van zwei Einzahlungen auf das Kanta." GK einzahlung: 100 asMoney. GK einzahlung: 500 asMoney.
<dolt>
"(5) OberprOfen des Zahlwerkes." ZW
<printlt> Zihlwerk (2)
"(6) Entfernen der globalen Variablen" Smalltalk removeKey: #ZW; removeKey: #GK
Programm 14-7 Einrichten und Testen einer direkten Informator-InformandBeziehung zwischen einem Konto und einem Ziihlwerk
390
14 Erweiterte Konzepte und Mechanismen
Wird das zu registrierende Ereignis durch mehrere Methoden ausgelost, im Beispiel durch die Einzahlungs- und Auszahlungsmethoden, so mu13 in allen diesen Methoden der Benachrichtigungsvorgang (self changed) verankert werden, obwohl es sich in jedem Fall um ein gleichartiges Ereignis handelt, namlich um die Veranderung des Buchsaldos eines Kontos. Es ware also besser, die Benachrichtigung genau an der einen Stelle zu plazieren, an der das Ereignis ausgelost wird, also in der Mutatormethode Konto»buchSaldo:. Dabei ist allerdings vorauszusetzen, da13 Veranderungen des Buchsaldos ausschlie13lich tiber diese Methode vorgenommen werden und nicht auch durch direkten ZugrifT auf die Instanzvariable buchSaldo.
Die Klasse ValueHolder 1m allgemeinen wird ein Geschaftsobjekt mehrere Attribute haben, deren Anderungen Gegenstand von Ereignismitteilungen sein sollen. Es ware daher notwendig, in allen Mutatormethoden dieser Attribute den Geweils bis auf das Aspektsymbol gleichen) Code fUr die Benachrichtigung von Informanden vorzusehen.
KlassenBrowser
Object () Model (,dependents') ValueModel () ValueHolder ('value') ValueModel methodsFor: 'accessing' value: newValue
"Zuordnen des Attributwertes mit Benachrichtigung der Informanden."
self setValue: newValue. self changed: #Value ValueHolder methodsFor: 'accessing' setValue: aValue
"Initialisieren des Attributwertes ohne Benachrichtigung der Informanden. "
value := aValue value
"value Programm 14-8 Objektzuordnung durch Instanzen von ValueHolder
391
14.1 Kommunikationsmeehanismen
Um dies zu vermeiden, konnen bei der Realisierung einer Zuordnung Auspragungen der Klasse Valueholder eingesetzt werden, welehe Behaltert fUr Partnerobjekte darstellen, die von sieh aus gewlihrleisten, daB bei jeder Zuordnung eines Partnerobjektes eine Benaehriehtigung der Informanden vorgenommen wird. Aus Programm 14-8 wird deutlieh, daB dureh die Methode ValueModel(ValueHolder»>value: nieht nur das Argument in den Behiilter eingefUgt und damit als Partnerobjekt zugeordnet wird, sondern daB aueh eine Benaehriehtigung der abhiingigen Informanden tiber die erfolgte "Wertanderung" stattfindet. Da die Benaehriehtigung nur beim Zuordnen eines Partnerobjektes, nieht aber bei einer Zustandsanderung eines bestehenden Partnerobjektes erfolgt, eignet sieh diese Teehnik besonders fUr Attributzuordnungen. Das zugeordnete Attribut kann dureh die Methode ValueHolder»value erhalten werden.
Attribute als Informatoren Bei der besehriebenen indirekten Realisierung einer Attributzuordnung tibernimmt die Instanz der Klasse ValueHolder die Rolle des Informators tiber . eine Anderung des Attributwertes, sodaB das eigentliehe Tragerobjekt davon nieht mehr beriihrt wird.
Konto
Z6hlwerk
ValueHolder
.....
buchSaldo 1--'
po
1 value
Geld (A)
Y
dep
1
~
MOdellJ
Abbildung 14-3 Ein ValueHolder eines Attributes als Informator
t Es handelt sich bier urn einen Behiilter fur genau ein Objekt, also nicht urn einen Samrnelbehiilter.
392
14 Erweiterte Konzepte und Mechanismen
Zur Verdeutlichung dieser Vorgangsweise wird das oben angeftihrte Beispiel so abgeandert, daB die Benachrichtigung des Zahlwerkes auf die Attributebene veriegt wird. Wahrend bisher die Buchsaldo-Beziehung zwischen Konten und Geldbetragen als normale Attributbeziehung realisiert war (siehe Abbildung 9-1), wird nunmehr der in Abbildung 14-3 im Detail veranschaulichte Modellausschnitt zugrundegelegt. Die zur Beriicksichtigung dieser Vorgaben notwendigen Anderungen von bereits eingerichteten Methoden sind in Programm 14-9 zusammengestellt und durch Unterstreichung hervorgehoben.
Konto methodsFor: 'initialize' initialize
"Initialisieren eines Kontos: der Anfangsbuchungssaldo betragt ATS 0.00." buchSaldo := 0 asMoney asValue "Buchungssaldo := 0.0 ATS."
(1)
Konto methodsFor: 'accessing' buchSaldo
"Zeigen des Buchsaldos." " buchSaldo ll8.l..ue. copy buchSaldoHolder
"Zeigen des ValueHolders fUr den Buchsaldo." " buchSaldo Konto methodsFor: 'private' buchSaldo: aMoney
"Verandern des Buchsaldos durch Zuordnen eines neuen Betrages." buchSaldo ~ aMoney (1) Die Methode Object»asValue verpackt den Empflinger in eine neu erzeugte Instanz von ValueHolder.
Programm 14-9 Adaption von Methoden der Klasse Konto Das in Programm 14-7 angegebene Beispiel arbeitet in dieser Variante gleich wie in der urspriinglichen Version, wenn man folgende Anderungen beachtet:
393
14.1 Kommunikationsmeehanismen
1. Die in Programm 14-7 unter Punkt (2) formulierte Einriehtung der Informator-Informand-Beziehung muB jetzt GK buchSaldoHolder addDependent: Z)N
lauten, weil nun nieht das Konto der Informator ist, sondem jene Auspriigung der Klasse ValueHolder, welehe den Buehsaldo des Kontos haIt. 2. Die Methode Zlihlwerk»update: aSymbol muB in diesem Fall statt auf das Symbol #saldo nunmehr auf das Symbol #value reagieren, weil Auspriigungen der Klasse ValueHolder bei der Anderung des von ihnen "gehaltenen" Objektes stets das Symbol #value aussenden. Es ist wiehtig darauf hinzuweisen, daB in diesem Fall die Ein- und Auszahlungsmethoden fUr Konten ihre urspriingliehe Form haben, also nieht mehr den in Programm 14-5 eingefugten Code fUr die Benachrichtigung von Informanden enthalten mussen, weil die Benaehrichtigung von den ValueHolderObjekten vorgenommen wird.
Indireld abhangige Informanden Einen weiteren Sehritt der Indirektion zeigt das in Abbildung 14-4 formulierte Modell, welches verlangt, daB das Ziihlwerk dureh Einschalten eines Transformatorobjektes von seiner Infomandenrolle entlastet wird.
Konto buchSaldo 1---+
(A)
,,
I"-
1 1 value
Geld
Y
lahlwerk
ValueHolder
~
dep
~~
Dependency Transformer receiver <#tilhle>
MOdell:
Abblldung 14-4 Ein ValueHolder eines Attributes als Informator Von der Klasse DependencyTransformer soIl hier nur erwiihnt werden, daB ihre Auspriigungen uber die Instanzvariable receiver jenes Objekt kennen, dem sie eine Botschaft senden sollen, wenn sie als abhiingiger Informand
394
14 Erweiterte Konzepte und Mechanismen
durch einen ihrer Informatoren dazu aufgefordert werden. Ebenso ist ihnen bekannt, welche Botschaft sie in diesem Falle iibermitteln sollen. Zur Realisierung des Beispieles in dieser Variante geniigt es, die Assoziation zwischen dem Informator (das ist der von der Instanzvariablen buchSaldo des Girokontos GK referenzierte ValueHolder des Geldobjektes, der durch Evaluation des Ausdruck GK buchSaldoHolder erreicht wird) und dem letztlich zu beeinflussenden Objekt (das Zlihlwerk ZW) durch folgende Anweisung herzustellen: GK bucbSaldoHolder onCbangeSend' #zable to' ZW.
Dieser Ausdruck ersetzt also jetzt den unter Punkt (2) von Programm 14-7 angeflihrten Ausdruck. Bei seiner Evaluation wird eine Ausprligung der Klasse DependencyTransformer erzeugt, als Informand des Informators GK buchsaldo registriert und mit der Information versorgt, daB im FaIle der Benachrichtigung dem Objekt ZW die Botschaft #zahle zu senden ist, was mit dem in Abbildung 14-4 gezeigten Modell konform ist. Wesentlich dabei ist zu bemerken, daB bei dieser indirekten InformatorInformand-Beziehung das Zlihlwerk in seiner urspriinglichen Form vorliegt, also nicht wie in den ersten beiden Varianten als abhlingiger Informand auftritt und daher nicht durch die Methode Za.hlwerk»update: auf diese Rolle vorbereitet sein muB! Als einzige Voraussetzung bleibt iibrig, daB die Buchsaldo-Zuordnung zwischen einem Konto als Quellobjekt und einem Geldbetrag als Zielobjekt durch eine Instanz der Klasse ValueHolder vermittelt werden muB.
Das MVC-Framework Die Abhangigkeitsbeziehung und der damit verbundene Abhangigkeitsmechanismus stellt einen Teil der im Smalltalk-System realisierten Model-ViewController-Architektur dar. Es handelt sich dabei urn ein Framework von Model-, View- und Controller-Klassen, die in ihrem Zusammenwirken die Basis einer Applikationsarchitektur bilden, deren Struktur in Abbildung 14-5 veranschaulicht ist. Ausprligungen einer Unterklasse der Klasse Model sind Geschliftsobjekte des jeweiligen Anwendungsgebietes, die als Modelle realer Objekte die sachlogische Funktionalitlit der Applikation tragen. Die Prlisentation von Geschliftsobjekten in einer Applikation erfolgt durch Visualisierungsobjekte, welche als Instanzen einer Unterklasse von View den jeweiligen Zustand ihres Model-Partners in die AuBenwelt projizieren. Sie stehen in einer gekoppelten Beziehung mit Kontrollobjekten, die als Ausprligungen einer Subklasse der Klasse Controller eine Sensorfunktion haben und somit in der Lage sind, Informationen aus der AuBenwelt entgegenzunehmen.
395
14.2 Selektive Kommunikation
Ein View-Controller-Paar bildet somit eine Verb indung zwischen dem konzeptionellen und dem realen Objektraum. Die View-Komponente eines solchen Paares erflillt in einer Applikation die Ausgabefunktion, die Controller-Komponente die Eingabefunktion.
O.. n
dep
t
1 ..n
Model 1..n
1 , '1 model
View
t
model controller . . view
Controller
1
y
Modell :~---------------------'
Abbildung 14-5 Die Struktur des MVC-Frameworks Ein Geschliftsobjekt (Model) ist mit seinen Visualisierungsobjekten (Views) und dadurch auch mit den zugehorigen Sensorobjekten (Controller) durch eine Informator-Informand-Beziehung verbunden. Verandert sich der Zustand eines Geschaftsobjektes, so werden die registrierten Visualisierungsobjekte tiber den Abhangigkeitsmechanismus von diesem Ereignis benachrichtigt. Als Reaktion auf diese Verstandigung lesen sie den aktuellen Zustand ihres Models und aktualisieren die visuelle Darstellung. Empfangt ein Sensorobjekt ein Signal aus der AuBenwelt, so tibersetzt es dieses in eine Botschaft an sein Model, wodurch eine Geschaftsmethode aktiviert wird. Auf diese Weise wird der zwischen den Objekten innerhalb des Objektraumes ablaufende Kommunikationsprozess in der AuBenwelt fortgesetzt und der Benutzer der Anwendung als Aktor [23] in den ProzeB mit einbezogen.
14.2 Selektive Kommunikation Der Basismechanismus flir die Kommunikation zwischen zwei Objekten sieht vor, daB ein Objekt als Klient einem anderen Objekt als Server durch Ubersenden einer Botschaft einen Auftrag erteilen kann. Der Empfanger der Botschaft
396
14 Erweiterte Konzepte und Mechanismen
fiihrt diesen Aufirag durch, falls er dazu in der Lage ist, und signalisiert dem Sender die Erledigung durch Ubermittlung eines Riickgabeobjektes. Die Durchfiihrung des Aufirages erfolgt bedingungslos und unabhlingig davon, von welchem Objekt der Auftrag erteilt wurde. Es sind leicht Situationen vorstellbar, in denen die Erledigung eines Auftrages nur dann erfolgen soil, wenn die Anforderung dafiir von einem bestimmten berechtigten Objekt oder von Objekten einer berechtigten Art stammt. Ein Beispiel daftir sind private Methoden, die nicht allgemein zuganglich sein sollen und nur fUr den Eigengebrauch eines Objektes gedacht sind. In der Folge wird ein Mechanismus skizziert und an einem Beispiel demonstriert, der es ermoglicht, Methoden derart zu schiitzen, daB sie nur von berechtigten Objekten aktiviert werden konnen.
14.2.1 Feststellen des Senders einer Methode Bei der Aktivierung einer Methode wird ein Objekt erzeugt, das als Ausprligung der Klasse MethodContext den Ausfiihrungskontext der aktiven Methode enthlilt.
aMethodContext
aMethodContext
.-------+--{
sender .....
Botschaft
sender
Botschaft thisContext
Abbildung 14-6 Struktur der Sender-Empfanger-Beziehung Abbildung 14-6 zeigt einen Ausschnitt aus dem konzeptionellen Objektraum, der jene Situation veranschaulicht, die bei aufrechter Sender-Empfanger-Beziehung zwischen zwei Objekten besteht. Das Objekt aSender ist mit der Abarbeitung einer Methode befaBt und hat in diesem Zusammenhang eine Botschaft an das Objekt aReceiver iibermittelt. Es hat seine Aktivitlit
14.2 Selektive Kommunikation
397
nunmehr unterbrochen und wartet auf das Ergebnis seiner Anforderung an das Objekt aReceiver. Jedes der beiden Objekte referenziert durch seine private Konstante thisContext den jeweiligen Methodenkontext, welcher neben dem hier nicht gezeigten Exekutionsstack mit den temporaren Variablen die Instanzvariablen sender und receiver enthiUt. Jedes aktive Objekt steht mit seinem Methodenkontext durch die Variablen thisContext und receiver in einer gegenseitig gekoppelten Beziehung, die Methodenkontexte sind untereinander durch die Instanzvariablen sender verkettet. Da in der Klasse Context fUr diese Instanzvariablen namenskonforme Zugriffsmethoden definiert sind, kann innerhalb einer Methode durch Evaluation des Ausdruckes thisContext sender receiver der Sender der aktiven Methode festgestellt und fiir eine Berechtigungspriifung herangezogen werden. Ein Beispiel fUr eine Methode, in der vor der Durchftihrung der eigentlichen Aktion iiberpriift wird, ob sie vom Empfanger der Methode an sich selbst gesandt wurde, ist in Programm 14-10 gezeigt. Es muB allerdings darauf hingewiesen werden, daB die Durchftihrung einer solchen Uberpriifung zur Laufzeit sehr aufwendig ist und daher nur in besonderen Hillen angebracht erscheint. Object methodsFor: 'absolute private' einePrivateAktion (thisContext sender receiver = self) if False: [self error: 'nicht pivater Zugriff'].
Programm 14-10 Eine wirklich private Methode
14.2.2 Geschiitzte Register In der an einer friiheren Stelle behandelten Fallstudie iiber das Bankwesen wurde angenommen, daB ein zentrales Bankenservice Verzeichnisse verwaltet, die fUr das Bankwesen wesentliche Daten enthalten. Zur Realisierung solcher Verzeichnisse wurde in Abschnitt 11.4 die Klasse Zentralregister eingefUhrt, dabei wurde bereits die Bedeutung offentlicher und nichtoffentlicher Methoden fUr Instanzen dieser Klasse angesprochen.
398
14 Erweiterte Konzepte und Mechanismen
Als Beispiel sei auf das Bankenregister hingewiesen, das durch den in Programm 14-11 gezeigten Vorgang korrumpiert werden kann, weil ein direkter Schreibvorgang in das Register nicht verhindert wird. Urn zu erreichen, daB Eintragungen in ein Register nur mehr von einem berechtigten Objekt veranlaBt werden konnen, wird eine Klasse GeschOtztesRegister als Unterklasse von Zentralregister eingerichtet und mit entsprechenden Vorkehrungen versehen, die auf der im vorangehenden Abschnitt erliiuterten Vorgangsweise beruhen. Workspace
"Fortsetzung von Programm 11-16."
BankenService aktivService registrierteBanken setzeBei: 150 denEintrag: 'JuxBank'.
<dolt>
BankenService aktivService registrierteBanken.
<printlt>
Zentralregister ( 1S0->'JuxBank' 100->BankRegistrierung Name: 'Testbank' BLZ: 100 )
Programm 14-11 Unerwiinschter direkter SchreibzugritT auf ein Zentralregister Aus Programm 14-12 ist zu erkennen, daB jedes geschtitzte Register tiber eine Instanzvariable berechtigtesObjekt verfUgt, die dazu dient, ein Objekt zu referenzieren, welches alleine in der Lage sein soli, geschtitzte Methoden erfolgreich durchfUhren zu lassen. Die Erzeugung eines geschtitzten Registers ist nur durch die Methode GeschOtztesRegister clasS»newMitBerechtigungFOr: moglich, welche tiber ihren Parameter die Festlegung des berechtigten Objektes verlangt. Diese Methode deponiert das berechtigte Objekt vorerst in der Klassenvariablen TempObj, erzeugt sodann eine nicht initialisierte Auspragung und ordnet dieser mit Hilfe der Methode GeschOtztesRegister»berechtige das tiber die Klassenvariable zwischengespeicherte berechtigte Objekt zu. Der Umweg tiber die Klassenvariable ermoglicht es dabei, eine Mutatormethode fUr die Instanzvariable berechtigtesObjekt zu vermeiden, so daB dieses nicht mehr ausgewechselt werden kann t.
t Diese Vorgangsweise bietet keinen Schutz vor einer vorsiitzlichen, Iistigen Manipulation, da es nach wie vor weitere Referenzen auf das berechtigte Objeld geben kann, die zu dessen Austausch herangezogen werden kannen.
14.2 Selektive Kommunikation
399
Zentralregister subclass: #GeschOtztesRegister instanceVariableNames: 'berechtigtesObjekt ' classVariableNames: 'TempObj' poolDictionaries: " category: 'OrgHilfe' GeschOtztesRegister class methodsFor: 'instance creation'
new self shouldNotlmplement
newMitBerechtigungFi.ir: einObjekt "Erzeugen eines geschiitzen Registers mit Angabe des schreibberechtigten Objektes." TempObj := einObjekt. "super newNichtlnitialisiert berechtige GeschOtztesRegister methodsFor: 'berechtigen und initialisieren'
berechtige berechtigtesObjekt := TempObj. TempObj:= nil
initialize self prOfeBerechtigungln: thisContext. inhalt := Dictionary new
Programm 14-12 Die Klasse GeschOtztesRegister
Die Initialisierung des geschiitzten Registers ist die erste Operation, die vom berechtigten Objekt vorgenommen werden muB, da sie die eigentliche Initialisierung bereits vom Ergebnis der Methode GeschOtztesRegister» prOfeBerechtigungln: abhiingig macht. Die fur die Uberpriifung der Berechtigungzustlindige Methode ist in Programm 14-13 vorgestellt. Die Methode GeschOtztesRegister»prOfeBerechtigungln: erwartet als Parameter den Kontext der aufrufenden Methode und iiberpriift mit dessen Hilfe, ob die aufrufende Methode vom berechtigten Objekt des geschiitzen Registers aktiviert wurde. 1st dies nicht der Fall, wird der ProzeB mit einem Fehlersignal abgebrochen. Der Einsatz dieser Methode fur die Durchfuhrung von Eintragungen in ein geschiitztes Register ist in Programm 14-14 wiedergegeben. Aufanaloge Weise ware die Methode GeschOtzesRegister»IOscheEintragBei: zu gestalten.
400
14 Erweiterte Konzepte und Mechanismen
GeschOtztesRegister methodsFor: 'berechtigung prOfen' priifeBerechtigungln: kontext
"Oberprufung, ob die aufrufende Methode yom berechtigten Objekt aktiviert wurde."
I test I
test := (kontext sender) receiver. (1) (test = berechtigtesObjekt) ifFalse: [self error: 'Unberechtigter Zugriff durch: " test printString]
(1) Man beachte, daB das Argument kontext den Methodenkontext der aufrufen-
den Methode bezeichnet, die tempo rare Variable test daher mit jenem Objekt belegt wird, welches die aufrufenden Methode aktiviert hat.
Programm 14-13 Berechtigungspriifung fUr geschiitzte Register
GeschOtztesRegister methodsFor: geschOtzt-Schreibzugriff setzeBei: einSchliissel denEintrag: einEintrag self prOfeBerechtigungln: thisContext. inhalt at: einSchlOssel put: einEintrag Programm 14-14 SchreibzugriiTe auf ein geschiitztes Register
BankenService methodsFor: 'initialize' initialisiereAllesGeschiitzt
"Initialisieren des Bankenservice." bkreg := (GeschOtztesRegister newMitBerechtigungFOr: self) initialize. wdreg := (GeschOtztesRegister newMitBerechtigungFOr: self) initialize. wgreg := (GeschOtztesRegister newMitBerechtigungFOr: self) initialize. name := 'Bankaufsicht'. bkZahler := Zahlwerk new Programm 14-15 Initialisierung des Bankenservice mit geschiitzten Registem SolI das zentrale Bankenservice statt mit »normalen" Zentralregistem mit geschiitzten Registem ausgestattet werden, so wlire die in Programm 11-6
401
14.3 Objekte mit dynamisch wechselnden Eigenschaften
angegebene Initialisierungsmethode durch jene aus Programm 14-15 zu ersetzen. Der Versuch einer unerlaubten Registrierung einer Bank durch direkten Zugriff auf das Bankenregister, wie er in Programm 14-11 durchgeftihrt wurde, ist im Falle von geschiitzten Registern nicht mehr moglich, wie aus dem Evaluationsergebnis der in Programm 14-16 gezeigten Ausdriicke ersichtlich ist. Zu diesem Ergebnis sei die Bemerkung hinzugefiigt, daB die in einem Workspace ausgeftihrten freien Methoden das Objekt nil als Sender haben. Workspace
"Fortsetzung von Programm 11-16." BankenService IOscheAktivesService; newGeschOtzt <dolt> BankenService aktivService registrierteBanken setzeBei: 150 denEintrag: 'JuxBank'. Unberechtigter Zugriff durch: nil
<dolt>
Programm 14-16 Erfolgloser Versuch einer direkten Bankregistrierung
14.3 Objekte mit dynamisch wechselnden Eigenschaften Bei der Modellierung der Realitiit trifft man immer wieder auf Objekte, die wiihrend ihrer Lebenszeit wechselnde RoUen spielen und die daher zusiitzlich zu ihren permanenten "Basiseigenschaften" temporiir rollenspezifische Eigenschaften aufweisen. Beispielsweise kann eine Personen zeitweise in der Rolle eines Schiilers, Angestellten, Patienten oder Bankkunden auftreten, wobei auch mehrere Rollen gleichzeitig angenommen werden konnen. Jeder dieser Rollen entsprechen charakteristische Zustands- und Verhaltenseigenschaften, die aber nicht zu den eigentlichen Eigenschaften einer Person gehoren. Da in einem klassenbasierten System die Eigenschaften von Objekten in ihrer Klasse festgelegt sind, weisen alle Auspriigungen einer Klasse ein gleiches Eigenschaftsmuster (Instanzvariable und Methoden) auf. Eine Anderung des Eigenschaftsmusters eines Objektes kann nur durch einen Wechsel der Klassenzugehorigkeit des Objektes unter Beibehaltung der Objektidentitiit erreicht werden. Dieser Vorgang wird hier Objektmutation genannt. t Eine andere Moglichkeit besteht darin, dem Basisobjekt entsprechend den jeweils angenommenen Rollen "Begleitobjekte" zuzuordnen, welche die rol-
402
14 Erweiterte Konzepte und Mechanismen
lenspezifische Funktionalitat tragen. Diese Zuordnung solI transparent sein, sodaB die Rollenobjekte nach AuBen hin nicht als eigene Objekte in Erscheinung treten. Ein solcher Mechanismus solI als Objektdekoration bezeichnet werden. t
14.3.1 Objektmutation Unter Objektmutation wird der Wechsel der Klassenzugehorigkeit eines Objektes verstanden. Programm 14-17 stellt eine Methode vor, welche den Empfanger von seiner urspriinglichen Klasse zu einer neuen Klasse (aClass) mutiert. Object methodsFor: 'mutation' mutateTo: aClass "Objektmutation zur Klasse aClass."
I newObject I newObject := (aClass new) transferComponentsFrom: self. self become: newObject
(1) (2)
(1) Durch die Methode Object>>transferComponentsFrom: sollen die relevanten Bestandteile des alten Objektes in das neue Objekt tibertragen werden.
Programm 14-17 Objektmutation Wie man aus diesem Programm erkennt, wird der Klassenwechsel dadurch erreicht, daB in einem ersten Schritt ein neues Objekt der gewiinschten Klasse erzeugt und mit jenen Komponenten versehen wird, die es vom alten Objekt iibernehmen solI. In einem zweiten Schritt wird das neue Objekt durch Vertauschen der Referenzen an die Stelle des alten Objektes gesetzt. Da das alte Objekt nach dieser Aktion nur mehr von der methodenlokalen Variablen
t Der Wechsel der Klassenzugehorigkeit eines Objelctes wird auch Objektmigration genannt. Da
t
Objektmigration im Zusammenhang mit Objektbanken (vergleiche Kapitel 13) die Ubersiedlung eines Objektes in den persistenten Objektraum bedeutet, wird hier der Bezeichnung Objektmutation der Vorzug gegeben. Siehe das in [161 beschriebenen Strukturmuster Decorator. Der Name "Dekorator" leitet sich aus der Anwendung dieses Konzeptes auf die dynamische Ausstattung von Textansichten mit Rahmen, Rollbalken und iihnlichen "Dekorationselementen" abo
14.3 Objekte mit dynamisch wechselnden Eigenschaften
403
newObject referenziert wird, verliert es mit der Beendigung dieser Methode seine Existenz. An dem Mutationsvorgang sind zwei Objekte beteiligt, die aus einer systemnahen Sicht verschiedene Objektidentitaten (im Sinne der Lokalisierung im technischen Objektraum) besitzen. Aus der Sicht des Ansprechens dieser Objekte durch Objektnamen bleibt jedoch die Objektidentitat erhalten, da der system interne ZugritT auf die Objekte im Speicher fUr den Benutzer irrelevant ist. Object methodsFor: 'mutation' transferComponentsFrom: anObject
"Obertragen namensgleicher Komponenten des Argumentes auf den Empfanger."
self initializelnstVarsFrom: anObject initializelnstVarsFrom: anObject
"Instanzvariable des Empfangers werden Synonyme zu namensgleichen Instanzvariablen des Argumentes. Namenskonforme Zugriffsmethoden werden vorausgesetzl"
(self commonlnstVarsWith: anObject) do: [:name I self perform: (name, ':') asSymbol withArguments: (Array with: (anObject perform: name asSymbol)))
(1) (1)
commonlnstVarsWith: anObject
"Erzeugen einer geordneten Sammlung jener Instanzvariablennamen, die sowohl im Empfanger als auch im Argument vorkommen."
I mylnstVars newlnstVars I
mylnstVars := self class alllnstVarNames. newlnstVars := anObject class alllnstVarNames. 1\ newlnstVars select: [:element I mylnstVars includes: element].
(2)
(1) Es wird vorausgesetzt, daB mit den Instanzvariablen namenskonforme ZugrifTsmethoden definiert sind.
(2) Die Methode Behavior»allinstvarNames liefert als Riickgabeobjekt ein Feld (Array) mit den Namen (String) aller Instanzvariablen, also auch jener, die aus den Oberklassen geerbt werden. Die Botschaft allinslVarNames wird von Klassenobjekten verstanden.
Programm 14-18 Ubertragung namensgieicher Komponenten
404
14 Erweiterte Konzepte und Mechanismen
Die Ubertragung von Komponenten des alten Objektes auf das neue Objekt ist fUr jede Anwendung verschieden. Meistens wird es jedoch der Fall sein, daB das neue Objekt einer Vnter- oder Oberklasse des alten Objektes angehOrt, so daB beide Objekte Instanzvariable mit gleichen Namen und gleichen Bedeutungen haben . In solchen Fallen ist es angebracht, daB die Methode Object»transferComponentsFrom: jene Instanzvariable des neuen Objektes, die namensgleich auch im alten Objekt vorkommen, mit denselben Objekten belegt, mit denen sie im alten Objekt belegt sind. Dies kann durch die in Programm 14-18 gezeigten Methoden erreicht werden. In der Methode Object»initializelnstVarsFrom: werden aus den im Empfanger und im Argument gleichnamigen Instanzvariablen die namenskonformen Zugriffsmethoden konstruiert und durch indirekte Botschaftsubermittlung (vergleiche Abschnitt 2.5.2) aktiviert. Fur jede dieser Instanzvariablen wird zuerst das zu ubertragende Objekt als Ergebnis der indirekt an das Argument gesandten Akzessormethode bestimmt, dieses wird sodann durch die ebenfall indirekt gesandte Mutatormethode an den Empfanger ubertragen. Diese Vorgangsweise kann nur dann zum Erfolg fUhren, wenn die namenskonformen Zugriffsmethoden fur aIle in Frage kommenden Instanzvariablen eingerichtet sind.
Beispiel: Mutation von Personen zu Bankkunden Ais Beispiel fUr die Objektmutation werden Person en herangezogen, die im Laufe ihrer Existenz Bankkunden werden. In Programm 10-1 wurde bereits die Klasse Bankkunde als Subklasse von Person eingerichtet. Die im Beispiel verwendeten Methoden fUr die Erzeugung von Personen und Bankkunden sowie fUr deren Druckausgabe konnen den Programmen 10-3 und 10-4 entnommen werden. Programm 14-19 zeigt ein Beispiel fUr die Mutation einer Auspragung der Klasse Person zu deren Vnterklasse Bankkunde und zuriick. Die Wirkung der Mutation ist sowohl an den durchgefUhrten Tests uber die jeweilige Klassenzugehorigkeit als auch an den Druckausgaben der TestPerson zu erkennen, die unter den Punkten (2) und (4) gezeigt sind. Zusatzlich sieht man an Hand der unter Punkt (3) ausgefUhrten Aktionen, daB die TestPerson als Bankkunde ein Konto zugeordnet bekommen kann und daB die gekoppelte Beziehung zwischen dem Bankkunden und dem Konto ordnungsgemaB eingerichtet wird. Aus der Evaluation der Ausdriicke Programm 14-20 wird deutlich, daB die Belegung der Instanzvariablen name und adresse bei der Mutation zwischen den Klassen Person und Bankkunde erhalten bleibt. Ware die Klasse Person als Subklasse von Model eingerichtet worden, dann wurde auch die Belegung
405
14.3 Objekte mit dynamisch wechselnden Eigenschaften
der von Model geerbten Instanzvariablen dependents erhalten bleiben, falls man fUr namenskonforme Zugriffsmethoden sorgtt. Workspace
"(1) Anlegen einer globalen Variablen, die eine Person referenziert." Smalltalk at: #TestPerson put: (Person newMitNamen: 'Maier' undAdresse: 'Wien'). TestPerson
<printlt> Person 'Maier'
"(2) Objektmulation: Die Testperson wird Bankkunde." TestPerson mutateTo: Bankkunde. TestPerson class TestPerson
<printlt> Bankkunde <printlt> Bankkunde'Maier' (Knr. nil)
"(3) Dem Bankkunden wird ein Konto zugeordnet." TestPerson bekommtKonto: (Girokonto newMitNummer: 999) <dolt> TestPerson konten first <printlt> Girokonto (Nummer: 999 Saldo: ATS 0.00 lnhaber: Bankkunde 'Maier' (Knr. nil»
"(4) Objektmutation: Die Testperson legt die Rolle eines Bankkunden wieder ab." TestPerson mutateTo: Person TestPerson class TestPerson
<printlt> Person <printlt> Person 'Maier'
Programm 14-19 Mutation von Person zu Bankkunde
Workspace
<printlt> Bankkunde alllnstVarNames OrderedColiection ('name' 'adresse' InrI 'konten') (Person new) commonlnstVarsWith: (Bankkunde new) Ordered Collection ('name' 'adresse')
<printlt>
Programm 14-20 Namensgleiche Komponenten von Personen und Bankkunden
t Die Zugriffsmethoden auf die Instanzvariable dependents sind Model>>myDependents und Model»myDependents:, diese sind also nicht namenskonform.
406
14 Erweiterte Konzepte und Mechanismen
Object methodsFor: 'mutation'
transferlnstVarsFrom: anObject
"Instanzvariable des Empflingers werden Synonyme zu namensgleichen Instanzvariablen des Argumentes. Namenskonforme Zugritfsmethoden werden nicht vorausgesetzt." (self commonlnstVarsWith: anObject) do: [:name I self instVarAt: (self class instVarlndexFor: name) put: (anObject instVarAt: (anObject class instVarlndexFor: name))]
Programm 14-21 Direkte Transferierung namensgleicher Komponenten
Sind namenskonforme Zugriffsmethoden nicht vorgesehen, so kann die Objektmutation mit Beibehaltung der Belegung von gleichnamigen Instanzvariablen erreicht werden, wenn man die in Programm 14-18 angegebene Methode Object»initializelnstvarsFrom: durch die "systemniiliere" Methode Object»transferlnstVarsFrom: (Programm 14-21) ersetzt. Diese Methode greift auf die Tatsache zurUck, daB eine Instanzvariable iiber einen internen Index ansprechbar ist, der aus ihrem Namen erhalten werden kann.
14.3.2 Objektdekoration Objektdekoration soli die dynamische Zuordnung eines oder mehrerer "Satellitenobjeke" zu einem "Kernobjekt" bezeichnen und zwar in der Art, daB die Satellitenobjekte (Dekoratoren) Trager von Struktur- und Verhaltenserweiterungen des Kernobjektes sind. Abbildung 14-7 zeigt die symbolische Darstellung der Dekorationsbeziehung zwischen einem Dekorator und seinem Dekoranden.
Dekorator
1
)
(1..n) !II.
----------.... ~>~ deco
Dekorand
AbbUdung 14-7 Die Dekorationsbeziehung
Wie aus dem in Abbildung 14-8 gezeigten Modell ersichtlich ist, kann das dekorierte Objekt eines Dekorators entweder ein anderer Dekorator oder ein
14.3 Objekte mit dynamisch wechselnden Eigenschaften
407
Kernobjekt sein, das selbst nicht die Eigenschaft eines Dekorators hat. Auf diese Weise ist es moglich, einem Kernobjekt eine Kette von Dekoratoren zuzuordnen, von denen jeder das Kemobjekt urn charakteristische Eigenschaften erweitert.
Decorator
4
Kern
deco Modell 11--_ _ _ _ _ _ _ _ _ _ _ _ _ _-----'
Abbildung 14-8 Modell einer Dekorationsbeziehung
Object subclass: #Decorator instanceVariableNames: 'decoratedObject ' classVariableNames: " poolDictionaries: " category: 'Decoration' Decorator methodsFor: 'conditional message delegation' doesNotUnderstand: aMessage
"Weiterleiten einer nicht verstandenen Botschaft an das dekorierte Objekt." A
(self decoratedObject) perform: aMessage selector withArguments: aMessage arguments
Decorator methodsFor: 'unconditional message delegation' at: anlndex put: anObject
"Umleiten des Zugriffes auf indizierte Instanzvariable zum Kernobjekt."
self kernelObject at: anlndex put: anObject Programm 14-22 Die abstrakte Klasse Decorator Satellitenobjekte oder Dekoratorobjekte sollen Auspragungen einer Unterklasse der in Programm 14-22 gezeigten abstrakten Klasse Decorator sein. Dekoratoren haben die Eigenschaft, eine empfangene Botschaft an die von ihnen begleiteten Objekte weiterzuleiten, wenn sie diese nicht selbst verstehen. Dieses Verhalten wird durch die in Programm 14-22 erfolgte Redefmition der Methode Object>>doesNotUnderstand: erreicht.
408
14 Erweiterte Konzepte und Meehanismen
In der gezeigten Implementation wird vorausgesetzt, daB Dekoratoren nieht mit indizierten Instanzvariablen ausgestattet sind und aueh nieht selbst als Informatoren auftreten. Botsehaften, die indizierte Instanzvariable ansprechen oder Informanden betreffen, sind daher an das Kernobjekt weiterzuleiten, was in Programm 14-22 am Beispiel der Botsehaft at:put: angedeutet ist. Programm 14-23 zeigt die Methode Decorator»kerneIObject zum Feststell en des Kernobjektes eines Dekorators, in der die Kette der Dekoratoren durehsueht wird, bis das Kernobjekt aufgefunden ist. Fur langere Ketten ware es effizienter, das Kernobjekt an eine Instanzvariable des Dekorators zu binden, sodaB es direkt erreieht werden kann. Eine Methode fUr die Druekausgabe von Dekoratoren samt einem Hinweis tiber die dekorierten Objekte ist in Programm 14-24 angefUhrt, wodureh das Verstandnis der in Programm 14-27 angegebenen Beispiele erleiehtert wird. Von einem Dekorator wird dureh die Dekorator-Dekorand-Beziehung verlangt, daB er nieht isoliert existieren darf, sondern stets an ein dekoriertes Objekt gebunden ist. Diese Forderung wird dureh die in Programm 14-25 angefUhrte Erzeugungsmethode erftillt. Diese Methode bewirkt aueh, daB aIle auf das dekorierte Objekt bestehenden Referenzen auf den neuen Dekorator umgesetzt werden, sodaB die Dekoration transparent erfolgt.
Decorator methodsFor: 'accessing-private' kernelObject
"Feststellen des Kernobjektes." 1\
self decoratedObject kernelObject
(1) Object»kerneIObject Aself
Programm 14-23 Aufsuehen des Kernobjektes eines Dekorators
Decorator methodsFor: 'printing' printOn: aStream aStream nextPutAlI: self class name, 'ON: '. self decoratedObject printOn: aStream
Programm 14-24 Druekausgabe eines Dekorators
(1)
14.3 Objekte mit dynamisch wechselnden Eigenschaften
409
Decorator class methodsFor: 'instance creation' transparentOn: anObject
"Transparente Dekoration des Argumentes (anObject) mit einem neuen Dekorator."
Ideco I deco := self new initialize. anObject primBecome: deco. anObject decoratedObject: deco
(1)
(1) Die Methoden Object>>primBecome: und Object>>become: unterscheiden sich nur in der Behandlung abhangiger Objekte, die hier nicht vorliegen.
Programm 14-25 Transparente Erzeugung eines Dekorators
Beispiel: Dekoration von Personen als Bankkunden Die beschriebene Vorgangsweise der Objektdekoration solI nun an Hand eines Beispieles demonstriert werden. Gegenstand des Beispieles sind wie im vorangehenden Abschnitt Personen, die temporar die Rolle eines Bankkunden annehmen. Zu diesem Zweck wird in Programm 14-26 der konkrete Dekorator BankkundenDekorator definiert. Ein Vergleich mit der friiher eingerichteten Klasse Bankkunde zeigt, daB in beiden Klassen die gleichen Instanzvariablen festgelegt sind. Zusatzlich wird durch die ebenfalls in Programm 14-26 angefiihrte Methode BankkundenDekorator»bekommtKonto: darauf hingewiesen, daB auch die der Klasse Bankkunde zugeordneten Methoden fast unverandert ubemommen werden konnen, was auch fUr die Durchftihrung des Beispieles (Programm 14-27) vorausgesetzt wird. . Decorator subclass: #BankkundenDecorator instanceVariableNames: 'nr konten ' classVariableNames: " poolDictionaries: " category: 'Decoration' BankkundenDecorator methodsFor: 'accessing' bekommtKonto: einKonto
"Errichten einer Kunde-Konto-Zuordnung."
Programm 14-26 Die Klasse BankkundenDekorator
410
14 Erweiterte Konzepte und Mechanismen
Zu beach ten ist allerdings, daB im FaIle der Klasse Bankkunde der Bezug auf die Eigenschaften einer Person auf dem Wege der Vererbung tiber die Superklasse Person erfolgt. 1m FaIle der Klasse BankkundenDekorator hingegen erfolgt der Rtickgriff' auf die Eigenschaften einer Person auf dem Wege der Delegation an jene Instanz der Klasse Person, die durch einen BankkundenDekorator dekoriert ist. Workspace
"(1) Anlegen einer globalen Variablen, die eine Person referenziert." Smalltalk at: #TestPerson put: (Person newMitNamen: 'Maier' undAdresse: 'Wien').
"(2) Transparente Objektdekoration: Die Testperson wird Bankkunde." BankkundenDecorator transparentOn: TestPerson. TestPerson class <printlt> BankkundenDecorator TestPerson <printlt> BankkundenDecorator ON: Person 'Maier'
"(3) Dem Bankkunden wird ein Konto zugeordnet." TestPerson bekommtKonto: (Girokonto newMitNummer: 999). <printlt> TestPerson konten first Girokonto (Nummer: 999 Saldo: ATS 0.00 Inhaber: BankkundenDecorator ON: Person 'Maier')
"(4) Transparente Objektdekoration: Die Testperson legt die Rolle eines Bankkunden wieder ab." BankkundenDecorator removeFrom: TestPerson. TestPerson class <printlt> Person TestPerson <printlt> Person 'Maier'
"(5) Entfernen der globalen Variablen." Smalltalk removeKey: #TestPerson
Programm 14-27 Transparente Dekoration einer Person als Bankkunde Das in Programm 14-27 gegebene Beispiel betrifft die gleiche Fragestellung wie jenes in Programm 14-19. Auch hier wird eine Instanz der Klasse Person erzeugt und fUr die Belange des Beispieles an die globale Variable TestPerson gebunden. Sodann wird unter Punkt (2) die TestPerson durch Ankoppeln einer Instanz von BankkundenDekorator mit den Eigenschaften eines Bankkunden versehen. Die Evaluation der unter Punkt (3) zusammengefaBten Ausdrticke zeigt, daB die TestPerson wie ein Bankkunde behandelt werden kann. Unter Punkt (4) wird der TestPerson die Rolle als Bankkunde wieder entzogen t, die TestPerson reagiert somit nur mehr wie eine Person.
14.3 Objekte mit dynamisch wechselnden Eigenschafien
411
Wie bereits kurz erwiihnt, bewirkt das Ankoppeln von Dekoratoren an ein Objekt einen Mechanismus, den man als Verhaltensvererbung auf Instanzebene bezeichnen kann, da das Suchen nach einer Methode nicht nur in der Klassenhierarchie erfolgt, sondem auch entlang der Kette der Dekoratoren. Als Beispiel sei angenommen, daB in der Klasse BankkundenDekorator zusatzlich zu den in Programm 14-26 angelegten Instanzvariablen noch eine Instanzvariable adresse mit entsprechenden nameskonformen Zugriffsmethoden vereinbart ist. Da in der Klasse Person ebenfalls eine Instanzvariable adresse festgelegt ist, wird die Antwort auf die Frage nach der Adresse einer Person davon abhangen, ob die Person in der Rolle eines Kunden erscheint oder nicht.
Workspace "(1) Erzeugen einer Testperson: siehe: Programm 14-27." "(2) Feststellen der Adresse der Testperson."
TestPerson adresse.
<printlt> 'Wien'
"(3) Objektdekoration: Die Testperson wird Bankkunde und erhalt eine Adresse."
BankkundenDecorator transparentOn: TestPerson. TestPerson adresse: 'Salzburg'. <dolt> "Ergebnis siehe: Abbildung 14-9." TestPerson inspect. "(4) Feststellen der Adresse der Testperson."
TestPerson adresse.
<printlt> 'Salzburg'
"(5) Objektdekoration: Die Testperson legt die Rolle eines Bankkunden wieder ab."
BankkundenDecorator removeFrom: TestPerson. "(6) Feststellen der Adresse der Testperson."
TestPerson adresse.
<printlt> 'Wien'
"(7) Entfernen der globalen Variablen: siehe Programm 14-27."
Programm 14-28 Verhaltensvererbung durch Delegation auf Instanzebene
Die Ergebnissen der unter den Punkten (2), (4) und (6) von Programm 1428 evaluierten immer gleichen Ausdriicke sollen dazu dienen, diese Situation zu veranschaulichen. t
Die Methode Decorator>>removeFrom: ist nicht gezeigt.
412
14 Erweiterte Konzepte und Mechanismen
Kom ponentensicht Instanzvariable des
Kernobjektes
·SankkundenDecorator ON: Person 'Meier'
Instanzvariable des Dekorators
Abbildung 14-9 Inspektion eines dekorierten Objektes
Abbildung 14-9 zeigt die Untersuchung einer Person als Bankkunde durch einen speziellen Inspektor, der unter Punkt (3) des Beispieles geoffnet wurde. Der Spezialinspektor t fUr dekorierte Objekte erlaubt einerseits eine getrennte Untersuchung des Kernobjektes und der angekoppelten Dekoratoren, verbirgt andererseits jedoch diese Komponenten und vermittelt durch die gemeinsame Auflistung aller Instanzvariablen den Eindruck eines einheitlichen Objektes. Durch die in Programm 14-25 gezeigte Methode Decorator class» transparentOn: wird nicht nur das Argument dekoriert, sondern es werden auch alle urspriinglich auf das Argument weisenden Referenzen auf den Dekorator umgeleitet, sodaB das dekorierte Objekt nicht mehr direkt, also unabhlingig von seinem Dekorator angesprochen werden kann. In den meisten Fallen wird es jedoch angebracht sein, gleichzeitig mehrere "Sichten" auf ein Objekt aufrechtzuerhalten, also beispielsweise eine Person einmal direkt, ein andermal als Bankkunde ansprechen zu konnen. Dies kann leicht dadurch erreicht werden, daB das zu dekorierende Objekt mit einem Dekorator versehen wird, der direkt zur Verfugung gestellt wird, ohne die bisherigen Referenzen auf das dekorierte Objekt zu behelligen. Diese Aufgabe wird von der Methode Decorator class subjectiveOn: (Programm 14-29)
t Der hier gezeigte Inspektor ist Instanz einer leicht einzurichtenden Subldasse der in der Klassenhierarchie vorliegenden Klasse Inspector. Die notwendigen Methoden werden hier nicht angefuhrt, doch soll durch dieses Beispiel auf die Flexibilitlit und Erweiterbarkeit des Smalltalk-Systems hingewiesen werden.
14.3 Objekte mit dynamisch wechselnden Eigenschaften
413
erfUllt. Der Name fUr den Selektor dieser Methode wurde in Anlehnung an die in [19] gewlihlte Bezeichnung »Subject-Oriented Programming" gewlihlt.
Decorator class methodsFor: 'instance creation' subjectiveOn: anObject
"Dekoration des Argumentes (anObject) mit einem neuen Dekorator." 1\
self new initialize decoratedObject: anObject
Programm 14-29 Erzeugung und subjektive Zuordnung eines Dekorators
In Programm 14-30 ist ein Beispiel gezeigt, in welchem lihnlich wie in Programm 14-27 eine Person mit der Rolle eines Bankkunden versehen wird, jedoch so, daB die Person als solche nach wie vor fiber ihren Namen TestPerson ansprechbar bleibt und die Bankkundenrolle an den zuslitzlichen Namen TestKunde gebunden ist. 1m Unterschied zu der Situation im vorigen Beispiel sind jetzt zwei »Sichten" auf die Person gleichzeitig vorhanden.
Workspace
"(1) Erzeugen einer Testperson: siehe: Programm 14-27." "(2) Subjektive Objektdekoration: Die Person wird auch Bankkunde." TestKunde := BankkundenDecorator subjectiveOn: TestPerson.
(1)
TestPerson <printlt> Person 'Maier' TestKunde <printlt> BankkundenDecorator ON: Person 'Maier' TestKunde adresse: 'Salzburg'.
"(3) Feststellen der Adresse der Testperson unde des Testkunden." TestPerson adresse TestKunde adresse
<printlt> Wien' <printlt> 'Salzburg'
(1) TestKunde ist wie TestPerson eine globale Variable, die fUr die Zwecke des Beispieles angelegt wurde.
Programm 14-30 Subjektive Dekoration einer Person als Bankkunde
414
14 Erweiterte Konzepte und Mechanismen
Erweiterungen des Rollenkonzeptes Das hier gezeigte Konzept, Objekte durch dynamisches Zuordnen und Entziehen von Satellitenobjekten in wechselnden Rollen erscheinen zu lassen, bildet die Basis fUr vielfaltige Erweiterungen. In [18] wird eine Erweiterung von objektorientierten Systemen durch Rollenkonzepte im allgemeinen und speziell auch von Smalltalk vorgestellt. Hier werden Rollenhierarchien eingefUhrt, durch welche das dynarnische Annehmen und Abgeben von Rollen bestimmter Objekte beschrieben werden kann, zusatzlich ist vorgesehen, Objekte mehrfach mit Rollen ein und derselben Art ausstatten zu konnen und Objekte gezielt in einer von mehreren Rollen anzusprechen. Vorausgesetzt wird allerdings, daB Objekte, die mit Rollen versehen werden sollen, Auspragungen einer Unterklasse von ObjectWithRoles sein mussen, einer abstrakten Klasse, die ihren Unterklassen Rollenverzeichnisse verftigbar macht. Rollenkonzepte aus der Warte von Datenmodellen werden in [2] vorgestellt, mit Rollen zusammenhangende konzeptionelle Fragen werden in [8] in den Vordergrund gestellt.
Literaturverzeichnis
[1]
A.V. Aho, J.E. Hopcroft and J.D. Ullman: Data Structures and Algorithm. Addison-Wesley, 1983
[2] A. Albano, R Bergamini, G. Ghelli, and R. Orsini: An Object Data Model with Roles. Proc. of the 19th VLDB Conference, Dublin, 1993 [3] C. Beeri: A formal approach to object-oriented databases. Data & Knowledge Engineering 5, 353-382, 1990 [4] C. Beeri: New Data Models and Languages - the Challenge. Proc. 11th ACM SIGACT-SIGMOD-SIGART Symposium on Principles of Database Systems, San Diego, I -15, 1992 [5] K. Beck: CRC: Finding objects the easy way. Object Magazine 3(4), 42-44, 1993 [6] K. Beck: To accessor or not to accessor? The Smalltalk Report 2(8), 1993 [7]
G. Booch: Object-Oriented Analysis and Design with Applications (2nd edition). Benjamin Cummings, 1994
[8] B.B. Bruun and K. 0sterbye: Roles: Conceptual Abstraction Theory and Practical Language Issues. Theory and Practice of Object Systems, Vol. 2(3), 143-160, 1996 [9] M.C. BUcker, J. Geidel und M.F. Lachmann: Programmieren in Smalltalk mit VisuaIWorks®: Smalltalk - nicht nur flir AnHinger. Springer, 1995 [10] RG.G. Catell (Hrsg.): The Object Database Standard: ODMG-93, Release 1.2. Morgan Kaufmann Publishers, 1996 [11] P. Coad and E. Yourdon: Object-Oriented Analysis, 2nd edition. Prentice Hall, 1990 [12] P. Coad and E. Yourdon: Object-Oriented Design. Prentice Hall, 1991 [13] E.F. Codd: The Relational Model for Database Management, Version 2. Addison-Wesley, 1990 [14] R Elmasri and S.B. Navathe: Fundamentals of Database Systems. Benjanim Cummings, 1989 G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
416
Literaturverzeichnis
[15] D.G. Firesmith and E. M. Eykholt: Dictionary of Object Technology. SIGS Books, 1995 [16] E. Gamma, R. Helm, R. Johnson and J. Vlissides: Design Patterns: elements of reusable object-oriented software. Addison Wesley, 1995 [17] A.Goldberg and D. Robson: Smalltalk-80 - The Language and its Implementation. Addison Wesley, 1983 [18] G . Gottlob, B. Rock and M. Schrefl: Extending Information Systems with Roles. ACM Transactions on Information Systems 14(3),268 - 296,1996 [19] W. Harrison and H. Ossher: Subject-Oriented Programming (A Critique of Pure Objects). OOPSLA 93, Hrsg. A. Paepcke Special Issue of SIGPLAN Notices 28 (19), ACM Press, 1993 [20] A. Heuer: Objektorientierte Datenbanken: Konzepte, Modelle, Systeme. Addison-Wesley, 1992 [21] T. Howard: The Smalltalk Developer's Guide to Visual Works. SIGS Books, 1995 [22] D. Ingalls: A simple technique for handling multiple polymorphism. Object-Oriented Programming Systems Languages and Applications OOPSLA 86, Special Issue of SIGPLAN Notices 21 (11), 1986 [23] I. Jacobson, M. Christerson, P. Jonson G. Overgaard: Object-Oriented Software Engineering: A Use Case Driven Approach. Addison-Wesley, 1992 [24] G . Kappel und M. Schrefl: Objektorientierte Informationssysteme: Konzepte, Darstellungsmittel, Methoden. Springer, 1996 [25] W.R. Lalonde and J. R. Pugh: Inside Smalltalk, Vol. I. Prentice-Hall International, 1990
*
*
[26] W. LaLonde and J.R. Pugh: Sub classing subtyping Is-a. Journal of Object-Oriented Programming, 3, 57-62, 1991 [27] W. Lalonde: Discovering Smalltalk. Benjamin/Cummings, 1994 [28] C. Lamb, G. Landis, J. Orenstein and D. Weinreb: The ObjectStore Database System. Communications of the ACM, 34(10), 50, 1991 [29] M. Lorenz: Rapid Software Development with Smalltalk. SIGS Books, 1995
Literaturverzeichnis
417
[30] J. Martin and J.J. Odell: Object-Oriented Analysis and Design. Prentice Hall, 1992 [31] ObjectStore Smalltalk User Guide, Release 1: Object Design, Inc. Part number: 320-000-10U [32] K.S. Rubin and A. Goldberg: Object Behavior Analysis. Communications of the ACM 35(9), 48-62, 1992 [33] J. Rumbaugh, M. Blaha, W. Premeriani, F. Eddy and W. Lorensen: Object-Oriented Modeling and Design. Prentice-Hall International, 1991 [34] J. Rambaugh: OMT: The Object Model. Journal of Object Oriented Programming 7(8), 21, 1995 [35] J. Rambaugh: Models for design: Generating Code for associations. Journal of Object Oriented Programming 8(9), 13, 1996 [36] J. Rambaugh: A a search for values: Attributes and Associations. Journal of Object Oriented Programming 9 (3), 6, 1996 [37] F. Penz und G. Vinek: Dynamische Reverse Engineering in Smalltalk. Softwarewartung und Reengineering, Erfahrungen und Entwicklungen Hrsg. F. Lehner, Deutscher UniversiUitsveriag, 1996 [38] M. Sakkinen: Disciplined Inheritance. ECOOP 89, Hrsg. S. Cook Cambridge University Press, 1989 [39] R. Sedgewick: Algorithms, 2nd edition. Addison-Wesley, 1988 [40] R. Sethi: Programming Languages, Concepts and Constructs. Addison-Wesley, 1989 [41] G. Vinek, P.F. Rennert und A Min Tjoa: Datenmodellierung: Theorie und Praxis des Datenbankentwurfes. Physica, 1982 [42] VisualWorks® User's Guide, Rev. 2.0 (Software Release 2.5). ParcPlace-Digitalk, October 1995, Part Number: DSI0005005 [43] P. Wegner and S.B. Zdonik: Inheritance as an Incremental Modification Mechanism or What Like Is and Isnt Like. ECOOP 88, Hrsg. S. Gjessing and K. Nygaard, Springer LNCS 322, 1988 [44] P. Wegner: Concepts and Paradigms of Object-Oriented Programming. OOPS Messenger 1(1), 1990
418
Literaturverzeichnis
[45] R. Wirfs-Brock and B. Wilkerson: Object-Oriented Design: A Responsibility-Driven Approach. OOPSLA 89, Hrsg. N. Meyrowitz, Special Issue of SIGPLAN Notices, 24 (10),1989 [46] R. Wirfs-Brock, B. Wilkerson and L. Wiener: Designing Object Oriented Software. Prentice-Hall, 1990 [47] X3J20 Working Draft of ANSI SmalItalk Standard, Version 1.1, May 1996
Program mverzeichn is 1-1 1-2 1-3 1-4 1-5 1-6 1-7 1-8 1-9 1-10 1-11 1-12 1-13 2-1 2-2 2-3 2-4 2-5 2-6 2-7 2-8 2-9 2-10 2-11 2-12 2-13 2-14 2-15 2-16 2-17 2-18 2-19 2-20 2-21 2-22 2-23 2-24
Globale Variable und Variablenverzeichnisse ................................ 39 Erzeugen von Klassen ....................................................................... 40 Variablenverzeichnisse einer Klasse ................................................ 40 Vererbungsbeziehungen zwischen Klassen ................................... .41 Strukturschablone einer Klasse ........................................................ 42 Auflistung von Methoden ................................................................. 43 Methodenverzeichnisse ..................................................................... 44 Modiftkation von Methoden durch Botschaften ........................... .45 Instanzieren einer Klasse .................................................................. 46 Instanzierungsbeziehung zwischen Instanz und Klasse ................ .47 Methodensuche und dynamisches Binden .................................... .48 Instanzierungsbeziehung zwischen Klasse und Metaklasse ......... .49 Vererbungsbeziehung zwischen Metaklassen ................................. 50 Zuordnung von Methoden zu Klassen ............................................ 53 Freie Methoden in einem Arbeitsbereich (Workspace) ............... 56 Ansprechen von »a-priori"-Objekten durch Literale ...................... 57 Erzeugen von Objekten durch Evaluation von Literalen ............... 58 Beispiele zur Notation von Literalen fUr Zahlen ............................ 59 Uberpriifen, ob Objekte eine Literaldarstellung besitzen .............. 60 Implementationen der Methode isLiteral ....................................... 61 Zur Literaldarstellung von Arrays .................................................... 62 Belegung einer Variablen mit unterschiedlichen Objekten ........... 64 Zuweisungsausdriicke ....................................................................... 66 Mehrfachzuweisung .......................................................................... 66 Eine Methode mit Schliisselwortselektoren .................................... 68 Verkettung uniirer Botschaften ........................................................ 70 Verkettung biniirer Botschaften ....................................................... 71 Verkettung unlirer und biniirer Botschaften ................................... 71 Interpretation von Schliisselwortem ................................................ 72 Verkettung verschiedener Arten von Ausdriicken ......................... 72 Getrennte und kaskadierte Botschaftsausdriicke ............................ 73 Ein Block ohne Argumente .............................................................. 75 Ein Block mit einem Argument ....................................................... 76 Unbedingte Wiederholung eines Blockes ....................................... 77 Bedingte Wiederholung eines Blockes ............................................ 78 Iteration durch Blockwiederholung ................................................. 79 Primiirmethoden der Klasse BlockClosure ..................................... 81
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
420 2-25 2-26 2-27 2-28 2-29 2-30 2-31 2-32 2-33 2-34 2-35 2-36 2-37 2-38 2-39 2-40 2-41 2-42 2-43 2-44 3-1 3-2 3-3 3-4 3-5 3-6 3-7 3-8 3-9 3-10 3-11 3-12 3-13 3-14 4-1 4-2 4-3 4-4 4-5 4-6 4-7
Programmverzeichnis Logische Operationen der Klasse Boolean ..................................... 83 Logisches Verhalten der Objekte true und false ............................ 84 Kontrollverhalten der Objekte true und false ................................ 84 Beispiele fUr Kontrollmethoden von true und false ...................... 85 Wiederholte Evaluierung eines Blockes .......................................... 86 Beispiel fUr die unbeeinfluBte Blockwiederholung ........................ 86 Iteration tiber eine arithmetische Zahlenfolge ............................... 87 Blockiteration mit arithmetischer Aufzahlung ............................... 88 Iteration tiber die aufgeziihlten Elemente eines Behiilters ............ 89 Blockiteration mit Aufzahlung der Elemente eines Behiilters ...... 89 Feststellen, welche Zeichen als binare Selektoren gelten .............. 90 Ftir binare Selektoren zuliissige Zeichen ........................................ 91 Eine Methode mit einem binaren Selektor. .................................... 91 Indirektes Senden einer Methode .................................................... 92 Konstruktion eines Selektors ........................................................... 92 Defmition und Verwendung eines Blockes .................................... 94 Zur Verwendung von globalen Variablen in Blocken .................... 95 Definition eines Blockes mit einer Rtickgabeanweisung ............... 96 Ein Rtickgabeobjekt kann nicht tibergeben werden ....................... 97 Erzeugen und "Ausdrucken" von Toleranzintervallen ................ 101 Definition der Klasse Zahlwerk ..................................................... 106 Namenskonforme Zugriffsmethoden auf die Instanzvariablen .. 108 Methoden zum Bedienen von Zahlwerken ................................... l08 Methoden zur Erzeugung und Initialisierung von Ziihlwerken .. 109 Defmition der Klasse ZahlwerkMitDatum ..................................... 112 Methoden zum Bedienen von Zahlwerken mit Datum ............... 113 Die Klasse Superzahlwerk ............................................................. 116 Methoden zur Bedienung eines Superzahlwerkes ....................... 116 Die Klasse Verbundzahlwerk ........................................................ 121 Methoden zur Bedienung eines Verbundzahlwerkes .................. 122 VisualZahlwerk, eine visualisierbare Variante von Zahlwerk ..... 125 Methoden zur Bedienung von visualisierbaren Zahlwerken ....... 126 Ausschnitt aus der Klasse ValueHolder ........................................ 127 Die Klasse Statistikzahlwerk .......................................................... 130 Zugriff auf die GroBe eines Sammelbehiilters .............................. 134 EinfUgen von Elementen in Samrnlungen .................................... 135 Entfernen von Elementen aus Sammlungen ................................ 136 Einsammeln transformierter Elemente ......................................... 137 Beispiele fUr Enumeration mit Transformation ........................... 138 Auswiihlen von Elementen ............................................................ 139 Beispiele fur Enumeration mit Auswahl ....................................... 139
Programmverzeichnis 4-8 4-9 4-10 4-11 4-12 4-13 4-14 4-15 4-16 4-17 4-18 4-19 4-20 4-21 4-22 4-23 4-24 4-25 4-26 4-27 4-28 4-29 4-30 4-31 4-32 4-33 4-34 4-35 5-1 5-2 5-3 5-4 5-5 5-6 5-7 5-8 5-9 5-10 5-11 5-12 5-13
421
Suchen eines Elementes, das eine Eigenschaft erfullt ................. 140 Beispiele fur das Aufsuchen eines Elementes .............................. 141 Akkumulation von Elementen ....................................................... 141 Beispiele fur Akkumulation von Elementen ................................. 142 Defmition und Instanzierung einer konstanten Klasse ................ 143 Defmition und Instanzierung einer variablen Klasse ................... 144 Beispiele fUr den Zugriff auf indizierte Instanzvariable ............... 147 Die Methode SequenceableColiection»do: ............................. 149 Beispiele fUr Methoden von Array ................................................. 151 Beispiele fur die Manipulation von Zeichenketten ...................... 152 Die SchHisselmethoden der Klasse OrderedColiection ............... 154 Redefinition der Methode Object»at: ........................................ 156 Erzeugen und Inspizieren einer geordneten Sammlung .............. 157 Scheinbare Dehnbarkeit eines Behalterobjektes .......................... 158 Alphabetisches Sortieren von Worten einer Zeichenkette .......... 160 Vorgabe eines Sortierblockes ......................................................... 160 Sortieren von Zeichenketten nach der Haufigkeit von $a ........... 161 Die Schltisselmethode SortedColiection»add: ......................... 162 Die Schltisselmethode Set»add: ................................................ 163 Beispiele fUr Assoziationen ..................................................•......... 164 Beispiele fUr Verzeichnisse ............................................................. 165 Die Methode OrderedColiection»addLast .............................. 167 Skizze von OrderedColiection»makeRoomAtLast... ................ 167 Kapazitatsvergr613erung einer geordneten Ansammlung ............. 168 Erzeugung eines Sortierblockes ..................................................... 171 Das Kreuzprodukt zwischen zwei Mengen ................................... 172 Bildung von Kreuzprodukten mehrerer Mengen ......................... 173 Beispiele fUr Kreuzprodukte von Mengen .................................... 174 Vereinigung, Durchschnitt und Differenz zweier Mengen ......... 176 Beispiele fUr Mengenoperationen .................................................. 176 Testmethoden fUr Relationen ........................................................ 179 EinfUgen von Tupel in Relationen ................................................. 180 Beispiele fUr Mengenoperationen mit Relationen ........................ 181 Die relationale Operation "Selektion" - Teill ............................... 182 Die relationale Operation "Selektion" - Teil2 ............................... 182 Beispiele fUr Selektionsoperationen ............................................... 183 Die relationale Operation "Projektion" .......................................... 184 Beispiele fUr Projektionsoperationen ............................................. 185 Verbund von Relationen tiber je eine Komponente .................... 186 Beispiele fUr Verbundoperationen ................................................. 187 Kreuzprodukte zwischen Mengen und Relationen ...................... 189
422 5-14 5-15 5-16 5-17 5-18 5-19 6-1 6-2 6-3 6-4 6-5 6-6 6-7 6-8 6-9 6-10 6-11 6-12 6-13 6-14 6-15 6-16 6-17 6-18 6-19 6-20 6-21 6-22 6-23 6-24 7-1 7-2 7-3 7-4 7-5 7-6 7-7 7-8 7-9 7-10 7-11
Programmverzeichnis Ein untauglicher Versuch fur die Methode Relation»x ........... 190 "Zweifachzuteilung" der Methode Relation»x ......................... 191 Natiirlicher Gleichverbund zweier Relationen ............................. 193 Zweifach polymorphe Auftragsmethoden ..................................... 195 Auftragsdelegation durch eine indirekte Methode ....................... 195 Beispiele fur die Vergabe von Auftragen ...................................... 196 Elementare Zuordnungsmethoden ................................................ 199 Beispiele fur Operationen mit Attributobjekten ........................... 203 Methoden fur eine Attributzuordnung ......................................... 203 Eine Methode fur seichtes Kopieren ............................................. 208 Die Methoden Object>>copy und Object»postCopy ............ 209 Eine Methode Adresse»postCopy ............................................ 209 Zugriff'smethoden fur eine (O .. n) Zuordnung ............................... 214 Zuordnung mit Multiplizitatstest ................................................... 215 Zugriff'smethoden fur eine (O .. n) Attributzuordnung .................. 216 Ein Attributbehlilter der Art OrderedAttributeColiection .......... 217 Initialisierung einer mehrwertigen Attributzuordnung ............... 218 Beispiel fur eine mehrwertige Attributzuordnung ....................... 218 Zuordnung mit Varietatstest .......................................................... 222 Zuordnung mit Test auf schwache Varietal .................................. 223 Zuordnung mit schwacher Heterogenitatseinschrllnkung ........... 227 Zuordnung mit starker Heterogenitatseinschrlinkung ................. 228 Direkter ZugrifT auf das erste Konto eines Kunden ..................... 232 Indirekter Zugriff' auf das erste Konto eines Kunden .................. 233 Private Hilfsmethoden fur die Kunde-Konto-Beziehung ............ 236 Errichten einer gekoppelten Zuordnung ....................................... 237 Auflosung einer gekoppelten Zuordnung ..................................... 238 Feststellen von Objekten, die ein Objekt referenzieren ............... 243 Uberpriifen der Attributeigenschaft eines Objektes ..................... 244 Beispiele fur die Uberpriifung der Attributeigenschaft ................ 245 Defmition der Klasse AssociableObject ...................................... 251 Metainformation der Beispielklassen ............................................ 253 Initialisierung der Modellinformation ........................................... 255 Registrierung der Modellinformationen ........................................ 256 Kontrolliertes Errichten einer Beziehung ..................................... 259 Zugriff' auf Modellinformationen ................................................... 260 Privater Zugriff' auf das Modellverzeichnis ................................... 261 Zugriff' auf das Beziehungsverzeichnis .......................................... 261 Kontrolliertes Losen einer bestehenden Beziehung .................... 262 Beziehungsmethoden: Studienwesen einer Universitat .............. 263 Beziehungsmethoden: Studien eines Studenten .......................... 263
Programmverzeichnis 7-12
423
Beispiel: Eine Universitat mit Studien und Studenten ................ 264 Kontrollierte Verwaltung von Beziehungen ................................. 265 7-14 Uberpriifung von Beziehungen ...................................................... 266 7-15 Test auf Heterogenitatskonformitat ............................................... 267 8-1 Die Klasse Magnitude in der Klassenhierarchie ........................... 272 8-2 Vergleichsmethoden der Klasse Magnitude (Auswahl) ............... 273 Instanzen der Klasse FixedPoint .................................................... 273 8-3 8-4 Basismethoden flir den Vergleich von Geldobjekten .................. 274 8-5 Kontrolliertes Zuordnen eines Wlihrungssymbols ....................... 275 8-6 Attributzugriff auf den Betrag eines Geldobjektes ....................... 275 8-7 Erzeugung von Geldobjekten ......................................................... 276 8-8 Druckdarstellung eines Geldobjektes ............................................ 277 8-9 Erzeugung und Druckdarstellung von Geldobjekten ................... 278 8-10 Vergleich von Geldbetragen ........................................................... 278 8-11 Rechenoperationen mit Geldobjekten ........................................... 279 8-12 Arithmetische Verkntipfung von Geldobjekten ........................... 279 9-1 Die abstrakte Klasse Konto ............................................................. 284 9-2 Die abstrakte Klasse Vollkonto ....................................................... 285 9-3 Konstruktormethode flir Konten ...................................................285 9-4 Initialisieren eines Vollkontos ........................................................ 286 9-5 Bestimmen der Zinssatze von Standardkonten ............................ 286 9-6 Kontoumsatze .................................................................................. 287 Eingangsbuchung auf Konten ........................................................ 288 9-7 9-8 Ausgangsbuchung auf Vollkonten ................................................. 288 Die Konditionen fUr Jugendsparkonten ........................................ 289 9-9 9-10 Zinssatzbestimmung durch Zugriff auf die Instanzvariable ........ 290 9-11 Der Variablenpool Wirtschaftsdaten ............................................ 291 9-12 Anlegen von Konten und Uberpriifen ihrer Konditionen ........... 291 9-13 Kontobewegungen ........................................................................... 292 10-1 Defmition und Initialisierung von Bankkunden ........................... 297 10-2 Zuordnung eines Kontos zu einem Kunden ................................. 298 10-3 »Druckausgabe" von Personen und Bankkunden ......................... 298 10-4 Instanzierungsmethoden der Klasse Person ................................. 299 10-5 Defmition und voriaufige Initialisierung der Klasse Bank .......... 301 10-6 Initialisierung einer Bank ................................................................ 302 10-7 »Druckdarstellung" einer Bank fUr Testzwecke ............................ 302 10-8 Erzeugen einer »Testbank" ............................................................. 303 10-9 Erzeugung eines Bankkunden in der Bankapplikation ................. 303 10-10 Herstellung der Beziehung zwischen Bank und Kunden ............ 304 10-11 Zugriff auf einen Kunden tiber die Kundennummer ................... 304 10-12 Geschliftsfall: Aufnahme neuer Kunden ....................................... 305
7-13
424 10-13 10-14 10-15 10-16 10-17 10-18 10-19 10-20 10-21 10-22 10-23 10-24 10-25 10-26 10-27 10-28 10-29 11-1 11-2 11-3 11-4 11-5 11-6 11-7 11-8 11-9 11-10 11-11 11-12 11-13 11-14 11-15 11-16 11-17 11-18 11-19 12-1 12-2 12-3 12-4 12-5
Programmverzeichnis Suchen alIer Kunden mit vorgegebenem Namen ........................ 306 Einrichten der Zuordnung zwischen Konto und Kunden ........... 307 Registrierung eines Kontos ............................................................. 307 Geschliftsmethode: Anlegen eines Kontos ................................... 308 Geschliftsfall: Eroffnen von zwei Konten ..................................... 309 Geschliftsfall: Eroffnen weiterer Konten ....................................... 309 Eine Familie von Buchungsmethoden .......................................... 311 Geschliftsfall: Ein- und Auszahlungen auf einem Konto ............ 312 Geschliftsmethode: Kontotiberweisung ........................................ 313 Geschliftsfall: Uberweisung zwischen Konten .............................. 313 Informationen tiber Konten von Kunden ..................................... 314 Beispiele fUr Informationen tiber Kunden .................................... 315 Erstellen einer Kundenliste ............................................................ 316 Beispiel fUr eine Kundenliste ......................................................... 316 Informationen tiber Konten ........................................................... 317 Erzeugung von Kontenlisten .......................................................... 318 Beispiel fur eine nach Salden sortierte Kontenliste ..................... 318 Nichtoffentliche Methoden fUr ein Zentralregister ...................... 323 Offentliche Methoden zum Lesen eines Zentralregisters ............ 324 Zentralregister» printOn: ........................................................... 324 Erstellen von Ausztigen aus einem Zentralregister ...................... 325 Erzeugung des (aktiven) Bankenservice ........................................ 326 Initialisierung des Bankenservice ................................................... 327 Laden der Wirtschafts- und Wlihrungsdaten ................................ 327 Hilfsmethoden fUr das Bankenservice ........................................... 328 BankenService» printOn: .......................................................... 328 Erzeugung und Ausgabe eines Bankenservice ............................. 329 Einige Methoden fUr Bankregistrierungen .................................... 330 Verwaltung des Bankenregisters .................................................... 331 Registrierte Banken ......................................................................... 331 Initialisierung der Klasse Bank fUr die Registrierung .................. 332 Registrierung einer Bank ................................................................ 333 Erzeugen und Registrieren der Testbank ...................................... 333 Geschliftsfall: Registrieren einer Bank .......................................... 334 Zentralregister mit verschiedenen Objekten ................................. 336 Zentralregister mit ungleichen Objekten ....................................... 336 Erweiterung der Klasse BankenService ....................................... 340 Adaption der Registrierung einer Bank ......................................... 341 Lesen und Schreiben des Zahlungsverkehrsregisters .................. 341 Die Klasse Kontolnfo ...................................................................... 342 Erzeugung einer Kontoinformation ............................................... 343
Programmverzeichnis 12-6 12-7 12-8 12-9 12-10 12-11 12-12 12-13 12-14 12-15 12-16 12-17 12-18 13-1 13-2 13-3 13-4 13-5 13-6 13-7 13-8 13-9 13-10 13-11 13-12 13-13 13-14 14-1 14-2 14-3 14-4 14-5 14-6 14-7 14-8 14-9 14-10 14-11 14-12 14-13
425
Defmition und Erzeugung von Bankauftragen ............................. 344 Zustandslinderungen von Bankauftragen ...................................... 344 Defmition und Erzeugung von Inlandstiberweisungen ............... 345 Formale Kontrolle eines Bankauftrages ........................................ 347 Inhaltliche Kontrolle eines Bankauftrages .................................... 348 Erweiterung der Klasse Bank ......................................................... 349 Einf1.igen eines Auftrages in den Auftragsbestand ....................... 350 Beispiele fUr Methoden des Geschliftsbetriebes ........................... 351 Zugriff auf Kunden- und Partnerauftrage ...................................... 351 Eine Methodenfamilie zur Auswahl von Kundenauftragen ........ 352 Eingang einer Inlandstiberweisung ................................................ 353 Kontrolle und Weiterleitung einer Inlandstiberweisung ............. 353 Kontrolle und Erledigung einer Inlandstiberweisung .................. 354 Testumgebung fUr persistente Objekte .......................................... 356 Die Methode PersistDemo»storeOn: ........................................ 358 Ein Smalltalk-Ausdruck zur Repriisentation eines Objektes ....... 358 Beispiel zur Kodierung durch Smalltalk-Ausdriicke .................... 359 Rekonstruktion eines Objektes aus einem Literalfeld .................. 360 Vorbereitung fUr die Literalfeld-Kodierung .................................. 361 Ein Literalfeld zur Repriisentation eines Objektes ....................... 361 Beispiel zur Literalfeld-Kodierung ................................................. 362 Beispiel zur BOSS-Kodierung ........................................................ 363 Beispiel zur Speicherung in ObjectStore ....................................... 367 Erzeugen von Objekten im persistenten Objektraum .................. 368 Benannte persistente Objekte ......................................................... 371 Ansprechen von persistenten Objekten tiber Namen .................. 373 Migration von Objekten in den persistenten Objektraum ........... 375 Administration der abhangigen Informanden .............................. 383 Die polymorphe Methode asDependentsWith: ........................... 384 Benachrichtigung der Informanden (abhlingigen Objekte) .......... 386 Die Methodenfamilie Object»update:with:from: ..................... 387 Adaption der Klasse Konto als Informatorklasse .......................... 388 Adaption der Klasse Z~hlwerk als Informandenklasse ................ 389 Einrichten und Testen einer direkten Informator-InformandBeziehung zwischen einem Konto und einem Zlihlwerk ............ 389 Objektzuordnung durch Instanzen von ValueHolder .................. 390 Adaption von Methoden der Klasse Konto ................................... 392 Eine wirklich private Methode ....................................................... 397 Unerwiinschter direkter Schreibzugriff auf ein Zentralregister. .. 398 Die Klasse GeschOtztesRegister ................................................... 399 Berechtigungspriifung fUr geschtitzte Register ............................. 400
426 14-14 14-15 14-16 14-17 14-18 14-19 14-20 14-21 14-22 14-23 14-24 14-25 14-26 14-27 14-28 14-29 14-30
Programmverzeichnis Schreibzugriffe auf ein geschiitztes Register................................. 400 Initialisierung des Bankenservice mit geschiitzten Registem ...... 400 Erfolgloser Versuch einer direkten Bankregistrierung ................ .40 1 Objektmutation ................................................................................ 402 Obertragung namensgleicher Komponenten ................................ 403 Mutation von Person zu Bankkunde ........................................... 405 Namensgleiche Komponenten von Personen und Bankkunden 405 Direkte Transferierung namensgleicher Komponenten .............. 406 Die abstrakte Klasse Decorator ..................................................... 407 Aufsuchen des Kemobjektes eines Dekorators ............................ 408 Druckausgabe eines Dekorators ..................................................... 408 Transparente Erzeugung eines Dekorators ................................... 409 Die Klasse BankkundenDekorator ............................................... 409 Transparente Dekoration einer Person als Bankkunde .............. .410 Verhaltensvererbung durch Delegation auflnstanzebene .......... 411 Erzeugung und subjektive Zuordnung eines Dekorators ............ 413 Subjektive Dekoration einer Person als Bankkunde .................... 413
Abbildungsverzeichnis 1-1 1-2 1-3 1-4 1-5 1-6 1-7 1-8 1-9 1-10 1-11 1-12 1-13 1-14 1-15 1-16 1-17 1-18 1-19 1-20 3-1 3-2 3-3 3-4 3-5 3-6 3-7 3-8 3-9 3-10 3-11 4-1 4-2 4-3 4-4 4-5 4-6 6-1 6-2 6-3 6-4 6-5 6-6
Objekte und Namen ........................................................................... 3 Die innere Struktur eines Objektes ................................................... 4 Konzeptioneller Objektraum auf Anwendungsebene ..................... 7 Konzeptioneller Objektraum auf Arbeitsebene ............................... 8 Konzeptioneller Objektraum auf Basisebene (1) ............................. 9 Konzeptioneller Objektraum auf Basisebene (2) ........................... 10 Der Zusammenhang zwischen Objektriiumen ............................... 12 Geschiifts- und Schnittstellenobjekte ............................................. 13 Klassen und ihre Auspriigungen (Instanzen) ................................. 14 Ausschnitt aus der Klassenhierarchie von Smalltalk ..................... 16 Strukturvererbung zwischen Klassen .............................................. 17 Methodensuche in der Klassenhierarchie ...................................... 20 Sichtbarkeit von statischen Objektnamen ...................................... 25 Sichtbarkeit von dynamischen Objektnamen ................................. 27 Strukturdiagramm einer Botschaftsiibermittlung .......................... 28 Prozef3diagramm einer Botschaftsiibermittlung ............................ 29 Der technische Objektraum (VisualWorks) ................................... 32 Schematischer Aufbau des Smalltalk-Systems .............................. 33 Klassen und ihre Metaklassen ......................................................... 34 Organisation von Variablenverzeichnissen .................................... 37 Ein Ziihlwerk in der realen Welt.. ................................................. 104 Ein Ziihlwerk im Objektraum ........................................................ 104 Inspektion eines Ziihlwerkes im Objektraum ............................... 105 System Browser mit Defmition der Klasse Z4hlwerk .................. 107 Erzeugung und Inspektion eines Ziihlwerkes .............................. 110 Inspektion eines ZilhlwerkMitOatum im Objektraum ................. 112 Erzeugung und Inspektion eines Ziihlwerkes mit Datum .......... 114 Initialisierungsprozef3 eines Superziihlwerkes .............................. 117 Inspektion eines Verbundziihlwerkes im Objektraum ................ 123 Inspektion eines VisualZiihlwerkes im Objektraum .................... 127 Werkzeuge zum Entwurf einer Benutzeransicht ......................... 128 Ausschnitt aus der Klassenhierarchie der Kollektionen ............. 132 Variable Klassen und ihre Auspriigungen .................................... 145 Inspektion einer Auspriigung von VariableClass .......................... 146 Sichten eines BehiUters der Art OrderedCollection ..................... 155 Inspektion von geordneten Sammlungen .................................... 157 Transparente Vertauschung zweier Objekte ................................ 169 Notation von Attributbeziehungen in einem Modell ................. 200 Attributzuordnung eines Adressenobjektes ................................. 204 Personen mit unterschiedlichen Adressen ................................... 205 Personen mit identischen Adressen .............................................. 206 Personen mit gleichen Adressen ................................................... 207 Ein Adressenobjekt und eine maximal tiefe Kopie ..................... 210
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
428 6-7 6-8 6-9 6-10 6-11 6-12 6-13 6-14 6-15 6-16 6-17 6-18 6-19 6-20 6-21 6-22 7-1 7-2 8-1 9-1 10-1 10-2 11-1 11-2 12-1 12-2 12-3 12-4 13-1 13-2 13-3 13-4 13-5 13-6 13-7 13-8 13-9 13-10 14-1 14-2 14-3 14-4 14-5 14-6 14-7 14-8 14-9
Abbildungsverzeichnis Objektzuordnung mit Multiplizitatsangabe ................................. 213 Eine Klassenhierarchie von Rechtssubjekten .............................. 220 Schwach variante Zuordnung von Kunden zu Firmen ............... 221 Stark variante Zuordnung von Kunden zu Firmen ..................... 221 Nicht variante Zuordnung von Kunden zu Firmen .................... 224 Modellierung spezieller Firmen auf Klassenebene ..................... 225 Stark variante Zuordnung mit Heterogenitatseinschrlinkung .... 226 Anordnung der Vomamen einer Person ...................................... 230 Verzeichnis der Konten einer Bank .............................................. 231 Direkte Zuordnung von Konten zu einem Bankkunden ............ 232 Indirekte Zuordnung von Konten zu einem Bankkunden ......... 233 Unabhangige gegenseitige Zuordnungen im Modell .................. 234 Unabhlingige gegenseitige Zuordnungen im Objektraum .......... 235 Gekoppelte Zuordnung zwischen Bankkunden und Konten ..... 235 Mutabilitatseinschrankungen ........................................................ 241 Flexibilitat von Zuordnungen ....................................................... 243 Modell fUr das Studienwesen ........................................................ 248 Ausschnitt aus dem Objektraum ................................................... 257 Ein Modell fur Geld ....................................................................... 271 Strukturmodell eines Kontos ........................................................ 282 Strukturmodell fUr den Bankbetrieb ............................................. 296 Strukturmodell einer Bank ............................................................ 300 Modell des Bankwesens ................................................................. 320 Ausschnitt aus dem Objektraum: zwei registrierte Banken ........ 322 Ein erweitertes Modell des Bankwesens ...................................... 338 Bankauftrage ................................................................................... 339 Zustandsdiagramm fUr eine Inlandsiiberweisung ....................... 346 Erweiterung des Modelles einer Bank .......................................... 349 Transiente Objekte im Objektraum .............................................. 357 Situation nach der Rekonstruktion eines kodierten Objektes .... 359 Situation nach der Rekonstruktion eines "gebossten" Objektes 364 Situation im Objektraum wlihrend einer Transaktion ................ 369 Situation im Objektraum auBerhalb einer Transaktion .............. 370 Inspektion eines persistenten Objektes ........................................ 370 Situation im transienten und permanenten Objektraum ............ 372 Situation im Objektraum wahrend einer Transaktion ................ 374 Objekte im Objektraum auBerhalb einer Transaktion ................ 376 Objekte im Objektraum wlihrend einer Transaktion ................... 377 Die Abhangigkeitsbeziehung ........................................................ 382 Ein Geschaftsobjekt als direkter Informator ................................ 388 Ein ValueHolder eines Attributes als Informator ....................... 391 Ein ValueHolder eines Attributes als Informator ....................... 393 Die Struktur des MVC-Frameworks ............................................. 395 Struktur der Sender-Empfanger-Beziehung ................................. 396 Die Dekorationsbeziehung ............................................................ 406 Modell einer Dekorationsbeziehung ............................................ 407 Inspektion eines dekorierten Objektes ......................................... 412
Klassen- und Methodenverzeichnis A Adresse postCopy 209 shaliowCopy 208 ArithmeticValue abs 71 squared 72 Array 150 decodeAsLiteralArray 360 isLiteral 61 ArrayedColiection class with:with:with: 62 AssociableObject 250 associateNamed:role:with:role: 259 associationsNamed :role: 261 cardinalityAt: 261 deAssociateNamed :role :from :role: 262 hasDesignFor: 260 homogenityAt: 260 initAssociationDesign 255 initClassDesign 251 initialize 255 isAssociable 251 isHeteroConformAt:with: 267 maxMultiplicityAt: 260 minMultiplicityAt: 260 partnerAt: 261 registerAIl 255 registerAssociations 256 registerAssociations: 256
B Bank 301, 349 alleErstelltenKundenlnlandsOberweisungen 352 alieKundenAuftrl!geDerArt: 351 aliePartnerAuftrl!geDerArt: 351 beauftrageUndObermittleAlleKundenlnlandsOberweisungen 351 initialisiereKunden 302 initialize 302 kontenliste 318
kontoMitNummer:einzahlung:mitText:undValutaDatum: 311 kontonummernVonKundenMitNummer: 314 kontrolliereAlieKundenlnlandsOberweisungen 351 kontrolliereAus: 347 kundeMitNummer: 304 kundenlisteMitSaldoSortiert 316 kundenMitNamen: 306 kundenNummernMitNamen: 306 printOn: 302 prOfeDeckungFOr: 348 registriereKonto: 307 registriereKonto:fOrKundenMitNummer: 307 registriereKunde: 304 saldenSumme 314 saldenSummeVonKundeMitNummer: 314 saldoVonKontoMitNummer: 317 transferiereBetrag:vonKontoMitNummer:nachKontoMitNummer:
313 BankenService 325 auftrl!geFQrBLZ: 341 initialisiereAlies 327 printOn: 328 publiziereBankrate 328 registriereAuftrag:fOrBLZ: 341 registriereBank:mitNamen:undAdresse: 333, 341 setzeBankrate: 328 BankenService class new 326 Bankkunde 297 addKonto: 236, 298 bekommtKonto: 237, 307 hatKonto: 236 initialize 297 newMitNamen:undAdresse: 299 printOn: 298 verliertKonto: 238
G. Vinek, Objektorientierte Softwareentwicklung mit Smalltalk © Springer-Verlag Berlin Heidelberg 1997
430
Klassen- und Methodenverzeichnis
Bankkunde class newBeiBank:mitNamen:undAdresse: 303 BankkundenDecorator bekommtKonto: 409 BankkundenDekorator 409 BankRegistrierung 330 Behavior alllnstances 47 allSelectors 44 allSuperclasses 41,50 canUnderstand: 44 includesSelector: 44 instanceCount 47, 57 selectors 44 sourceCodeAt: 45 subclasses 50 superclass 41, 50 BlockClosure 77 repeat 77 value 75, 81, 88 value: 76 valueWithArguments: 77, 81 whileTrue: 78, 88 BlockHolder 94 defineBlockNoReturn 94 defineBlockWithReturn 96 useBlock 94 Boolean 17 eqv: 83 xor: 83 Browser allClasseslmplementing: 60 ByteString 151
C
Collection class with: 53, 64 with :with: 68 Compiler evaluate: 359 Controller 394
D Date readFrom: 88 Decorator 407 doesNotUnderstand: 407 kernelObject 408 printOn: 408 Decorator class subjectiveOn: 413 transparentOn: 409 DependencyTransformer 393 DependentsCollection asDependentsWith: 384 update:with:from: 387 Dictionary 164 at:put: 98
E ExternalReadWriteStream 358
Character 24 Class classPool 40 sharedPools 40 ClassDescription alllnstVarNames 42 instVarNames 42, 49 Collection 17, 132 add: 72, 73, 132 addAII: 135, 161 asSortedCollection: capacity 134 collect: 137
detect:ifNone: 140 do: 89, 133 includes: 140 inject:into: 141 isEmpty 53 reject: 139 remove: 73 remove:ifAbsent: 133 select: 139 size 53, 134
F False 17,83 & 84 184 and: 84 ifFalse: 84 ifTrue: 84 or: 84
160
Firma addKundeHettest: 227 addKundeHomTest: 228 addKundeVarTest: 222, 223
431
Klassen- und Methodenverzeichnis auftragAn: 195 auftragVonFirma: 195 auftragVonlnstitution: 195 auftragVonPrivatperson: 195
G GeschOtztesRegister 398 berechtige 399 initialize 399 GeschOtztesRegister class newMitBerechtigungFOr: 399
I IdentityDictionary 382 Integer asMoney 276 timesRepeat: 86 Interval
do: 87
J Jugendsparkonto zinsSatzHaben 289 Jugendsparkonto class initialize 289
K Konto 283 buchSaldo 392 buchSaldo: 392 buchSaldoHolder 392 einzahlung:mitText:undValutaDatum: 288, 388 initialize 285, 392 printOn: 284 vermerkeUmsatz: 288 zinsSatzHaben 286 zinsSatzSoll 286 Konto class initialize 284 newBeiBank:fOrKundenMitNummer: 308 newMitNummer: 285 Kontolnfo 342 newVonKonto: 343 Kontoumsatz class newBetrag:buchungsText:valutaDatum: 287
M Magnitude 271
<=273
between:and: 273 MethodContext 396 Model 383, 394 Money 274
- 279 + 279 <274
amount: 275 currency: 275 isSameCurrencyAs: 274 new 276 printOn: 277 scaleBy: 279 Money class newAmount: 276 newAmountandCurrency: 276
N Number ± 91 floor 70 to:by:do: 87
o Object 19,382
=69 =69 -=69 -- 69
addDependent: 383 asDependentsWith: 384 at: 146 at:put: 146 basicAt: 146 basicAt:put: 146 basicSize 146 become: 168 changed 386 changed: 386 class 47, 49, 57 commonlnstVarsWith: 403 copy 209 countReferencesFromlnstancesOf:
244
countReferencesTo: 244
432
Klassen- und Methodenverzeichnis
doesNotUnderstand: 19 hanged:with: 386 initializelnstVarsFrom: 403 isAssociable 251 isAttributeln: 244 islmmediate 57 isKindOf: 47, 49 isLiteral 60, 61 isMemberOf: 47, 49 isVarietyOf: 222 mutateTo: 402 ownedBylnstancesOf: 243 perform:with: 92 perform:withArguments: 92 postCopy 209 removeDependent: 383 size 146 storeOn: 357 transferlnstVarsFrom: 406 update: 387 update:with: 387 update:with:from: 387 OrderedAttributeColiection 216 addLast: 217 first 217 postCopy 217 OrderedColiection 152 add: 154 add:after: 153 add:before: 153 addFirst: 153 add Last: 153, 167 after: 153 at: 156 before: 153 do: 154 remove:ifAbsent: 154 removeFirst 153 removeLast 153 OrderedeColiection changeCapacityTo: 168 increaseCapacity 168 makeRoomAtLast 167 OSTransaction transact: 368, 373, 375
p PersistDemo 357 IiteralArrayEncoding 361
makePersistentNamed: 373 printPersistentNamed: 373 storeOn: 358 Person addVorname: 214 addVornameAlsAttribut: 216 addVornameMultTest: 215 cardVomamen 214 name 199 name: 199 nameAlsAttribut 203 nameAlsAttribut: 203 removeVorname: 214 vornamenAlsAttribut 216
R RegistrierteBank 331 Relation 178 x 186, 191 add: 180 anyTupel 179 equiJoinAt:with:at: 186 greaterJoinAt:with:at: 186 isTupelCompatibleWith: 179 joinAt:with:at:using: 186 naturaIJoinAt:with:at: 193 projectAt: 184 selectAt:andAt:using: 182 selectAtlessThanAt: 182 selectAt:value:using: 182 selectAt:valueEqual: 182 selectAt:valueLess: 182 tupelDimension 179
s Scanner class binarySelectors 90 SequenceableColiection 149 , 150 copyWith: 150 do: 149 first 149 indexOf:ifAbsent: 150 indexOfSubCollection:startingAt: 150 last 149 Set 162 + 176 1176
433
Klassen- und Methodenverzeichnis \ 176
x 172
add: 163 crossAdd: 173 crossProductwithAII: 173 prepareCrossAdd 173 Smalllnteger 24 maxVal79 odd 70 SortedColiection 159 add: 162 StatistikzAhlwerk 130 Student belegt: 263 studien 263 Supe~hlwerk 116 initialize 116 liesZAhlerstand 116 start 116 tiihle 116
T Toleranzintervall printOn: 101 von:bis: 101 True 17,83 & 84 184 and: 84 ifFalse: 84 ifTrue: 84 or: 84
U UndefinedObject asDependentsWith: 384 UniversitAt bietetStudium: 263 kursangebot 263 studienangebot 263 veranstaltetKurs: 263
V ValueHolder 126, 390 setValue: 390 value 127, 390 ValueModel value: 390 Variable Binding 40
VerbundzAhlwerk 121 initialize 121 liesZAhlerstand 122 start 122 zAhle 122 VerbundzAhlwerk class new 121 View 394 Visualisierungsobjekte 394 VisualZAhlwerk 125 liesZAhlerstand 126 register: 125 start 126 zAhle 126 Vollkonto auszahlung:mitText:undValutaDatum: 288 initialize 286 Vollkonto class initialize 285
Z ZAhlwerk 106 initialize 109 liesZAhlerstand 108 register 108 register: 108 start 108 update: 389 zAhle 108 ZAhlwerk class new 109 ZAhlwerkMitDatum III initialize 112 liesDatum 113 start 113 Zentralregister 322, 397 eintragBei: 324 IOscheEintragBel: 323 printOn: 324 setzeBei:denEintrag: 323 setzeEquKontrolliertBei:denEintrag: 336 setzeldKontrolliertBei:denEintrag: 336
Index A
Abhlingigkeitsbeziehung 382-395 Abhlingigkeitsmechanismus 126,
379, 381-395
Aggregationsbeziehung 197,210 Analyse- und Designtechniken 294 Anwendungsfall 294 Arbeitsbereich 104 Argument 189 Assoziationsbeziehung 197,210 Attribut 199, 391 Attributbeziehung siehe: Attributzuordnung Attributeigenschaft 276 Uberpriifung der 244 Attributsammelbehalter 216-218 Attributzuordnung 197, 199-204,
210
mehrfache 215-218 Ausdruck 56-74 Auspragung 13, 105
B Behlilterobjekt siehe: Sammelbehalter Beziehungsmethode 263 Beziehungsname 248-250 Beziehungsverzeichnis 252, 257-261 Zugriff auf das 261 Binary Object Streaming Service
362-364
Binden dynamisches 21, 47 spates 21 Block 74-82 bedingte Wiederholung 78 unbedingte Wiederholung 77 Botschaft 5,54 binare 69 Kaskadierung einer 73 unare 67
Botschaftsausdruck 67-74 Verkettung von 69-73 Botschaftsubermittlung indirekte 91 Mechanismus der 28-30 Browser 106
C
Canvas Tool 129
D Datenbank objektorientierte 198, 365 relationale 177, 364 Debugger 117 Dekoration subjektive 413 transparente 410 Dekorator-Dekorand-Beziehung
406-413
Delegation 410 dependency mechanism siehe: Abhlingigkeitsmechanismus double dispatching 192 Druckdarstellung 277
E Eigenschaften dynamische 401 rollenspeziftsche 401 Einfachvererbung 290 Einfachzuordnung 213 Einschrlinkung siehe: Integritatsbedingung Empfanger 28, 189 Entwurfsmuster 380 Enumerationsmethoden 85-88 Erreichbarkeit eines Objektes 22 Erreichbarkeitsmenge 198, 232 Extension 47,200
436
Index
F Faktorisierung 290 false 17,24 Fehlermeldung 109 Feld 150 Flexibilitat 241-243 beschrankte 242 uneingeschriinkte 242 framework siehe: Geriist
G garbage collection siehe: Speicherbereinigung Geriist 380 Geschiiftsfall 305,309,312,313,334,
353
Geschaftsklasse 262, 293 Geschiiftsmethode 8, 303, 304, 308,
311,313,333,347,348,351
Geschaftsobjekt 13, 382, 387
H
HeterogeniHit 225-228 Heterogenitatseinschrankung 226 schwache 226 starke 226 Uberpriifung der 227, 259 Homogenitiit 255 Horizont dynamischer 23, 26 statischer 23 Horizont eines Objektes 22
I Identitat 2 Immutabilitat 240, 302 Implementierungsvererbung 283 Inflexibilitat 242 Informand 381-394 Informator 381-393 Informator-Informand-Beziehung
381,389
Initialisierung 30 einer Zuordnung 239 verz6gerte 30, 385
Initialisierungseinschriinkung 239 Inspektor 110 Instanz siehe: Auspragung Instanzierung 15 Instanzierungsbeziehung 15,46,47,
49 Instanzkonstante 5 Instanzmethode 19, 110 Instanzvariable 4, 23, 39 benannte 145 indizierte 142-147 Integritatsbedingung dynamische 238-243 statische 212-237 Integritiitskontrolle 247 Integritatsverletzung 265
K Kapazitat eines SammelbehaIters 134 Kardinalitat 213 einer Sammlung 134 maximale 258 Kardinalitatseinschriinkung Uberpriifung der 259 Klasse 13 abstrakte 15 Erzeugen einer 36, 39 konkrete 15 konstante 143 variable 143-147 Klassendiagramm 200 Klassenhierarchie 15, 18 Klasseninstanzvariable 14,39,250,
283,284,286
Klassenkategorie 106 Klassenmethode 110 Klassenmigration 44 Klassenmutation 44 Klassenvariable 14, 24, 275 Klassiftkation 221 Kodierung von Objekten 356-365 Kollektion siehe: SammelbehaIter Kommunikation
437
Index gezielte 381 selektive 395 ungezielte 381 Kommunikationsmechanismen
380-401
Konstante 3, 63 Konstruktormethode 285 Kontrollstrukturen 82-89 Kopie siehe: Objektkopie
L Lebenszyklus 30 in einer Applikation 30 technischer 30 Lexical Scoping 93-97 Literal 57-{)3 Literalfeldkodierung 360
M Mehrfachzuordnung 192,213 gekoppeite 249 konditionale 213 Organisation einer 228 Mehrfachzuweisung 65 Menge 162 Mengenoperationen 175 Metainformation 247, 252 Metaklasse 34, 48 Metaprogrammierung 44 Methode 51-56 Aktivierung einer 26 freie 55 mehrfach polymorphe 188-192 Modiftkation einer 45 Zuordnung zu einer Klasse 52 Methodenersetzung siehe: Redefmition Methodenfamilie 276 Methodenkategorie 106 Methodenname 54 Methodensuche 19-21,47 Methodenverzeichnis 19,42 Modell 200 des Bankbetriebes 295-296 des Bankwesens 320-321,338-
339
des Geldes 270-271 des Studienwesens 248 einer Bank 299-300 eines Kontos 282 Modellverzeichnis 251,254-256 Zugriff auf das 260 Model-View-Controller-Architektur 125, 382, 394-395 Multiplizitiit 15, 212-215, 255 maximale 212 minimale 212 Mutabilitiit 239-241 eingeschrankte 240 uneingeschriinkte 240 Mutation siehe: Objektmutation
N Nachricht siehe: Botschaft Navigation 15 nil 24 Nutzelemente eines Behiilters 134,
156
o
Oberklasse 16 ObjectS tore 366 Objekt 2 a-priori 57,201 berechtigtes 398 Kodierung eines siehe: Kodierung komplexes 197 persistentes 356, 365 transientes 356 Objektabstufungen 35 Objektbank siehe: Datenbank objektorientierte Objektdekoration 402, 406-413 Objektidentitiit 403 Objektkopie 204-211 seichte 207-208 tiefe 208-211 Objektlebenszyklus 201,345-348 Objektmigration 402
438
Index
Objektmutation 212,401 Objektname 3 Objektnetz 355 Objektraum 6 Abbild des 355 Erweiterung des 356 Grenze des 12 konzeptioneller 6, 104 Arbeitsebene 8 Basisebene 10, 134 Ebenen 7 Geschaftsebene 7 persistenter 366 physischer siehe: technischer realer 6, 104 SchnappschuB 33 technischer 6, 31 transienter 366 Objektrekonstruktion 359,360 Objektsichten 412 Objektstruktur zirkulare 209 Objektvertauschung 169 Objektzuordnung siehe: Zuordnung OMT-Methode 345 ordinalskalierte GroBen 271
p Parameter 67 Partnerobjekt 197 pattern siehe: Entwurfsmuster Polymorphismus 115, 219 ad-hoc 124, 220 begrenzter 219 inharenter 220 Teilmengen- 120 Poolvariable 24, 286 Prirniirmethode 80--81 Programmhaltepunkt 117
Q
Quellobjekt siehe:Tragerobjekt
R
receiver 397
Redefmition einer Methode 21 Rekonstruktion siehe: Objektrekonstruktion Relation 177-187 Relationenalgebra 178 Projektion 184-185 Selektion 181-183 Verbund 185-187, 187-?? Reverse Engineering 46 Rolle eines Objektes 401 in einer Beziehung 249 Rollenname 249, 257 Riickgabeanweisung 54 Riickgabeobjekt 5, 28, 53 einer Einfiigemethode 136 Verwendung in einer Methode
29
S Sammelbehalter 131-174,213 Akkumulation von Elementen
141
Auffmden von Elementen 140 Auswahl von Elemente 138 Enumerationsmethoden 136-
142
Hierarchie der 132 Inspektion eines 157 Kapazitatserweiterung eines 168 mit geordneten Elementen 152-
158 mit konstantem Fassungsvermogen 148 mit sortierten Elementen 159-
162
mit variablem Fassungsvermogen
148
ohne Anordnung der Elemente
162
Schliisselmethoden 133 Transformation der Elemente
136
Sammlung siehe: SammelbehaIter Satellitenobjekt 406
439
Index Schemaevolution 254 Schliissel-Wert-Paar 164 Schliisselwortbotschaft 67 Schliisselwortselektor 67 Schnittstellenobjekt 13 Selektor biniirer 90 Konstruktion eines 92 self 21, 23 Sender 5,28 Feststellen des 397 Sender-Empfanger-Beziehung 381,
396
Sichtbarkeit 22 Signatur 54, 67 Singleton-Klasse 15 Smalltalk (Systemverzeichnis) 24,
25, 36, 38, 266
Smalltalk-Image 355, 359 Smalltalk-Kompiler 358 Speicherbereinigung 32, 111 Spezifikationsvererbung 283 Strukturen zirkullire 363 Strukturpolymorphismus 219 Strukturschablone 18, 42 der Metaklasse 39 variable 143 Strukturvererbung 15, 42, 113, 118 super 21,63 Synonym 4 SystemBrowser 107
T
thisContext 27,63, 397 Tragerobjekt 197 Transaktion 237, 366 true 17,24 Tupel 177 Typisierung 221
U Unterklasse 15, 16 use case siehe: Anwendungsfall
V Variable 3,64 Benennung einer 97 globale 24 Anlegen 264 Entfemen 266 lokale 76 temporiire 55 Variablenpool siehe: Variablenverzeichnis Variablenverzeichnis 24,37,38,39,
290
Varietat 219-224,255 schwache 219 starke 219 Varietatseinschrankung 220 schwache 223 starke 224 Uberpriifung der 222, 223 Vererbungsbeziehung 18,41,49 Vererbungspfad 17 Verhalten 2, 26-30 Verhaltensvererbung 18,42, 113,
119,272
auf Instanzebene 411 Verzeichnis 164-165 virtuelle Maschine 32
W
Wert 201 Wiederverwendung von Code 121 workspace siehe: Arbeitsbereich
Z Zahlwerke 103-130 Zeichenkette 151 Zielobjekt siehe: Partnerobjekt Zugriffsmethoden namenskonforme 404, 405 Zuordnung 197 direkte 232 Eigenschaft einer 211-231 flexible 241-243 gekoppeite 234-238 Auflosung einer 238
440 Errichtung einer 237 heterogene 249 homogene 228 immutable 300 indirekte 231-233 nicht variante 224 variante 221,249 Zuordnungsname 257 Zustand 2 Zustandslinderung 53, 343 Zustandsdiagramm 345 Zustandsgraph 345 Zustandsvariable siehe: Instanzvariable Zuweisung 3,65
Index