92
Geo- Processing Reihe Geoprocessing Series Vol.23 Geographisches Institut Universität Zürich, 1996 Bernhard SCHNEIDER OBJEKTPROGRAMMIERUNG FÜR RAUMBEZOGENE FRAGESTELLUNGEN Erstellung einer Klassenbibliothek raumbezogener Objekte

Geo- Processing Reihe · i Zusammenfassung Die Konzeption eines Geographischen Informationssystems ist eine anspruchs-volle Aufgabe für ein Team aus Geographen und Informatikern

Embed Size (px)

Citation preview

Geo-ProcessingReiheGeoprocessing Series

Vol.23Geographisches InstitutUniversität Zürich, 1996

Bernhard SCHNEIDER

OBJEKTPROGRAMMIERUNG FÜR RAUMBEZOGENE FRAGESTELLUNGENErstellung einer Klassenbibliothek raumbezogener Objekte

Diese Arbeit wurde 1993 von der Philosophischen Fakultät IIder Universität Zürich als Diplomarbeit angenommen.

Copyright 1996:Geographisches InstitutUniversität Zürich-Irchel

All rights reserved

i

Zusammenfassung

Die Konzeption eines Geographischen Informationssystems ist eine anspruchs-volle Aufgabe für ein Team aus Geographen und Informatikern. Erstere steuerndazu die nötigen Anwendungskenntnisse sowie das spezifische Interesse anräumlichen Elementen bei, letztere die Erfahrung beim Aufbau einer wohl-strukturierten Grundarchitektur. In dieser Arbeit ist versucht worden, einigewichtige Konzepte der Informatik - die Methoden des objekt-orientiertenDesigns - für Geographen aufzuarbeiten. Damit soll ein Beitrag geleistetwerden, diese in den Geowissenschaften noch wenig verbreitete Denkweisedem Geographen näher zu bringen und ihm die Möglichkeit zu geben, vertieftbei der Gestaltung von Informationssystemen mitzuarbeiten. Der Leser wirdbald merken, dass ihm der Formalismus zwar ungewohnt vorkommen mag,die Konzepte aber mit der geographischen Sichtweise gut übereinstimmen.

Die Arbeit setzt sich mit der Eignung der Objektprogrammierung für raumbe-zogene Fragestellungen, insbesondere mit der Verwendung von Klassenbiblio-theken auseinander. Sie untersucht die Vorteile und Möglichkeiten, die dieseTechnik bietet und zeigt auf, wie sie für eigene Projekte genutzt werden kann.Den zentralen Punkt der Arbeit stellt die Entwicklung einer eigenen Klassen-bibliothek dar, die raumbezogene Klassen beinhaltet und deren Einsatz mit derNutzung der oben genannten Vorteile und Möglichkeiten verbunden ist.

Die Arbeit ist in zwei Teile gegliedert. Der erste Teil fasst die theoretischenGrundlagen der objekt-orientierten Sichtweise zusammen, wobei dieseKonzepte für Nichtinformatiker aufbereitet werden. Die zwei Kapitel desersten Teils beinhalten die Einführung der Objektprogrammierung an sichsowie die Erläuterung des Prinzips der Klassenbibliotheken. Sie sollen in ersterLinie Studierende ansprechen, die wissen wollen, was Objektprogrammierungist und wie sie in raumbezogenen Fragestellungen genutzt werden kann.

Der zweite Teil der Arbeit beschreibt die Entwicklung einer eigenen Klassen-bibliothek raumbezogener Klassen sowie eine Möglichkeit, diese in eigenenProjekten einzusetzen. Nachdem auf die konzeptionellen Überlegungenwährend der Entwicklung dieser Bibliothek eingegangen worden ist, führt daserste Kapitel des zweiten Teils die Bestandteile der Bibliothek vor. Das nächsteKapitel zeigt anhand eines konkreten Beispiels eine ihrer Einsatzmöglichkeiten.Die Klassenbibliothek raumbezogener Klassen stellt einen zentralen Punktdieser Arbeit dar, denn sie zeigt deutlich die bereits erwähnten Vorteile undMöglichkeiten auf, die die Verwendung der Objektprogrammierung bei derSoftwareentwicklung bietet.

ii

iii

Vorwort

Die vorliegende Arbeit ist im Rahmen der wissenschaftlichen Auseinanderset-zung mit Algorithmen und Datenstrukturen zur Verarbeitung räumlicherDaten entstanden. Ausserdem wurde sie von weiteren Aktivitäten der Abtei-lung Geographische Informationsverarbeitung des Geographischen Institutsbeeinflusst. Die Arbeit mit Algorithmen und Datenstrukturen schafft Grundla-gen für die Forschung im Bereich 'Computergestützte Modellierung undDarstellung von räumlichen Strukturen' (Nationalfonds-Projekt) wie auch imBereich der digitalen Geographie, speziell für die Forschung in Richtung auto-matisierter Generalisierung. Beide Gebiete sind potentielle konkrete Anwen-dungsgebiete der Ergebnisse, die in meiner Arbeit beschrieben sind, unddienten somit als Motivation wie auch als Leitfaden, der die Richtung meinerArbeit mitbestimmte.

Diese Arbeit ist mit vielfältiger Unterstützung zahlreicher Personen zustandegekommen. Mein Dank richtet sich in erster Linie an Herrn Prof. Dr. KurtBrassel, der einerseits durch die Leitung und Durchsicht und andererseitsdurch das Zur-Verfügungstellen eines Arbeitsplatzes wesentlich zum Gelingendieser Arbeit beigetragen hat. Schliesslich verdanke ich es ihm, dass das Themadieser Arbeit, das auf den ersten Blick nur wenig mit Geographie zu tun hat,trotzdem als Thema einer geographischen Diplomarbeit Anerkennung findet.

Der eigentliche Wegbereiter dieser Diplomarbeit ist Martin Heller. Durch ihnfand ich den Zugang zur Objektprogrammierung und lernte die dahinterlie-gende Denkweise in Bezug auf räumliche Fragestellungen kennen undschätzen. Mit seiner grossen Erfahrung auf diesem Gebiet und mit viel Phanta-sie und Witz leitete er die Durchführung dieses Projekts. Ich schätze sehr dieinteressanten und überaus fruchtbaren Diskussionen, die ich mit ihm führteund hoffentlich noch führen werde.

Speziellen Dank gebührt auch Hans-Ruedi Bär, Martin Brändli und Prof. Dr.Robert Weibel. Sie beantworteten mir viele meiner konzeptionellen und v.a.technischen Fragen, und meine Probleme, bei deren Lösung ich sie um Hilfebat, waren auch immer ihre Probleme, solange bis diese Probleme keine mehrwaren.

Viele Anregungen, Korrekturen, Bemerkungen und Ablenkungen erhielt ichvon Felix Bucher, Dr. Guido Dorigo, Regula Ehrliholzer, Andreas Ernst, SaraFabrikant, Christian Gees, Tumasch Reichenbacher, Michael Schaepman,Andreas Stoffel, Thomas Werschlein und Ingrid Paschedag (natürlich!).

Zürich, im Juli 1993 Bernhard Schneider

iv

Inhaltsverzeichnis

Zusammenfassung ................................................................................................ iVorwort .................................................................................................................. iiiInhaltsverzeichnis ............................................................................................... ivAbbildungs- und Tabellenverzeichnis ............................................................. vi

1. Einleitung ........................................................................................................... 1

2. Was ist objektorientierte Programmierung ................................................ 4

2.1. Zur Geschichte der objekt-orientierten Programmierung (OOP) ......... 42.2. Das Konzept von OOP: die Klasse 'Student' ........................................... 5

2.2.1. Was ist ein Objekt .............................................................................. 52.2.2. Objektklasse, Objektinstanz ............................................................. 52.2.3. Superklassen, Subklassen ................................................................. 82.2.4. Vererbung, Überschreiben ............................................................... 102.2.5. Polymorphismus ................................................................................ 11

2.3. Programmiertechnische Aspekte: die Klassen 'Punkt', 'Linie','Polygon' ...................................................................................................... 132.3.1. Das Modell ......................................................................................... 132.3.2. Klassendefinitionen ......................................................................... 152.3.3. Instanzen ............................................................................................ 182.3.4. Subklassen .......................................................................................... 192.3.5. Abstraktion ......................................................................................... 222.3.6. Polymorphismus ............................................................................... 23

2.4. Spezielle Bemerkungen ........................................................................... 242.4.1. Information Hiding ......................................................................... 242.4.2. Objekt Oriented Analysis, Objekt Oriented Design ................... 25

3. Klassenbibliotheken, MacApp ...................................................................... 28

3.1. Klassenbibliotheken .................................................................................. 283.2. MacApp: Einleitende Bemerkungen ..................................................... 283.3. Überblick über die wichtigsten Klassen ................................................ 30

3.3.1. TObject ................................................................................................ 303.3.2. TEvtHandler ...................................................................................... 313.3.3. TApplication ..................................................................................... 313.3.4. TDocument ........................................................................................ 323.3.5. TView ................................................................................................. 323.3.6. TCommand ....................................................................................... 353.3.7. TList ..................................................................................................... 36

v

3.4. Der Ablauf in einem MacApp-Programm ........................................... 363.4.1. Das Hauptprogramm ....................................................................... 363.4.2. Die Applikation, Event Loop ......................................................... 383.4.3. Subklassen von TApplication, TDocument und TView ........ 393.4.4. Menu-, Mouse- und Tastaturbefehle, Commands ................... 40

4. Punkt-Linien-Polygon-Klassenbibliothek ................................................. 42

4.1. Warum eine objekt-orientierte Klassenbibliothek ............................ 424.2. Einzubeziehende Klassen ........................................................................ 424.3. Einbettung in MacApp ............................................................................. 44

4.3.1. Einbettung der geometrischen Primitiven ................................. 454.3.2. Layer und Cluster in MacApp ....................................................... 46

4.4. Implementation ......................................................................................... 484.4.1. Die abstrakten Klassen .................................................................... 484.4.2. Punktlayer .......................................................................................... 504.4.3. Array-Linien ...................................................................................... 524.4.4. Listen-Linien ..................................................................................... 534.4.5. Hybride Linien .................................................................................. 544.4.6. Statische Linien ................................................................................ 544.4.7. Polygone/Linien - Arcs - Punkte .................................................. 56

5. Ein Beispiel: Douglas-Poiker-Filterung ...................................................... 58

5.1. Der Ansatz der herkömmlichen, prozeduralen Methode ............... 585.2. Die Lösung mit MacApp und der raumbezogenen

Klassenbibliothek ....................................................................................... 615.2.1. Applikation, Dokument, Fenster ................................................. 625.2.2. Die Klasse TDPLine .......................................................................... 645.2.3. Mouse- und Menu-Aktionen ........................................................ 655.2.4. Verwendung von Commands ...................................................... 665.2.5. Zusammenfassung des Programmablaufs ................................. 69

6. Ausblick ............................................................................................................. 726.1. Attribute ...................................................................................................... 726.2. Topologie ..................................................................................................... 73

Anhang A ............................................................................................................... 75Anhang B ............................................................................................................... 81

Literaturvezeichnis .............................................................................................. 83

vi

Abbildungs- und Tabellenverzeichnis

Abb. 1: Beispiele der VDL (Visual Design Language) .................................. 7Abb. 2: Die Superklasse 'Student' mit seinen Subklassen ............................ 8Abb. 3: Beispiel einer Hierarchie von Sub- und Superklassen .................... 9Abb. 4: Beispiel von mehrfacher Vererbung .................................................. 10Abb. 5: Beispiel für Polymorphismus ............................................................. 12Abb. 6: Varianten des Linienpunkt-Arrays von 'Linie' ................................ 15Abb. 7: Beispiel von CalculateOutlet .............................................................. 21Abb. 8: Hierarchie von TPoint, TFountain, TLine, TRiver, TPolygon,

TDrainage ............................................................................................. 22Abb. 9: Klassenhierarchie mit abstrakter Superklasse TGeomPrimitive .. 23Abb. 10: Verflechtung der Schritte beim objekt-orientierten Design ........... 27Abb. 11: Eine Auswahl wichtiger Klassen von MacApp ............................. 30Abb. 12: Beispiel einer View-Hierarchie ......................................................... 33Abb. 13: Beispiel von verschiedenen Objekten in einem Dialog-Fenster .. 34Abb. 14: Die Verkettung von Elementen in einer Liste des Typs TList ..... 36Abb. 15: Beispiel der Verarbeitung eines Events in einem Event Loop ..... 38Abb. 16: Die Hierarchie der raumbezogenen Klassen .................................. 48Abb. 17: Das Konzept von TPointLayer ......................................................... 50Abb. 18: Listen der Punkte, die in der jeweiligen Gitterzelle liegen .......... 51Abb. 19: Die Arrays der Punktkoordinaten und der Gitterzellen-Verweise . 52Abb. 20: Das Konzept von TArrayLine .......................................................... 53Abb. 21: Das Konzept von TListLine .............................................................. 53Abb. 22: Das Konzept von THybridLine ....................................................... 54Abb. 23: Das Konzept von TStaticLine .......................................................... 55Abb. 24: Das Konzept von TConnectedArcs, TArc und TBasicPointArray . 57Abb. 25: Die neuen, für die Applikation spezialisierten Klassen in der

Hierarchie der erweiterten MacApp-Klassenbibliothek ............... 62Abb. 26: Die Klasse TPoint durch Attribute erweitert zur Kategorie 'Quelle' 74

Tab. 1: Die Spezifikation der Klasse 'Student' (ohne 'Fähigkeiten') ......... 6Tab. 2: Zwei Instanzen der Klasse 'Student' ................................................ 6Tab. 3: Spezifikation der Klasse 'Geographiestudent' ................................ 11Tab. 4: Liste der Eigenschaften und Fähigkeiten der Klasse 'Punkt' ....... 14Tab. 5: TFountain mit allen vererbten und neuen Instanzvar. sowie

Methoden ............................................................................................. 19Tab. 6: Liste aller direkten und indirekten Subklassen von TView ........ 35

1

1. Einleitung

Geographie oder Informatik

Wie bereits der Titel suggeriert, wird in dieser Arbeit ein Bereich derGeographie behandelt, der auf den ersten Blick nicht oder nur noch entferntmit der Geographie im klassischen Sinn zu tun hat. Das Programmieren isteigentlich ein Thema der Informatik, und als Geograph hat man höchstens mitbereits fertigen Applikationen zu tun. Es stellt sich die Frage, warum nicht nurdie Programmierung an sich, sondern sogar die Erstellung von Programmier-werkzeugen ein Thema einer geographischen Arbeit sein soll. Ich hoffe, dassmeine Ausführungen klar machen werden, dass die Geographie in derheutigen Zeit die Herstellung ihrer Werkzeuge nicht vollständig anderenFachgebieten überlassen kann, auch wenn es sich um trockene Informatikhandelt, in welcher geographisches Wissen nur am Rande notwendig ist.

'Objekt' – orientiert

Ein Ausgangspunkt dieser Arbeit war die Untersuchung, inwiefern sich dieObjektprogrammierung für die Implementierung von Lösungen zu raumbe-zogenen Fragstellungen eignet. Da die objektorientierte Denkweise in derGeoinformatik noch nicht dieselbe Verbreitung gefunden hat wie die her-kömmliche, prozedurale Programmierung, sollten die speziellen Eigenschaftenuntersucht werden, die die Objekt-Orientiertheit für geographische Aspekte sointeressant macht. Das auffallendste Merkmal der Objektprogrammierung, dasdiese Denkweise mit raumbezogenen Problemen verbindet, ist die abstrakteUnterteilung von realen Begebenheiten in 'Objekte'.

Der physische Raum wird in konkreten Fragestellungen immer in Objekteunterteilt und durch sie definiert und charakterisiert. Diese Objekte können aufeiner gewissen Abstraktionsstufe in die Klassen 'Punkte', 'Linien' und'Polygone' unterteilt werden. (Beispiele für Punkte: Kreuzungen, Brunnen,einzelstehende Bäume, Ortschaften, Berggipfel, Punktmessungen irgendwel-cher Art, etc.; für Linien: Strassen, Bahnlinien, politische und andere Grenzen,Ufer, fliessende Gewässer, Isolinien, z.B. Höhenkurven, etc.; für Polygone:Gemeinden, Parzellen, Gebäude, Seen, Wälder, in irgendeiner Art abgegrenzteGebiete, z.B. Sprachregionen, vordefinierte Testgebiete, etc.) Diese Klassenbilden die Basis der Kartographie, denn auf Karten können punktförmige,linienförmige sowie flächenhafte Einheiten lokalisiert werden. ObjektorientierteProgrammiersprachen bieten nun die Möglichkeit, die Objekte der realen Weltnachzumodellieren; man definiert die Objektklassen, indem man ihnen für siecharakteristische und relevante Eigenschaften gibt und sie mit Fähigkeiten undVerhaltensweisen ausstattet, die im Zusammenhang der Fragestellung wichtigsind. Auch Wechselbeziehungen und Interaktionen zwischen den Einheitenlassen sich auf diese Weise in ein Computermodell der realen Situationeinbauen.

2

Wiederverwendbarkeit von Objekt-Klassen

Gerade Punkte – oder Punktebenen –, Linien und Polygone sind Objekte, diewie bereits erwähnt in praktisch jeder von Geographen bearbeiteten Fragestel-lung in der einen oder anderen Weise eine Rolle spielen. Die Objektprogram-mierung bietet die Möglichkeit, solche Einheiten, die immer wieder in denBearbeitungen dieser Probleme mit dem Computer neu entworfen und imple-mentiert werden, als fertige, vorfabrizierte Bausteine dem Entwickler vonraumbezogenen Programmen zur Verfügung zu stellen.

Diese Eigenschaft, die von programmiertechnischem Nutzen ist, liegt in derModularisierung und somit in der Wiederverwendbarkeit von Objekten. Beider Erstellung solcher Einheiten werden diese mit fest definierten Schnittstellenversehen; beim Einsatz solcher Bausteine in einem eigenen Projekt muss derBenutzer nur deren Funktionen sowie die dazugehörigen Schnittstellen kennen,nicht aber über die dahinterliegenden Algorithmen Bescheid wissen.Ausserdem reduziert die Verwendung bereits bestehender Bausteine denEntwicklungsaufwand von Projekten, denn die Implementierung dieserEinheiten ist oft zeitraubend und hat mit der eigentlichen, beim Geographenmeist raumbezogenen Fragestellung keinen direkten Zusammenhang. Wirddem Benutzer diese Arbeit abgenommen, kann er sich ganz auf sein konkretesProblem konzentrieren.

Trotzdem muss die Implementierung einer solchen Bibliothek wiederverwend-barer Objekte von einem Programmierer erledigt werden, der den Einsatz derBausteine voraussehen und somit die Funktionalität und Schnittstellen dement-sprechend bestimmen kann. An dieser Stelle wird klar, worin die Verbindungdieser 'informatiklastigen' Arbeit mit der Geographie besteht. Die Informatikbeschäftigt sich zwar eingehend mit Problemen der objektorientierten Imple-mentierung von Bausteinen und Bibliotheken, die Objekt-Sichtweise ist abernicht so abstrakt und kompliziert, dass sie nur von einem Informatiker nach-vollzogen werden könnte – zumal sie gerade Geographen anspricht. Geogra-phen besitzen ausserdem mehr Kenntnisse über die Problembereiche, die vonder Geographie bearbeitet werden, und somit können sie auch die Einsatz-gebiete von Objekt-Bibliotheken besser abschätzen und sie den Bedürfnissender Anwender anpassen. In meiner Arbeit versuchte ich, dieses Thema imGrenzbereich zwischen Informatik und Geographie als Geograph zu unter-suchen und zu bearbeiten.

Ziel dieser Arbeit

Der Zweck dieser Arbeit liegt einerseits darin, durch die Implementierung vongeometrischen Klassen einen wissenschaftlichen – und handwerklichen –Beitrag zur Entwicklung einer Klassenbibliothek für die Programmierung mitraumbezogenen Fragestellungen zu leisten. Es soll aufgezeigt werden, wie eineKlassenbibliothek für 'Raum-Objekte' aufgebaut sein könnte und wie sie ineinem Programm zur Lösung eines raumbezogenen Problems verwendetwürde.

3

Andererseits geht es aber auch darum, die objekt-orientierten Denkweise fürGeographen aufzubereiten. Diese Diplomarbeit soll den Einstieg in die Objekt-programmierung erleichtern und aufzeigen, wie man vorgehen könnte, umSchritt für Schritt eigene kleinere geometrisch-raumbezogene Projekte zuverwirklichen. Zusätzlich soll auch die Basis gelegt werden für weitere Diplom-und andere Arbeiten, welche sich konkret mit der Umsetzung von theoreti-schen Ansätzen in der Geoinformatik in ausprogrammierte Algorithmen undDatenstrukturen beschäftigen. Es soll die Wiederverwendbarkeit von Objekt-Klassen ausgenützt werden, um diese Arbeiten von der Programmierung vonelementaren, aber zeitraubenden Basisklassen wie eben Punkte, Linien undPolygone zu entlasten.

Die Arbeit ist in zwei Teile gegliedert. Der erste Teil enthält einführendeKapitel zum Thema Objektprogrammierung, die einerseits als theoretischeGrundlagen für die Ausführungen des zweiten Teils der Arbeit, andererseitsals Einführung in das objekt-orientierte Denken allgemein – z.B. für Studen-ten – dient. Das erste Kapitel beschäftigt sich mit der Frage, was objektorien-tierte Programmierung überhaupt ist, was anhand von einfachen Beispielenerläutert werden soll. Die Idee von Klassenbibliotheken und ihre Verwendungwird im zweiten Kapitel behandelt. Im zweiten Teil der Arbeit geht es danndarum, wie man sich eine Klassenbibliothek vorstellen könnte, wie ich versuchthabe, eine solche zu verwirklichen und wie sie Verwendung finden soll.

4

2. Was ist objektorientierte Programmierung

Den zentralen Punkt der Objektprogrammierung bilden – wie der Name sagt –Objekte. Was ist nun ein Objekt ? Diese Frage wie auch das ganze Konzept derObjektprogrammierung möchte ich an zwei Beispielen behandeln. Das erste hatzwar nichts mit Programmierung zu tun, veranschaulicht aber die Idee derobjektorientierten Sichtweise. Beim zweiten Beispiel wird einerseits gezeigt,wie man auf Programmierebene mit Objekten und Klassen umgeht, anderer-seits soll etwas deutlicher werden, wie man das Konzept der Objektprogram-mierung auf raumbezogene Anwendungen übertragen könnte.

2.1. Zur Geschichte der objekt-orientierten Programmierung(OOP)

Obwohl die Objektprogrammierung erst in den letzten Jahren eine Euphorieausgelöst hat, geht ihre Entwicklung in die späten 60er-Jahre zurück. Damalsentwickelten zwei Norweger (Kristen Nygaard, Ole-Johann Dahl) für komplexeSimulationsanwendungen die Programmiersprache SIMULA. Ohne vollständigobjekt-orientiert entworfen zu sein, zeigte sie aber zum ersten Mal die Kon-zepte und deren Möglichkeiten auf. SIMULA erreichte zwar nie die Popularitätwie andere objekt-orientierte Sprachen, auf deren Entwicklung aber hatte siegrossen Einfluss.

Aufbauend auf den Erkenntnissen wurde – zuerst als Programmiersprache fürKinder gedacht – in der Alan Kay's Learning Research Group im Xerox PaloAlto Research Center SMALLTALK entwickelt. Im Gegensatz zu SIMULA istSMALLTALK von Anfang an objekt-orientiert aufgebaut worden. In SMALL-TALK ist alles ein Objekt, von einfachen Variablen bis zu den Komponentender Programmieroberflächen. Man erkannte bei SMALLTALK auch dieChancen der objekt-orientierten Sichtweise bei der Gestaltung von Benutzer-oberflächen, was zur Entwicklung der User-Interface-Klassenbibliothek Model-View-Controler (MVC) führte. Die Einbettung der damals neuen Idee derObjekt-Orientiertheit in eine für unterschiedlichste Anwendungen offeneProgrammiersprache und in eine für objekt-orientierte Entwicklungen idealeProgrammieroberfläche verschafften SMALLTALK in den 80er-Jahren grosseAnerkennung.

Neben den zwei genannten Sprachen entstanden noch zahlreiche weitere,entweder durch die Schaffung neuer, vollständig objekt-orientierter Program-mierumgebungen oder durch die Erweiterung von bestehenden Sprachen zusog. hybriden Sprachen. Zu letzteren gehören z.B. Objective-C, C++ sowieObjekt Pascal.

5

2.2. Das Konzept von OOP: die Klasse 'Student'

2.2.1. Was ist ein Objekt

Als erstes stelle man sich einen Studenten vor. Er geht zur Uni oder an die ETHoder an eine andere Hochschule. Er ist in irgendeinem bestimmten Semester,studiert eine bestimmte Fachrichtung und besitzt einen Stundenplan, den ersich mehr oder weniger selbständig zusammengestellt hat. Dieser bestimmt,wie die Tage der Woche für ihn aussehen, welche Vorlesungen und Übungener besucht und wann er wo mittagessen geht. Sein Erkennungsmerkmal für dieHochschulverwaltung ist seine Matrikelnummer. Daneben besitzt er auch nochName, Vorname, Adresse, Telephonnummer, Semesterzahl, Alter, Geschlecht,Konfession, Zivilstand, etc. Diesen Studenten kann man sich als Objektvorstellen.

Zwei Punkte machen das 'Objekt' aus: erstens seine Verhaltensweisen bzw.Fähigkeiten und zweitens seine Eigenschaften, die man salopp als 'Daten'umschreiben könnte. Die Fähigkeiten des Studenten bestehen z.B. darin, dass erjeden Morgen den Weg an seine Hochschule findet, dass er sich seine Lehrmit-tel beschafft, an der für ihn günstigsten Stelle mittagessen geht und sich recht-zeitig bei der richtigen Kanzlei für die Prüfungen anmeldet. Wichtig für dieobjektorientierte Denkweise ist die Annahme, dass das Objekt – der Student –selbständig weiss, wie es seine Fähigkeiten ausführen muss. Diese ermöglichtes ihm, auf Anweisungen auf seine eigene Art und Weise zu reagieren. (DerStudent weiss, was er auf die Kommandos 'Geh zur Uni !' oder 'Melde dichzum 2. Vordiplom an !' zu tun hat.)

Als Eigenschaften könnte man sicherlich Matrikelnummer, Name, Vorname,Adresse, etc. ansehen. Aber auch sein Stundenplan, das Verkehrsmittel, dassihn am Morgen zur Hochschule bringt, der Dozent, der seine Diplomarbeitbetreut sowie seine beruflichen Ziele sind Kandidaten für ihm eigene Eigen-schaften.

2.2.2. Objektklasse, Objektinstanz

Es gibt in Zürich mehr als nur einen Studenten. Wenn man sich allerdings mitihnen aus irgendeinem Grund beschäftigen muss, wird man feststellen, dass sieeinerseits viele Fähigkeits- und Eigenschaftsarten gemeinsam haben und dassandererseits nur einige davon für die Problemstellung interessant sind. MitFähigkeits- und Eigenschaftsarten soll die Tatsache verstanden werden, dasszwar die meisten Studenten verschiedene Namen und alle verschiedeneMatrikelnummern haben, dass aber alle solche Eigenschaften wie 'Name','Vorname', 'Matrikelnummer', etc. besitzen. Dies gilt ebenso für Fähigkeitenund Verhaltensweisen: Jeder Student bringt den morgendlichen Weg vonzuhause zur Hochschule zwar auf seine eigene Weise hinter sich, alle Studen-ten müssen aber die Fähigkeit 'zur Hochschule kommen' besitzen, wenn dieseauch bei allen verschieden zum Ausdruck kommt.

6

Um die Studenten als zusammengehöhrende Gruppe von Menschen mitdenselben Eigenschaftsarten sowie Fähigkeiten und Verhaltensweisen abzu-trennen von allen andern Menschen, bedient man sich des Begriffs der Klasse.Eine Klasse ist die Spezifikation für eine unbestimmte Menge 'ähnlicher'Objekte, d.h. Objekte gleicher Art. Diese Definition auf das Beispiel der Studen-ten angewendet, bedeutet, dass man einen Prototyp-Studenten vorsieht, derzwar alle Fähigkeiten sowie Eigenschaften besitzt, diese aber noch nicht näherbestimmt. Man kann sich diese Spezifikation eines solchen Prototypen als einenicht ausgefüllte Liste der Fähigkeiten und Eigenschaften vorstellen. (Leider istes schwierig, Fähigkeiten in einer Liste darzustellen.)

Matrikelnummer ...Name ...Vorname ...Hochschule ...Fachrichtung ...Semester ...Abschlussprüfungsnote ...

Tab. 1: Die Spezifikation der Klasse 'Student' (ohne 'Fähigkeiten')

Die Tabelle 1 zeigt also die Spezifikation einer Klasse, die alle Studentenbeinhalten kann. Greift man nun aus dieser Menge ein ganz bestimmtes Objekt– in unserem Fall einen ganz bestimmten Studenten – heraus, so spricht manvon einer Instanz dieser Klasse. Bei dieser Instanz kann für alle (oder zumin-dest einige) Eigenschaften der Spezifikation ein Wert angegeben werden. Auchdie Fähigkeiten und Verhaltensweisen sind jetzt fest definiert. (Student XY gehtam Morgen zuerst ein Stück zu Fuss, dann fährt er mit dem Tram und gehtschliesslich noch ein Stück zu Fuss, um an die Uni zu gelangen.)

Matrikelnummer 93-123-456Name SchneiderVorname BernhardHochschule Uni ZürichFachrichtung GeographieSemester 10Abschlussprüfungsnote ?

Matrikelnummer 89-987-654Name BeispielVorname SabineHochschule ETH ZürichFachrichtung ArchitekturSemester 9Abschlussprüfungsnote 5.5

Tab. 2: Zwei Instanzen der Klasse 'Student'

Eine Klasse gibt also an, welche Eigenschaften zu einem Studenten gehörenund was er alles können muss. Eine Instanz dieser Klasse ist ein Student.

Um Klassen, Instanzen und Beziehungen zwischen diesen Einheiten zuillustrieren, aber auch für das Ableiten von Klassen und Instanzen ausBegebenheiten der realen Welt sowie für den Entwurf von Programmkonstruk-ten, die aus Objekten aufgebaut sind, ist es sehr oft hilfreich, wenn diese

7

Klassen und Instanzen graphisch dargestellt werden. Um diese Darstellungenetwas zu standartisieren, wird in Goldstein und Alger (1992) das sog. VDL(Visual Design Language) vorgestellt. Es handelt sich dabei um eine Zusam-menstellung von Symbolen, die die Einheiten der objekt-orientierten Denk-weise sowie Beziehungen zwischen ihnen repräsentieren sollen. Ihre Gestal-tung ist einerseits einfach gehalten, um es einem Entwickler zu erlauben, sieauch in skizzenhaften, von Hand erstellten Entwürfen zu verwenden, anderer-seits wurde eine pseudo-dreidimensionale Darstellung gewählt, um z.B. denContainer-Charakter von Klassen deutlich zu machen. Auch in den Abbil-dungen dieser Arbeit werden die Symbole von VDL verwendet.

A

B C

Tut irgendwas

Klassen und Objekteauf konzeptioneller Ebene

Klassen und Objekteauf Programmebene

Instanz besitzt Attribut Instanz besitzt Fähigkeit

Instanz A besteht ausden Instanzen B und C

A a

Instanz A der realen Welt (deskonzeptionellen Entwurfs) wird als Instanz

a im Programm implementiert

Abb. 1: Beispiele der VDL (Visual Design Language) (Quelle: Goldstein und Alger, 1992)

Wie in einem späteren Kapitel genauer beschrieben wird, kann man in derEntwicklung von objekt-orientierten Applikationen zwei Schritte unterschei-den. Im ersten (object-oriented Anaysis) werden in der realen Welt Objekte undObjektklassen identifiziert, die in der Fragestellung eine Rolle spielen, wobeisich dieser Entwurf auf die konzeptionelle Ebene beschränkt; im zweiten(object-oriented Design) werden diese Konzepte in Objektklassen auf Program-mierebene übersetzt. Da dabei die auf konzeptioneller Ebene definiertenKlassen sehr oft nicht genau mit jenen übereinstimmen, die schliesslich imProgramm implementiert werden, unterscheiden sich in VDL auch die Symbole

8

für Klassen und Instanzen auf den jeweiligen Ebenen. Obwohl in dieser ArbeitObjekte beider Ebenen behandelt werden, sind der Einfachheit und eineseinheitlichen Aussehens der Graphiken wegen alle Klassen und Instanzendurch Symbole der konzeptionellen Ebene dargestellt.

2.2.3. Superklassen, Subklassen

Die Studenten fast aller Fachrichtungen unterscheiden sich in den Eigenschaf-ten und Fähigkeiten, die sie betreffen. Dies ist so zu verstehen, dass Eigen-schaftsarten, die für die Studenten einer bestimmten Fachrichtung typisch sind– z.B. gibt es für Geographiestudenten mit dem neuen Studienplan die Eigen-schaft 'Anzahl absolvierter Exkursionstage' –, für die Studenten einer andernüberhaupt keinen Sinn machen – von Wirtschaftsstudenten wird die Absolvie-rung von Exkursionen nicht verlangt. Auch bei den Fähigkeiten und Verhal-tensweisen gibt es Unterschiede zwischen den Fachrichtungen. Fähigkeiten wiez.B. 'sich für die Schlussprüfung anmelden' mögen zwar bei allen Studentengleich heissen, die eigentliche Ausführung dieser Tätigkeit wird aber stark vonder jeweiligen Fachrichtung beeinflusst – der Ort der Prüfungsanmeldung istein anderer, einige Studenten müssen Kopien ihrer Diplomarbeit mitbringen,andere machen die Prüfung vor der Diplomarbeit, etc.

Hier liegt es wieder nahe, die Studenten der einzelnen Fachrichtungen inKlassen zusammenzufassen – 'Geographiestudent', 'Wirtschaftsstudent', 'Biolo-giestudent', u.s.w. Diese Klassen können jetzt als Klassen einer zweiten Hierar-chiestufe angesehen werden, denn es existiert ja bereits eine Klasse 'Student',der nach wie vor alle Elemente der neuen Klassen angehören. Man nennt dieneuen Klassen Subklassen der Klasse 'Student'. Für die neuen Klassen ist dieKlasse 'Student' die gemeinsame Superklasse.

Student

Geographie-student

Wirtschafts-student

Biologie-student

Superklasse

Subklassen

Abb. 2: Die Superklasse 'Student' mit seinen Subklassen

Wenn man davon ausgeht, dass sich nicht nur Studenten der einzelnen Fachbe-reiche, sondern dass sich auch ETH- von Unistudenten, Studenten in Bern sichvon denen in Basel und Zürich und Studenten der physischen sich von denender Anthropo- sowie von denen der methodischen Geographie unterscheiden,könnte man alle diese Studenten zu Klassen zusamenfassen, was neue Hierar-chiestufen in den Komplex der Super- und Subklassen einfügen würde.

9

Student

Geographie-student

Wirtschafts-student

Biologie-student

ETH-Student Unistudent

Unistudentin Bern

Unistudentin Zürich

Unistudentin Basel

Student derphys.GG

Student derAnthro.

Student dermeth.GG

Abb. 3: Beispiel einer Hierarchie von Sub- und Superklassen

Es besteht nicht nur die Möglichkeit, zu bestehenden Klassen Subklassen zudefinieren, sondern es ist auch oft notwendig, zu zwei oder mehreren bestehen-den Klassen eine gemeinsame Superklasse zu finden. Beschäftigt man sich z.B.nicht nur mit Studenten, sondern auch mit Lehrlingen, Schülern auf denverschiedenen Schulstufen und andern in der Ausbildung stehenden Personen,so kann es hilfreich sein, zu diesen Klassen 'Student', 'Lehrling', 'Schüler', etc.die gemeinsame Superklasse 'Auszubildender' ins Leben zu rufen. Dieseenthält unter anderem Eigenschaften 'Name', 'Vorname', 'Ort der Ausbildung','Verkehrsmittel zur Erreichung des Ausbildungsorts' sowie Fähigkeiten wie'Prüfung schreiben' oder 'am Morgen an den Ort der Ausbildung gelangen'.Den Prozess der Schaffung einer gemeinsamen Superklasse nennt manAbstraktion.

Wie bereits implizit angenommen und später genauer erklärt, besitzen Subklas-sen alle Eigenschaften und Fähigkeiten, die auch in ihrer Superklasse enthaltensind. Durch die Schaffung von Superklassen für Klassen, die Eigenschaftenoder Fähigkeiten gemeinsam haben, kann man Arbeit sparen, indem man dieseEigenschaften und Fähigkeiten nicht in jeder Subklasse einzeln, sondern nureinmal in der Superklasse definiert. Dies ist einer der Gründe, warum man oft

10

Superklassen ins Leben ruft, ohne dass man je eine Instanz davon bilden wird.Solche Klassen, von denen nie eine Instanz existieren wird, nennt man abstrak-te Klassen. Ein Student studiert immer irgendeine Fachrichtung, ist also immereine Instanz einer Subklasse von 'Student'. Für die Klasse 'Student' bedeutetdas, dass von ihr keine Instanzen gebildet werden, sondern nur von ihren Sub-klassen. Sie ist also ein Beispiel einer abstrakten Klasse. Wie wir später sehenwerden, gibt es neben der Arbeitsersparnis noch einen weiteren Grund zurSchaffung solcher abstrakter Klassen.

An dieser Stelle sei noch erwähnt, dass nicht zwingend jede Klasse entwederkeine oder genau eine Superklasse haben muss. Die objektorientierte Sichtweisesieht auch vor, dass eine Klasse zwei oder mehreren Superklassen zugewiesenwerden kann. Ein Praktikant, der in der Industrie ein Praktikum absolviert undeinen gewissen geringen Stundenlohn erhält, ist zwar immer noch ein Auszu-bildender, vielleicht sogar ein Student, er ist aber gleichzeitig ein Arbeitneh-mer, der gegen Bezahlung Arbeit leistet. Diese neue Klasse 'Praktikant' ist alsoeinerseits eine Subklasse von 'Student' (in der Annahme, es handle sich um einPraxissemester), erhält also alle Eigenschaften und Fähigkeiten dieser Super-klasse – 'Matrikelnummer', 'Fachrichtung', 'zur Ausbildungsstätte gelangen',etc. Andererseits ist 'Praktikant' aber auch eine Subklasse von 'Arbeitnehmer',erbt von ihr folglich Eigenschaften wie 'AHV-Nummer', 'Arbeitgeber', 'Lohn',u.s.w.

PraktikantSubklasse

Student ArbeitnehmerSuperklassen

Abb. 4: Beispiel von mehrfacher Vererbung

Dieser Vorgang der mehrfachen Vererbung birgt interessante Möglichkeitenbei der Modellierung von Klassen und Klassenhierarchien. (Als weiteres,klassisches Beispiel sei die Klasse 'Hausboot' genannt.) Da dieser Aspekt derobjektorientierten Denkweise aber nicht in allen verbreiteten Programmier-sprachen unterstützt wird – dazu gehört u.a. Pascal –, wird er in der Literaturmeist nur am Rande behandelt und findet in der herkömmlichen Program-mierung wenig Verbreitung.

2.2.4. Vererbung, Überschreiben

Ein Geographiestudent ist also laut Abb.1 ein Student. Das bedeutet für ihn,dass alle Eigenschaften und Fähigkeiten, die für die Klasse 'Student' postuliert

11

wurden, auch für ihn gelten. Diesen Vorgang des 'Mitnehmens' von Eigen-schaften und Fähigkeiten bei der Bildung von Subklassen zu einer bestehendenKlasse nennt man Vererbung. Die Eigenschaften, die in der oben abgebildetenListe (siehe Tab.1) aufgeführt sind, gelten also für alle Klassen, die Subklassenvon 'Student' sind. 'Matrikelnummer', 'Name', u.s.w. sind folglich auch Eigen-schaften aller Klassen, die im Hierarchie-Baum der Abb.2 erscheinen, denn jedeKlasse erbt alle Eigenschaften und Fähigkeiten ihrer jeweiligen direkten Super-klasse. Zu den vererbten Eigenschaften und Fähigkeiten kommen aber nochweitere, nämlich solche, die nur für die Subklasse – z.B. 'Geographiestuden-ten' – Gültigkeit haben und deshalb dieser Klasse hinzugefügt werden.

Von der Klasse Matrikelnummer ...'Student' vererbte Name ...Eigenschaften Vorname ...

Hochschule ...Fachrichtung ...Semester ...Abschlussprüfungsnote ...

Neu hinzugefügte Erstes Nebenfach ...Eigenschaften Anzahl Exkurs.-Tage ...

Diplomarbeitsthema ...

Tab. 3: Spezifikation der Klasse 'Geographiestudent'

Eine Besonderheit ergibt sich bei den Fähigkeiten: auch sie werden vererbt oderkönnen neu zu Subklassen hinzugefügt werden. Es besteht aber zusätzlich dieMöglichkeit, Fähigkeiten und Verhaltensweisen, die bereits für die Superklassefestgelegt und deshalb vererbt wurden, bei der Subklasse mit einer neuenBedeutung zu versehen.

Angenommen man teilt die Studenten der Geographie nicht nur nach derAnthropo-, physischen und methodischen Geographie, sondern weiter nachden Fachbereichen, dann ergibt sich z.B. für die Klasse 'Student der methodi-schen Geographie' die neuen Subklassen 'Student der Fernerkundung' sowie'Student der geographischen Informationsverarbeitung/Kartographie'. Für dieKlasse 'Geographiestudent' ist die Fähigkeit 'Diplom machen' definiert als dieAbfolge 'Grund- und Fachstudium absolvieren', 'Diplomarbeit schreiben','grosses Kolloquium halten' und 'Schlussprüfung bestehen'. Die Bedeutungdieser Fähigkeit gilt nun wegen der Vererbungsregel für alle Subklassen von'Geographiestudent'. Für die Subklasse 'Student der geographischen Informa-tionsverarbeitung/Kartographie' muss diese Fähigkeit aber verändert bzw.ergänzt werden, denn zwischen 'Grund- und Fachstudium absolvieren' und'Diplomarbeit schreiben' wird noch das Bestreiten des sog. kleinen Kolloqui-ums erwartet. Um die Fähigkeit 'Diplom machen' dieser Klasse den speziellenAnforderungen anzupassen, wird sie überschrieben, d.h. ihre Bedeutung wirdso verändert, dass sie den genannten Forderungen entspricht.

12

2.2.5. Polymorphismus

Von jedem Studenten wird verlangt, dass er in einem gewissen Zeitraum undin einer bestimmten Reihenfolge gewisse Prüfungen schreibt. Man kann dieseVerordnung auch als Aufforderung der Universitätsverwaltung an jedenStudenten auffassen, diese Prüfungen ordnungsgemäss zu absolvieren. Beidieser Aufforderung geht die Hochschule nun davon aus, dass jeder Studentimstande ist, die Anzahl, Reihenfolge und Zeitpunkte der Prüfungen sowiederen Zulassungsbestimmungen mit Hilfe von Studienwegleitung und -beraterselbst herauszufinden. Die Universitätsverwaltung braucht also nur jedemStudenten die Aufforderung mitzuteilen, die Prüfungen ordnungsgemäss zuabsolvieren, und jeder Student wird dann je nach Fachrichtung selber wissen,wie dies zu tun ist. Die Tatsache, dass jedes Objekt – in diesem Fall jederStudent – auf die gleiche Aufforderung je nach Klasse, aus der es stammt,unterschiedlich reagiert, nennt man Polymorphismus.

Student

Geographie-student

Wirtschafts-student

Biologie-student

Universitäts-Verwaltung

Prüfung absolvieren

Prüfungabsolvieren:

Prüfungabsolvieren:

Prüfungabsolvieren:

- nach 2 Semest.1.VD- nach 4 Semest.2.VD- nach Grund-studium, 6 TageExkursionen undDiplomarbeitSchlussprüfung

- nach 3 Semest.1.Vorprüfung- ...

- ...

Abb. 5: Beispiel für Polymorphismus

Voraussetzung für das polymorphe Verhalten der Objekte der einzelnen Klas-sen ist eine gemeinsame Superklasse, in der die Fähigkeit, die von den Objek-ten der Klassenzugehörigkeit entsprechend ausgeführt werden soll, bereitsvorhanden ist. In unserem Beispiel wird klar, dass diese Fähigkeit in der Super-klasse nicht unbedingt vollständig definiert sein muss. Es reicht, dass die Klas-se 'Student' die Fähigkeit 'Prüfungen absolvieren' enthält, auch wenn nicht

13

näher bestimmt wird, wie diese Fähigkeit von einer Instanz dieser Klasseausgeführt werden muss. Dies ist deshalb nicht nötig, da ein Student in jedemFall irgendeine Fachrichtung studiert und deshalb in die entsprechende Klassefällt. Für diese Klasse – z.B. 'Geographiestudent', 'Wirtschaftsstudent', – istdann allerdings die Fähigkeit 'Prüfung absolvieren' genau spezifiziert. DieUniversitätsverwaltung beschäftigt sich also nur mit der abstrakten Klasse'Student', von der sie weiss, dass sie die Fähigkeit 'Prüfung absolvieren' besitzt.Da es aber keine Instanzen dieser abstrakten Klasse gibt, spielt es wie erwähntauch keine Rolle, dass hier diese Fähigkeit nicht spezifiziert ist. Die Aufforde-rung 'Prüfungen absolvieren' geht ohnehin an Instanzen von Subklassen von'Student', und bei diesen Subklassen wurde die Fähigkeit je nach Fachrichtungüberschrieben. Polymorphie ist also einer der Gründe für die Schaffung vonabstrakten Klassen.

2.3. Programmiertechnische Aspekte: die Klassen 'Punkt', 'Linie','Polygon'

An diesem zweiten Beispiel soll nun die Umsetzung der oben beschriebenenAspekte der Objektprogrammierung anhand der Terminologie von Pascalerläutert werden. Ausserdem kann man mit diesen elementaren, 'computer-geometrischen' Objekten erkennen, wie die objektorientierte Denkweise fürraumbezogene Fragestellungen eingesetzt werden kann. Das in diesem Kapitelvorgestellte Modell ist nicht so konstruiert, dass es effizient implementiertwerden könnte und elegante Lösungen zu raumbezogenen Problemenermöglicht. Es soll vielmehr zur Erläuterung und Veranschaulichung dienen.

2.3.1. Das Modell

Um raumbezogene Probleme mit einem Programm bearbeiten zu können,muss dieses Programm über die raumbezogenen Elemente verfügen, dieanalysiert werden sollen. Bei den Elementen, die in solchen Fragestellungen imVordergrund stehen, handelt es sich in erster Linie um Punkte, Linien undPolygone. Es liegt also nahe, als erstes diese Basiselemente als Klassen einesProgrammes zur Bearbeitung raumbezogener Fragestellungen zu postulieren.

Als zweites stellt sich die Frage, was für Eigenschaften und Fähigkeiten mandiesen Klassen geben soll. Punkte haben je eine X- und eine Y-Koordinate; diesesind sicher ihre wichtigsten Eigenschaften. Oft ist auch die Z-Koordinate vonPunkten von Interesse, also ist auch diese eine Eigenschaft dieser Klasse.Genauso von Bedeutung ist das reale Objekt, das durch den Punkt im Compu-ter dargestellt wird. Dieses reale Objekt kann z.B. eine Stadt, ein Brunnen, einfreistehender Baum oder eine Messstation irgendeiner Art sein. Je nach Bedeu-tung werden dem Punkt verschiedene Attribute zugeschrieben. Wenn mandavon ausgeht, dass man Klassen modelliert, die in andern Programmen

14

wiederverwendbar sein sollen – ein wichtiger Aspekt der Objektprogrammie-rung, der später noch genauer behandelt wird –, kann man sich folgendehierarchische Gliederung vorstellen: Als Superklasse wird eine Klasse 'Punkt'eingeführt, die alle Eigenschaften enthält, die allen Punkten unabhängig vomthematischen Zusammenhang gemeinsam sind; dazu gehören eigentlich nurdie Koordinaten. Werden Punkte in einem Programm zu einer konkretenFragestellung gebraucht, d.h. erhalten die Punkte besondere, der Thematikentsprechende Eigenschaften, so bildet man eine Subklasse der Klasse 'Punkt'und verwendet diese durch die genannten Eigenschaften ergänzten Objekte.

Nach den Eigenschaften müssen noch die Fähigkeiten und Verhaltensweisengefunden werden, die für die Klasse 'Punkt' definiert werden sollen. Bei diesenhandelt es sich ausschliesslich um Fähigkeiten, die die Verwendung der Klasseim Programm bzw. die Bearbeitung der Punkte im Computer betreffen. Wiejede Klasse benötigt auch 'Punkt' eine Fähigkeit, die Werte der Eigenschaftenzu initialisieren. Dazu kommen Fähigkeiten, die das Zeichnen, das Verschiebenund das Löschen des Punktes ermöglichen. Weitere Fähigkeiten sind wiedervon der themagebundenen Verwendung der Punkte abhängig und werden erstin der oben beschriebenen Subklasse von 'Punkt' näher spezifiziert.

Klasse 'Punkt'Eigenschaften X-Koordinate ...

Y-Koordinate ...Z-Koordinate ...

Fähigkeiten Initialisieren ...Zeichnen ...Löschen ...Verschieben ...

Tab. 4: Liste der Eigenschaften und Fähigkeiten der Klasse 'Punkt'

Wie die Klasse 'Punkt' soll auch die Klasse 'Linie' Eigenschaften und Fähigkei-ten erhalten. Eine Linie soll in diesem Beispiel eine Anzahl nacheinanderfolgen-der, gerader Linienstücke oder mit andern Worten eine Liste von Punkten sein.Damit sind bereits zwei Eigenschaften dieser Klasse gegeben: die Anzahl derPunkte und die Punkte selber bzw. deren Koordinaten. Es gibt verschiedeneMöglichkeiten, wie man die Punkte innerhalb der Klasse 'Linie' organisiert. Dieeinfachste ist sicherlich ein Array, wobei an der ersten Stelle des Arrays dererste Punkt der Linie steht, an der zweiten Stelle der zweite Punkt, an derdritten der dritte, etc. Als Punkt, der an einer bestimmten Stelle des Arrayssteht, kann man nun seine Koordinaten verstehen. Man könnte sich aber auchvorstellen, dass die Punkte nicht nur durch ihre Koordinaten repräsentiert sind,sondern dass im Array jeweils Instanzen der Klasse 'Punkt' enthalten sind. Zudiesem Zweck würde man eine Subklasse von 'Punkt', die Klasse 'Linienpunkt'bilden, die man mit geeigneten Eigenschaften ergänzen könnte. Der Einfachheithalber sollen im Array aber nur die Koordinaten der Punkte stehen.

15

P1 P2 P3 P4 P5 P6...

1 2 3 4 5 6

...

Punkt

1 2 3 4 5 6

x/y x/y x/y x/y x/y x/y

Abb. 6: Varianten des Linienpunkt-Arrays von 'Linie': links die Stellen mit X/Y-Paaren, rechtsmit Instanzen der Objektklasse 'Punkt' belegt

Mit weiteren Eigenschaften verhält es sich wie bei der Klasse 'Punkt'. Für einekonkrete Anwendung der Klasse 'Linie' wird eine Subklasse gebildet.Abhängig davon, welcher Art das Objekt, das durch die Linie dargestellt wird,in der realen Welt ist, werden dieser Subklasse weitere Eigenschaften hinzuge-fügt. Auch die Fähigkeiten, die schon für die Klasse 'Punkt' definiert wurden– 'Zeichnen', 'Verschieben', 'Löschen' –, müssen für die Klasse 'Linie' spezifiziertwerden. Dazu kommen aber noch Fähigkeiten, die das Einfügen einzelnerPunkte in die Linie sowie deren Verschieben und Löschen ermöglichen sollen.Fähigkeiten, die erst bei der Verwendung in konkreten Fragestellungen entste-hen, werden wieder der Subklasse von 'Linie' beigefügt.

Die Klasse 'Polygon' schliesslich kann als Spezialfall der Klasse 'Linie' aufge-fasst werden, bei dem der letzte Punkt des Linienzugs zugleich der erste ist.Dazu kommt noch ein sog. Labelpunkt, dessen Koordinaten nicht im Array derPunkte stehen, sondern der als eigene Eigenschaft zu 'Polygon' gehört. Eskommen zwar keine neuen Fähigkeiten dazu, aber ihre Funktionsweisenmüssen den Polygonen angepasst werden. Die Fähigkeit 'Zeichnen' muss z.B.auch das Zeichnen des Labelpunkts sowie der Verbindung vom letzten zumersten Punkt beinhalten.

In diesem Beispiel werden die topologischen Beziehungen zwischen Objektengleicher oder verschiedener Art vernachlässigt. Das hat zur Folge, dass sich die– auf ihre Geometrie reduzierte – Klassen 'Linie' und 'Polygon' nur wenigunterscheiden. In einer konkreten Anwendung dieser Klassen, in welcher dieTopologie eine Rolle spielt und die Klassen weitere Attribute als Eigenschaftendazuerhalten, werden die erheblichen Unterschiede der Bedeutungen dieserKlassen ersichtlich. Polygone sind nicht nur sich schliessende Linien, sondernFlächen. Gemäss einer exakteren Definition besteht ein Polygon aus einerAussen- und einer bestimmten Anzahl Innengrenzen. Wie eine solche Strukturals Klasse verwirklicht werden kann, zeigt Kapitel 4.4.7. An dieser Stelle sollaber das Bild einer sich schliessenden Linie genügen.

16

2.3.2 Klassendefinitionen

Die Klassen des besprochenen Modells müssen in einem Programm als solchegekennzeichnet und definiert werden. Wie dies geschieht, soll anhand derProgrammiersprache Pascal geschildert werden. Die Definition der Klasse'Punkt' sieht wie folgt aus:

TPoint = objectfX, fY, fZ: LongInt;procedure IPunkt (X, Y, Z: LongInt);procedure Draw;procedure Erase;procedure Move (deltaX, deltaY, deltaZ: LongInt);

end;

Zuerst einige Bemerkungen zur Terminologie: In Programmen kommen vieleKlassen, Eigenschaften, Prozeduren, aber auch andere Variablen, Funktionenund Datenstrukturen vor. Um ein Chaos bei der Namensgebung zu vermeiden,versucht man, eine Terminologie für die Bezeichnungen der genannten Ele-mente einzuführen. In dieser Arbeit wird die Terminologie verwendet, wie siesich bei der Verwendung von MacApp (siehe Kap. 3) durchgesetzt hat. Klassenerhalten ein T (für 'Type'), also heisst die Klasse 'Punkt' jetzt TPoint. (Da dieSchlüsselwörter in Pascal – wie auch in fast allen andern Programmiersprachen– aus dem Englischen entnommen sind, erhalten Klassen, Eigenschaften, etc.meistens englische Namen.) Die Eigenschaften der Klassen beginnen mit einemkleinen f (für 'field'), weswegen die Koordinaten fX, fY und fZ heissen. Fähig-keiten schliesslich werden mit Verben versehen, die mit einem Grossbuch-staben beginnen (z.B. Draw). Bei der Objektprogrammierung werden ausser-dem die Begriffe 'Instanzvariablen' für Eigenschaften und 'Methoden' fürFähigkeiten verwendet. Im folgenden werden diese Ausdrücke verwendet.

Die Deklaration von Klassen in Pascal ist leicht zu verstehen. Zuerst wirdTPoint als Objektklasse ins Leben gerufen, und anschliessend werden alleInstanzvariablen und Methoden aufgelistet. Die einzigen Instanzvariablen vonTPoint sind die Koordinaten fX, fY und fZ. Diese Koordinaten sind als LongIntdeklariert, d.h. ihnen können ganzzahlige Werte zwischen -2'147'483'648 und2'147'483'647 zugewiesen werden. (Diese Grenzen gelten für Macintosh-Computer und können für andere Rechener andere Werte besitzen.)

Nach den Instanzvariablen folgen die vier Methoden der Klasse. In der Klas-sendeklaration werden nur die sog. Interfaces der Methoden aufgelistet, die ausdem Namen der jeweiligen Methode sowie den Parametern, die ihr übergebenwerden, bestehen. Sie dienen dazu, die Syntax zu definieren, die bei derVerwendung der Methode im Programm befolgt werden muss. Die eigentlicheImplementation der Methoden erfolgt an einer andern Stelle im Programm.

Die Funktionsweise der Methoden ist klar: Draw zeichnet den Punkt mit seinerSignatur an der richtigen Stelle, Erase löscht ihn an dieser Stelle wieder (derPunkt existiert noch im Layer, er ist nur nicht mehr gezeichnet), und Movelöscht den Punkt an der einen Stelle, berechnet mit deltaX, deltaY und deltaZ

17

die neue und zeichnet ihn dort. (Auf Methoden für das Einfügen und Entfernenvon Punkten im Layer wird vorläufig verzichtet.) Nicht auf Anhieb ersichtlichist der Zweck der Mehode IPoint. Jede Klasse enthält eine Methode, derenName aus einem grossen I (für 'Init') sowie dem Namen der Klasse besteht.Diese Methode wird immer dann aufgerufen, wenn eine neue Instanz derKlasse gebildet wird. Sie übernimmt die Initialisierung dieser Instanz, d.h. eswerden z.B. alle Instanzvariablen auf einen Initialwert gesetzt. Für die KlasseTPoint heisst diese Mehode IPoint, und sie setzt die Koordinaten fX, fY und fZauf die Parameterwerte X, Y und Z.

Analog zur Klasse TPoint wird auch die Klasse TLine deklariert:

TLine = objectfNumberOfPoints: Integer;fPoint: array [1..cMaxNumberOfPoints] of VPoint;procedure ILine;procedure Draw;procedure Erase;procedure Move (deltaX,deltaY: LongInt);procedure InsertPoint (PointBefore: Integer; X,Y: LongInt);procedure MovePoint (PointNumber: Integer; deltaX, deltaY: LongInt);procedure DeletePoint (PointNumber: Integer);

end;

Diese Klasse besitzt zwei Instanzvariablen und sieben Methoden. Die ersteInstanzvariable, fNumberOfPoints, definiert die Anzahl Punkte, aus der dieLinie besteht. Sie ist als Integer deklariert, d.h. ihr können Werte zwischen-32'768 und 32'767 zugewiesen werden. (Auch diese Werte gelten für Macintosh-Computer.) Für Linien mit hunderttausenden oder mehr Punkten müsste manstatt Integer LongInt wählen.

fPoint ist der im vorhergehenden Kapitel beschriebene Array, in dem die Koor-dinaten der Punkte abgelegt sind. Der Array ist durchnummeriert von 1 biscMaxNumberOfPoints. cMaxNumberOfPoints ist eine Konstante, die vor derDeklaration von TLine festgelegt werden muss und die dazu da ist, dem Arrayder Linienpunkte eine maximale Länge zu geben. Die Anzahl Stellen einesArrays wird bei seiner Deklaration festgelegt und kann danach nicht mehrverändert werden. Da aber die Möglichkeit bestehen soll, Punkte in die Linieeinzufügen sowie aus ihr zu entfernen, muss der Array mit mehr Stellen dekla-riert werden, als die Linie Punkte besitzt. Ausserdem kann bei der Deklarationder Linienklasse nicht vorausgesehen werden, wieviele Punkte die Linieschliesslich haben wird. (cMaxNumberOfPoints kann höchstens 32'767betragen, da fNumberOfPoints als Integer deklariert wurde und somit nichtgrösser als dieser Betrag sein kann.)

Um im Array die Koordinaten der Punkte wieder – wie in TPoint – als LongIntablegen zu können, wird die vordefinierte Datenstruktur VPoint verwendet.Sie wird von der Klassenbibliothek MacApp (siehe Kap.3) zur Verfügunggestellt und besteht aus einer h- sowie einer v-Komponente, die beide alsLongInt definiert sind. (Ähnlich wie Vektoren enthält die Datenstruktur

18

VPoint zwei Werte.) fPoint [17].h ist also die X-Koordinate des 17. Punkts derLinie, fPoint [17].v dessen Y-Koordinate.

Die Methoden der Klasse TLine sind wieder mehr oder weniger selbsterklä-rend. Wieder existiert eine Initialisierungsmethode, die dieses Mal ILine heisst.Zu den Methoden, die schon die Klasse TPoint besitzt, kommen noch die dreidazu, die das Einfügen, Verschieben und Eliminieren einzelner Punkte derLinie betreffen.

Die Deklaration von TPolygon sieht ähnlich wie die von TLine aus:

TPolygon = objectfNumberOfPoints: Integer;fPoint: array [1..cMaxNumberOfPoints] of VPoint;fLabelPoint: VPoint;procedure IPolygon;procedure Draw;procedure Erase;procedure Move (deltaX,deltaY: LongInt);procedure InsertPoint (PointBefore: Integer; X,Y: LongInt);procedure MovePoint (PointNumber: Integer; deltaX, deltaY: LongInt);procedure DeletePoint (PointNumber: Integer);

end;

Es gibt zwei Unterschiede zur Klasse TLine: Erstens besitzt TPolygon eineweitere Instanzvariable fLabelPoint, die mit Hilfe der Datenstruktur VPointdefiniert wird. Wie oben erklärt, besteht VPoint aus zwei LongInt-Komponen-ten, die in diesem Fall die Koordinaten des Labelpunkts darstellen. Der zweiteUnterschied besteht darin, dass die Methoden der Klassen verschieden imple-mentiert sind. Bei der Klasse TPolygon zeichnet die Methode Draw zusätzlichzum Linienzug noch die Verbindung vom letzten zum ersten Punkt sowie denLabelpunkt. Die Unterschiede in den Implementationen haben allerdings nichtzur Folge, dass sich die Interfaces der Methoden in den Klassendeklarationenebenfalls unterscheiden.

2.3.3. Instanzen

Instanzen sind wie bereits erwähnt tatsächlich existierende Objekte einerbestimmten Klasse, deren Instanzvariablen bestimmte Werte haben und diedurch ihre Methoden angesprochen werden können. In einem Programmbedeutet das, dass eine Instanz einer Klasse eine eindeutig bestimmte,Speicherplatz belegende Einheit ist, die Aufforderungen ausführen kann undsich in unserem Fall auf dem Bildschirm repräsentiert. Um so eine Instanz insLeben zu rufen, sind folgende Zeilen im Programmcode nötig: Am Anfang desProgrammes oder einer Prozedur muss eine Variable deklariert werden, die dieInstanz enthalten wird:

var aNewPoint: TPoint;

19

Wenn für diese Variable des Typs TPoint Speicherplatz reserviert wird (diesgeschieht mit dem Befehl New), existiert die Instanz dieser Klasse bereits. DieInstanz muss nur noch initialisiert werden (mit IPoint).

New (aNewPoint);aNewPoint.IPoint (200, 350, 635);

Von nun an existiert also eine Instanz der Klasse TPoint mit dem NamenaNewPoint und den Koordinaten 200, 350 und 635. Dieser Instanz können nunAufforderungen geschickt werden, die sie dann ausführt, wie z.B.

aNewPoint.Draw;

2.3.4 Subklassen

Wie bereits erwähnt würde man in einer konkreten Anwendung nicht Instan-zen von TPoint, TLine und TPolygon bilden, sondern für die Fragestellungangepasste Subklassen dieser Klassen entwerfen. Wenn z.B. Quellen imZentrum des Interesses stehen, so wird man eine Klasse TFountain entwerfen,die vielleicht etwa folgendermassen aussehen könnte:

TFountain = object (TPoint)fName: String;fLitersPerSec: Real;fQuality: Real;fGround: String;fRiver: TRiver;procedure IFountain (X, Y, Z: LongInt);procedure Draw;procedure Erase;

end;

TFountain ist also eine Subklasse von TPoint, denn object (TPoint) bedeutet,dass TFountain eine Objektklasse des Typs TPoint ist. Folglich erbt diese neueKlasse alle Instanzvariablen – die Koordinaten – sowie Methoden ihrer Super-klasse. Ausserdem kommen laut Deklaration noch weitere Eigenschaften dazu:Eine Quelle besitzt einen Namen (String entspricht dem Begriff 'Zeichenkette').Für die durchschnittliche Anzahl Liter Quellwasser pro Sekunde steht dieVariable fLitersPerSec, für die Wasserqualität die Variable fQuality. Beide sindals Real deklariert, d.h. ihre Werte sind reelle Zahlen mit 7 bis 8 gültigenStellen. Weiter soll die Quelle die charakteristische Eigenschaft Untergrund-gestein (fGround) haben. Und schliesslich fliesst das Wasser einer Quelle in einFliessgewässer, das durch die Variable fRiver des Typs TRiver dargestelltwird. TRiver ist eine Subklasse von TLine und wird weiter unten näher erklärt.

Auch TFountain besitzt eine Initialisierungsmethode IFountain. In ihr wird alserstes die Initialisierungsmethode der Superklasse, IPoint, aufgerufen. Dies istder Grund, warum IFountain die Parameter X, Y und Z übergeben werden,

20

denn diese werden in dieser Prozedur der Methode IPoint weitergegeben, diedann ihrerseits die Instanzvariablen fX, fY und fZ auf X, Y und Z setzt. DieMethoden Draw und Erase werden überschrieben, d.h. ihre Funktionsweisenwerden für die Subklasse verändert. Dies ist nötig, da Quellen mit einerspeziellen Signatur gezeichnet werden sollen.

Klasse TFountainInstanz- fX ...variablen fY ... vererbt

fZ ...fName ...fLitersPerSec ... neufQuality ... (lokal, nur fürfGround ... TFountain gültig)fRiver ...

Methoden IFountain ... neu (lokal, ...)IPoint ... vererbtMove ...Draw ... vererbt, aberErase ... überschrieben

Tab. 5: TFountain mit allen vererbten und neuen Instanzvariablen sowie Methoden

Wie bereits angetönt, kann man Quellen im Zusammenhang mit fliessendenGewässern betrachten. Um auch Gewässer bearbeiten zu können, soll eineentsprechende Subklasse von TLine gebildet werden.

TRiver = object (TLine)fName: String;fLength: Real;fNextRiver: TRiver;fPrevRiver: array [1..cMaxNumberOfRivers] of TRiver;fHasFountain: boolean;fFountain: TFountain;procedure IRiver;procedure Draw;procedure Erase;function CalculateOutlet: Real;

end;

Wieder ist eine der Instanzvariablen der Name des Gewässers; eine zweite istseine Länge. Der Fluss, in den das Gewässer mündet, ist eine weitere Variable.Um die Berechnung zu ermöglichen, wieviel Wasser der Fluss bei dessenMündung führt, muss bekannt sein, aus welchen Gewässern Wasser in diesenFluss fliesst. Zu diesem Zweck ist die Variable fPrevRiver ('previous River') alsArray definiert. In diesem Array sind alle Gewässer aufgeführt, die in diesenFluss münden. Die nächste Instanzvariable fHasFountain gibt an, ob der Flussaus einer Quelle entspringt, oder ob er aus dem Zusammenfluss zweier andererGewässer hervorgeht (der Rhein z.B. entsteht durch den Zusammenfluss von

21

Vorder- und Hinterrhein). Der Datentyp boolean ist zweiwertig, und zwarentweder TRUE ('wahr') oder FALSE ('falsch'). Ist fHasFountain TRUE, dannbesitzt der Fluss eine Quelle. In diesem Fall enthält die Variable fFountain dieentsprechende Instanz der Klasse TFountain.

Wie schon die Initialisierungsmethode von TFountain ruft auch IRiver dieInitialisierungsmethode ihrer Superklasse, ILine, auf. Die Methoden Draw undErase müssen deshalb überschrieben, d.h. neu definiert werden, da ein Fliess-gewässer mit einer speziellen Signatur gezeichnet werden soll. Man könnte sichz.B. vorstellen, dass die Linienstärke abhängig ist von der Wassermenge desFlusses. Die letzte Methode ist keine Prozedur, sondern eine Funktion, d.h. sieliefert einen Wert zurück: In CalculateOutlet werden die Wassermengen derzufliessenden Gewässer und der Quelle addiert. Die Wassermenge der Quelleist eine ihrer Eigenschaften, also kann dieser Wert direkt gelesen werden. DieWassermengen der vorhergehenden Flüsse müssen allerdings wieder mitdieser Funktion berechnet werden. Dies bedeutet, dass in dieser Methode füralle Instanzen des Arrays fPrevRiver die Methode CalculateOutlet erneutaufgerufen wird, wo dann wieder dasselbe geschieht. Irgendein Fluss wirddann nur noch von einer Quelle gespeist; dort wird die Kette der sichaufrufenden Funktionen beendet.

A

B C

D

E12

3 4

Abfluss von A

Abfluss von B Abfluss von C Abfluss von D

Wassermengevon Quelle 3

Wassermengevon Quelle 4

Wassermengevon Quelle 1

Wassermengevon Quelle 2

Abfluss von E

A.CalculateOutlet = 192.7 l/s

Abb. 7: Beispiel von CalculateOutlet: CalculateOutlet von A ruft zuerst CalculateOutlet von B,dann von C und schliesslich von D auf; CalculateOutlet von D ruft zusätzlich CalculateOutlet

von E auf.

22

Um dieses Gewässermodell zu vervollständigen, könnte man versuchen, zuden Flüssen auch ihre Einzugsgebiete miteinzubeziehen. Da es sich bei diesenum flächenhafte Elemente handelt, würde man eine Subklasse von TPolygonbilden. Eine Eigenschaften dieser neuen Klasse TDrainage wäre die Flächen-grösse, eine andere die vorherrschende Vegetation, dazu kämen vielleicht auchder mittlere Niederschlag oder Grössen, die die durchschnittliche Höhe unddie vertikale Ausdehnung betreffen. Es soll hier aber nicht weiter darauf einge-gangen werden.

TDrainage

TLine

TFountain TRiver

TPoint TPolygon

Abb. 8: Hierarchie von TPoint, TFountain, TLine, TRiver, TPolygon, TDrainage

2.3.5 Abstraktion

Um das im letzten Kapitel entworfene GIS (Gewässer-Informationssystem)möglichst flexibel zu gestalten, ist es hilfreich, zu den Klassen TPoint, TLineund TPolygon eine gemeinsame Superklasse zu finden. Da zu Beginn nichtvoraussehbar ist, wieviele Fliessgewässer, Quellen und Einzugsgebiete verwal-tet werden sollen, und ob vielleicht auf die eine oder andere Klasse verzichtetwird, sollte das System bereit sein, Instanzen von allen Klassen aufzunehmenund gleich zu behandeln. Dabei wird ausgenützt, dass eine Instanz z.B. derKlasse TRiver ebenso eine Instanz der Klasse TLine wie auch von weiterenSuperklassen von TRiver bzw. TLine ist. Da dies auch für Instanzen vonTFountain und TDrainage gilt, wären also alle erfassten Quellen, Flüsse undEinzugsgebiete Instanzen der zu findenden Superklasse – sie wird TGeom-Primitive heissen. Durch die Verwendung dieser gemeinsamen Superklassekann ausserdem das polymorphe Verhalten der Objekte ausgenützt werden,das im nächsten Kapitel noch einmal ausführlicher besprochen wird.

Ein weiterer Vorteil bei der Erstellung dieser neuen Klasse besteht darin, dassweitere Eigenschaften ergänzt werden können, die alle Klassen betreffen. DieKlassen-Deklaration sieht folgendermassen aus:

TGeomPrimitive = objectfColor: Color;fSelected: boolean;procedure IGeomPrimitive;procedure Draw;procedure Erase;

23

TLine

TFountain TRiver TDrainage

TPoint TPolygon

TGeom-Primitive

Abb. 9: Klassenhierarchie mit abstrakter Superklasse TGeomPrimitive

procedure Move (deltaX,deltaY:LongInt);procedure Select;procedure Deselect;

end;

Jede Subklasse von TGeomPrimitive ('Geometric Primitive') besitzt nun eineFarbe sowie eine Instanzvariable, die anzeigt, wenn die Instanz selektiert ist.Dazu kommen die entsprechenden Methoden, die das Selektieren und Deselek-tieren erlauben. Anders als bei den Instanzvariablen werden die Methodennicht einfach in dieser Form von den Subklassen übernommen. Da von dieserSuperklasse nie direkt Instanzen gebildet werden, sind auch die Methodennicht näher spezifiziert. Die Implementationen – an einer anderen Stelle imProgramm – sehen alle etwa so aus:

procedure TGeomPrimitive.Draw;beginend;

Natürlich werden alle Methoden in den Subklassen überschrieben. Ausnahmeist die Methode IGeomPrimitive: Sie wird von den Initialisierungsmethodender drei Subklassen aufgerufen und setzt die Variablen fColor auf schwarz undfSelected auf FALSE (als Beispiel für die Aufgabe einer Initialisierung).

Durch die neue Superklasse ergeben sich auf die Klassen TPoint, TLine undTPolygon Veränderungen. Da sie jetzt Subklassen sind, sieht die erste Zeileihrer Deklarationen etwas anders aus, so z.B. bei TPoint:

TPoint = object (TGeomPrimitive)

Ausserdem werden in der Deklaration die Methoden Select und Deselecthinzugefügt. Sie werden wie die andern Methoden auch in den Subklassenüberschrieben. Die Methoden Draw und Erase werden so geändert, dass sieberücksichtigen, ob sich die Instanz in selektiertem Zustand befindet. Ist dies

24

der Fall, wird sie hervorgehoben gezeichnet bzw. gelöscht. Die Initialisierungs-methoden schliesslich rufen zusätzlich die Methode IGeomPrimitive auf.

2.3.6 Polymorphismus

Um mit den Quellen, Flüssen und Einzugsgebieten arbeiten zu können, mussdas System nur wissen, welche Instanzen existieren, nicht aber, von welchemTyp diese sind. Um eine bestimmte Anzahl solcher Instanzen zu verwalten, legtdas System diese z.B. in einem Array ab, der etwa wie folgt definiert ist:

aWaterObject: array [1..cMaxNumberOfObjects] of TGeomPrimitive;

Die Instanz, die durch aWaterObject[23] (das an der 23. Stelle dieses Arraysgespeicherte Objekt) ausgedrückt wird, ist also vom Typ TGeomPrimitive,obwohl es sich z.B. um eine Quelle handelt. Da aber ein Objekt vom TypTGeomPrimitive eine Draw-Methode besitzt, kann das System diesemtrotzdem die folgende Aufforderung schicken:

aWaterObject[23].Draw;

Die Instanz aWaterObject[23] ist aber auch vom Typ TFountain – eine Subklas-se von TGeomPrimitive – und wird deshalb seine Implementation von Drawausführen: Es wird an der richtigen Stelle die Signatur für eine Quelle zeichnen.Die Instanz aWaterObject[42], das z.B. ein Fluss sein könnte, wird auf dieselbeAufforderung anders reagieren: Es wird auf Grund seiner Implementation vonDraw die Signatur eines Flusses zeichnen. aWaterObject[56], das ein Einzugs-gebiet darstellt, wird auf die Aufforderung Draw sein Gebiet mit einerbestimmten Farbe schattieren. Dieses Verhalten, auf dieselbe Aufforderungverschieden zu reagieren, nennt man wie bereits erwähnt Polymorphismus.Jede Instanz, die von einer Klasse stammt, die eine Subklasse von TGeom-Primitive ist, kann in diesem Array abgelegt werden und wird sich polymorphverhalten.

Um die ganze Gewässer-Szenerie zu zeichnen, sind also die folgenden ZeilenProgrammcode nötig:

for i:=1 to NumberOfObjects doaWaterObject[i].Draw;

2.4. Spezielle Bemerkungen

2.4.1. Information Hiding

Ein Grund dafür, dass sich die Objektprogrammierung als Alternative zurprozeduralen Programmierung durchgesetzt hat, liegt im sog. Information

25

Hiding. Unter diesem 'Information verbergen' ist die Modularisierung vonProgrammteilen zu verstehen. Bei der Entwicklung von Klassen wird daraufgeachtet, dass die Methoden eine genau definierte Funktionalität besitzen unddass sie möglichst unabhängig von andern Methoden, Klassen oder andernProgrammteilen implementiert sind. Auf diese Weise wird erreicht, dass dieKlassen sowie ihre Methoden in sich geschlossene Einheiten bilden. Sie könnenlosgelöst von ihrer Entwicklungsumgebung weiterverwendet werden, ohnedass sie verändert werden müssen und ohne dass der Benutzer dieser Klassenüber die Implementation Bescheid wissen muss. Andererseits kann das Innerevon Methoden verändert werden, ohne dass es notwendig wäre, die Umge-bung, in der die Klasse eingesetzt wird, anzupassen. Methoden können so z.B.nachträglich mit effizienteren Algorithmen ausgerüstet werden.

Zur Illustration dieses Aspekts der objekt-orientierten Sichtweise stelle mansich ein Auto vor. Viele Leute wissen ungefähr, wie ein Auto funktioniert, diewenigsten aber wissen genau über die technischen Details und RaffinessenBescheid. Trotzdem können fast alle erwachsenen Leute in der Schweiz ohneProbleme ein Auto steuern. Dies wird ihnen erlaubt durch eine Bedienungs-oberfläche, die in allen Autos mehr oder weniger gleich ist: ein Lenkrad, Gas-und Bremspedal, Kupplung, Gangschaltung und einige weitere Schalter undKnöpfe. Dadurch, dass diese Ausrüstung in allen Wagen dieselbe ist, genügt es,das Autofahren in einem Auto zu lernen, um es in allen andern auch zukönnen, unabhängig davon, wie der Motor und die andern Elementefunktionieren.

Wie dieses Beispiel zeigt, ist es beim Entwurf von Klassen und deren Methodenwichtig, dass das Augenmerk nicht immer auf den inneren Aufbau, sonderngenauso auf den späteren Gebrauch gerichtet ist. Durch einfach gehalteneSchnittstellen erhöht sich die Wiederverwendbarkeit, was wiederum denEntwicklungsaufwand von kommenden Projekten reduziert. Die klare Struktu-rierung von Klassen und die eindeutige Funktionalitätszuweisung an dieMethoden reduziert aber auch die Komplexität der Klassen. Dazu kommt, dasssie in der Entwicklungsphase leichter zu testen sind, was wiederum denAufwand verringert.

2.4.2. Objekt Oriented Analysis, Objekt Oriented Design

Wie im letzten Kapitel geschildert, ist der Entwurf von grosser Wichtigkeit fürdie Qualität von Klassen. Die Entwicklungsphase von der Formulierung derProblemstellung bis zum fertigen Programm wird grob in zwei Teilaufgabengeteilt: die objekt-orientierte Analyse und das objekt-orientierte Design.

Die erste Aufgabe besteht darin, die Fragestellung genauer zu untersuchen. Esist notwendig herauszufinden, was ein zukünftiges Programm können muss,welche Probleme es zu lösen hat und was für Fähigkeiten es nicht zu besitzenbraucht. Ebenso müssen in der Fragestellung Objekte identifiziert werden, undzwar nicht solche, die als Klassen implementiert werden sollen, sondernObjekte der realen Welt, die in der Fragestellung irgendeine Rolle spielen und

26

die Lösung beeinflussen. (Die Modellierungen in den Kapiteln 2.2. und 2.3.1.sind Beispiele einer solchen Objekt-Identifizierung.) Zu diesen Objektengehören auch ihre Eigenschaften sowie vor allem ihre Fähigkeiten und Verhal-tensweisen. Um das Modell des Problems zu vervollständigen, werdenschliesslich die Beziehungen und Wechselwirkungen dieser 'realen' Objekteanalysiert.

Wenn die Modellierung der Fragestellung abgeschlossen ist, folgt das objekt-orientierte Design der Implementation, d.h. das Entwerfen der Architektur fürdas problemlösende Programm. Es geht diesesmal darum, die Klassen wieauch die dazugehörigen Eigenschaften und Methoden zu definieren, die imProgramm implementiert werden sollen. Dazu muss bemerkt werden, dass esoft erstaunlich ist, wie stark sich die programminternen Klassen von denObjekten, die während der objekt-orientierten Analyse gefunden wurden,unterscheiden. Viele der realen Objekte eignen sich nicht als Klassen, da sieentweder nur Teile von andern Objekten sind oder die Fragestellung nichtwirklich beeinflussen. So wurden z.B. die Punkte der Klasse TLine im Kapitel2.3.2. aus Effizienzgründen nicht als eigene Objekte, sondern als Teile derObjekte 'Linie' eingeführt. Für den zweiten Fall wird in der Literatur (Goldsteinund Alger, 1992) das Beispiel eines Lohnverwaltungssystems genannt: In dero.-o. Analyse werden unter anderem die Objekte 'Lohnauszahlung' und 'Lohnauszahlender Buchhalter' gefunden. Im o.-o. Design wird die Klasse 'Lohnauszahlender Buchhalter' nicht mehr berücksichtigt, denn wichtig ist, dass derLohn ausgezahlt wird, und nicht von wem dies erledigt wird. Die effizienteGestaltung dieser Klassen führt dann zu sich selber auszahlenden Löhnen, d.h.die Methode 'Auszahlung vornehmen' wird nicht mehr dem Buchhalter,sondern der Lohnauszahlung selber zugeschrieben. Auf dieselbe Weise führtdas o.-o. Design zu Dokumenten, die sich selber drucken oder Punkte, Linienund Polygone, die sich selber zeichnen. Es gilt generell, dass nicht Objekte derrealen Welt als Klassen implementiert werden, sondern dass Metaphernverwendet werden sollen.

Das objekt-orientierte Design kann wieder in verschiedene Schritte aufgeteiltwerden. Ausgangspunkt ist die Funktionalität, die das Programm erfüllenmuss. Dies ist meist eine fixe Grösse und wird während der Entwicklungs-phase nicht oder kaum verändert. Der nächste Schritt besteht in der Identifi-zierung der Klassen, die aus den 'realen' Objekten der o.-o. Ananlyse hervor-gehen und die implementiert werden sollen, sowie der Zuweisung der notwen-digen Eigenschaften und Methoden. Während dieses Vorgangs muss meistensdie Definition der Klassen sowie ihrer Bestandteile korrigiert und angepasstwerden. Danach werden die Klassen in einer Hierarchie aus Super- und Sub-klassen zusammengefügt, die schliesslich implementiert wird.

So linear wie oben dargestellt verläuft der Entwicklungsprozess im Normalfallnicht. Jeder Schritt beeinflusst in hohem Masse den vorhergehenden wie auchden folgenden Schritt. Bei der Entwicklung des Programms wird man auchnicht nur zwischen sich folgenden Schritten hin und her springen, man wirdvielmehr von überall Veränderungen und Anpassungen an irgendeiner Stelleanbringen müssen, sei dies bei der Klassendefinition, der Hierarchieerstellungoder der Implementation. Es kommt noch dazu, dass nach der abgeschlossenen

27

Implementation des Programmes die Arbeit nicht zu Ende ist: zuerst wird zuüberprüfen sein, ob das Programm seine Aufgaben einwandfrei erfüllen kann,dann muss mit dem späteren Benutzer die Funktionalität verifiziert werden– während der Entwicklungsphase besteht die grosse Gefahr, dass die eigent-liche Aufgabe des Programmes aus den Augen verloren wird –, und schliess-lich müssen 'gute' Programme, die über einen längeren Zeitraum Verwendungfinden, gewartet und weiterentwickelt werden. Dies bedeutet, dass dieEntwicklung eines Programmes gewissermassen einen Kreislauf darstellt, deraber nicht linear durchlaufen wird. Abbildung 10 soll den Ablauf illustrieren.

was muss dasProgramm können

Identifikation derKlassen

Zuweisung derEigenschaftenund Methoden

Verfeinerungder Klassen-definitionen

Erstellung derKlassenhierarchie

Implementation

Abb. 10: Verflechtung der Schritte beim objekt-orientierten Design (Quelle: Apple DevelopmentUniversity, 1991)

28

3. Klassenbibliotheken, MacApp

3.1. Klassenbibliotheken

Ein Nutzen, den man aus der Objektprogrammierung im Vergleich zurherkömmlichen Technik zieht, ist die verbesserte Wiederverwendbarkeit vonProgrammteilen. Eine gut gestaltete Klasse erlaubt den Zugriff auf Instanz-variablen nur via eigene Methoden. So kann man eine saubere Schnittstelledefinieren, die die Klasse aus ihrem Kontext löst und es ermöglicht, sie invielen andern Anwendungen einzusetzen. Dazu kommt, dass sie durch Sub-klassierung in irgendeiner Art spezialisiert und der gegebenen Verwendungangepasst werden kann. Diese Wiederverwendbarkeit von Klassen macht mansich zunutze, indem man nicht Klassen aus einer bestehenden Anwendungherauslöst, sondern Klassen losgelöst von einem konkreten Zusammenhangentwickelt und sie von vornherein zu einem nicht völlig vorhersehbaren Zweckentwirft. Meist sind diese Klassen nur als abstrakte Klassen gedacht, und eswird erwartet, dass diese dem Einsatz entsprechend subklassiert werden.Werden mehrere solcher wiederverwendbarer Klassen zusammen angeboten,spricht man von einer Klassenbibliothek.

Die meisten Klassenbibliotheken dienen als Reservoir für Objekte, die in derBenutzerschnittstelle (User Interface) einer Applikation Anwendung finden(z.B. Buttons, Fenster, Icons, etc.). Sie sind Metaphern für Steuermechanismen,die dem Benutzer der Applikation die Möglichkeit geben, durch gezielteAktionen dem Programm Befehle zu geben. Sie sind also klar abgegrenzteEinheiten, die Eigenschaften und Fähigkeiten besitzen. Ausserdem existierenverschiedene Kategorien von Objekten der gleichen Art, z.B. unterschiedlicheButtons, Dialogfenster oder Scrollbars. Natürlich liegt es nahe, diese Einheitenals Objekte bzw. als Klassen zu implementieren. Da sie in allen Programmeneingesetzt werden, man aber nicht voraussehen kann, welche Aufgaben dieseProgramme erfüllen werden, werden solche Klassen in sehr allgemeiner Formzusammengefasst und als Klassenbibliothek dem Entwickler zur Verfügunggestellt. Man geht oft sogar noch weiter und versucht, die ganze Applikationwie auch die damit zu bearbeitenden Daten (Text, Zahlen, Graphik, etc.) alsObjekte zu verstehen und den Programmablauf von diesen verwalten zulassen. Werden solche Klassen in der Klassenbibliothek zu denen des UserInterface hinzugefügt, entsteht ein sog. Application Framework, das als eine(fast) fertige Programmhülle als Basis für eine eigene Entwicklung eingesetztwerden kann.

3.2. MacApp: Einleitende Bemerkungen

Ein solches Application Framework ist MacApp. Es wurde von Apple entwor-fen, um dem Entwickler von eigenen kleinen (und auch grösseren) Program-

29

men ein Werkzeug in die Hand zu geben, das ihn in kürzerer Zeit zu effizien-teren Ergebnissen kommen lassen soll.

MacApp ist auf der Grundlage der Macintosh User Interface Standards entwik-kelt worden. Diese Interface Standards sind ein essentieller Bestandteil derMacintosh-Philosophie und beschreiben, wie die Benutzer-Oberfläche vonApplikationen auszusehen hat, damit sich der Benutzer leicht zurechtfindenkann. Ein wichtiger Punkt dabei ist, dass gleiche Funktionen in verschiedenenProgrammen immer gleich aussehen bzw. gleich angesprochen werdenkönnen. Durch die Verwendung von MacApp wird dieses Aussehen von vorn-herein so bestimmt, dass es den User Interface Standards entspricht, so dassalle selbstentwickelten Programme bei allen Entwicklern gewissen Normenentsprechen. Ausserdem muss sich der Entwickler des eigenen Programmsnicht mehr um die Implementation von Fenstern, Menus, etc. kümmern, denndiese Einheiten sind in MacApp bereits enthalten und müssen nur noch deneigenen Bedürfnissen angepasst werden.

Ausserdem übernimmt MacApp Aufgaben, die befriedigend zu lösen einNicht-Experte für das Macintosh-System nicht imstande ist. Dazu gehören dasMemory Management, das Auffangen von Programmierfehlern, wie auch derEinbau von Mechanismen, die es dem Benutzer des zukünftigen Programmserlauben werden, Aktionen wieder rückgängig zu machen. Genauso ist dasErstellen von Texteditier-Fenstern sowie das Ausdrucken von Text undGraphik vorbereitet.

Um MacApp so allgemein verwendbar wie möglich zu halten, sind sehr vieleverschiedene Klassen mit oft zahlreichen Methoden für die verschiedenstenAnwendungen entworfen worden. Man wird in einer eigenen Anwendung niealle Möglichkeiten ausschöpfen, die MacApp anbietet. Dies bedeutet abergleichzeitig, dass bei der Verwendung dieses Application Frameworks durchdie Klassen, die nicht gebraucht werden, ein grosser Balast entsteht, der dasentstehende Programm belastet. Oft ist es aber so, dass Programme, die mitMacApp entwickelt wurden, schneller sind als solche, die von Grund auf selbstimplementiert wurden. Dies liegt daran, dass MacApp von Programmierernzusammengestellt wurde, die den Macintosh und sein System durch und durchkennen und wissen, wie man welche Probleme am effizientestenimplementiert.

30

3.3. Überblick über die wichtigsten Klassen

TCommand

TApplication TDocument TView

TEvtHandler TList

TObject

TWindow TScroller TControl

TIcon TPopup TCtlMgr

TScrollBar TButton TRadio TCheckBox

TDialogView

TStaticText TCluster

TEditText

TNumberText

Abb. 11: Eine Auswahl wichtiger Klassen von MacApp (Es sind nicht alle Klassen abgebildet !)

3.3.1. TObject

Alle Klassen von MacApp stammen von der Klasse TObject ab. In dieserabstrakten Superklasse sind zwar keine Instanzvariablen enthalten, dafür

31

besitzt sie aber Methoden, um neue Instanzen von Klassen zu erzeugen und siewieder zu eliminieren. Ausserdem sind in ihr Methoden zur Fehlerverfolgungbeim Programmieren ('Debugging') deklariert, die – wie auch die vorhingenannten Methoden – von allen andern Klassen von MacApp geerbt werden.

3.3.2. TEvtHandler

Eine weitere abstrakte Klasse und direkte Subklasse von TObject ist TEvt-Handler ('Event Handler'). Ihre Aufgabe ist es, Methoden und Instanzvariablenbereitzuhalten, mit denen die Subklassen von TEvtHandler sogenannte Eventsverarbeiten können. Als Events werden Ereignisse verstanden, auf die einProgramm je nach Situation reagieren können muss. Dazu gehören Mouse-Klicks, das Schreiben auf der Tastatur, das Einschieben von Disketten, u.a. Allesichtbaren Elemente auf dem Bildschirm wie z.B. Fenster, deren Inhalte, But-tons, Scrollbars, der Menubalken, etc., aber auch Dokumente und sogar dieApplikation selber sind Subklassen von TEvtHandler, d.h. sie können alleseparat auf Events, die sie betreffen, auf die angemessene Art und Weisereagieren. In einem Programm sind diese Objekte miteinander verbunden, d.h.jedes Objekt zeigt in einer Liste auf das nächste, das auf einen Event reagierenkönnte. Erfolgt nun ein Ereignis – z.B. ein Mouse-Klick –, dann wird für daserste Objekt in dieser Liste getestet, ob der Event für dieses gedacht ist. Wennnicht, wird dieser Test für das nächste Objekt in der Liste wiederholt. DieserVorgang dauert so lange, bis entweder ein Objekt gefunden wurde, das denEvent entsprechend verarbeiten kann, oder bis man am Ende der Liste ange-langt ist. Um so eine Liste aufbauen zu können, enthält die Klasse TEvt-Handler einen Zeiger auf eine nächste Instanz von TEvtHandler. Ausserdemsind in dieser Klasse Methoden deklariert, die das Verarbeiten von Events fürdie Subklassen vorbereiten.

3.3.3. TApplication

In einem MacApp-Programm wird die Applikation selber als Objektinstanzverstanden. Die zu diesem Zweck nötige Klasse TApplication ist eine Subklas-se von TEvtHandler. In erster Linie enthält sie Methoden zur Steuerung desProgrammablaufs, zur Verwaltung von Dokumenten, Fenstern u.a. sowie zurBearbeitung von Events. Für jede Applikation wird genau eine Instanz dieserKlasse gebildet, die für den Ablauf des Programms verantwortlich ist und beimBeenden des Programms als letzte eliminiert wird. Eine wichtige Aufgabedieser Applikationsinstanz ist das Durchlaufen des sog. Event Loops, der imKapitel 3.4. detailliert besprochen wird.

32

3.3.4. TDocument

Jedes Programm bearbeitet in der einen oder andern Weise Daten, z.B. Text,Tabellen, Graphiken, Bilder, etc. Um diese Daten bereitzuhalten, sie zu verwal-ten und um den Datenaustausch mit Speichermedien zu gewährleisten, ist dieKlasse TDocument vorgesehen. Wie TApplication ist auch sie direkte Subklas-se von TEvtHandler, d.h. auch sie kann auf Events reagieren; wählt der Benut-zer der Applikation im Menu z.B. den Punkt 'Open' oder 'Save', wird eineInstanz von TDocument angesprochen und zur Verarbeitung dieses Befehlsaufgefordert. Entsprechend der Tatsache, dass ein Benutzer mehrere Files ineinem Programm öffnen kann, vermag eine Applikation mehrere Dokumentezu erzeugen. Da Daten im Normalfall in einem Fenster auf dem Bildschirmdarge-stellt werden, enthält die Klasse TDocument als Instanzvariable eineListe von Windows, die verschiedene Funktionen erfüllen können.

3.3.5. TView

Eine weitere zentrale Klasse von MacApp ist TView. Alle Objekte, die inirgendeiner Weise auf dem Bildschirm erscheinen können, sind Instanzen vonSubklassen von TView. Natürlich ist auch diese Klasse eine direkte Subklassevon TEvtHandler, denn praktisch alle Objekte am Bildschirm können vomBenutzer mit Mouse-Klicks oder via Tastatur angesprochen werden. Objekteam Bildschirm sind oft hierarchisch aufgebaut und können komplex zusam-mengestellt sein – z.B. besteht ein Window aus einem Rahmen, der oben einenBalken enthält, der wiederum eine sog. Close Box und eine Zoom Box besitzenkann; dazu kommen Scroll Bars, eine Ecke, um die Grösse des Windows zuverändern und schliesslich der Inhalt, der seinerseits in verschiedene komplexeEinheiten unterteilt sein kann. Um diese und andere Strukturen zu ermögli-chen, besitzt TView eine Instanzvariable fSuperView, die für eine bestimmteView angibt, in welcher andern Instanz von TView sie liegt, sowie eine weiterefSubViews, wo alle Views aufgelistet sind, die in ihr enthalten sind. (EinBeispiel einer View-Hierarchie zeigt Abb. 12.) Ausserdem besitzt TViewInstanzvariablen wie fDocument (das Dokument, zu dem es gehört), fSize,fLocation (Grösse und Position auf dem Bildschirm), u.a.

Es gibt sehr viele verschiedene Objekte, die in einer Applikation auf dem Bild-schirm erscheinen können. Dementsprechend viele Subklassen von TViewbietet MacApp an. Eine elementare Klasse ist TWindow. Sie sorgt für dengewohnten Rahmen und den Titelbalken, die ein Window auf dem Bildschirmausmachen, sowie für die oben erwähnten kleinen Zusätze wie Close Box,Zoom Box und Scroll Bars. Es ist aber auch möglich, ein Window ohne Balkenund Zusätze zeichnen zu lassen, wodurch ein typisches Dialogfenster entsteht.Um das Aussehen, das Zeichnen und spezielle Konfiguration muss man sichals Entwickler von MacApp-Programmen nicht oder kaum kümmern, Win-dows werden automatisch in der in der Situation angebrachten Weise gezeich-net. Eine in diesem Zusammenhang ebenfalls erwähnenswerte Klasse istTScroller: Um das Scrollen von grossen Texten, Graphiken oder ähnlichem zu

33

TWindow

TScroller

TView

TSScrollBar

TSScrollBar

TControl

Abb. 12: Beispiel einer View-Hierarchie

gestatten, muss eine der Subviews des Windows eine Instanz dieser Klassesein. Sie übernimmt das Verschieben des Fensterinhalts bei der Betätigung derScroll Bars, die Justierung der letzteren wie auch die automatische Verschie-bung des Fensterinhalts, wenn der Benutzer z.B. eine Selektion über denFensterrand hinaus vornimmt.

Eine weitere Klasse, die dem Entwickler viel Arbeit abnimmt, ist TDialog-View. Sie übernimmt das Zeichnen eines Dialogs, den der Entwickler nacheigenen Bedürfnissen zusammenstellen kann, sowie die Verarbeitung vonAktionen, die der Benutzer des Programms in diesem Dialog vornehmen wird.Zu den Objekten, die in Dialogen oft erscheinen, gehören z.B. Buttons, CheckBoxes, Radio Buttons, Text- und Zahl-Eingabefelder. Für diese wie auch füreinige andere Einheiten sieht MacApp eigene Klassen vor, die alle Subklassenvon TView sind – TButton, TCheckBox, TRadio, TEditText, TNumberText.Mit wenig Aufwand kann man Instanzen dieser Klassen so konfigurieren, dasssie in Aussehen, Zusammenstellung und Funktionalität den eigenen Wünschenentsprechen. So ist es u.a. möglich, zusammengehörende Objekte in einem sog.Cluster zu gruppieren und sie in den Verarbeitungen von Eingaben aufeinan-der abzustimmen. Auch für diese Aufgabe wird von MacApp eine eigeneKlasse, TCluster, bereitgestellt. Ein fiktives Beipiel eines Dialogs mit verschie-

34

denen Objekten wie statischen Texten, Eingabefelder, Buttons, Clustern, CheckBoxes und Radio Buttons zeigt Abbildung 13.

Abb. 13: Beispiel von verschiedenen Objekten in einem Dialog-Fenster

Zu beachten ist die Hierarchie der erwähnten Klassen. Wie in Abbildung 10ersichtlich, existiert unter TView eine Subklasse TControl, die als Superklassealler Objekte dient, die unter Umständen vom Benutzer zur Interaktion mit derApplikation verwendet werden und deswegen erstens mit einer bestimmtenFunktionalität ausgestattet sein müssen und zweitens dem Benutzer direkt einevisuelle Antwort (Feedback) auf seine Aktionen liefern müssen (z.B. invertiereneines gedrückten Buttons). Dazu gehören z.B. Icons, Popup-Menus und Einga-befelder. Ebenfalls Subklasse von TControl ist die abstrakte Klasse TCtlMgr('Control Manager'), die als Superklasse jener Objekte dient, bei deren Realisie-rung MacApp direkt auf die Implementation des Macintosh-Systems zurück-greift. Diese Objekte sind Buttons (TButton), Check Boxes (TCheckBox), RadioButtons (TRadio) und Scroll Bars (TScrollBar).

Um zu zeigen, wie mächtig MacApp in Bezug auf die Unterstützung des User-Interfaces angelegt ist, werden in Tabelle 6 alle Subklassen von TView mitihren typischen Verwendungszwecken aufgelistet.

Klassen typischer VerwendungszweckTWindow normales oder DialogfensterTScroller Scrollen in einem FensterTTEView TexteditierfensterTDeskScrabView Darstellung von Text oder Graphik im ClipboardTDialogView Dialogverwaltung und -verarbeitungTGridView Tabellen-FensterTTextGridView Tabelle von TexteinträgenTTextListView Liste von Text (wie im Dialogfenster nach 'Open')

35

TControl Superklasse für Objekte mit Mouse-OperationenTCluster Gruppe von Objekten (meist mit Radio Buttons)TStaticText nicht veränderbarer TextTEditText TexteingabefeldTNumberText ZahleneingabefeldTPicture zeichnet ein PictureTPopup Popup-MenuTIcon zeichnet ein IconTCtlMgr Objekte, die MacApp direkt dem System entnimmtTScrollBar beliebig einsetzbarer ScrollbarTSScrollBar Scrollbar für das Scrollen in einem FensterTButton normaler ButtonTCheckBox Check BoxTRadio Radio Button

Tab. 6: Liste aller direkten und indirekten Subklassen von TView (Quelle: Wilson et al., '90 I)

3.3.6. TCommand

Neben den Klassen des Typs TEvtHandler existieren noch weitere. Eine davonist die Klasse TCommand. Jede Aktion eines Benutzers – das Löschen vonBuchstaben in einem Text, das Verändern von Zahlenwerten in einer Tabelle,das Verschieben von gezeichneten Objekten in einer Graphik, u.v.m. – löst ineinem MacApp-Programm die Schaffung einer Instanz einer Subklasse vonTCommand aus. Nach der Initialisierung wird ihr die Aufforderung DoIt– eine ihrer Methoden – geschickt. In dieser Methode stehen dann die genaueAnweisungen, was zu geschehen hat, damit die Aktion des Benutzers korrektumgesetzt wird. Zusätzlich besitzt diese Instanz die sehr hilfreichen MethodenUndoIt und RedoIt. Mit ihrer Hilfe ist es einfach, in einem Programm dieMöglichkeit für den Benutzer einzubauen, seine Aktionen wieder rückgängigzu machen. Alle Subklassen von TControl besitzen aber noch weitere, dieMouse betreffende Fähigkeiten: Sie können, solange der Benutzer die Mouse-Taste gedrückt hält, die Bewegungen der Mouse verfolgen und entsprechendreagieren. Wird z.B. ein Text selektiert, so wird während der Mausbewegungder selektierte Text markiert. Ein anderes Beispiel ist 'Zeichnen eines Linienseg-ments: Nach dem Drücken der Maustaste ist der Ausgangspunkt festgelegt,während der Bewegung mit der Maus wird das Segment so bewegt, dass esimmer zwischen Ausgangspunkt und der momentanen Mausposition liegt,und erst beim Loslassen der Maustaste wird es an seiner endgültigen Stellegezeichnet. Solche Fähigkeiten eines Programmes sind mit MacApp einfach zuverwirklichen, denn es sind nur in einer eigenen Subklasse von TCommand dierichtigen Methoden zu überschreiben. In der MacApp-Klassenbibliothek sindbereits einige Subklassen von TCommand vorbereitet, so z.B. verschiedeneCommands zur Editierung von Texten (TTECutCopyCommand, TTEPaste-Command, u.a.), zur Bearbeitung von Tabellen (TColumnSelectCommand,TRowSelectCommand) sowie einige weitere nützliche Commands, die anverschiedenen Stellen im Programm Verwendung finden können (TClose-WindowCommand, TPrintCommand, TSaveDocCommand, TQuitCom-mand).

36

3.3.7. TList

In vielen Anwendungen von MacApp von grossem Nutzen – insbesonderer beider Modellierung von raumbezogenen Fragestellungen – ist die Klasse TList.Auch in der MacApp-internen Organisation während des Programmablaufswird TList an einigen Stellen eingesetzt (z.B. bei der Verkettung von Instanzender Klasse TEvtHandler oder bei der Auflistung von Subviews einer bestehen-den Instanz von TView). Eine Instanz dieser Klasse besteht aus einer beliebi-gen Zahl Elemente, die Zeiger besitzen auf das vorhergehende und dasfolgende Element wie auch auf eine Instanz der Klasse TObject. Auf dieseWeise ist es möglich, eine beliebige Anzahl Objekte aneinanderzureihen.

Instanz einerSubklasse von

TObject

erstesElement

Instanz einerSubklasse von

TObject

zweitesElement

Instanz einerSubklasse von

TObject

drittesElement

Instanz einerSubklasse von

TObject

viertesElement

Instanz einerSubklasse von

TObject

fünftesElement

Abb. 14: Die Verkettung von Elementen in einer Liste des Typs TList

Der interessante Aspekt liegt aber in der Tatsache, dass erstens TObject Super-klasse aller andern Klassen ist und somit eine Instanz irgendeiner Klasse in dieListe eingefügt werden kann, und dass zweitens Objekte ja nicht nur Instanz-variablen – 'Daten' – enthalten, sondern ebenso Methoden. TList bietet dieMöglichkeit, an alle Objekte der Liste Aufforderungen zu schicken, die sie dannselbständig ausführen können. Die Elemente der Liste sind durchnummeriertund können dementsprechend durch einen Index einzeln angesprochenwerden. Es ist aber ebenfalls möglich, Objekte auf Grund einer bestimmtenBedingung herauszugreifen. Daneben sind natürlich alle für eine Listenotwendigen Operationen wie das Einfügen und Eliminieren von Elementenan einer bestimmten Stelle bereits vorbereitet.

3.4. Der Ablauf in einem MacApp-Programm

3.4.1. Das Hauptprogramm

Die folgenden Zeilen bilden ein Programm, mit dem man Fenster öffnen undschliessen kann und das die Menu-Einträge ' ', 'File' und 'Edit' bereitstellt.

37

program DoesNothing;

usesSysEqu,Traps,ULoMem,UMacAppUtilities,UPatch,UObject,UViewCoords,UMemory,UFailure,UMenuSetup,UList,UMacApp,

constkSignature = 'Nada';kFileType = 'Nada';

vargApplication: TApplication;

beginInitToolBox;InitUMacApp(8);New(gApplication);FailNIL(gApplication);gApplication.IApplication(kFileType);gApplication.Run;

end.

Im ersten Moment mag dieser Programmcode kompliziert wie jeder andereProgrammcode auch erscheinen. Bei näherer Betrachtung erkennt man, dasshier einfache Schritte unternommen worden sind, um die Klassen von MacAppins Leben zu rufen und sie den Ablauf dieses Programmes übernehmen zulassen. Die erste Zeile program DoesNothing markiert nur den Beginn sowieden Titel des Programmes. Die uses-Anweisung gibt an, wo das Programm dieMacApp-Klassen finden kann, die es brauchen wird. Die Anweisung constdefiniert zwei Konstanten, die bei der Initialisierung des Programmes notwen-dig sein werden und die beim Abspeichern eventueller Dateien eine Rollespielen würden. (Anstelle von 'Nada' könnte auch etwas Sinnvolles stehen.) Diezwei Anweisungen uses und const sind also in diesem Zusammenhanguninteressant. Als nächstes folgt die Deklaration der einzigen Variablen desProgramms, gApplication, vom Typ TApplication. Diese Variable wird dieApplikation, die offensichtlich auch als Objektinstanz verstanden wird, aufneh-men. (Das g als erster Buchstabe der Variable markiert diese als global, d.h. siekann an jeder Stelle im Programm verwendet werden.) Danach folgt zwischenbegin und end das eigentliche Programm. Die ersten zwei Zeilen sind Initiali-sierungen der vom System bereitgestellten Toolbox sowie von MacApp selber.Diese Initialisierungen müssen vorgenommen werden, um für das Programmeinen Grundzustand herzustellen, von dem aus es starten kann.

Schliesslich folgen die vier interessantesten Zeilen des Programms. Als ersteswird eine Instanz der Klasse TApplication ins Leben gerufen (New) und in derVariable gApplication abgelegt. Mit FailNIL wird überprüft, ob die Schaffungder neuen Instanz erfolgreich war. Danach wird die neue Instanz mit ihrereigenen Methode initialisiert (wobei eine der oben erwähnten Konstanten alsParameter übergeben wird) und endlich ihre Methode Run aufgerufen. Vondiesem Moment an übernimmt alles weitere MacApp. (Dies bedeutet, dass je

38

eine uses-, const- und var-Anweisung sowie 6 Programmstatements genügen,um ein Programm zu erzeugen, das Fenster verwaltet, das Anwählen vonMenupunkten erlaubt und sich sauber wieder beenden lässt.)

3.4.2. Die Applikation, Event Loop

Was geschieht nun beim Aufruf der Methoden von gApplication ?• Die Initialisierungsmethode IApplication übernimmt die Initialisierung der

Instanzvariablen von gApplication, die Initialisierung vieler MacApp-eigener, dem Entwickler mehr oder weniger verborgener globaler Variablen sowie die Installation des Menubalkens.

• Die Methode Run enthält im wesentlichen den sog. Event Loop: Wie erwähnt sind die Applikation, von ihr verwaltete Dokumente sowie alle sichtbaren Elemente auf dem Bildschirm Instanzen von Subklassen von TEvtHandler, d.h. sie sind alle imstande, Events zu verarbeiten bzw. auf Aktionen des Benutzers der Applikation zu reagieren. Alle diese Event Handler sind in einer Liste zusammengehängt, die von gApplication verwaltet wird. Dieser Event Loop ist nun eine Schleife, die bei jedem Durchgang testet, ob vom Betriebssystem ein Event, also z.B. ein Mouse-Klick oder das Drücken einer Taste gemeldet wird. Ist dies der Fall, wird jedes Element der Liste überprüft, ob es den Event verarbeiten kann. Wenn nicht, wird das nächste Element getestet, und dieser Vorgang wiederholt sich so lange, bis entweder ein Element gefunden ist, das den Event verarbeitet, oder bis die ganze Liste abgearbeitet wurde.

TApplication: Event Loop

ist ein Event aufgetreten ?

ja: was ? wo ? durchsuche Event Handler-Liste wenn gefunden: führe entsprechenden Befehl aus

nein: tu nichts

zurück

Untitled

Mouse-KlickWindow-Balken

Instanz vonTApplication

Instanz vonTDocument

Instanz vonTWindow

nichtzuständig

nichtzuständig

gefunden:kann Eventverarbeiten

Abb. 15: Beispiel der Verarbeitung eines Events in einem Event Loop

39

Wird als Beispiel die Mouse im Window-Balken gedrückt (man möchte viel-leicht das Fenster verschieben), so wird zuerst vom System ein Mouse-Klick mitdessen Bildschirmkoordinaten gemeldet. Die Applikation testet nun dieElemente der Liste auf deren Fähigkeit, diesen Event zu verarbeiten: als erstesElement wird die Applikation selbst getestet, diese kann einen Mouse-Klickallerdings nicht verwerten. Dasselbe gilt für das nächste Element, ein eventuellvorhandenes Dokument. Schliesslich wird der Test für das Fenster durchge-führt und es wird auf Grund der Koordinaten festgestellt, dass der Mouse-Klick den Window-Balken getroffen hat. Nun kann das Fenster diesen Eventübernehmen und die Aktion des Benutzers ausführen.

3.4.3. Subklassen von TApplication, TDocument und TView

Das Programm, wie es oben aufgelistet ist, läuft zwar und ist für viele Artender Gestaltung und Funktionalität ausgerüstet, der Benutzer kann damit abernur Fenster öffnen und schliessen, die Menus ansehen und die Applikationbeenden. Um eine sinnvolle Aufgabe mit einem MacApp-Programm erfüllenzu können, müssen von verschiedenen bestehenden Klassen Subklassen erstelltwerden, wo dann bestimmte Methoden überschrieben werden.

Die erste Klasse, die eine Subklasse erhält, ist TApplication, denn es soll janicht eine oben beschriebene Default-Applikation entstehen, sondern eineeigene mit einem vorbestimmten Zweck. Für diese Subklasse – z.B. TYour-Application – wird zuerst eine eigene Initialisierungsmethode erstellt – IYour-Application –, und als zweites die Methode DoMakeDocument überschrieben.Diese Methode wird automatisch bei der Initialisierung der Applikation aufge-rufen und erstellt im nicht überschriebenen Zustand eine Instanz der KlasseTDocument. Diese Dokument-Instanz ist dafür ausgerüstet, Daten zu verwal-ten, diese von einem File auf einem Speichermedium einzulesen oder sie aufein solches hinauszuschreiben. Allerdings ist es wiederum nötig, von TDocu-ment eine Subklasse zu erzeugen, wo man einige Methoden überschreiben undsie so mit einer bestimmten Funktionalität versehen muss. Damit von derApplikation nicht eine Instanz der Klasse TDocument, sondern von dereigenen, mit den gewünschten Fähigkeiten ausgerüstete Subklasse – z.B.TYourDocument – kreiert wird, wird die Methode DoMakeDocument in derSubklasse von TApplication, TYourApplication, entsprechend überschrieben.

Meist fügt man der neuen Subklasse von TDocument neue Instanzvariablenhinzu, die die sog. Daten enthalten werden. Dies kann ein Text oder eineZahlentabelle sein, dies könnten aber auch z.B. die Objekte des Quellen-Fluss-Einzugsgebiet-Beispiels von Kapitel 2.3. sein. Zu den Methoden, die in der Sub-klasse von TDocument überschrieben werden, gehören unter anderen solche,die für das Lesen und Schreiben dieser Daten zuständig sind, aber auchDoMakeViews, die automatisch bei der Initialisierung der Dokument-Instanzaufgerufen wird und das Zeichnen von Fenstern erledigt. Wird diese Methodenicht überschrieben, zeichnet sie ein einfaches Fenster mit dem Titel 'Untitled'.Man kann aber auch sehr komplexe View-Kompositionen zusammenstellen,wobei jede Einheit dieses Fensters im Programm durch eine eigene Objekt-

40

Instanz repräsentiert wird. Fenster sind im Dokument nicht in eigenen Instanz-variablen, sondern in einer Liste abgelegt, was es ermöglicht, für jedes Doku-ment mehrere Fenster unterschiedlicher Komplexität gleichzeitig offen zuhalten.

Fenster erfüllen ihrerseits wieder verschiedene Aufgaben: sie können zur Text-editierung, zur Tabellenkalkulation oder zum Zeichnen von Graphik gebrauchtwerden. Je nach Verwendung müssen sie auf Events verschieden reagieren. Zudiesem Zweck müssen wieder spezielle Methoden überschrieben werden,wozu von TView eine Subklasse gebildet wird – z.B. TYourView. Es ist zubeachten, dass nicht das Fenster an sich, d.h. eine Instanz von TWindow dieVerarbeitung von Benutzer-Aktionen im Fensterinhalt übernimmt, sonderneine Instanz von TView. Der Inhalt eines Fensters ist nicht Teil der Instanz vonTWindow, sondern eine Subview davon. Diese Subview aber ist eine Instanzvon TView, weshalb diese Klasse eine neue Subklasse erhalten muss. Über-schrieben wird die Methode Draw, die immer dann aufgerufen wird, wenn dasFenster ganz oder teilweise neu gezeichnet werden muss. Oft greift dieseMethode auf die Daten des zugehörigen Dokuments zu, denn meist sind esdiese, die auf die eine oder andere Weise im Fenster dargestellt werden sollen.

3.4.4. Menu-, Mouse- und Tastaturbefehle, Commands

Eine Aufgabe, die alle im Programmablauf bis jetzt vorkommenden Objekteerfüllen, ist die Aktualisierung des Menubalkens sowie die Verarbeitung vonMenubefehlen. Als Subklassen von TEvtHandler besitzen alle entsprechendenKlassen die Methoden DoSetupMenus und DoMenuCommand. Klickt derBenutzer einer Applikation in den Menubalken, wird als erstes für jedesElement in der bereits besprochenen Event Handler-Liste DoSetupMenusaufgerufen. Damit erhalten alle Event Handler-Objekte die Gelegenheit, eigeneMenupunkte zu aktualisieren, d.h. sie unter dem entsprechenden Menupunkterscheinen zu lassen und sie jeweils entweder zu aktivieren oder zu deaktivie-ren. Solche objekteigenen Menupunkte sind z.B. 'Save' und 'Open' für dasDokument, verschiedene Schreib-, Zeichen- wie auch 'Copy'- und 'Paste'-Befehle für die Views sowie 'Quit' für die Applikation selber. Wird schliesslichein Menupunkt vom Benutzer angewählt, gelangt dieser Befehl via Event Loopund Event Handler-Liste zum richtigen Objekt. Für diese Instanz wird dieMethode DoMenuCommand aufgerufen, wo für jeden Menupunkt, den dieseInstanz verwaltet, die entsprechende Verarbeitung implementiert ist.

Neben DoMenuCommand besitzen Event Handler auch die MethodenDoMouseCommand und DoKeyCommand, um auf Mouse-Aktionen bzw.Tastatur-Eingabe reagieren zu können. Der Vorgang ist derselbe wie bei Menu-befehlen: Der Event gelangt über den Event Loop und die Event Handler-Listezum Objekt, das sich um den Befehl kümmern kann. Für diese Instanz wirdschliesslich je nach Benutzeraktion die Methode DoMouseCommand oderDoKeyCommand aufgerufen. Es gibt nun verschiedene Möglichkeiten, dieVerarbeitung des Events zu implementieren. Verlangt die Ausführung desBefehls nur wenige Schritte, so kann die Implementation innerhalb der

41

genannten Methoden erfolgen. Sind die auszuführenden Schritte aber komplexund soll sogar das Rückgängigmachen des Befehls ermöglicht werden, dannerfolgt die Implementation in sog. Commands. Um eine bestimmte Aktionauszuführen, wird von der für diesen Zweck vorgesehenen Klasse TCommandeine Subklasse erzeugt – z.B. TYourCommand. Die Methode DoIt dieser Klassewird überschrieben, d.h. in ihr wird die Ausführung des Befehls implementiert.Dasselbe geschieht mit den Methoden UndoIt zur Rückgängigmachung undRedoIt zur Wiederholung des Befehls. Wird der Command für einen Mouse-Befehl entworfen, besteht die Möglichkeit, zusätzliche Methoden zu über-schreiben. Es handelt sich dabei um Methoden, die ununterbrochen aufgerufenwerden, solange der Benutzer die Mouse-Taste gedrückt hält. Durch die Über-schreibung dieser Methoden können visuelle Rückmeldungen implementiertwerden, wie sie in Textverarbeitungs- oder graphischen Programmen üblichsind (z.B. die Selektion von Text oder die Veränderung der Lage einer Liniewährend ihres Zeichnens).

Die Erstellung und Initialisierung einer Instanz der Subklasse von TCommandmuss vom Entwickler in die entsprechende Methode DoMenuCommand,DoMouseCommand bzw. DoKeyCommand eingebaut werden, die MethodeDoIt wird danach automatisch aufgerufen. Wählt der Benutzer danach denMenubefehl 'Undo' bzw. 'Redo', so werden auch UndoIt bzw. RedoIt vonMacApp selbständig ausgeführt.

42

4. Punkt-Linien-Polygon-Klassenbibliothek

4.1. Warum eine objekt-orientierte Klassenbibliothek

Die bereits besprochenen Vorteile bei der Benutzung von Klassenbibliothekenwerden bei der Arbeit mit raumbezogenen Objekten besonders deutlich. DieImplementation der immer wieder auftretenden Objekte Punkt, Linie undPolygon ist zwar nicht ausgesprochen schwierig, die elementaren Schritte sindjedoch oft ähnlich oder gleich, die Ausarbeitung ist zeitaufwendig und fehler-anfällig, und jede implementierte Klasse müsste wieder getestet werden. Einenzusätzlichen Vorteil bietet die Einbettung einer Klassenbibliothek in ein Appli-cation Framework. Bei der Entwicklung der raumbezogenen Klassen kanneinerseits auf das bereits implementierte Framework zurückgegriffen werden(so können z.B. bestehende Klassen oder andere Datenstrukturen genutztwerden), andererseits erscheint für den Entwickler dieses erweiterte Applica-tion Framework als Einheit, in welcher die raumbezogenen auf die andernKlassen abgestimmt sind und wie diese subklassiert und in das eigene Projekteingebaut werden können.

4.2. Einzubeziehende Klassen

Am Anfang des Entwurfs der Klassenbibliothek für raumbezogene Objektesteht die Frage, welche Klassen diese Bibliothek enthalten soll. Klarheit bestehtüber die elementaren Objekte Punkte, Linien und Polygone, die man zusam-menfassend geometrische Primitiven nennen könnte. Diese Objekte sollen inder Bibliothek in verschiedenen Varianten angeboten werden. VerschiedeneAnwendungen stellen oft unterschiedliche Ansprüche an die verwendeteKlasse. Einerseits soll sie Fähigkeiten besitzen oder Erweiterungen anbieten, diedem Entwickler elegante Lösungen seines Problems ermöglichen, andererseitssoll sich die verwendete Klasse effizient, d.h. zeit- und arbeitsspeichersparendverhalten. In einer statischen Anwendung mit sehr vielen Daten, bei der diesenur als Arbeitsgrundlage dienen und nicht oder kaum verändert werden,finden andere Datenstrukturen und Algorithmen Verwendung als bei einerdynamischen, interaktiven Bearbeitung mit vergleichsweise wenigen Daten.Dementsprechend soll die Klassenbibliothek eine relativ breite Grundlagebieten, aus der der Entwickler die geeignetste Variante auswählen kann.

Geometrische Primitiven sind nicht die einzigen Objekte, die bei der Betrach-tung eines raumbezogenen Problems eine Rolle spielen. In vielen Fällen sindorganisatorische Einheiten ebenso von Bedeutung. Zu diesen Ordnungs- undZuordnungsobjekten gehören u.a. die sog. Layer. Unter ihnen werden Daten-ebenen verstanden, die Objekte gleicher thematischer Zugehörigkeit beinhaltenund diese so von anderen unterscheiden. (In ArcInfo z.B. werden entsprechen-de Einheiten 'Coverages' genannt.) Layer sind also dazu da, die Daten zu

43

organisieren, ihre Konsistenz zu gewährleisten und für den Benutzer Überblickzu verschaffen. Oft werden diese Ebenen dazu gebraucht, um an den zuge-hörigen Objekten Operationen auszuführen, die mehrere thematische Bereichemiteinbeziehen. Ausserdem übernehmen Layer die Kommunikation mit denSpeichermedien, d.h. sie sind für das Lesen und Schreiben der Daten auf einFile verantwortlich.

Eine Aufgabe von Layern ist die Verwaltung der geometrischen Primitiven. Siemüssen diese Objekte also in irgendeiner Form beinhalten; dies wird weiterunten genauer besprochen. Es stellt sich aber die Frage, ob ein Layer nurObjekte eines Typs (z.B. nur Punkte) aufnehmen soll, oder ob er fähig sein soll,Objekte verschiedener Art zu verwalten. Wie das Beispiel des Gewässer-Systems zeigt, muss davon ausgegangen werden, dass in einer Datenebenemehr als ein Objekttyp auftreten kann. Bei der Implementierung eines solchenFalles ist das polymorphe Verhalten von Objekten sehr hilfreich. Allerdingswird es genauso oft der Fall sein, dass der Layer nur Objekte einer Klasseaufnehmen muss. Es ist dann nicht mehr nötig, auf die allgemeine Verwend-barkeit des Layers zu achten. Vielmehr ist es dann von Vorteil, diesen fürseinen konkreten Einsatz zurechtzuformen, womit einerseits der Implemen-tationsaufwand geringer wird und andererseits die Effizienz der Applikationgesteigert werden kann. Dementsprechend soll die Klassenbibliothek nicht nureine allgemeine Form eines Layers, sondern auch für Punkte, Linien und Poly-gone spezialisierte Subklassen der Klasse 'Layer' anbieten.

Eine weitere hilfreiche Fähigkeit, die die Klassenbibliothek beinhalten soll, istdie Möglichkeit, Objekte auf Grund von thematischen oder räumlichen Eigen-schaften – unabhängig ihrer Ebenenzugehörigkeit – in Gruppen zusammenzu-fassen. Die dazu dienenden Objekte sind sog. Cluster. Sie werden häufig fürden Benutzer mehr oder weniger unsichtbar in den Algorithmen als Hilfs-datenstrukturen verwendet, um Probleme zu lösen, die z.B. von der Art 'Findeein Objekt, das bestimmte Eigenschaften besitzt und in der Nähe eines andernliegt' sind. Solche Cluster können aber auch explizit in eine Applikation soeingebaut werden, dass für den Benutzer die Möglichkeit besteht, diese alsOrganisationseinheit in seinen Projekten zu verwenden. So können z.B.Objekte, die auf Grund irgendeines Kriteriums zusammengehören (eineGruppe freistehender Bäume, landwirtschaftlich genutzte Parzellen an einembestimmten See, oder auch die zu einem Teilnetz eines Gewässersystems gehö-renden Flüsse und Bäche) zeitweise oder permanent als Einheit betrachtetwerden, ohne auf die Layerstruktur Rücksicht nehmen zu müssen.

Um einzelne Objekte auf ihre Zugehörigkeit zu einem Cluster zu testen, ist einKriterium notwendig. Oft gilt als Entscheidungsgrundlage die Entfernungeines Objekts zu anderen Objekten, für die bereits bekannt ist, ob sie zumCluster gehören oder nicht; häufig bestimmen also Distanzmasse die Objektedes Clusters. Da einerseits nicht nur die Distanz zwischen Objekten gleichen,sondern ebenso unterschiedlichen Typs bestimmt werden kann und anderer-seits diese Distanzen auf verschiedene Arten definiert und berechnet werdenkönnen, existiert keine allgemein verwendbare Implementation dieses Kriteri-ums. Dies gilt auch für alle andern Varianten der Zugehörigkeitsüberprüfung:Da nicht vorausgesehen werden kann, welche Attribute die Objekte für eine

44

konkrete Fragestellung besitzen werden, kann auch kein allgemeingültiger,sich auf diese Attribute beziehender Cluster-Test vorbereitet werden.

Oft wird die Zugehörigkeit von Objekten zu einem Cluster im Laufe derProjektbearbeitung verändert, was von der Datenstruktur, die die Objekte demCluster zuweist, verlangt, dass Elemente schnell und einfach zugefügt undentfernt werden können. Aus diesem Grund drängt sich als Datenstruktur eineListe auf, da diese das geforderte dynamische Verhalten besitzt. In andernAnwendungen, in denen viele Objekte permanent bestimmten Clustern zuge-hören, eignet sich ein Array besser. Von welcher Klasse die Objekte stammen,die durch die gewählte Datenstruktur verwaltet werden, hängt von derkonkreten Problemstellung ab. Wenn Objekte verschiedener Klassen in Fragekommen, wird die im Hierarchiebaum allen Klassen gemeinsame tiefst-mögliche Superklasse gewählt, wodurch das polymorphe Verhalten derObjekte genutzt werden kann.

4.3. Einbettung in MacApp

Die Einbettung der neuen Klassen in MacApp besteht in erster Linie aus derEinfügung dieser Klassen in die bestehende MacApp-Klassenhierarchie. Essind verschiedene Stellen in diesem Hierarchiebaum denkbar, an denen dieraumbezogenen Klassen plaziert werden können. Es ist ausserdem nicht vonvornherein bestimmt, dass alle Klassen der gemeinsamen Superklasse unmittel-bar untergeordnet werden müssen. Sicher sind aber alle Klassen, wie auch alleKlassen von MacApp, Subklassen der allgemeinen Superklasse TObject.

Als erstes stellt sich die Frage, ob sich zu den verschiedenen raumbezogenenKlassen eine gemeinsame Superklasse finden lässt. Dies würde einerseits dieEinbettung dieser Klassen vereinfachen – nach dem Einfügen dieser gemein-samen Superklasse wären alle andern Klassen ebenfalls in MacApp enthalten –,andererseits wären die neuen Klassen nicht über den Hierarchiebaum verteilt,sondern unter dieser Superklasse konzentriert, was zur übersichtlichen Gestal-tung der Klassenbibliothek beitragen würde. Die Schaffung einer solchenSuperklasse würde allderdings voraussetzen, dass die raumbezogenen Klassengemeinsame Instanzvariablen oder Methoden besitzen. Da die neuen Klassensehr unterschiedliche Aufgaben erfüllen sollen und deshalb unterschiedlichkonzipiert werden, ist dies leider nicht der Fall. Die Klassen müssen in dreiGruppen unterteilt werden, die dann jeweils mit einer eigenen Superklasse imHierarchiebaum untergebracht werden.

45

4.3.1. Einbettung der geometrischen Primitiven

Die erste der drei genannten Gruppen (geometrische Primitiven, Layer undCluster) wird gebildet durch die geometrischen Primitiven, d.h. durch diePunkt-, Linien- und Polygon-Klassen. Ihnen gemeinsam sind Eigenschaften wiez.B. ihre Farbe, die Anzahl Punkte, aus denen sie bestehen, ihr umschreibendesRechteck, u.a. (Die zwei letztgenannten Eigenschaften sind für Punktklassendann sinnvoll, wenn man nicht einzelne Punkte, sondern Punktebenen alsObjekte betrachtet.) Dazu kommen Methoden wie z.B. das Zeichnen, Selektie-ren u.a., die zwar für die einzelnen Klassen unterschiedlich implementiert sind,die aber polymorphisch eingesetzt werden können sollen. Es ist also möglichund sehr hilfreich, zu diesen geometrischen Primitiven eine gemeinsameSuperklasse zu definieren. Diese enthält die genannten Instanzvariablen undMethoden und wird in der Bibliothek TGeomPrimitive heissen.

Für das Einfügen der geometrischen Primitiven in die Klassenbibliothek vonMacApp bieten sich im wesentlichen drei Standorte an. Die erste Möglichkeitbesteht darin, dass diese Klassen in der obersten Stufe der Hierarchie eingesetztwerden. Die Klasse TGeomPrimitive ist dann direkte Subklasse von TObject.Diese ist die einfachste Variante, die auch für den Benutzer der Bibliothek leichtnachzuvollziehen ist und ihm erlaubt, die neuen Klassen ohne Aufwand inseiner eigenen Entwicklung einzusetzen.

Eine weitere Variante eröffnet sich dadurch, dass die Objekte, die am Bild-schirm dargestellt werden, meistens in irgendeiner Art vom Benutzer derApplikation manipuliert werden. Die Kommunikation des Benutzers mit denBestandteilen der Applikation, zu denen auch die raumbezogenen Objektegehören, erfolgt bekanntlich via Maus oder Tastatur, was wiederum überEvents verarbeitet wird. Da die am Bildschirm dargestellten geometrischenPrimitiven auf Aktionen des Benutzers reagieren können sollen, liegt es nahe,sie auf irgendeine Weise in die Event Handler-Liste einzufügen. Dort würdensie wie alle andern Elemente dieser Liste auch – Fenster, Buttons, Menubalken,etc. – beim Auftreten eines Events auf ihre Fähigkeit überprüft, diesen zu verar-beiten, worauf sie mit einer entsprechenden Reaktion antworten könnten. Umdies zu ermöglichen, müssen die geometrischen Primitiven als Subklassen vonTEvtHandler implementiert werden, denn so erben sie die für Event Handlernotwendige Methoden und Eigenschaften.

Da es sich bei den geometrischen Primitiven um auf dem Bildschirm darstell-bare Objekte handelt, könnte man sich ebenso vorstellen, dass sie als Subklas-sen von TView in die Bibliothek eingefügt werden. Da TView Subklasse vonTEvtHandler ist, wären die geometrischen Primitiven auch in diesem FallEvent Handler. Zusätzlich könnten sie so in eine hierarchische View-Struktureingebaut werden und würden dementsprechend von MacApp verwaltet.

Bei genauerer Betrachtung zeigt sich allerdings, dass die letzte Variante für dieImplementation der raumbezogenen Klassen nicht geeignet ist: Instanzen vonSubklassen von TView sind immer in irgendeiner Weise rechteckig, was fürraumbezogene Objekte nur dann der Fall ist, wenn man ihren umschreibendenRechtecken als äussere Grenze grösseres Gewicht beimisst. Die Instanz von

46

TView, in der die raumbezogenen Objekte gezeichnet werden, würde ausser-dem eine Liste von Subviews enthalten, die soviele Elemente hätte, wie dasbearbeitete Projekt Objekte besitzt. Da praktisch immer mit der Grössenord-nung von hunderten, in verschiedenen Fällen aber auch mit zehntausenden,hundertausenden oder mehr Objekten gerechnet werden muss, führt dieseVariante oft zu unangenehmen Ineffizienzen. Schliesslich zeigt sich, dass esebenfalls nicht notwendig ist, die geometrischen Primitiven als Subklassen vonTEvtHandler einzufügen. Möchte der Benutzer der Applikation eine Aktionauf ein raumbezogenes Objekt ausüben, so wird diese Aktion – da ja dieObjekte in einer Instanz von TView liegen – diese View-Instanz ebenfallsbetreffen. Statt die Zuweisung der Aktion zum betreffenden Objekt dem EventLoop zu überlassen, ist es v.a. bei Projekten mit zahlreichen Objekten effizien-ter, diese Aktion von der View-Instanz bearbeiten d.h. im Event Loop abfangenzu lassen und danach die Zuweisung dieser Aktion zum entsprechenden raum-bezogenen Objekt einer selbst implementierten Methode der View-Instanz zuübergeben. Dort muss dann nicht jedes Objekt auf seine Zuständigkeit für dieBearbeitung der User-Aktion getestet werden, wie es im Event Loop der Fallwäre, sondern es könnten eigene, bedeutend schnellere Algorithmen eingesetztwerden, die auf die thematischen und räumlichen Eigenschaften der ObjekteRücksicht nehmen.

4.3.2. Layer und Cluster in MacApp

Beim Versuch, die Klasse 'Layer' in die MacApp-Bibliothek einzufügen, stelltman fest, dass die Aufgaben, die die Objekte dieser Klasse erfüllen, zum Teilmit denen übereinstimmen, für die die MacApp-Klasse TDocument vorgese-hen sind. Zu diesen Aufgaben gehören u.a. das Verwalten der raumbezogenenDaten, das Aufrechterhalten ihrer Konsistenz und das Lesen und Schreiben aufden Speichermedien. Layer werden aus diesem Grund als Subklassen vonTDocument in der Klassenbibliothek aufgenommen. Bei der konkreten Imple-mentation treten aber einige Fragen auf. Das erste, bereits erwähnte Problembesteht darin, dass oft verschiedene Objekte – Punkte Linien und Polygone –gleichzeitig im gleichen Layer bearbeitet werden, dass es in andern Fällen abervon Vorteil sein kann, wenn sich die Fähigkeiten eines Layers auf einen Objekt-typ konzentrieren. Daraus folgt, dass allgemein verwendbare wie auch aufeinen Objekttyp spezialisierte Layer in der Klassenbibliothek vorhanden seinsollten. Das zweite Problem stellt sich bei der Wahl der Datenstruktur, die zurVerwaltung der raumbezogenen Daten verwendet werden soll. Wie in andernBeispielen wird auch hier die Charakteristik der konkreten Anwendung denAusschlag geben. (Bei statischen Projekten mit grossen Datenmengen werdendie Objekte in Arrays verwaltet; wird mit vielen Veränderungen der raumbezo-genen Daten gerechnet, werden Listen eingesetzt.) Schliesslich stellt sich nochdie Frage, was die Klasse 'Layer' ausser der Datenstruktur zur Datenhaltungnoch an Instanzvariablen und Methoden besitzen soll, die nicht schon inTDocument enthalten sind. Die Antwort kann nur das konkrete Projekt geben,in dessen Zusammenhang die Klasse eingesetzt werden soll. Erst dort wird sichentscheiden, welcher Art die raumbezogenen Objekte sind, welche Datenstruk-tur zu deren Verwaltung gewählt wird, was für Konsistenzbedingungen und

47

auf welche Weise diese erfüllt werden müssen, was für Operationen möglichsein sollen und wie das Lesen und Schreiben der Daten auf Files geschehensoll. Da die Klasse TDocument bereits einige hilfreiche Methoden und Instanz-variablen für diese Aufgaben vorsieht und dem Entwickler kaum Spezialisie-rungsarbeit im voraus abgenommen werden kann, wird auf die Implementie-rung spezieller Layer-Klassen verzichtet. Stattdessen wird auf die Verwendungvon Subklassen von TDocument verwiesen, deren Spezialisierung für daskonkrete Projekt vom Entwickler selber vorgenommen werden muss.

Dieselben Probleme wie beim Versuch, Layer-Klassen zu implementieren,treten beim Einfügen von Klassen des Typs 'Cluster' in die MacApp-Bibliothekauf. Wieder kann nicht im vornherein bestimmt werden, welche Datenstrukturfür den konkreten Fall die geeignetste ist, was für Objekte zu erwarten sind,welche Kriterien für die Zugehörigkeit von Objekten zu einem Clusterausschlaggebend sind und was für Eigenschaften und Fähigkeiten ein Clustersonst noch besitzen soll. Allerdings kann wieder auf eine bereits in MacAppexistierende Klasse verwiesen werden: Instanzen von TList besitzen Eigen-schaften zur flexiblen Verwaltung von Objekten irgendwelcher Klassen(solange sie Subklassen von TObjekt sind) und erlaubt ausserdem denpolymorphen Gebrauch von Methoden der in der Liste enthaltenen Instanzen.Der Entwickler kann für seine konkrete Anwendung eine Subklasse von TListbilden und diese den Ansprüchen seines Projekts anpassen.

48

4.4. Implementation

TChainArray

TPointLayer TLine

TGeom-Primitive

TBasicPoint-Array

TGeom-Object

TStaticPolyTArrayLine

TListLine

TArcLine TArcPoly

THybridLine

TSquareNet

TPointLayer-ForSquares

TConnected-Arcs

Abb. 16: Die Hierarchie der raumbezogenen Klassen

Abbildung 16 zeigt alle in der Klassenbibliothek implementierten Klassensowie ihre Position innerhalb der Hierarchie. Sie soll beim Lesen der folgendenKapitel als Orientierungshilfe und Referenz dienen. Ausserdem sind imAnhang A die Programmcodes von Deklarationen einiger ausgewählterKlassen aufgelistet.

4.4.1. Die abstrakten Klassen

Die oberste Klasse in der Klassenhierarchie ist TGeomObject. Sie enthält allge-meine Instanzvariablen wie das umliegende Rechteck, das Fenster, in dem diejeweilige Instanz der Klasse liegt, fVisible, die angibt, ob das Objekt sichtbar istund fNumberOfPoints, die die Anzahl Punkte enthält, aus denen das geome-trische Objekt besteht. Ausserdem sind in ihr die Interfaces einiger Methoden

49

definiert, die alle andern Klassen ebenfalls benötigen (z.B. MakeBoundaryBox,Draw, Remove, Move, etc.). Diese Klasse dient einerseits dazu, die genanntenInstanzvariablen zu deklarieren, was auf diese Weise nur einmal und nicht injeder Subklasse einzeln zu geschehen hat, andererseits werden die raumbezo-genen Klassen so an einer Stelle in der Hierarchie von MacApp konzentriert,was sehr zur Übersichtlichkeit der Klassenbibliothek beiträgt.

Die Klassen unterhalb von TGeomObject kann man auf Grund ihrer Funktionin zwei Gruppen teilen: einerseits folgt die Klasse TGeomPrimitive, die alsSuperklasse für Punkt-, Linien- und Polygonobjekte dient, andererseits stehenKlassen direkt unterhalb von TGeomObject, die keine eigentlichen geometri-schen Objekte darstellen, sondern dazu dienen, die geometrischen Daten zustrukturieren und zu organisieren. TGeomPrimitive besitzt die Instanzvari-ablen fColor und fSelected, denn alle geometrischen Primitiven werden inirgendeiner Farbe gezeichnet und können durch den Benutzer selektiertwerden. Dazu gehören auch Methoden, die den Wert dieser Variablen abfragenund verändern.

Unterhalb von TGeomPrimitive besteht für alle Linien- und Polygonklassendie abstrakte Klasse TLine. In ihr werden die Variablen fVertexSize, fVertex-Visible, fNodeSize und fNodesVisible eingeführt sowie Methoden definiert,die diese Variablen manipulieren. Es besteht also die Möglichkeit, alle Linienund Polygone mit oder ohne End- und Zwischenpunkte zu zeichnen sowiediese Punkte in ihrer Grösse zu verändern. Alle Subklassen von TLine habennoch weitere linienspezifische Methoden gemeinsam, z.B. DrawPoint, Insert-Point, MovePoint, etc., es liegt also nahe, diese ebenfalls in dieser abstraktenKlasse vorzudefinieren. Diese Methoden brauchen aber als Parameter einenVerweis auf den Punkt, für den die Operation ausgeführt werden soll. Da diePunkte in allen Linienklassen anders verwaltet und deshalb unterschiedlichangesprochen werden, sind auch diese Parameter für jede Klasse von einemanderen Datentyp (für TArrayLine wird der Punkt z.B. durch eine Integer-Variable dargestellt, für TListLine durch einen Pointer). Aus diesem Grundkönnen diese Methoden nicht schon in der Klasse TList deklariert und späterpolymorphisch verwendet werden.

Die Andordnung der Klassen im hierarchischen Baum widerspiegelt nicht ihreeigentliche Zusammengehörigkeit. Einige Varianten der Implementationgeometrischer Daten bestehen aus mehreren Klassen. Die einzelnen Implemen-tationen werden im Folgenden als Gruppen zusammengehöriger Klassenbeschrieben.

50

4.4.2. Punktlayer

Für die Verarbeitung von in grosser Zahl auftretenden Punkten in einer zuge-hörigen Punktebene sind zwei Varianten implementiert. Die eigentliche Klassezur Darstellung von Punktlayern ist TPointLayer. In ihr werden die Punkte ineinem Array von x/y-Paaren abgelegt, wobei die Koordinaten als LongIntdeklariert sind. Dazu kommen z.B. die Instanzvariable fPointSize sowieMethoden, die das Zeichnen des Punktlayers oder einzelner Punkte, dasVerschieben von Punkten, u.s.w. ermöglichen.

x/y x/y x/y x/y x/y x/y x/y x/y x/y x/y x/y

1 2 3 4 5 6 7 8 9 10 11 12 13 14

Abb. 17: Das Konzept von TPointLayer

Es muss davon ausgegangen werden, dass die Fragestellung, für die dieseKlasse eingesetzt wird, sehr viele Punkte enthalten kann. Dies führt dazu, dassAlgorithmen wie z.B. Suchvorgänge sehr zeitaufwendig werden; sucht manz.B. Punkte nach ihren x-/y-Koordinaten, so müssen alle Punkte des Layerseinzeln überprüft werden. In solchen Fällen ist es oft hilfreich, wenn demPunktlayer eine weitere, den Raum gleichmässig unterteilende Ebene unterlegtist. Da sich als solche Organisationsstruktur ein quadratisches Gitternetz meistam besten eignet, ist in der Klassenbibliothek eine solche Gitterebene vorberei-tet. Diese Klasse TSquareNet enthält Instanzvariablen, die die Seitenlänge derGitterzellen sowie ihre Anzahl in vertikaler und horizontaler Richtung festhal-ten. Ausserdem besitzt sie für jede Gitterzelle eine Liste aller Punkte des Punkt-layers, die in der entsprechenden Zelle liegen. Das Suchen eines Punktes auf

51

Grund seiner Koordinaten macht nun nicht mehr das Überprüfen jedes einzel-nen Punktes notwendig; es wird vielmehr aus den Koordinaten des gesuchtenPunktes die entsprechende Gitterzelle berechnet, worauf nur noch die Punktegetestet werden, die in der Liste dieser Zelle vorkommen. Es bleibt dem Ent-wickler einer Applikation überlassen, die optimale, durchschnittliche AnzahlPunkte pro Zelle zu bestimmen, die wiederum die Seitenlänge bzw. AnzahlZellen in horizontaler und vertikaler Richtung festlegt.

1

2

34

5 6

7

8

9

10

11

1/1 1/2 1/3 1/4

2/1 2/2 2/3 2/4

3/1 3/2 3/3 3/4

Instanz vonTSquareNet

Quadrat 1/1Quadrat 1/2Quadrat 1/3Quadrat 1/4Quadrat 2/1Quadrat 2/2Quadrat 2/3Quadrat 2/4Quadrat 3/1Quadrat 3/2Quadrat 3/3Quadrat 3/4

Punkt 1Punkt 5Punkt 6Punkt 8Punkt 2Punkt 3

Punkt 9

Punkt 11

Punkt 4

Punkt 10

Punkt 7

Abb. 18: Listen der Punkte, die in der jeweiligen Gitterzelle liegen

In der oben erläuterten Implementation weiss jede Zelle, welche Punkte in ihrliegen. Um umgekehrt auch dem Punktlayer die Möglichkeit zu geben, auf dasGitternetz zuzugreifen (jeder Punkt soll wissen, in welcher Gitterzelle er liegt),enthält die Klassenbibliothek eine Subklasse von TPointLayer, TPointLayer-ForSquares. Sie besitzt als weitere Instanzvariable einen Array, der gleich langist wie der Array der Punktkoordinaten und für jeden Punkt einen Verweis aufdie Gitterzelle enthält, in der dieser liegt. Auf diese Weise ist für jeden Punktimmer bekannt, in welcher Zelle er liegt, was z.B. die Lösung von Problemenwie das Finden des nächsten zu einem gegebenen Punkt erheblich beschleu-nigt. Weiter enthält diese Klasse einige neue bzw. überschriebene Methoden,die das Vorhandensein des Gitternetzes miteinbeziehen. So wird es z.B.

52

ermöglicht, nur Punkte zu zeichnen, die in einer bestimmten Zelle liegen. Auchdie Methoden zur Manipulation einzelner Punkte sind so verändert, dass siedie Auswirkungen dieser Manipulationen auf die Lage der Punkte bezüglichdes Gitternetzes berücksichtigen (so muss z.B. beim Verschieben eines Punktesgetestet werden, ob dieser in eine andere Gitterzelle zu liegen kommt).

1

2

34

5 6

7

8

9

10

11

1/1 1/2 1/3 1/4

2/1 2/2 2/3 2/4

3/1 3/2 3/3 3/4

x/y x/y x/y x/y x/y x/y x/y x/y x/y x/y x/y

1 2 3 4 5 6 7 8 9 10 11 12 13 14

Punktkoordinaten:

Gitterzelle, in der der Punkt liegt:

1/2 2/2 2/3 2/3 1/3 1/4 2/3 2/1 3/2 3/2 3/4

1 2 3 4 5 6 7 8 9 10 11 12 13 14

Abb. 19: Die Arrays der Punktkoordinaten und der Gitterzellen-Verweise, beideInstanzvariablen der Klasse TPointLayerForSquares

4.4.3. Array-Linien

Die Klasse TArrayLine ist in ihrem Aufbau der Klasse TPointArray sehrähnlich. Wieder sind die Koordinaten der Punkte in einem Array abgelegt; hierentspricht aber die Reihenfolge der Punkte im Array ihrer Reihenfolge in derLinie. Diese Linie kann mit ihren Methoden ganz, abschnittweise oder Punktfür Punkt gezeichnet und gelöscht werden. (Dies gilt für alle Linien- undPolygonklassen.) Natürlich sind auch alle Editieroperationen möglich.

53

x/y x/y x/y x/y x/y x/y x/y x/y x/y x/y

1 2 3 4 5 6 7 8 9 10 11 12 13 14

Abb. 20: Das Konzept von TArrayLine

4.4.4. Listen-Linien

Im Gegenstatz zu TArrayLine, wo die Punkte der Linie in einem relativ stati-schen Array gespeichert werden, besitzt TListLine eine Liste, um die Punkte zuverwalten. Der programmiertechnische wie auch der Speicheraufwand sindzwar grösser, Funktionen aber wie z.B. das wiederholte Einfügen und Entfer-nen von Punkten lassen sich auch bei einer grossen Anzahl Linienpunkteneffizient ausführen. TListLine ist somit v.a. für ein Programm zur interaktivenLinieneditierung geeignet.

x/y x/y x/y x/y x/y x/y x/y x/y

Abb. 21: Das Konzept von TListLine

54

4.4.5. Hybride Linien

Die Klasse THybridLine verbindet die Vorteile von Arrays und Listen. Liniendieser Klasse bestehen aus kleinen, zu einer Liste zuammengesetzten Arrays,die selber Instanzen einer Klasse TChainArray sind. Um diese Struktur flexibelzu machen, werden diese kleinen Arrays, die vielleicht 8, 16 oder 32 Elementeentahlten können, nur etwa zur Hälfte mit x/y-Punktkoordinaten gefüllt. Dierestlichen leeren Stellen werden nur dann benötigt, wenn die Linie in irgend-einer Weise editiert wird; werden z.B. mehrere Punkte eingefügt, so geschiehtdies an der richtigen Stelle im richtigen Array solange, bis dieser Array voll ist.Da in einem kleinen Array nur wenige Punkte verschoben werden müssen,erfolgt das Einfügen und Entfernen von Punkten sehr effizient. Erst wenn derArray voll ist, werden entweder die neuen Punkte im nächsten Array einge-fügt, oder es wird nach dem vollen ein neuer, leerer Array eingeschoben unddieser mit den überzähligen Punkten besetzt.

x/y

1 2 3 4 5 6 7 8

x/y x/y x/y x/y x/y

1 2 3 4 5 6 7 8

x/y x/y x/y x/y

Abb. 22: Das Konzept von THybridLine

4.4.6. Statische Linien

Wenn Linien, die ins Programm eingelesen worden sind, nicht editiert, sondernunverändert in Analysen miteinbezogen und dargestellt werden sollen, dannlohnt sich der Aufwand für die flexible Gestaltung der Linienstruktur imSpeicher nicht. Stattdessen empfielt es sich, eine Struktur zu verwenden, dienicht viel Speicher benötigt und auf die schnell zugegriffen werden kann.

Für jeden Linien- oder Polygonlayer wird eine Instanz der Klasse TStaticPolyins Leben gerufen. Die Koordinaten der Punkte aller Linien und Polygone eines

55

III

III

1

2

3

4

5

6

7

8

9 10

11

12

13

1415

16

1718

1920

21

Polygon hat Startpunkt:

I II III

1 10 16

Polygon hat Punkte:

I II III

9 6 8

Punkte:

x/y von Punkt 1x/y von Punkt 2x/y von Punkt 3x/y von Punkt 4x/y von Punkt 5x/y von Punkt 6x/y von Punkt 7x/y von Punkt 8x/y von Punkt 1x/y von Punkt 9x/y von Punkt 10x/y von Punkt 11x/y von Punkt 12x/y von Punkt 13x/y von Punkt 14x/y von Punkt 15x/y von Punkt 16x/y von Punkt 17x/y von Punkt 18x/y von Punkt 19x/y von Punkt 20x/y von Punkt 21x/y von Punkt 15

123456789

111213141516171819

10

20212223

Abb. 23: Das Konzept von TStaticLine

Layers sind in einem einzigen Array gespeichert. Dieser Array ist eine Instanz-variable der Klasse TStaticPoly. Die Klasse besitzt neben diesem noch zweiweitere Arrays als Instanzvariablen: Für jedes Polygon und jede Linie steht imersten Array die Stelle des Anfangspunktes im Punktarray und im zweiten dieAnzahl Punkte. Das bedingt, dass die Punkte der Linien und Polygone in derrichtigen Reihenfolge im Punktarray abgespeichert sind, d.h. die ersten Stellendes Punktarrays werden von den Punkten des ersten Polygons eingenommen,danach folgen alle Punkte des zweiten, u.s.w.

56

Das Finden der Punkte eines Polygons oder einer Linie funktioniert folgender-massen: Im Array der Startpunkte kann für das Polygon mit der Nummer p ander Stelle p die Zahl b gelesen werden. Dieses b gibt die Stelle im Array derPunktkoordinaten an, an der die Punkte des Polygons i beginnen. Im Array derAnzahl Punkte wird an der p-ten Stelle die Zahl a gelesen, die angibt, auswievielen Punkten das Polygon p besteht. Im Array der Punktkoordinatengehören also von der b-ten Stelle an die nächsten a Punkte zum Polygon p.

4.4.7. Polygone/Linien – Arcs – Punkte

Um es dem Entwickler zu erlauben, die verschiedenen Arten der geometri-schen Primitiven – Punkte, Linien, Polygone – auf einfache Weise miteinanderin ein Projekt miteinzubeziehen und diese selber mit topologischen Bezie-hungen zu versehen, bietet die Bibliothek eine Gruppe zusammengehörenderKlassen an, die dem Datenverwaltungskonzept von Arc/Info nachempfundenist. Die eigentlichen Linieneinheiten werden repräsentiert durch die KlassenTArcLine und TArcPoly. Sie sind Subklassen von TConnectedArcs, von der siedie meisten Instanzvariablen und Methoden übernehmen. Alle Arcs, aus deneneine Linie oder ein Polygon besteht, sind in der Klasse TConnectedArcs ineinem Array aufgezählt.

Wie auch TConnectedArcs ist die Klasse TArc eine Subklasse von TLine. DieseKlasse TArc verweist auf ein Objekt der Klasse TBasicPointArray, in welchemdie Koordinaten aller Punkte gespeichert sind. Ausserdem besitzt TArc einenArray, wo für jeden Punkt des Arcs die Stelle in TBasicPointArray vermerktist, an der seine Koordinaten gespeichert sind. Diese Klasse TBasicPointArrayschliesslich besteht praktisch nur aus einem grossen Array, in dem alle Punkteder Arcs notiert sind. Ein Vorteil dieser Struktur ist, das jeder Punkt nur eineinziges Mal gespeichert werden muss, auch wenn er zu mehreren Arcs, Linienoder Polygonen gehört.

57

1

2

3

4

5

6

7 8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

Polygon besteht aus Arcs:

I II III

Arc I besteht aus Punkten:

Punkte:

I

II

III

IV

IV

2 3 41

Arc II besteht aus Punkten:

5 6 7 8 9 10 11 12

Arc III besteht aus Punkten:

12 13 14 15 1

Arc IV besteht aus Punkten:

x/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/yx/y

123456789

111213141516171819

10

20212223

1 2 3 4 5 6 7 8

1 2 3 4 5

1 2 3 4 5 6 7 8

1 2 3 4 5 6 7 8

1 2 3 4 5 6 7 8

16 17 18 19 20 21 22 16

Abb. 24: Das Konzept von TConnectedArcs, TArc und TBasicPointArray

58

5. Ein Beispiel: Douglas-Poiker-Filterung

In diesem Kapitel soll anhand eines einfachen Beispiels gezeigt werden, wie dieraumbezogenen Klassen in eigenen Applikationen zu konkreten Fragestel-lungen eingesetzt werden können. Die als Beispiel dienende Aufgabe sei dieEntwicklung einer Applikation, die es erlaubt, Linien nach der Methode vonDouglas-Poiker zu filtern. Es soll möglich sein, Linien mit der Maus am Bild-schirm zu zeichnen, sie zu editieren, eine Filtertoleranz zu wählen und dieLinien filtern zu lassen. Die gefilterten Linien sollen mit einer anderen Signaturgezeichnet werden als die ungefilterten. Dieses Beispiel ist ein Vertreter einertypischen Fragestellung, zu deren Lösung die raumbezogenen Klassen verwen-det werden. So können sie z.B. als Basis dienen, um digitale Liniengeneralisie-rungsalgorithmen zu implementieren, zu testen und untereinander zu verglei-chen.

Die Filterung nach Douglas-Poiker wird etwa folgendermassen vorgenommen:Anfangs- und Endpunkt gehören von Anfang an zur gefilterten Linie. Nach derBestimmung einer Filtertoleranz wird durch diese zwei Punkte eine Basisge-rade definiert. Man sucht danach den Punkt der Linie, dessen Abstand zurBasisgerade am grössten ist. Ist dieser Abstand grösser als die Filtertoleranz, sogehört der gefundene Punkt zur gefilterten Linie. Durch ihn und die zwei End-punkte der Linie werden zwei neue Basisgeraden definiert, die ihrerseits einenach der anderen auf dieselbe Art gefiltert werden. Dieser rekursive Vorgangwird dann abgebrochen, wenn die Distanz des am weitest entfernten Punktkleiner als die Filtertoleranz ist. (Siehe auch: Douglas und Poiker, 1973.) Esmuss aber betont werden, dass es in diesem Kapitel nicht um die Implementa-tion dieses Filteralogirthmus geht, sondern dass er nur als Beispiel einer kon-kreten Fragestellung dient.

Zuerst wird kurz die Lösung dieser Aufgabe mit der herkömmlichen, prozedu-ralen Methode erläutert. Danach wird als Gegenüberstellung auf die objekt-orientierte Programmierung und die Verwendung der Klassenbibliothek einge-gangen.

5.1. Der Ansatz der herkömmlichen, prozeduralen Methode

Bei der Entwicklung der Applikation mit der prozeduralen Technik könnenverschiedene Schritte unterschieden werden. Diese Unterteilung der Entwick-lungsarbeit ist nicht allgemeingültig, stellt aber einen möglichen Ablauf darund enthält die wichtigsten Aspekte, die bei der Erstellung der Applikationberücksichtigt werden müssen.

Der erste Schritt besteht darin, für die Linien, die gefiltert werden sollen, eineDatenstruktur zu finden. Hier besteht im wesentlichen die Wahl zwischen

59

einem Array und einer Liste. Da die Punkte in der Applikation 'von Hand'gezeichnet werden, kann davon ausgegangen werden, dass die Anzahl Punkte,die verwaltet werden müssen, nicht allzu gross wird. Daher werden in derApplikation die Effizienzunterschiede zwischen diesen Varianten kaumspürbar sein. Weil programmiertechnisch die Liste mit mehr Aufwandverbunden ist, fällt die Wahl auf den Array. Es muss aber bedacht werden, dasses wahrscheinlich ist, dass die Applikation zu einem späteren Zeitpunkt durchdie Fähigkeit erweitert werden könnte, Linien von Files zu lesen und zuspeichern. Da in diesem Fall die Anzahl zu verarbeitender Punkte bedeutendhöher sein wird, dürfte sich die Wahl einer listenhaften Datenstrukturaufdrängen. Andererseits muss man sich dann aber auch fragen, ob man dieMöglichkeit der Linieneditierung nicht fallen lassen möchte; von Files eingele-sene Linien können z.B. digitalisierte Höhenlinien oder andere Elemente einerLandeskarte sein, deren direkte Editierung keinen Sinn machen würde. Imeinfachen Beispiel dieses Kapitels sollen solche Fragen aber ausgeklammertwerden.

Als nächstes – im zweiten Schritt – folgt der Entwurf des Programmablaufs,was zur Konstruktion eines Mechanismus führt, der diesen Ablauf steuert unddie Aktionen des Benutzers der Applikation verarbeitet sowie die Reaktionendarauf organisiert. Es muss also versucht werden, einen Event Loop, wie er inKapitel 3.4.2. vorgestellt wurde, aufzustellen. Diese Aufgabe ist sehr komplex,denn es muss z.B. in jeder Situation mit ganz verschiedenen Benutzeraktionenund anderen Ereignissen gerechnet werden. Dazu gehört die Verwaltung vonFenstern, Menus und anderen Elementen der Interaktion sowie die Fähigkeit,überhaupt eine Benutzeraktion zu bemerken, sie dem entsprechenden Elementzuzuordnen und die verlangte Reaktion auszulösen.

Im zweiten Schritt wurde der Programmablauf detailliert in einzelne Abschnit-te unterteilt, was bedeutet, dass spätestens zu diesem Zeitpunkt genau bekanntist, welche Aufgaben die Applikation mit ihren Bestandteilen erfüllen muss,insbesondere welche Teilaufgaben zu deren Bewältigung notwendig sind. Imdritten Schritt kann also damit begonnen werden, die einzelnen Prozeduren,die diese Teilaufgaben ausführen, zu implementieren. Dazu gehören u.a. Proze-duren wie das Zeichnen einer Linie, das An- oder Einfügen eines neuenPunktes, das Verschieben oder Entfernen eines Punktes, das Festlegen undÄndern der Filtertoleranz sowie die eigentliche Linienfilterung. Als einfachesBeispiel sei das Anfügen eines neuen Punktes am Ende der Linie nähererläutert.

60

procedure PunktAnfügen (MouseLocation: VPoint);beginif AnzahlPunkte + 1 < maxAnzahlPunkte then

beginAnzahlPunkte := AnzahlPunkte + 1;LinienPunkt [AnzahlPunkte] := MouseLocation;DrawPoint (AnzahlPunkte);if AnzahlPunkte > 1 then

beginMoveTo (LinienPunkt [AnzahlPunkte – 1]);LineTo (LinienPunkt [AnzahlPunkte]);

end;end;

end;

Dieser Prozedur wird der Parameter MouseLocation übergeben, der die Koor-dinaten des Mouse-Klicks im Zeichenfenster darstellt. (VPoint ist eine vonMacApp vordefinierte Datenstruktur, die aus einer Horizontal- und einerVertikalkomponente besteht, die beide als LongInt deklariert sind.) Zu Beginnder Prozedur muss überprüft werden, ob der bereitgestellte Array, der nur einebestimmte Länge maxAnzahlPunkte hat, nicht schon zur Gänze mit Punktenbesetzt ist. Ist die Anzahl Linienpunkte kleiner als diese maximale AnzahlPunkte, kann der Punkt der Linie angehängt werden. Zuerst wird die AnzahlPunkte der Linie um 1 erhöht und danach dem Punkt bzw. der Stelle im Arraymit dem Index AnzahlPunkte die Koordinaten des Mouse-Klicks zugewiesen.Der neue Punkt wird zwar in jedem Fall gezeichnet – DrawPoint ist eineweitere zu implementierende Prozedur, die den Punkt z.B. als kleinen ausge-füllten Kreis zeichnet –, die Verbindung zum vorhergehenden Punkt muss abernur gezeichnet werden, falls dieser existiert, d.h. wenn die Anzahl Punktegrösser als 1 ist. Ist dies der Fall, wird die Linie mit den Befehlen MoveTo undLineTo gezeichnet. In ähnlicher Weise werden auch alle andern Prozedurenimplementiert, wobei berücksichtigt werden muss, dass diese Prozeduren oftauch andere Programmelemente wie z.B. Fenster, Menus etc. miteinbeziehenund dass die Verwendung dieser Programmelemente ebenfalls eine Vielzahleigener Prozeduren verlangt.

Sind die Prozeduren bereitgestellt, können sie in den Programmablauf einge-baut werden, d.h. sie müssen an der richtigen Stelle des Event Loops aufgeru-fen werden. Nach dem Testen und dem Verbessern von Fehlern entsteht soeine erste Version der Applikation. Meist besitzt diese Version noch nicht alleFähigkeiten, die man für die Applikation ursprünglich vorgesehen hat.Vielmehr wird man sich im ersten Entwicklungsanlauf auf die notwendigstenTeile des Programms beschränken, um die so entstehende Applikation nachund nach auszubauen. Aber auch an und für sich fertig erstellte Programmewerden in vielen Fällen durch neue, spezielle Fähigkeiten ergänzt. Die Erweite-rung von Applikationen stellt einen wichtigen Punkt in der Entwicklung darund kann deshalb als weiterer Schritt angesehen werden. Im Beispiel derDouglas-Poiker-Filterung besteht eine Erweiterung z.B. darin, dass die gefil-terte Linie anders als die ungefilterte gezeichnet werden soll, eine weitere istdie Fähigkeit, Linien beenden zu können, um die Bearbeitung mehrerer Linien

61

zu erlauben. Ausserdem soll vielleicht auch das Lesen und Schreiben derLinien auf einem Speichermedium möglich sein.

Probleme bei der Erweiterung von Applikationen ergeben sich dann, wennProzeduren andere Prozeduren aufrufen. Da in diesem Beispiel nur relativwenige Prozeduren benötigt werden, ist es einfach, die Übersicht über sichgegenseitig aufrufende Prozeduren zu bewahren. Normalerweise sind inkonkreten Projekten die Datenstrukturen und Prozeduren aber bedeutendkomplexer, so dass es in vielen Fällen sehr schwierig ist, abzuschätzen, welcheanderen Programmteile von einer Änderung in einer Prozedur betroffen sind.Veränderungen können sich auf diese Weise über viele Programmelementefortpflanzen, was eine strukturierte Implementierung erheblich erschwert.

Der letzte Schritt in der Entwicklung von eigenen Applikationen ist zugleichein zentraler Punkt dieser Diplomarbeit wie auch der Objektprogrammierungan sich. Ist eine Programmentwicklung zufriedenstellend beendet worden,wird in den meisten Fällen ein weiteres, neues Projekt in Angriff genommen. Esstellt sich an dieser Stelle die Frage, ob es nicht möglich ist, in irgendeinerWeise Programmteile aus den bisher erstellten Programmen wiederzuver-wenden. Es ist erstaunlich, wieviel Zeit, Mühe (und Geld) gespart werdenkann, wenn auf bereits bestehende und getestete Datenstrukturen, Algorith-men und andere Elemente zurückgegriffen werden kann. Die prozeduraleProgrammierung erlaubt diese Wiederverwendbarkeit nur bis zu einemgewissen Grad. Meist sind die Datenstrukturen und Prozeduren so auf diekonkrete Fragestellung spezialisiert und mit den anderen Programmteilenderart verwoben, dass sie nicht ohne grossen Aufwand in anderen Entwick-lungen eingesetzt werden können.

5.2. Die Lösung mit MacApp und der raumbezogenenKlassenbibliothek

Um die Aufgabe mit Hilfe von Klassenbibliotheken in Angriff nehmen zukönnen, müssen die Voraussetzungen bekannt sein, die von MacApp undseinen raumbezogenen Erweiterungen vorgegeben sind. Als erstes besteht wieerwähnt eine Auswahl an geometrischen Objektgruppen, aus denen man diefür die Fragestellung geeignetste bestimmt. Zweitens bietet MacApp eineApplikationsbasis, die an den dafür vorgesehenen Stellen ergänzt werdenmuss. Wie in Kapitel 3.4.1. beschrieben, stellt MacApp bereits an sich einProgramm dar, das mit den im genannten Kapitel erläuterten Programmzeilenin Gang gebracht wird und es dem Benutzer erlaubt, Fenster zu öffnen sowieeinige Menupunkte anzuwählen. Es geht nun darum, wie man diese elemen-tare Applikation mit den Fähigkeiten versieht, die die Fragestellung verlangt.

Der Entwickler kann sich also ganz auf die problembezogenen Aspekte derAufgabe konzentrieren, denn Datenstrukturen, Event Loop und alle wichtigenProgrammelemente sind bereits vorbereitet. Seine Arbeit besteht darin, diese

62

Elemente nach seinen Bedürfnissen zusammenzustellen und die problemspezi-fischen Methoden zu implementieren.

TCommand

TApplication TDocument TView

TEvtHandler TGeom-Objekt

TObject

TGeom-Primitive

TLine

TArrayLine

TDPLine

TDPAppli-cation

TDPDocu-ment

TDPView

TDrawPoint-Command

TInsertPoint-Command

TRemovePoint-Command

Abb. 25: Die neuen, für die Applikation spezialisierten Klassen in der Hierarchie dererweiterten MacApp-Klassenbibliothek

5.2.1. Applikation, Dokument, Fenster

Wenn MacApp die Grundlage einer eigenen Entwicklung ist, besteht der ersteSchritt immer in der Subklassierung der von MacApp vorbereiteten KlasseTApplication. Die so neu entstehende Klasse TDPApplication (Douglas-Poiker-Application) – oder besser eine Instanz davon – wird die Applikationzur Douglas-Poiker-Filterung repräsentieren. (Alle für diese Applikation neuspezifizierten Subklassen finden sich in Abb. 25 wieder.) Sie erhält keine neuenInstanzvariablen, dafür wird aber eine neue Initialisierungsmethode definiertund die Methode DoMakeDocument überschrieben. Wie in Kapitel 3.4.3.erläutert, sieht es MacApp vor, dass Daten, zu denen auch die zu filterndenLinien gehören, als Instanzvariablen einer Subklasse von TDocument betrach-tet werden. Damit also durch die Applikation nicht ein Default-Dokument insLeben gerufen wird, sondern eine Instanz der für diese Applikation vorgesehe-nen und spezialisierten Subklasse von TDocument, muss die genannte Metho-de DoMakeDocument in der Klasse TDPApplication entsprechend über-

63

schrieben werden. Diese Methode wird beim Start der Applikation automatischaufgerufen, die Applikation bildet also von sich aus ein Dokument.

Die für die Applikation spezialisierte Subklasse von TDocument, TDPDocu-ment, wird durch einige Instanzvariablen erweitert. fLine ist ein Array, der diezu filternden Linien aufnehmen wird, fNumberOfLines ist als Integer dekla-riert und enthält die Anzahl existierender Linien. Dazu kommt fView, einVerweis auf das zum Dokument gehörenden Fenster, in dem die Daten desDokuments, d.h. die Linien dargestellt werden. Wie die Applikation selbstän-dig ein Dokument bildet, veranlasst das Dokument quasi selbständig dieBildung einer Instanz von TView. Da aber nicht ein Default-Fenster verlangtwird, sondern eine Instanz der für diese Anwendung erweiterten SubklasseTDPView, wird die Methode DoMakeViews der Klasse TDPDocumentdementsprechend abgeändert.

Die Subklasse von TView, TDPView, enthält schliesslich mit der Instanzva-riablen fDocument einen Verweis zurück auf das Dokument, zu dem es gehört.Dieser wird benötigt, da bei Aktionen des Benutzers im Fenster die View-Instanz auf die Linien zugreifen können muss. Das Fenster ist das Element derApplikation, mit dem der Benutzer in erster Linie kommuniziert. Aus diesemGrund soll die View-Instanz die Aufgabe übernehmen, Reaktionen auf dieseBenutzeraktionen auszuführen. Dies hat zur Folge, dass die Klasse TDPViewdruch einige weitere Instanzvariablen ergänzt wird. Dazu gehört z.B. fMagnifi-cation, die den momentanen Visualisierungsmassstab angibt. Es soll also demBenutzer ermöglicht werden, die Linien in verschiedenen Vergrösserungenanzusehen und zu bearbeiten. fWhatToDo gibt an, welche Operation mit demnächsten Mouse-Klick ausgeführt werden soll (Verschieben, Ein- bzw. Anfügenoder Entfernen eines Linienpunktes). Die wichtigste Grösse der Filterung ist dieFiltertoleranz, die in der Variable fLevel als LongInt deklariert ist. Da dieFiltertoleranz zum Fenster und nicht zu den einzelnen Linien gehört, könnenalle Linien nur mit derselben und nicht mit unterschiedlichen Toleranzengefiltert werden. Diese Variante wurde der Einfachheit halber gewählt. (Eswäre durchaus möglich, wenn auch mit etwas mehr Aufwand, die Linien mitseparaten Toleranzen zu filtern.)

Neben den Instanzvariabeln müssen auch einige Methoden neu hinzugefügtoder überschrieben werden. Die erste Methode der View-Instanz, die aufgeru-fen wird, ist IRes. Sie liest das Aussehen des Fensters (Grösse, Position amBildschirm, Scroller, Titel, etc.) in einem sog. Ressourcenfile, auf das hier nichtnäher eingegangen werden soll. So ist es aber möglich, alle Fenster und Dialogeim Voraus zu entwerfen und einzurichten. Zu diesem Zweck stehen demEntwickler verschiedene View-Design-Programme zu verfügen, die dasZusammenstellen von Views nach dem Baukastenprinzip visuell am Bild-schirm ermöglichen. Die fertigen Views werden in das genannte Ressourcenfilegespeichert und von dort beim Start der Applikation wieder gelesen. Eineweitere Methode, die überschrieben wird, ist Draw, die immer dann aufge-rufen wird, wenn das Fenster mit seinem Inhalt ganz oder teilweise gezeichnetwerden muss. Die Methode wird so verändert, dass sie für jede Linie, die imLinienarray des Dokuments enthalten ist, deren Draw-Methode aufruft,wodurch sich jede Linie selbst am richtigen Ort zeichnet. (Auf die Draw-

64

Methode der Linien wird noch genauer eingegangen.) Schliesslich braucht esnoch weitere, neue Methoden, wie z.B. SetMagnification, um den Vergrösse-rungsmassstab zu verändern, SetLevel, um die Filtertoleranz neu zu setzenund DoDouglasPoiker, um die Linienfilterung auszulösen.

5.2.2. Die Klasse TDPLine

Sind Applikation, Dokument und Window soweit subklassiert und erweitertworden, so kann man bereits mit ein paar weiteren Programmzeilen (sieheKapitel 3.4.1.) eine kleine, lauffähige Applikation erstellen. Sie reagiert aller-dings nicht auf Mouse-Klicks, d.h. man kann noch keine Linien zeichnen,geschweige denn filtern. Erst die Erweiterung des Event Loops durch dieentsprechenden Methodenaufrufe wird die gewünschten Interaktionsmöglich-keiten in die Applikation einfügen. Die von MacApp dafür vorgesehenenMechanismen machen es für den Entwickler sehr einfach, die verschiedenstenBenutzeraktionen zu erlauben und von der Applikation verarbeiten zu lassen.

Bevor der Event Loop erweitert werden kann, muss die Entscheidung getroffenwerden, welche Klasse aus der raumbezogenen Klassenbibliothek sich ambesten für die Linienfilterung eignet. Es wurde bereits erwähnt, dass dieLiniendaten als Instanzvariablen dem Dokument angehängt werden. Dabeiwurde aber noch nicht festgelegt, von welchem Typ diese Linien sein sollen.Um Linien zu verarbeiten, kommen verschiedene Objektgruppen in Frage. Danicht sehr viele Punkte zur Verarbeitung zu erwarten sind, dafür aber dasinteraktive Edititeren der Linien möglich sein soll, wird die Wahl nicht auf die'statische' Linien-Variante, d.h. nicht auf die Klasse TStaticPoly fallen. Da auchtopologische Beziehungen in der Fragestellung keine Rolle spielen, fallenebenso die Arc/Info nachempfundenen Klassen aus der Wahl. Es bleiben diedrei Klassen TArrayLine, TListLine und THybridLine. Die Wahl wird auf dieArray-Linien fallen, denn der programmiertechnische Aufwand ist bei dieserVariante am kleinsten. Weil nur wenige Punkte pro Linie zu erwarten sind,wird auch das Editieren trotz der Array-Struktur genügend effizient erfolgen.

Der nächste Schritt besteht in der Subklassierung der gewählten Klasse. Dieneue Klasse TDPLine erhält für ihre Aufgabe einige Instanzvariablen undMethoden dazu. (Anhang B enthält eine Auflistung des Programmcodes derDeklaration von TDPLine sowie der Methoden, die für die Filterung der Liniezuständig sind.) Nach der Filterung soll keine neue Linien-Instanz entstehen, essoll stattdessen jeder Punkt, der zur gefilterten Linie gehört, speziell markiertwerden. Zu diesem Zweck besitzt die Klasse die Instanzvariable fSignificant;sie besteht aus einem Array, der die gleiche Länge hat wie der Array derPunktkoordinaten und an jeder Stelle für jeden Punkt einen boolschen Wertenthält, der angibt, ob der Punkt zur gefilterten Linie gehört. Die Filterungerfolgt durch die neue Methode DoDouglasPoiker. Auf diese Methode solletwas genauer eingegangen werden:

65

Mittels der Instanzvariable fFiltered – ein boolscher Wert – überprüft dieseMethode, ob bereits eine Filterung durchgeführt wurde. Ist dies der Fall, wirddie alte gefilterte Linie gelöscht, und die neue Filterung kann beginnen. Zuerstwerden der erste und der letzte Punkt der Linie als zur gefilterten Liniegehörend markiert (die entsprechenden Stellen des Arrays fSignificant werdenauf TRUE gesetzt). Danach wird die ebenfalls neue Methode DoOn2Pointsaufgerufen, wobei die zwei Endpunkte als Parameter übergeben werden.Streng dem Douglas-Poiker-Algorithmus folgend, sucht diese Methode den amweitest entfernten Punkt von der Verbindung der zwei übergebenen Punkte,wobei nur die auf der Linie zwischen diesen Punkten liegenden Punkte inFrage kommen. Ist der Punkt gefunden, wird überprüft, ob er weiter weg ist alsdie Filtertoleranz von der genannten Verbindung. Wenn ja, dann wird er alszur gefilterten Linie gehörend markiert, wodurch zwei neue Teilstücke derLinie entstehen: eines vom ersten zum gefundenen, ein zweites vom gefunde-nen zum letzten Punkt der Linie. Die Methode DoOn2Points wird also zweiweitere Male aufgerufen, wobei jeweils die Endpunkte der zwei neuenAbschnitte als Parameter übergeben werden. Dieser rekursive Vorgang wirddann abgebrochen, wenn die Distanz des gefunden, am weitesten vom geradebearbeiteten Teilstück entfernten Punkt zu diesem Teilstück kleiner ist als dieFiltertoleranz. Der gefundene Punkt wird in diesem Fall nicht markiert, esentstehen keine zwei neuen Teilstücke und die Methode DoOn2Points wirdnicht wieder aufgerufen. Ist der Filtervorgang zu Ende, steht im Array fSigni-ficant für jeden Punkt, ob er nun zur gefilterten Linie gehört oder nicht. AufGrund dieser Information kann nun die gefilterte Linie mit einer speziellenFarbe (fDPColor ist ebenfalls eine Instanzvariable von TDPLine) gezeichnetwerden. Schliesslich wird die Variable fFiltered auf TRUE gesetzt, damit dieLinie weiss, dass sie bereits einmal gefiltert wurde.

Zu den neuen Methoden der Klasse TDPLine gehören auch Dist, das im obenerklärten Algorithmus gebraucht wird und die Distanz eines Punktes zurVerbindung zweier weiterer berechnet, sowie EraseDP und DrawDP, die diegefilterte Linie löscht bzw. mit der Farbe fDPColor zeichnet. Daneben werdeneinige Methoden, die von TArrayLine geerbt werden, überschrieben. Dazugehören z.B. Draw und Erase, wo je nach dem Wert von fFiltered nach demZeichnen der eigentlichen Linie auch die gefilterte Linie gezeichnet bzw.gelöscht wird.

5.2.3. Mouse- und Menu-Aktionen

Wie aber können die Mouse-Operationen des Benutzers aufgefangen und indas Zeichnen oder Bearbeiten von Linienpunkten verwandelt werden ? AlleProgrammelemente, die auf Benutzeraktionen reagieren sollen, sind Instanzenvon Subklassen der Klasse TEvtHandler. Diese Klasse – also auch alle ihre Sub-klassen – besitzt verschiedene Methoden, die ja nach aufgetretenem Eventaufgerufen werden: Nach einem Mouse-Klick wird z.B. die MethodeDoMouseCommand aufgerufen, nach einer Menu-Auswahl ist es DoMenu-Command, und für Tastatureingaben ist DoKeyCommand zuständig.

66

Stellt im Beispiel dieses Kapitels die Applikation einen Mouse-Klick fest, sowird im Event Loop auf Grund der Bildschirmkoordinaten dieses Events dasFenster als verantwortliches Objekt bestimmt, worauf die Methode DoMouse-Command der entsprechenden View-Instanz aufgerufen wird. Da diesemMethodenaufruf die Koordinaten des Mouse-Klicks als Parameter übergebenwerden, kann jetzt die entsprechende Reaktion auf die Benutzeraktion ausge-führt werden, d.h. es wird z.B. ein neuer Linienpunkt gezeichnet. Ein weiteresBeispiel ist das Auslösen der Douglas-Poiker-Filterung, das via Menu-Auswahlgeschieht. Da zu Beginn postuliert wurde, dass die Kommunikation des Benut-zers mit der Applikation hauptsächlich über das Fenster geschieht, wird auchdieser Menu-Befehl von der View-Instanz verarbeitet. Das bedeutet, dass dieApplikation die Methode DoMenuCommand der View aufruft, wo jeder Liniedie Aufforderung DoDouglasPoiker geschickt wird. Ebenfalls in der DoMenu-Command-Methode erledigt werden das Ändern der Filtertoleranz – zudiesem Zweck lässt die Methode ein Dialogfenster erscheinen, wo demBenutzer zur Eingabe der neuen Toleranz ein Nummereingabefeld zurVerfügung steht –, das Ändern des Zeichenmassstabs sowie das Festlegen desZeichenmodus.

Als Zeichenmodi werden die verschiedenen Editiermöglichkeiten verstanden.Im Anfangsmodus können Punkte gezeichnet und bewegt werden. (Bei einemMouse-Klick wird getestet, ob ein bereits existierender Linienpunkt getroffenwurde. Ist dies der Fall, kann er mit gedrückter Mouse-Taste bewegt werden,wurde aber kein Punkt getroffen, wird ein neuer gezeichnet und der Liniehinzugefügt.) Möchte der Benutzer aber Punkte in die Linie einfügen oder ausihr entfernen, muss er im Menu 'Insert Point' bzw. 'Remove Point' angeben. Inder Methode DoMenuCommand wird die Instanzvariable fWhatToDo derView-Instanz, die den jeweiligen Zeichenmodus repräsentiert, entsprechendgeändert. Der Wert dieser Variable (entweder DrawPoints, InsertPoints oderErasePoints) wird in der Methode DoMouseCommand bei jedem Mouse-Klickberücksichtigt.

5.2.4. Verwendung von Commands

MacApp sieht noch einen weiteren Schritt in der Verarbeitung von Benutzer-aktionen vor. Er soll es einerseits ermöglichen, einen Mechanismus in Applika-tionen einzubauen, der dem Benutzer das Rückgängigmachen seiner Aktionenerlaubt, andererseits können damit auch komplexe Mouse-Operationen imple-mentiert werden, denn es wird zwischen dem Drücken und dem Loslassen derMouse-Taste unterschieden; auf diese Weise kann der Entwickler u.a. dasBewegen der Mouse mit gedrückter Taste mit visuellem Feedback versehen.Diese weitere Stufe der Event-Verarbeitung besteht in der Verwendung vonsog. Commands. Sie sind selber Objekte und werden immer dann alloziert,wenn die Verarbeitung einer Benutzeraktion einem solchen Command überlas-sen werden soll. Die Klasse TCommand besitzt u.a. die Methoden DoIt, Undo-It und RedoIt.

67

Tritt ein Event auf und wird das Objekt gefunden, das diesen Event verarbeitet,dann wird diesem Objekt wie erwähnt die entsprechende DoEventCommand-Aufforderung geschickt (z.B. DoMenuCommand). Diese DoEventCommand-Methoden sind eigentlich Funktionen, d.h. sie liefern einen Rückgabewert, indiesem Fall einen Command. Wird der Event bereits in der DoEventCom-mand-Methode abgearbeitet, wird ein Command zurückgegeben, der derApplikation meldet, dass die Verarbeitung des Events bereits erledigt ist. Sollaber der Event in einem Command verarbeitet werden, so gibt die DoEvent-Command-Methode eine spezielle Command-Instanz zurück, die vomEntwickler vorbereitet werden muss. Die Applikation ruft nun selbständig dieDoIt-Methode dieses Commands auf. Die Verarbeitung des Events wird also indieser Methode implementiert. Wählt nun der Benutzer des Programms nachseiner Aktion den Menupunkt 'Undo', so ruft die Applikation UndoIt auf: indieser Methode wird das Rückgängigmachen der Benutzeraktion erledigt.Schliesslich kann das erneute Ausführen der Aktion in der Methode RedoItimplementiert werden, denn diese wird bei der Auswahl von 'Redo' automa-tisch aufgerufen.

Die folgende, schematische Beschreibung des Ablaufs bei der fiktiven Menu-Auswahl 'XY' soll den Vorgang illustrieren.

• Die Instanz von TDPApplication – stellt einen Menu-Event fest.– bestimmt die Instanz von TDPView

als für diesen Event verantwortlich.– schickt dieser Instanz die Aufforde-

rung DoMenuCommand.• Die Instanz von TDPView – lässt eine Instanz der für diese

Menu-Auswahl vorgesehenenKlasse TXYCommand entstehen.

– gibt diese Command-Instanz an dieApplikation zurück.

• Die Instanz von TDPApplication – schickt diesem Command die Auf-forderung DoIt.

• Die Instanz von TXYCommand – führt DoIt aus, d.h. sie erledigt dieAusführung der Aktion, die derBenutzer mit seiner Menu-Auswahlbeabsichtigt hatte, auf Grund der inDoIt implementierten Anweisung-en.

Wählt der Benutzer nun den Menu-Punkt 'Undo It' bzw. 'Redo It', so schicktwie erwähnt die Applikationsinstanz dem Command die Aufforderung UndoItbzw. RedoIt, die das Rückgängigmachen bzw. die erneute Ausführung derAktion enthalten. Dieser Ablauf bei der Event-Verarbeitung ist von MacAppsoweit vorbereitet, dass der Entwickler nur die Command-Methoden DoIt,UndoIt und RedoIt der auszuführenden Aufgabe entsprechend implemen-tieren muss.

Ebenfalls automatisch geschieht die Verfolgung der Mouse-Bewegungen unddie Überprüfung des Zustands der Mouse-Taste. Klickt der Benutzer in ein

68

Fenster, wird der entsprechenden View-Instanz die Aufforderung DoMouse-Command geschickt. Diese Methode liefert als Rückgabe eine Instanz einervom Entwickler vorbereiteten Command-Klasse. Da es sich bei dem aufgetrete-nen Event um einen Mouse-Klick handelt, ruft die Applikation selbständigimmer wieder drei Methoden des Commands auf. Dies geschieht solange, bisder Benutzer die Mouse-Taste loslässt. In diesen ununterbrochen nacheinanderaufgerufenen Methoden können z.B. bei jedem Aufruf die Lage der Mouse imVergleich zu andern Objekten getestet und dem Benutzer entsprechende visu-elle Rückmeldungen geliefert werden. Ein Beispiel der Verwendung dieserMouse-Kontrollmethoden ist die Selektion von Punkten durch ein Rechteck,das der Benutzer durch das Bewegen der Mouse mit gedrückter Tasteaufspannt; je nach der Lage eines Punktes innerhalb oder ausserhalb desRechtecks wird er speziell gezeichnet.

Im Douglas-Poiker-Beispiel dieses Kapitels werden Commands für die Imple-mentation der Zeichen- und Editierfunktionen verwendet, denn einerseitshandelt es sich dabei um Mouse-Operationen, bei denen der Benutzer einenvisuellen Feedback erwartet, andererseits sollen diese Operationen auch wiederrückgängig gemacht werden können. Für diese Commands werden Subklassenvon TCommand gebildet, so z.B. für das Zeichnen eines neuen Linienpunktesdie Klasse TDrawLineCommand. Der visuelle Feedback bei dieser Operationbesteht im Zeichnen eines neuen Punktes sowie seiner Verbindung zumvorhergehenden. Es stellt sich die Frage, ob die Koordinaten des neuen Punktesbeim Drücken oder beim Loslassen der Mouse-Taste erfasst werden. Je nachSituation muss auch das Zeichnen im richtigen Moment geschehen. Man kannsich z.B. vorstellen, dass beim Drücken der Mouse-Taste ein Punkt sowie dieStrecke zum vorhergehenden gezeichnet werden und dass sich die Lage desneuen Punktes am Bildschirm zusammen mit der zugehörigen Streckeverändert, wenn der Benutzer die Mouse mit gedrückter Taste bewegt. Erstbeim Loslassen der Mouse-Taste werden die Koordinaten dem neuen Punktdefinitiv zugewiesen. Die Implementation dieser Variante ist mit denHilfsmitteln der Command-Klasse ziemlich einfach zu verwirklichen. Inähnlicher Weise werden auch die visuellen Rückmeldungen beim Einfügenund Bewegen von Linienpunkten ausgearbeitet.

Da das Zeichnen des neuen Linienabschnitts als visueller Feedback aufgefasstund implementiert wird, muss in der DoIt-Methode noch die Erhöhung derAnzahl Punkte um 1 sowie das Zuweisen der Koordinaten zum neuen Punktvorgenommen werden. Beide Teilaufgaben werden mit Methodenaufrufen andie Linieninstanz delegiert. Im Gegensatz zur Methode DoIt müssen UndoItund RedoIt das Löschen bzw. Zeichnen des neuen Linienabschnitts explizitenthalten. In UndoIt wird zudem die Anzahl Punkte um 1 verkleinert, in Redo-It wieder um 1 erhöht.

Bei den drei Editiervorgängen muss vor dem Allozieren eines Commands derOrt des Mouse-Klicks mit der Lage der Linienpunkte verglichen werden: BeimVerschieben und Löschen von Punkten muss der Mouse-Klick (mehr oderweniger) genau einen solchen Punkt treffen, beim Einfügen eines Punktes mussdie Verbindung zweier Punkte getroffen werden. Um diese Tests durchzu-führen, besitzt die Klasse TArrayLine zwei Methoden, die als Parameter die

69

Koordinaten des Mouse-Klicks sowie eine Toleranz, die angibt, wie genau derPunkt getroffen werden muss, übernehmen und als Rückgabewert TRUEliefern, wenn ein Punkt bzw. eine Linienabschnitt getroffen wurde; in diesemFall geben die Methoden ausserdem den getroffen Punkt bzw. den erstenPunkt des getroffenen Abschnitts zurück.

Wird also nach einem Mouse-Klick die DoMouseCommand-Methode derView-Instanz aufgerufen, ruft diese zuerst eine der beiden erläuterten Test-methoden auf, und erst wenn diese das Treffen eines Punktes bzw. einesAbschnitts bestätigen, wird ein entsprechender Command kreiert und derApplikation zur Verarbeitung übergeben. Die Commands schliesslich sindInstanzen von TMovePtCommand, TInsertPtCommand und TRemovePt-Command, Subklassen von TCommand. Die Feedback-Operationen sind beimEinfügen und Verschieben eines Linienpunktes – wie bereits erwähnt – ähnlichgestaltet, denn in beiden Fällen verändert der Benutzer mit gedrückter Mouse-Taste die Lage des Punktes, was ohne Verzögerung sichtbar sein soll. Die Do-It-, UndoIt- und RedoIt-Methoden bestehen bei allen drei Editieroperationenim wesentlichen aus Aufforderungen an die Linieninstanz, einen Punkt zuverschieben, einzufügen, zu entfernen und das Bild der Linie im Fensterentsprechend zu verändern.

Ein Problem ergibt sich bei der Bearbeitung einer bereits gefilterten Linie, denndas Verändern der Punkte hat auch einen Einfluss auf die gefilterte Version derLinie. Eine einfache Lösung dieses Problems ist die erneute Filterung der Linienach jeder Veränderung durch den Benutzer. Es wird dabei der Zustand dergefilterten Linie vor und nach der Manipulation verglichen (sind immer nochdie gleichen Punkte in der gefilterten Linie enthalten, wurde einer von ihnenverschoben ?). Wenn durch die Veränderung der ursprünglichen Linie auch diegefilterte beeinflusst wurde, wird diese ebefalls neu gezeichnet. Nicht auf dieseWeise gelöst wird das Problem, wenn neue Linienpunkte am Ende der Linieangefügt werden, denn der Benutzer wird oft in sehr kurzer Zeit viele neuePunkte zeichnen. Um unangenehme Verzögerungen durch die wiederholteNeufilterung zu vermeiden, wird die Linie als nicht gefiltert markiert (dieInstanzvariable fFiltered wird auf FALSE gesetzt). Die erneute Filterung beimAnfügen eines neuen Linienpunktes wird so verhindert, kann aber vom Benut-zer zu einem beliebigen Zeitpunkt nachgeholt werden.

5.2.5. Zusammenfassung des Programmablaufs

An dieser Stelle soll der Ablaufs der Applikation noch einmal zusammenge-fasst werden. Diese kurze Beschreibung soll veranschaulichen, wie kompaktund strukturiert eine solche Entwicklung gestaltet werden kann.

Nach dem Start der Applikation wird zuerst eine Instanz der KlasseTDPApplication gebildet, die von nun an die Applikation repräsentiert. Sieinitialisiert sich selber und bildet eine Instanz von TDPDocument. Diese initia-lisiert sich ebenfalls (fNumberOfLines wird auf 0 gesetzt) und bildet ihrerseitseine Instanz der Klasse TDPView. Auch diese wird initialisiert (fMagnifica-

70

tion und fLevel werden auf einen Defaultwert gesetzt, fWhatToDo erhält denWert DrawLines, fDocument zeigt auf des Dokument und die InstanzvariablefView der Dokument-Instanz wird auf die neue View-Instanz gerichtet). Nachdiesen vorbereitenden Schritten beginnt die Applikation mit dem Event Loop,d.h. von nun an wartet die Applikation auf die Aktionen des Benutzers. In dennächsten Abschnitten werden die Reaktionen auf alle möglichen Benutzerak-tionen einzeln beschrieben.

Dem Benutzer stehen einige Menupunkte zur Auswahl:

• 'Zoom In', 'Zoom Out', 'Reset Zoom':Die Applikation ruft DoMenuCommand der View-Instanz auf, wo fMagni-fication entsprechend verändert wird. Mit ForceRedraw, einer von TView geerbten Methode, die in MacApp angeboten wird und nicht neu implemen-tiert werden muss, wird das Fenster mit dem neuen Vergrösserungsmassstabgezeichnet. In ForceRedraw wird die Methode Draw aufgerufen, wo jede Linie dazu aufgefordert wird, sich selber zu zeichnen.

• 'Draw Lines', 'Insert Point', 'Remove Point':Wieder wird DoMenuCommand der View aufgerufen, wo die Instanzva-riable fWhatToDo entsprechend der Menu-Auswahl verändert wird: nach 'Draw Lines' erhält sie den Wert DrawLines, nach 'Insert Point' den Wert InsertPoint und nach 'Remove Point' RemovePoint. Die View-Instanz braucht fWhatToDo, um bei einem Mouse-Klick zu entscheiden, wie dieser zu verarbeiten ist.

• 'Set Filter Level':In DoMenuCommand wird FilterDialog aufgerufen. Diese Methode gehört ebenfalls zu TDPView und öffnet ein Dialogfenster. Dieses besitzt ein Zahleneingabefeld und erwartet vom Benutzer die Eingabe der neuen Filtertoleranz. Nachdem der Benutzer das Dialogfenster mit dem Button 'OK' wieder geschlossen hat, wird fLevel auf Grund der Eingabe geändert.

• 'Douglas-Poiker':In DoMenuCommand der View wird in einer for-Schlaufe für jede Linie ihre Methode DoDouglasPoiker aufgerufen. Diese Methode überprüft zuerst den Wert von fFiltered (eine Instanzvariable von TDPLine); ist dieser TRUE, wird die alte gefilterte Linie mit EraseDP gelöscht. Danach wird der erste und der letzte Punkt der ursprünglichen Linie als zur gefilter-ten gehörend markiert (im Array fSignificant). Jetzt beginnt die eigentliche Filterung mit dem Aufruf der Methode DoDouglasPoiker, wobei ihr die beiden markierten Punkte als Parameter übergeben werden. Da die Funk-tionsweise dieser Methode bereits detailliert geschildert wurde, soll dies nicht wiederholt werden. Nach der Filterung wird auf Grund der Werte im Array fSignificant die gefilterte Linie mit der Methode DrawDP und der Farbe fDPColor gezeichnet. Schliesslich wird fFiltered der Wert TRUE zugewiesen.

• Die Auswahl aller anderen Menupunkte – u.a. 'Quit' – wird von der Appli-kation selber abgefangen.

71

Mouse-Klicks werden alle in der Methode DoMouseCommand der View-Instanz ausgewertet. Je nach dem Wert von fWhatToDo sind unterschiedlicheAufgaben zu erfüllen:

• Besitzt fWhatToDo den Wert DrawLines, wird in DoMouseCommand getestet, ob ein Punkt getroffen wurde, wobei jede Linie diesen Test mit ihrer eigenen Methode durchführt. Meldet eine Linie zurück, dass einer ihrer Punkte getroffen wurde, dann wird die Suche abgebrochen und eine Instanz der Klasse TMovePtCommand ins Leben gerufen. Diese übernimmt das Verschieben des Punktes, d.h. das Liefern des visuellen Feedbacks, den Aufruf der Methode MovePoint der entsprechenden Linie sowie das Bereit-stellen der Möglichkeit, diese Aktion wieder rückgängig zu machen. Wurde kein Punkt getroffen, wird einer Instanz von TDrawLineCommand das Hinzufügen und Zeichnen eines neuen Linienpunktes übertragen.

• Ist der Wert von fWhatToDo InsertPoint, dann prüft zuerst eine Linie nach der anderen mit ihrer dazu vorgesehenen Methode, ob irgendein Linienab-schnitt getroffen wurde. Ist dies der Fall, übernimmt eine Instanz der Klasse TInsertPtCommand das Einfügen des neuen Punktes. Sie sorgt für den notwendigen visuellen Feedback und schickt der entsprechenden Linie die Aufforderung InsertPoint. Zu ihren Aufgaben gehört auch das eventuelle Rückgängigmachen des Vorgangs.

• Ist schliesslich RemovePoint der Wert von fWhatToDo, dann wird wiederum getestet, ob ein Punkt irgendeiner Linie getroffen wurde. Ist dies der Fall, wird das Entfernen eines Linienpunktes von einer Instanz von TRemovePtCommand übernommen, wobei das Entfernen und Neuzeichnenan die Linien-Instanz delegiert wird.

72

6. Ausblick

6.1. Attribute

Im Gegensatz zu den Klassen der einleitenden Beispiele im Kapitel 2. besitzendie Klassen der raumbezogenen Klassenbibliothek keine Attribute. Da dieseBibliothek als allgemein verwendbare Grundlage für eigene Entwicklungen zuirgendeinem Thema dienen soll, ist es klar, dass den Klassen der Bibliothek nurdie geometrischen (Koordinaten, Anzahl Punkte, umschreibendes Rechteck,etc.) sowie einige weitere, beim Einsatz in einem Programm nützliche Attributezugewiesen werden können, da nur diese losgelöst von der Problemstellung inallen Anwendungen benötigt werden. Alle andern Eigenschaften stehen indirektem Zusammenhang mit der Fragestellung und können daher erst vomEntwickler der Applikation festgelegt werden.

Es bestehen im wesentlichen zwei Möglichkeiten, den Klassen Attribute zuzu-weisen. Die erste, einfachere besteht darin, dass die verwendete Klasse derBibliothek subklassiert wird, und dass diese Subklasse für die Problemstellungmit weiteren Eigenschaften und Methoden ausgerüstet wird. Dieses Vorgehenwird bei kleinen und grossen eigenen Projekten eingesetzt und entspricht denPrinzipien der objekt-orientierten Denkweise. Alle benötigten Objekte könnenso für die Fragestellung optimal modelliert werden, sind dann aber für dieseeine Entwicklung spezialisiert und nur dort einsetzbar.

Steht nicht die Entwicklung einer Applikation für eine konkrete Fragestellungim Vordergrund, sondern soll die Applikation für verschiedene Problemeeingesetzt werden können, kann die oben erwähnte Variante des Subklassie-rens und Spezialisierens nicht verwendet werden. Erst während des Einsatzesder Applikation werden die Objekte und deren Attribute festgelegt. Zu diesemZeitpunkt ist es aber nicht mehr möglich, den Objekten Attribute als Instanzva-riablen zuzuweisen. Ein Weg, der es dem Benutzer einer solchen Applikationtrotzdem erlaubt, Objekte nach eigenen Vorstellungen zu entwerfen, bestehtdarin, Attribute selber als Objekte aufzufassen sowie die raumbezogenenObjekte mit der Möglichkeit auszustatten, solche Attributobjekte aufzunehmen.So kann der Benutzer die geometrischen Primitiven nach dem Bausteinsystemmit Attributen ergänzen und sich Objekte nach den eigenen Vorstellungenzusammenstellen.

Die erste Vorraussetzung ist wie erwähnt die Erweiterung der geometrischenPrimitiven durch eine Vorrichtung, die das Anfügen der Attribute an dieseObjekte ermöglicht. Um eine grosse Flexibilität bei der Zusammenstellung vonObjektattributen zu gewährleisten, wird z.B. als attributverwaltende Daten-struktur eine Liste gewählt. In diesem Fall müssen die geometrischen Objektemit einem Zeiger auf das erste zu erwartende Attribut ausgerüstet werden.Attribute erhalten ebenfalls solche Zeiger auf ein nachfolgendes Attribut, sodass sie in beliebiger Anzahl in einer Liste aneinandergehängt werden können.Zu allen Attributklassen, die in allgemeiner Form vorbereitet werden sollen,

73

wird dann eine Superklasse – z.B. TAttribute – deklariert und die Zeiger voneinem Attribut zum nächsten als Zeiger auf Objekte dieser Superklasse defi-niert. Dadurch ermöglicht man, dass erstens Attribute verschiedenen Typs inirgendeiner Reihenfolge aneinandergereiht und dass zweitens diese Attributepolymorphisch angesprochen werden können.

Werden Attribute als Instanzvariablen implementiert, so finden bei derenDeklaration verschiedene Datentypen wie z.B. String als Text oder Integer,LongInt und Real als Zahlentypen Verwendung. Um auch bei der Implemen-tation von Attributen als Objekte diese verschiedenen Datentypen einsetzen zukönnen, werden zur bereits erwähnten Superklasse TAttribute Subklassengebildet wie z.B. TStringAttr, TIntegerAttr, TLongIntAttr oder TRealAttr. DieSuperklasse TAttribute besitzt die Instanzvariablen fName (der Name desAttributs) und fNextAttr (Zeiger auf das nächste Attribut) sowie die MethodeIAttribute, wo diese Variablen auf einen Initialwert gesetzt werden. Die Sub-klassen enthalten die Instanzvariable fValue, die je nach Attributklasse vomTyp String, Integer, LongInt, Real oder eines andern Datentyps ist, sowie dieMethoden SetValue und GetValue, um den Wert des Attributs zu setzen undzu lesen. Durch Subklassieren können leicht Attribute erzeugt werden, dieandere, auch selbst definierte Datentypen verwenden und mit weiteren Metho-den ergänzt werden, die die Fähigkeiten und Einsatzmöglichkeiten dieserAttribute erweitern.

Im Beispiel aus dem Kapitel 2.3.4. wurde die Aufgabe, eine Quelle als Klasse zumodellieren, mit Hilfe einer Klasse TFountain gelöst, die als Subklasse vonTPoint für ihren thematischen Zusammenhang mit neuen Instanzvariablenund Methoden erweitert wurde. Werden Attribute nicht als Instanzvariablen,sondern als Objekte implementiert, muss anders vorgegangen werden. DieSubklasse von TPoint wird nicht vom Entwickler spezialisiert, sondern erstvom Benutzer der Applikation. Er wählt z.B. ein Attribut des Typs Text, umden Objekten der Kategorie 'Quelle' die Eigenschaft 'Name' zu geben. Dadurchwird im Programm der Zeiger des Punkt-Objekts auf ein Objekt der KlasseTStringAttr gerichtet. Fügt der Benutzer das Attribut 'Liter pro Sekunde' hinzu,so wird im Programm ein Objekt der Klasse TRealAttr gewählt, und der Zeigerdes ersten Attributs weist nun auf dieses neue. Das Anhängen von weiterenAttributen geschieht analog. Die neue Kategorie 'Quelle' (es handelt sich nichtmehr um die Quellen-Klasse mit dem Namen TFountain) könnte nach demAnfügen aller nötigen Attribute das in Abbildung 26 dargestellte Aussehenhaben.

6.2. Topologie

Bei der Implementation der raumbezogenen Klassen wurde auf den Einbezugvon Topologie verzichtet. Der Grund dafür liegt darin, dass der Aufwand zugross wäre, in den Klassen die Möglichkeit vorzubereiten, alle topologischenRelationen zwischen den Objekten verwenden zu können. Die einzelnen

74

TPoint

TStringAttr

TRealAttr

TRealAttr

TStringAttr

TRiverAttr

Kategorie 'Quelle'

Attribut 'Name'

Attribut 'Liter pro Sekunde'

Attribut 'Qualität'

Attribut 'Untegrund'

Attribut 'entspringender Fluss'

Abb. 26: Die Klasse TPoint durch Attribute erweitert zur Kategorie 'Quelle'

Fragestellungen, zu deren Lösung die raumbezogenen Klassen eingesetztwerden, verlangen unterschiedliche Aspekte dieser Objektbeziehungen, dieihrerseits verschieden implementiert werden können. Aus diesem Grund ist esnicht sinnvoll, die Klassenbibliothek mit einer allgemeinen Form räumlicherRelationen zu überladen.

Räumliche Beziehungen zwischen Objekten können als Attribute dieserObjekte angesehen werden. Dementsprechend können topologische Eigen-schaften auf eine der im letzten Kapitel vorgestellten Arten in eine Entwick-lung einbezogen werden. Der einfachste Weg ist wiederum die Subklassierungder bestehenden raumbezogenen Klassen und die Erweiterung dieser Subklas-sen mit der angemessenen Implementation der räumlichen Relationen. EinBeispiel einer solchen Verbindung von Objekten mittels einer Instanzvariablenist das Attribut fRiver der Klasse TFountain, die im Kapitel 2.3.4. vorgestelltwurde: Diese Instanzvariable stellt einen Zeiger des Punktobjekts auf das nach-folgende Objekt der Klasse TRiver, ein Linienobjekt, dar. Ebenfalls vorstellbarwäre die Entwicklung von neuen Klassen, die die einzelnen topologischenBeziehungen repräsentieren. Eine Möglichkeit wäre die Deklarierung einerabstrakten Superklasse – z.B. TRelation – sowie einer Subklasse für jedeverlangte Art der räumlichen Beziehung – z.B. für Punkt-Linien-, Linien-Linien- oder Punkt-Polygon-Beziehungen. Da diese Problematik aber für sichallein Thema einer Diplomarbeit sein könnte, soll an dieser Stelle nicht weiterdarauf eingegangen werden.

75

Anhang A:

Beispiele von Klassendeklarationen der raumbezogenen Klassen-bibliothek

Die folgenden Programmcode-Zeilen sind ausgewählte Beispiele der Klassender in dieser Arbeit besprochenen Klassenbibliothek. Deklarationen definierendie Instanzvariablen und Methoden einer Klasse und legen so das Aussehender Klasse nach aussen fest. Die eigentliche Implementation der Methodenwird an anderer Stelle im Programm erledigt und ist hier nicht von Interesse.Es handelt sich hier nicht um eine vollständige Liste aller Klassen, sondern umeine exemplarische Auswahl, die einige der in Kapitel 4.4. beschriebenenKonzepte illustrieren und so zum Verständnis beitragen sollen. Die vollstän-dige Auflistung aller Klassendeklararionen würde zu viel Platz in Anspruchnehmen und mehr zur Verwirrung als zur Illustration beitragen.

Im genannten Kapitel wurden nur wenige der Instanzvariablen und Methodender Klassen erwähnt. Mit einigen Ausnahmen soll auch hier nicht genauer aufdie einzelnen Details der Klassen eingegangen werden. (Einerseits sind dieFunktionen der Variablen und Methoden meist aus der Namensgebung ersicht-lich, andererseits sind die genauen Beschreibungen zur Klassenbibliothek ineinem Handbuch zusammengefasst, welches am Geographischen Institut derUniversität Zürich erhältlich ist.) Trotzdem kann man den Umfang der Dekla-rationen sowie den inneren Aufbau der Klassen anhand dieser Liste erkennenund einen Einblick in die Gestaltung der Schnittstellen der Methoden erhalten.

Auf einige, im Text nicht erwähnte Besonderheiten soll hier noch hingewiesenwerden.• Viele Deklarationen benötigen Konstanten. Diese sind den Klassen vorange-

stellt und können bei Gebrauch vom Entwickler verändert und so denProjektanforderungen angepasst werden.

• Der Datentyp VRect wird wie VPoint von MacApp zur Verfügung gestelltund besteht aus den vier Komponenten top, bottom, left und right, die alleals LongInt deklariert sind. Er wird für die Beschreibung von Rechtecken eingesetzt.

• Das Pascal-Statement override bedeutet, dass die zuletzt erwähnte Methodein der betreffenden Klasse überschrieben wird.

• In Programmen unterscheidet man zwei Arten von Variablen: statische unddynamische. Die meisten in Programmen verwendeten Variablen werden alsstatisch deklariert. Der Platz für solche Variablen im Arbeitsspeicher ist aberaus Gründen der Speicherarchitektur sehr beschränkt. Die Bearbeitung einerFragestellung, in der hunderttausende Punkte die Objekte im Raumbeschreiben, wäre auf diese Weise unmöglich. Im Gegensatz zu den stati-schen werden die dynamischen Variablen nicht von dieser restriktivenBeschränkung betroffen. Ein Beispiel von dynamischen Variablen sindListen. Um der internen Speicherverwaltung die Möglichkeit zu geben, dieseVariablen flexibel zu verwalten, sieht das Programmierungskonzept auf demMacintosh die Verwendung sog. Handles vor. (Sie sind als Pointer auf Poin-

76

ter zu verstehen.) Dieses Konzept wird bei jenen Klassen in der besproche-nen Bibliothek verwendet, die als Datenstruktur zur Verwaltung der Punkt-daten Arrays verwenden. Für diese Klassen wird im Anschluss an dieabstrakten Klassen eine solche Handle-Datenstruktur (PointArrayHandle)vordefiniert. (Für die exakte Definition und Verwendung von Handles sieheApple Computer, Inc. (I), 1988.)

Die abstrakten Klassen

typeTGeomObject = object(TObject)

fVisible: Boolean;fView: TView;fDocument: TDocument;fBoundaryBox: VRect;fNumberOfPoints: LongInt;procedure IGeomObject (theView: TView);procedure SetView (theView: TView);procedure SetDocument (theDocument: TDocument);procedure Draw (theMagnification: Integer);procedure Erase (theMagnification: Integer);procedure DrawInArea (theMagnification: Integer; theArea: VRect);procedure EraseInArea (theMagnification: Integer; theArea: VRect);procedure Move (theXOffset, theYOffset: LongInt);procedure SetNoP (theNumber: LongInt);procedure GetNoP (var theNumber: LongInt);procedure IncrementNoP;procedure DecrementNoP;procedure SetRelativeCoords (theOOPoint: VPoint);procedure SetTrueCoords (theOOPoint: VPoint);procedure MakeBoundaryBox;function ZoomedBoundaryBox (theMagnification: Integer): Rect;

end;

typeTGeomPrimitive = object(TGeomObject)

fSelected: Boolean;fColor: LongInt;procedure IGeomPrimitive (theView: TView);procedure Select (theMagnification: Integer);procedure Deselect (theMagnification: Integer);procedure Hilite (theMagnification: Integer);procedure EraseHilited (theMagnification: Integer);procedure SetColor (theColor: LongInt);procedure GetColor (var theColor: LongInt);

end;

constcDefaultNodeSize = 2;cDefaultVertexSize = 1;

typeTLine = object(TGeomPrimitive)

fNodeSize, fVertexSize: Integer;fNodesVisible, fVertexVisible: Boolean;fLineIsOpen: Boolean;procedure ILine (theView: TView; theNodesVisible, theVertexVisible: Boolean);procedure SetNodeSize (theSize: Integer);procedure GetNodeSize (var theSize: Integer);procedure SetVertexSize (theSize: Integer);

77

procedure GetVertexSize (var theSize: Integer);procedure SetNodeVisibility (theVisibility: Boolean);function NodesVisible: Boolean;procedure SetVertexVisibility (theVisibility: Boolean);function VertexVisible: Boolean;function CrossesRect (P1, P2: VPoint; theTLtoRB: Boolean; theArea: VRect): Boolean;

{Is used in the method 'DoItInArea' wich is defined in the subclasses.}end;

typePointArray = array[1..cMaxNumberOfArrayPoints] of VPoint;PointArray Ptr = PointArray ;PointArray Handle = ^PointArray Ptr; {this handle structur is used by various classes}

Punktlayer

Da in der Klasse TSquareNet die Verweise auf die in den jeweiligen Quadratenliegenden Punkte als Liste organisiert sind, wird vor der Klassendeklaration einsimples Listenelement als Datentyp definiert (LayerPoint). Für die Verein-fachung der Beschreibung der einzelnen Quadrate des Netztes wird der Daten-typ SquarePos eingeführt. Zur Zuweisung der Quadratnetz-Positionen dereinzelnen Punkte in einem Array schliesslich dient die Handle-StrukturSquarePosHandle.

typeTPointLayer = object(TGeomPrimitive)

fPoint: PointArrayHandle;fPointSize: Integer;fDrawn: Boolean;procedure IPointLayer (theView: TView; thePointSize: Integer);procedure Draw (theMagnification: Integer);override;procedure Erase (theMagnification: Integer);override;procedure DrawInArea (theMagnification: Integer; theArea: VRect);override;procedure EraseInArea (theMagnification: Integer; theArea: VRect);override;procedure Move (theXOffset, theYOffset: longint);override;procedure DrawPoint (theMagnification, thePointNumber: LongInt);procedure ErasePoint (theMagnification, thePointNumber: LongInt);procedure MovePoint (thePointNumber: LongInt; theXOffset, theYOffset: LongInt);procedure AddPoint (thePoint: VPoint);procedure RemovePoint (thePointNumber: LongInt);procedure SetPointSize (thePointSize: Integer);procedure MakeBoundaryBox;override;function ZoomedBoundaryBox (theMagnification: Integer): Rect;override;procedure SetRelativeCoords (theOOPoint: VPoint);override;procedure SetTrueCoords (theOOPoint: VPoint);override;

end;

78

typeLayerPointPtr = ^LayerPoint;LayerPoint = record

Layer: TPointLayer;Point: LongInt;NextPoint, PrevPoint: LayerPointPtr;

end;FirstLayerPoint = LayerPointPtr;

typeSquarePos = record

left, down: Integer;end;

typeTSquareNet = object(TGeomObject)

fPointInSquare: array[0..cMaxNumOfSquares, 0..cMaxNumOfSquares] of FirstLayerPoint;fSide: LongInt;fSquaresHor, fSquaresVert: Integer;procedure ISquareNet (theView: TView; theSide: LongInt; theSquaresHor, theSquaresVert: Integer);function IsInList (theLayer: TPointLayer; thePoint: LongInt; theSquare: SquarePos): Boolean;function IsVPointInList (theVPoint: VPoint; var theLayer: TPointLayer; var thePoint: LongInt):

Boolean;function IsPointNearVPointInList (theVPoint: VPoint; theDistance: LongInt; var theLayer:

TPointLayer; var thePoint: LongInt): Boolean;procedure GetLayerPoint (theLayer: TPointLayer; thePoint: LongInt; theSquare: SquarePos;

var theLayerPoint: LayerPointPtr);procedure InsertNewPoint (theLayer: TPointLayer; thePoint: LongInt; theSquare: SquarePos);procedure InsertPoint (thePoint: LayerPointPtr; theSquare: SquarePos);procedure RemovePoint (thePoint: LayerPointPtr; theSquare: SquarePos);procedure GetVisibleSquares (theVArea: VRect; var theFirstH, theFirstV, theLastH, theLastV:

Integer);procedure DrawSquare (theSquare: SquarePos; theMagnification: Integer);procedure EraseSquare (theSquare: SquarePos; theMagnification: Integer);procedure DrawPointsOfArray (theSquare: SquarePos; theArray: TPointLayer; theMagnification:

Integer);procedure ErasePointsOfArray (theSquare: SquarePos; theArray: TPointLayer; theMagnification:

Integer);procedure CalcSquareForPoint (thePoint: VPoint; var theSquare: SquarePos);

end;

typeSquarePosArray = array[1..cMaxNumberOfArrayPoints] of SquarePos;SquarePosPtr = ^SquarePosArray ;SquarePos Handle = ^SquarePosPtr;

typeTPointLayerForSquares = object(TPointLayer)

fSquareNet: TSquareNet;fPtInSquare: SquarePos Handle;procedure IPointArrayForSquares (theView: TView; thePointSize: Integer; theSquareNet:

TSquareNet);procedure DrawInArea (theMagnification: Integer; theArea: VRect);override;procedure EraseInArea (theMagnification: Integer; theArea: VRect);override;procedure Move (theXOffset, theYOffset: Longint);override;procedure MovePoint (thePointNumber: LongInt; theXOffset, theYOffset: LongInt);override;procedure AddPoint (thePoint: VPoint);override;procedure RemovePoint (thePointNumber: LongInt);override;

end;

79

Array-Linien

constcMaxNumberOfArrayPoints = 500;

typeTArrayLine = object(TLine)

fPoint: PointArrayHandle;procedure IArrayLine (theView: TView; theNodesVisible, theVertexVisible: Boolean);procedure Draw (theMagnification: Integer);override;procedure Erase (theMagnification: Integer);override;procedure DoItInArea (theMagnification: Integer; theArea: VRect; procedure DoItWithPiece

(theFirstPoint: LongInt; theMagnification: Integer));{Is used in the following two methods.}

procedure DrawInArea (theMagnification: Integer; theArea: VRect);override;procedure EraseInArea (theMagnification: Integer; theArea: VRect);override;procedure Deselect (theMagnification: Integer);override;procedure Hilite (theMagnification: Integer);override;procedure EraseHilited (theMagnification: Integer);override;procedure Move (theXOffset, theYOffset: LongInt);override;procedure MakeBoundaryBox;override;procedure DrawPiece (theFirstPoint: LongInt; theMagnification: Integer);procedure ErasePiece (theFirstPoint: LongInt; theMagnification: Integer);procedure DrawPoint (thePoint: LongInt; theMagnification: Integer; big: Boolean);procedure ErasePoint (thePoint: LongInt; theMagnification: Integer; big: Boolean);procedure MovePoint (thePoint: LongInt; theXOffset, theYOffset: Integer);procedure InsertPoint (thePointBefore: LongInt; theNewPoint: VPoint);procedure RemovePoint (thePoint: LongInt);procedure SetRelativeCoords (theOOPoint: VPoint);override;procedure SetTrueCoords (theOOPoint: VPoint);override;

end;

80

Listen-Linien

Für die Verwaltung der Punktkoordinaten in einer Liste wird zu Beginn derDeklaration ein einfaches Listenelement als Datenstruktur eingeführt (RPoint).

typeRPointer = ^RPoint;RPoint = record

h, v: longint;PrevPoint, FollPoint: RPointer;Number: Integer;

end;

typeTListLine = object(TLine)

fFirstPoint, fLastPoint: RPointer;procedure IListLine (theView: TView; theNodesVisible, theVertexVisible: Boolean;

theNumberOfPoints: LongInt);procedure Draw (theMagnification: Integer);override;procedure Erase (theMagnification: Integer);override;procedure DoItInArea (theMagnification: Integer; theArea: VRect; procedure DoItWithPiece

(theFirstPoint: RPointer; theMagnification: Integer));{Is used in the following two methods.}

procedure DrawInArea (theMagnification: Integer; theArea: VRect);override;procedure EraseInArea (theMagnification: Integer; theArea: VRect);override;procedure Deselect (theMagnification: Integer);override;procedure Hilite (theMagnification: Integer);override;procedure EraseHilited (theMagnification: Integer);override;procedure Move (theXOffset, theYOffset: LongInt);override;procedure MakeBoundaryBox;override;procedure DrawPiece (theFirstPoint: RPointer; theMagnification: Integer);procedure ErasePiece (theFirstPoint: RPointer; theMagnification: Integer);procedure DrawPoint (thePoint: RPointer; theMagnification: Integer; big: Boolean);procedure ErasePoint (thePoint: RPointer; theMagnification: Integer; big: Boolean);procedure InsertPoint (thePointBefore: RPointer; theNewPoint: VPoint);procedure MovePoint (thePoint: RPointer; theXOffset, theYOffset: LongInt);procedure RemovePoint (thePoint: RPointer);procedure SetRelativeCoords (theOOPoint: VPoint);override;procedure SetTrueCoords (theOOPoint: VPoint);override;procedure Free;override;

end;

81

Anhang B:

Klassendeklaration von TDPLine sowie die für die Linienfilte-rung verantwortlichen Methoden

Der Pascal-Code der Deklaration der in Kapitel 5.2.2. beschriebene KlasseTDPLine ist hier zur Illustration und für das tiefere Verständnis aufgelistet.Für den Array fSignificant, der für jeden Punkt seine Zugehörigkeit zur gefil-terten Linie enthält, wird die Handle-Struktur BoolArrayHandle vordefiniert.Zur Referenzierung solcher Handle-Strukturen wird die Zeichenkombination'^^' verwendet; so bedeutet z.B. fPoint^^[17].h die x-Koordinate des 17. Punk-tes der Linie. (Der Begriff 'Handle' wird im Anhang A erläutert.) Nach derKlassendeklaration folgt die Implemetierung der Methoden DouglasPoiker,DoOn2Points und Dist, die die Filterung der Linie übernehmen und imerwähnten Kapitel besprochen werden.

typeBoolArray = array[1..cMaxNumberOfArrayPoints] of Boolean;BoolArrayPtr = ^BoolArray;BoolArrayHandle = ^BoolArrayPtr;

typeTDPLine = object(TArrayLine)

fSignificant: BoolArrayHandle;fFiltered: Boolean;fDPColor: LongInt;procedure IDPLine (theView: TView; theNodesVisible, theVertexVisible: Boolean;

theNumberOfPoints: LongInt; theLevel: LongInt);procedure Draw (theMagnification: Integer);override;procedure DrawDP (theMagnification: Integer);procedure Erase (theMagnification: Integer);override;procedure EraseDP (theMagnification: Integer);procedure InsertPoint (thePointBefore: LongInt; theNewPoint: VPoint);override;procedure RemovePoint (thePoint: LongInt);override;procedure SetSignificanceOfPoint (thePoint: LongInt; theSignificance: Boolean);procedure DoDouglasPeucker (theMagnification: Integer);procedure DoOn2Points (s, t: LongInt);function Dist (LP1, LP2, P: VPoint): LongInt;procedure SetLevel (theLevel: LongInt);procedure GetLevel (var theLevel: LongInt);procedure Free;override;

end;

82

••• ••• •••

procedure TDPLine.DoDouglasPeucker (theMagnification: Integer);var

i: LongInt;begin

if fView.Focus and fFiltered thenEraseDP (theMagnification); {erase filtered line}

fSignificant^^[1] := TRUE;fSignificant^^[fNumberOfPoints] := TRUE; {set significance of points ...}for i := 2 to fNumberOfPoints - 1 do {... to not filtered}

fSignificant^^[i] := FALSE;DoOn2Points(1, fNumberOfPoints); {filter the line}fFiltered := TRUE;DrawDP(theMagnification); {draw filtered line}

end;

procedure TDPLine.DoOn2Points (s, t: LongInt);var

i, aMaxDistPoint: LongInt;aDist, aMaxDist: LongInt;

beginif t - s > 1 then

beginaMaxDist := 0;aMaxDistPoint := 0;for i := s + 1 to t - 1 do {look for the point with maximum distance}

beginaDist := Dist(fPoint^^[s], fPoint^^[t], fPoint^^[i]);if aDist > aMaxDist then

beginaMaxDist := aDist;aMaxDistPoint := i;

end;end;

if aMaxDist > fLevel then {if maximum distance is bigger than fLevel ...}begin

fSignificant^^[aMaxDistPoint] := TRUE; {... mark the point as filtered ...}DoOn2Points(s, aMaxDistPoint); {... and filter the right ...}DoOn2Points(aMaxDistPoint, t); {... and the left part}

endend;

end;

function TDPLine.Dist (LP1, LP2, P: VPoint): LongInt;var {LinePoint1, LinePoint2, Point}

a, b, d: Real;begin

if LP1.h = LP2.h thend := abs(LP1.v - P.v);

elsebegin

a := (LP1.v - LP2.v) / (LP1.h - LP2.h);b := LP1.v - a * LP1.h;d := abs((a * P.h - P.v + b) / sqrt(a * a + 1));

end;Dist := round(d);

end;

••• ••• •••

83

Literaturverzeichnis

APPLE COMPUTER , INC. (I)Inside Macintosh, Volumes I, II, and IIICupertino, Calif.: Apple Computer, Inc. 1988

APPLE COMPUTER , INC. (II)MacApp 2.0, General Reference, Beta DraftCupertino, Calif.: Apple Computer, Inc. 1989

APPLE DEVELOPER UNIVERSITYIntroduction to Object-Oriented Programming (CD)Cupertino, Calif.: Apple Computer, Inc. 1991

BORENSTEIN, P., MATTSON, J.THINK Pascal: User ManualCupertino, Calif.: Symantec 1990

BORENSTEIN, P., MATTSON, J.THINK Pascal: Object-Oriented Programming ManualCupertino, Calif.: Symantec 1991

BURROUGH, P.A.Principles of Geographical Information Systems for Land Resource AssessmentOxford: Oxford University Press, 1986

COAD, P., YOURDON, EObject-Oriented DesignEngelwood Cliffs, New J.: Prentice Hall International Editions 1991

COX, B.J., NOVOBILSKI, A.J.Object-Oriented Programming: An Evolutionary ApproachReading, Mass.: Addison-Wesley Publishing Company 1991

DOUGLAS, D.H., POIKER (VORMALS PEUCKER), T.K.Algorithms for the Reduction of the Number of Points Required to Represent a Digitized Line or its Caricaturein: The Canadian Cartographer, 1973, Vol. 10, No. 2, pp. 112-122

GOLDSTEIN, N., ALGER, J.Developing Object-Oriented Software for the Macintosh: Analysis, Design,ProgrammingReading, Mass.: Addison-Wesley Publishing Company 1992

KEMP, Z.An Object-Oriented Model for Spatial Datain: Proceedings of the 4th International Symposium on Spatial Data Handling 1990, Zürich, Vol. 2, pp. 659-668

ORENSTEIN, J.A.An Object-Oriented Approach to Spatial Data Processingin: Proceedings of the 4th International Symposium on Spatial Data Handling 1990, Zürich, Vol. 2, pp. 669-678

84

SCHMUCKER, K.J.Objekt-Oriented Programming for the MacintoshHasbrouck Heights, New J.: Hayden Book Company 1986

SPHAR, C.Object-Oriented Programming PowerRedmont, Wash.: Microsoft Press 1991

WILSON, D.A., ROSENSTEIN, L.A., SHAFER, D. (I)Programming with MacAppReading, Mass.: Addison-Wesley Publishing Company 1990

WILSON, D.A., ROSENSTEIN, L.A., SHAFER, D. (II)C++ Programming with MacAppReading, Mass.: Addison-Wesley Publishing Company 1990

WORBOYS, M.F., HEARNSHAW, H.M., MAGUIRE, D.J.Object-Oriented Data and Query Modelling for Geographical Information Systemsin: Proceedings of the 4th International Symposium on Spatial Data Handling 1990, Zürich, Vol. 2, pp. 679-688

ZAHN, F., MARK, D.M.Object-Oriented Spatial Knowledge Representation and Processing: Formalizationof Core Classes and their Relationshipsin: Proceedings of the 5th International Symposium on Spatial Data Handling 1992, Charleston, South Carolina, Vol. 2, pp. 662-671