57
Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E. Horn Praktikumsdokumentation Aufgabe: Persistente Verwaltung von Konten einer Bank in einem Kontenregister Autor: Christoph Stöpel, Matr.-Nr. 711071 ([email protected]) Basismaschine: Microsoft Visual Studio 6 SP5, Microsoft Foundation Classes (MFC), Microsoft Windows XP Professional Potsdam, den 29.08.2003 Betreuer: Bearbeitungsvermerk:

Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E. Horn

Praktikumsdokumentation Aufgabe: Persistente Verwaltung von Konten einer Bank in einem Kontenregister Autor: Christoph Stöpel, Matr.-Nr. 711071 ([email protected]) Basismaschine: Microsoft Visual Studio 6 SP5,

Microsoft Foundation Classes (MFC), Microsoft Windows XP Professional Potsdam, den 29.08.2003 Betreuer: Bearbeitungsvermerk:

Page 2: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

II

Page 3: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

III

Inhaltsverzeichnis

Kapitel 1 Aufgabenstellung..................................................................................................................... 1 Kapitel 2 Erläuterung der Aufgabenstellung........................................................................................... 3

2.1 Lesart des Belegs........................................................................................................................... 3 2.2 Erläuterung .................................................................................................................................... 3 2.3 Verwendung von Klassenbibliotheken.......................................................................................... 4 2.4 MVC-Konzept ............................................................................................................................... 4

Kapitel 3 Entwurf des Lösungsmodells................................................................................................... 7 3.1 Darstellung der Lösungsidee ......................................................................................................... 7 3.2 Vor- und Nachbedingungen der Methoden ................................................................................... 8 3.3 Dialogdatensichten ........................................................................................................................ 9 3.4 Darstellung der Architektur des Programmsystems .................................................................... 12

Kapitel 4 Realisierung des Lösungsmodells.......................................................................................... 15 4.1 Namenskonventionen .................................................................................................................. 15 4.2 Realisierung/ Implementation ..................................................................................................... 16

4.2.1 Allgemeine Bemerkungen.................................................................................................. 16 4.2.2 MVC-Konzept/ Ereignisbehandlung.................................................................................. 17 4.2.3 Architekturinformationen/ RTTI........................................................................................ 18 4.2.4 Objektkonstruktion............................................................................................................. 19 4.2.5 Polymorphe Mengen/ Iteratoren ........................................................................................ 20 4.2.6 Objektpersistenz................................................................................................................. 21

4.3 Testergebnisse ............................................................................................................................. 23 Kapitel 5 Wertung des erreichten Ergebnisses ...................................................................................... 33 Anhang A Die Quelltexte des Praktikums........................................................................................... A-1

A.1 Account.h ................................................................................................................................. A-1 A.2 Giro.h........................................................................................................................................ A-2 A.3 StudentGiro.h ........................................................................................................................... A-3 A.4 Savings.h .................................................................................................................................. A-3 A.5 Register.h.................................................................................................................................. A-4 A.6 GSEBank.h ............................................................................................................................... A-5 A.7 GSEBankDoc.h ........................................................................................................................ A-6 A.8 GSEBankView.h ...................................................................................................................... A-8 A.9 ManageDlg.h ............................................................................................................................ A-9 A.10 DateChooser.h ...................................................................................................................... A-10 A.11 InputBox.h............................................................................................................................ A-11

Anhang B Abbildungsverzeichnis..................................................................................................... B-13 Anhang C Literaturverzeichnis ......................................................................................................... C-15

Page 4: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

IV

Anhang D Eidesstattliche Erklärung ................................................................................................. D-17

Page 5: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

V

Page 6: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E
Page 7: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

1

Kapitel 1 Aufgabenstellung Die vollständige Aufgabenstellung befindet sich einschließlich der CEDL-Beschreibung der zu erstellenden Klassen am Ende dieser Dokumentation angeheftet.

Page 8: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

2

Page 9: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

3

Kapitel 2 Erläuterung der Aufgabenstellung

2.1 Lesart des Belegs Dieser Beleg ist in 4 Hauptteile gegliedert, die zur besseren Strukturierung wiederum untergliedert sein können.

• Aufgabenstellung (Kapitel 1 und 2): gibt die Aufgabenstellung wieder und soll mit allgemeinen Erläuterungen das Verständnis für die Anforderungen und Ziele des Praktikums vertiefen

• Lösungsmodell (Kapitel 3): beschreibt allgemeine Anforderungen an Klassenbibliotheken um verwendetete Patterns (Entwurfsmuster) zu realisieren und mögliche Arbeitsabläufe, die durch die grafische Oberfläche des Programmsystems unterstützt werden sollen

• Realisierung (Kapitel 4): geht konkret auf die programmtechnische Lösung der Aufgabenstellung ein und beschreibt besonders hervorzuhebende Lösungsansätze sowie Methoden und Maßnahmen der Qualitätssicherung

• Ergebnisse und Quelltext (Kapitel 5 und Anhang): wertet die erreichten Ergebnisse und beinhaltet Ausdrucke der Quelltexte (oder zumindest der Schnittstellen) um den direkten Vergleich mit der vorgegebenen Spezifikation zu ermöglichen und so den Nachweis der Funktionalität zu erbringen

Die Dokumentation ist in der Schriftart Times New Roman verfasst. Programmtechnische Bezeichner wie Klassen- oder Variablennamen sind in der Schriftart Courier New hervorgehoben. Für Quelltextausschnitte wird ebenfalls eine nicht-proportionale Schrift verwendet und programmier-sprachliche Schlüsselworte farbig hervorgehoben (Syntax-Highlight). Besonders wichtige Sachverhalte in einem Kontext werden kursiv dargestellt. Bei der Besprechung einzelner Methoden werden Parameter in der Signatur oft weggelassen, sofern diese nicht Gegenstand der Betrachtung sind. Auch Rückgabewerte werden besonders dann nicht aufgeführt, wenn es nur um die Identifikation signifikanter Stellen im Quelltext geht. Das impliziert aber nicht, dass es Parameter oder Rückgabewerte nicht gibt, oder diese vom Typ void sind. Grafische Darstellungen von Klassenhierarchien und Beziehungen innerhalb des zu erstellenden Programmsystems sind durchgängig in der Unified Modeling Language (UML) aufgeführt, wie sie durch die OMG spezifiziert wurde (vgl. http://www.omg.org/uml/ ). Produktnamen und –marken werden in dieser Dokumentation nicht als solche gekennzeichnet (®,™), dennoch ist bei den meisten davon auszugehen, dass sie eingetragene Warenzeichen der jeweiligen Inhaber sind.

2.2 Erläuterung Ziel dieses Praktikums ist die Erstellung einer objektorientierten Lösung zur persistenten Verwaltung von Konten einer Bank unter Verwendung einer Klassenbibliothek und des MVC-Konzepts. Es ist eine in Form einer CEDL-Beschreibung vorgegebene Klassen-Hierarchie in Anlehnung an praktische Belange einer Bank zu implementieren. Dabei ist eine der Programmiersprachen C++, C# oder Java zu verwenden. Die Semantik des Vererbungsbaumes ist hierbei die Verfeinerung und Erweiterung eines allgemeinen Kontos (Wurzelklasse CAccount) über ein Girokonto bis hin zu einem Studentenkonto mit Sonderkonditionen. Persistent bedeutet in diesem Zusammenhang, dass der Programmzustand (bereits erstellte Konten im Register) über die Lebenszeit des eigentlichen Programms hinaus gespeichert und zu späteren Zeitpunkten wiederhergestellt werden kann.

Page 10: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

4

2.3 Verwendung von Klassenbibliotheken Zur Realisierung der Mengenorganisation einer Anzahl von Konten verschiedener Art aber auch zur Verwendung grafischer Bauelemente ist eine Klassenbibliothek nachzunutzen. Zur Auswahl stehen dabei die Java Foundation Classes (JFC), die Qt, die Foundation Class Library (FCL) des .NET Frameworks sowie die Microsoft Foundation Classes. „Klassenbibliotheken sind komplexe Systeme von Klassen und Frameworks, die allgemeinen, applikationsunabhängigen Charakter haben und wiederverwendbares Wissen [...] darstellen“ ([HR02], S. 281). In diesem Sinne sind Bibliotheken also zunächst unabhängig vom Problem des Entwicklers und benötigen einiges an Vorarbeit bzw. Anpassung des avisierten Lösungsmodells.

• Da Klassenbibliotheken gewöhnlich nur für die Nachnutzung, nicht aber die Modifikation vorgesehen sind (i.A. auch nicht im Quelltext vorliegen), kommt es besonders darauf an, sich in verwendete Modelle und Hierarchien einzuarbeiten, um sie sinnvoll und zweckmäßig zur Problemlösung einsetzen zu können.

• Oft werden eine oder mehrere Wurzelklassen eingeführt, die eine gewisse Basisfunktionalität bereitstellen. Eine Integration der eigenen Klassen in die benutzte Hierarchie ist meist erforderlich, um alle Aspekte nutzen zu können. Ebenso sind im Sinne der Heterogenität des Programmsystems oft elementare Datentypen durch Klassen der verwendeten Bibliothek zu ersetzen. Eine Wiederverwendung bereits erstellter Klassen ist damit nicht ohne weitere Anpassungen zugunsten der Klassenbibliothek möglich.

• Komplexe Verwaltung von grafischen Oberflächen wird durch gebotene Applikationsrahmen meist stark vereinfacht und auf einfache Funktionsaufrufe zurückgeführt. Trotzdem sind meist zumindest Grundkenntnisse des darunter liegenden Fenstersystems (Windows, X11 u.a.) notwendig.

• Ohne die Benutzung (und damit als Vorraussetzung die Einarbeitung) einer entsprechenden Entwicklungsumgebung sind alle Facetten einer Klassenbibliothek nicht überschaubar. Bei Nutzung dieser ermöglichen aber verschiedene Automatismen (Wizards) dem Programmierer im evolutionären Entwicklungsprozess schnell zu lauffähigen Programmen zu kommen.

Zusammenfassend kann man sagen, dass Klassenbibliotheken die Freiheit des Programmierers zwar einschränken, da verschiedene Nutzungsbedingungen einzuhalten sind, die Vorteile der Vorfertigung komplexer Zusammenhänge jedoch überwiegen.

2.4 MVC-Konzept Das MVC-Konzept ist ein Entwurfsmuster (engl. Pattern) mit dem Probleme in verschiedene, in sich abgeschlossene Bestandteile zerlegt und somit an verschiedenen Stellen entwickelt werden können. Beim MVC-Konzept sind dies die 3 Teilsysteme Model, View und Controller durch die eine Dekomposition erreicht wird. Im folgenden werden die englischen Begriffe verwendet, da diese im Bereich der Softwareentwicklung international etabliert sind. Den Kern jeder MVC-basierten Anwendung bildet das Model. Es repräsentiert die Datenverwaltungsschicht und hat für gewöhnlich keinen Zugriff auf andere Bauelemente des Programmsystems. In [Abbildung 1] sind daher keine Importe ausgehend vom Teilsystem Model eingezeichnet. Idealerweise kennt das Model nur den Kontext seiner zu verwaltenden Daten und ist unabhängig von der Repräsentation. Diese erfolgt in grafisch orientierten Benutzersystemen meist in Fenstern und untergeordneten Bauelementen und wird durch die sog. View repräsentiert. Zur Darstellung der Daten benötigt die View Zugriff auf das darunterliegende Model, um dessen Daten z.B. in einem Listensteuerelement zu visualisieren. Im klassischen MVC-Konzept kann die View keine Benutzereingaben annehmen, sondern sollte auf Anweisungen des Controllers reagieren.

Page 11: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

5

Der Controller übernimmt die Steuerung der Eingaben und damit des gesamten Programmsystems (der Applikation). Er nimmt Eingaben entgegen und leitet diese an die View oder direkt an das Model weiter. Dazu muss er beide Elemente natürlich kennen, was im Bild unten durch import-beziehungen dargestellt wird. So können beispielsweise Daten im Model geändert werden, wobei sich auch die View aktualisieren muss. Entsprechende Aktionen (objektorientiert: Nachrichten) werden im klassischen Konzept ausschließlich vom Controller verwaltet.

Controller

ViewModel

«import»

«import»

«import»

Abbildung 1: Teilsystemstruktur des MVC-Konzepts

Das MVC-Pattern wird sehr unterschiedlich durch Klassenbibliotheken unterstützt. Aktuelle Frameworks verschmelzen in Anlehnung an das Publisher-Subscriber-Pattern den Controller und die View zu einem Bestandteil und die View kann selbst Ereignisse entgegennehmen sowie auslösen. Inwiefern dies auf die hier verwendete Lösungsidee Einfluss hat, wird im Kapitel 4 besprochen.

Page 12: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

6

Page 13: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

7

Kapitel 3 Entwurf des Lösungsmodells Dieser Abschnitt wird sich größtenteils rein hypothetisch auf Anforderungen an Klassenbibliotheken beziehen, die sich aus der Aufgabenstellung ergeben, und die Lösungsidee losgelöst von einer Programmiersprache erläutern.

3.1 Darstellung der Lösungsidee Das Programm soll eine Programmoberfläche als Repräsentation der Mengenverwaltungsklasse CRegister bieten und damit gängige Operationen wie das Einfügen, Suchen und Löschen von Konten durch den Anwender unterstützen. Dem Nutzer muss es möglich sein, alle Konten der Hierarchie (also CAccount, CGiro, CStudentGiro und CSavings) neu zu erstellen und auch später zu bearbeiten. Dazu muss ein Persistenzhaltungsmechanismus zur Verfügung gestellt werden, der idealerweise mithilfe einer Klassenbibliothek realisiert wird. Das Register beinhaltet Attribute für das Erstellungsdatum und zur Selbstbeschreibung (RegisterInformation). Während letzteres beliebig durch den Anwender ausgelesen und verändert werden kann, soll DateOfCreation nur durch das Laden aus einer Datei oder die Neuanlage (sprich: Konstruktoraufruf) belegt werden. In das Register darf jedes Konto nur einmal eingefügt werden (Mengeneigenschaft), wobei sich die Gleichheit hier nur auf den Vergleich des impliziten Schlüssels bezieht - dieser wird zur Laufzeit aus wenigen ausgezeichneten Attributen gebildet. In der Lösung wird die Menge polymorph realisiert, so dass alle Arten von Konten, die von CAccount erben, verwaltet werden können. Dies bringt zwar zusätzlichen Aufwand durch Typprüfungen mit sich, erleichtert aber die Organisation dadurch, dass nur eine Mengeninstanz benötigt wird. Für einen hohen Grad an Wiederverwendung, soll das Programmsystem nach dem MVC-Konzept erstellt werden. Dadurch wird auch die „Separation of Concerns“, wie sie im Teile-und-Herrsche-Prinzip gefordert wird, erreicht. Später können dann einzelne Komponenten ausgewechselt werden ohne das ganze Programmsystem anpassen zu müssen. Eine Klassenbibliothek sollte diese Separation unterstützen, indem die Klassen CModel, CView und CController in irgendeiner Form (z.B. für Vererbung) zur Nachnutzung mitgeliefert werden. Die Klasse CModel ist als eine Ausprägung der Register-Klasse zu verstehen. Das Model verwaltet ein Menge von Konten, wobei eine Mengenklasse CSet durch die verwendete Bibliothek zur Verfügung gestellt werden soll. Als Abstraktion der Datenhaltungschichungsschicht ist das Model auch dafür verantwortlich, seine Daten persistent abzulegen (u.a. auf Anweisung des Controllers). Dafür ist eine Klasse CArchive nötig, die die Kommunikation mit dem Datenträger kapselt, da hier die Persistenzhaltung mit Archiven benutzt wird. Weitere Möglichkeiten wären die Persistenzhaltung ohne Archiv, wobei allerdings sämtliche Details selbst implementiert werden müssten und der Vorteil einer Klassenbibliothek dahin wäre, oder die Speicherung mit Versionshaltung, was hier aber weit über das Ziel hinausgeht. Die Klasse CView ist für die Darstellung der Daten des Models verantwortlich. Für sinnvolles Arbeiten sollte die Klassenbibliothek grafische Steuerelemente wie Buttons, Eingabefelder, Checkboxen u.ä. zur Verfügung stellen, deren Ereignisse (durch den Nutzer ausgelöste Aktionen) an den Controller weitergeleitet werden können, so dass das Zusammenspiel des MVC-Konzepts umgesetzt werden kann. CController sollte die Ereignisbehandlung der Klassenbibliothek kapseln und Nachrichten an betroffene Methoden delegieren. Dabei ist es von Vorteil, wenn Werkzeuge bereitgestellt werden, die das darunterliegende Konzept des Betriebssystems (API-Aufrufe) oder der virtuellen Maschine möglichst vereinfachen oder verbergen.

Page 14: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

8

Zur Gewährleistung einer gewissen Grundfunktionalität (z.B. Metainformationen) sollten alle (oder zumindest die meisten) Klassen der Bibliothek von einer Basisklasse erben. Von dieser soll auch CAccount abgeleitet sein und sich so „nahtlos“ einfügen. Zur Integration der eigenen Klassen in die verwendete Bibliothek, werden anstelle selbst erstellter Hilfsklassen bereits vorgefertigte verwendet. Exemplarisch können dies String-, Währungs- oder Datumsklassen sein. Wie weit diese Integration in der Praxis geht, wird im Abschnitt 4.2 beschrieben.

3.2 Vor- und Nachbedingungen der Methoden Im folgenden werden die Vor- und Nachbedingungen von Methoden der zu erstellenden Klassen in Kategorien zusammengefasst aufgeführt, da eine ausführliche Betrachtung bereits im ersten Beleg erfolgte und die Klassen im wesentlichen dieselben sind. Lediglich auf CRegister wird näher eingegangen, denn aufgrund der Einbettung in eine Klassenbibliothek sind einige Erweiterungen vorzunehmen.

• Konstruktoren haben keine Vorbedingungen (außer das genügend freier Speicher vorhanden ist, was bei aktuellen Rechnern kein Problem sein sollte), die Nachbedingungen unterscheiden sich je nach Art der Konstruktors

o Der Standardkonstruktor hat im Gegensatz zum ersten Praktikum keine Implementation mehr, da vorgegebene Initialisierungen bei der Deserialisierung ersetzt werden würden. Es wird ein Speicherobjekt erstellt, dessen Invarianz in den meisten Fällen false ergeben wird.

o Der Initialisierungskonstruktor erstellt ein Speicherobjekt anhand der übergebenen Werte. Auch hier wird noch keine Prüfung der Invarianz vorgenommen.

o Der Kopierkonstruktor übernimmt die Attribute einer bereits vorhandenen Instanz und damit auch dessen Invarianz.

• Destruktoren haben keine Vorbedingungen, da „Bereinigungsarbeiten“ immer ausgeführt werden sollten. Im Ergebnis ist die Instanz aus dem Speicher entfernt und verwendete Ressourcen sollten freigegeben werden. Daher sind Exceptions in Destruktoren unbedingt zu vermeiden. In diesem Praktikum besteht das Problem allerdings nicht.

• Get-Methoden liefern einen Wert nach außen und haben definitionsgemäß nur lesenden Zugriff auf Instanzvariablen (dies kann zumindest in C++ und C# auch programmatisch gesichert werden). Daher haben sie weder Vor- noch Nachbedingungen.

• Für Methoden die lediglich den Inhalt von Instanzen bewerten (ClassInvariant, Equal, EqualValue, EqualKey, KeyOf, Show) gelten dieselben Aussagen wie bei Get-Methoden.

• Set-Methoden ersetzen den Wert einer Instanzvariablen durch einen neuen. Per Implementationsentscheidung wird hierbei keine Sicherheitskopie für Invarianzprüfungen erzeugt, so dass sich die Invarianz der Instanz ändern kann. Dies zu prüfen, bleibt der Verantwortung des Nutzers der Klassen überlassen, steigert aber die Performance erheblich.

• Vererbte nicht-virtuelle Methoden ändern ihre Vor- und Nachbedingungen im Zuge der Vererbung nicht und können bereits in der Klasse, in der sie eingeführt werden, in eine der oben genannten Kategorien eingeordnet werden.

• Vererbte virtuelle Methoden können ihre Bedingungen durch die Überschreibung ändern. Dies ist hier aber nicht der Fall, so dass sie in die Kategorie der Basisklasse einzuordnen sind.

Page 15: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

9

Vor- und Nachbedingungen von CRegister: Card Vor: keine Nach: keine

Bem: Gibt Anzahl der Konten im Register zurück ClassInvariant Vor: keine Nach: keine Bem: Überprüft Attribute und jedes einzelne Mengenelement auf Invarianz Copy Vor: Invarianz der übergeben Instanz ist true Nach: Attribute werden gemäß Vorlage übenommen Bem: Kopiert auch die Mengenelemente mit Equal Vor: keine Nach: keine Bem: Vergleicht Adressen von Instanzen (Objektäquivalenz) EqualValue Vor: keine Nach: keine Bem: Vergleicht Attribute von Instanzen (Wertäquivalenz) EqualKey Vor: keine Nach: keine Bem: Vergleicht die Schlüssel von Instanzen (Schlüsseläquivalenz) Find Vor: keine Nach: Cursor wird auf Fundstelle gesetzt oder beibehalten Bem: Sucht in der Menge nach dem übergebenen Objekt Generate Vor: keine Nach: neues Speicherobjekt gemäß Muster erstellt (konstruiert und kopiert) GetActual Vor: Mindestens ein Element in der Menge Nach: keine Bem: Gibt Objekt am Cursor zurück GetFirst Vor: Mindestens ein Element in der Menge Nach: Cursor steht auf dem ersten Mengenelement GetNext Vor: letztes Element noch nicht erreicht Nach: Cursor wird um 1 weitergeschoben Insert Vor: Objekt noch nicht enthalten (Schlüsseläquivalenz), noch Speicher frei Nach: Objekt in Menge eingefügt KeyOf Vor: keine Nach: keine Bem: bildet den impliziten Schlüssel für die Instanz Scratch: Vor: Cursor auf gültigem Element Nach: Aktuelles Element gelöscht, Cursor auf erstem Element

3.3 Dialogdatensichten In diesem Abschnitt soll die Funktionsweise der Benutzeroberfläche und damit die Bedien-Möglichkeiten durch den Anwender vorgestellt werden. Dazu wird jeweils ein Screenshot (Bildschirmfoto) des realen Programms gezeigt und im folgenden beschrieben.

Page 16: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

10

Abbildung 2: Hauptfenster des Programmsystems

Das Hauptfenster stellt einen Überblick über den Inhalt des Registers (resp. Models) dar und zeigt die Attribute an, die allen Elementen der polymorphen Menge gemein sind, also in der Basisklasse CAccount der Kontenhierarchie deklariert sind. Diese Attribute müssen über öffentliche Get-Methoden abfragbar und ohne Cast auf abgeleitete Klassen erreichbar sein. So gesehen zeigt die Hauptansicht (View) den kleinsten gemeinsamen Nenner der vorhandenen Daten. Wie bei grafischen Oberflächen üblich, diktiert der Nutzer dem Programm die Vorgehensweise und nicht umgekehrt. Dabei hat er stets mehrere Wege zur Auswahl, die zum selben Ziel führen. Im Hauptfenster des Bankverwaltungsprogramms sollen sich detaillierte Angaben zu einem Konto beispielsweise über einen einfachen Doppelklick in die Liste realisieren lassen. Es existiert aber auch ein Menüpunkt und ein Symbolleisten-Button, die das ausgewählte Konto im einzelnen (zum editieren) anzeigen. Befehle, die sowohl vom Hauptmenü als auch durch die Symbolleiste entgegengenommen werden, sind insbesondere:

Datei/ Neu Erstellt ein neues (leeres) Registers, Speichernachfrage bei zuvor geändertem Model

Datei/ Öffnen... Zeigt den Auswahldialog (Klassenbibliothek) für eine zu öffnende Datei an

Datei/ Speichern Speichert das Model samt Inhalt persistent

Verwalten/ Account erstellen... Erstellt ein neues Konto aus der Hierarchie und fügt es in das Register ein

Verwalten/ Account bearbeiten... Zeigt ein bereits vorhandenes Konto zum Editieren an

Verwalten/ Account löschen Löscht das im Hauptfenster selektierte Konto

Aktion/ Einzahlen... Betrag in selektiertes Konto einzahlen

Aktion/ Auszahlen... Betrag vom ausgewählten Konto abheben

?/ Info Programminformationen anzeigen

Page 17: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

11

Menüeintrage, denen 3 Punkte nachgestellt sind, öffnen weitere Dialoge (Fenster), in denen der Nutzer Eingaben machen kann. Alle anderen führen unmittelbar eine Aktion aus.

Abbildung 3: Dialog zur Verwaltung von Konten

Dieses Fenster kann in verschiedenen Varianten auftreten: Zur Anzeige eines Kontos sind alle Felder auf „nur lesend“ oder inaktiv gesetzt und stellen sämtliche Attribute dar. Um die Felder im Bereich „Erweitert“ zu füllen, ist Typecasting notwendig. Zum Edieren eines Kontos werden alle Attribute angezeigt und zusätzlich Felder zu denen Set-Methoden existieren, editierbar gesetzt. Zum Neuerstellen eines Kontos wird die Auswahl-Combobox editierbar gemacht und je nach Auswahl des Anwenders (Account, Giro usw.) die benötigten Eingabefelder freigeschaltet. Die Verwendung dieses einen Dialoges für viele Zwecke stellt einen hohen Grad der Nachnutzung dar und erlaubt einen direkten Vergleich der verschieden Konton.

Zudem wird der Anwender an eine einheitliche, intuitive Oberfläche gewöhnt, die den flüssigen Arbeitsablauf fördern soll.

Abbildung 4: Standard Eingabeaufforderung

Auch der obige Dialog kann in mehreren Varianten auftreten und ist auf Wiederverwendbarkeit ausgelegt. Er wird überall benutzt, wo kurze Eingaben erforderlich sind. So zum Beispiel:

• beim Auslesen und Setzen der Beschreibung eines Registers • zur Angabe eines einzuzahlenden Betrages • zur Festlegung eines auszuzahlenden Betrages

Page 18: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

12

Mit diesen wenigen Menüeintragen und Dialogen kann bereits die gesamte Funktionalität des Programms geboten werden. Zur komfortablen Datumseingabe wird allerdings noch das folgende Fenster verwendet.

Abbildung 5: Dialog zur einfachen Datumsauswahl

Hier ist es möglich monatsweise durch einen Kalender zu navigieren und per Mausklick ein beliebiges Datum festzulegen. Der Anwender kann diesen Dialog z.B. bei Ablaufdaten von EC-Karten und Studentenkonten benutzen.

3.4 Darstellung der Architektur des Programmsystems Im Abschnitt 3.2 wurden bereits die Klassen benannt, die eine Klassenbibliothek zur Realisierung des Programmsystem bereitstellen sollte. Diese werden nun logisch gruppiert. Diese Aufteilung ist meist nicht physikalisch, d.h. in Dateien oder Ordnern, nachgebildet.

• Teilsystem Object: enthält die Wurzelklasse(n) der Klassenbibliothek mit Unterstützung für Architekturinformationen und Objektpersistenz

• Teilsystem Persistence: enthält Klassen zur Objektpersistenz, insbesondere Klassen die die Kommunikation mit Datenträgern übernehmen und die Serialisierung/ Deserialisierung von Klassen, die von CObject abgeleitet sind (muss daher nichts über applikationsspezifische Klassen wissen).

• Teilsystem Collections: stellt verschiedene Klassen zur Verwaltung von Mengen von Objekten zur Verfügung, in diesem Beleg ist im wesentlichen eine polymorphe Menge von Bedeutung, die Typunhabhängigkeit durch den Import von CObject gewährleistet.

• Teilsystem Misc (Verschiedenes): Klassen die allgemeine Probleme wie Systemanpassung, Zeichenkettenoperationen u.ä. kapseln und eher anwendungspezifisch verwendet werden. Die exportierten Klassen sollten, aber müssen nicht, von CObject erben.

• Teilsystem Bank: für das Bankproblem spezifische Klassen, also die Kontenhierarchie selbst sowie Hilfstypen wie CAccountTpye.

• Teilsystem MVC: enthält Klassen, die für die Realisierung des MVC-Modells nötig sind, also auch die Steuerelemente, Dialoge und die Klasse CRegister, die hier die Rolle des Model übernimmt.

• Teilsystem Application: Verbindet die Teilsysteme zu einer ausführbaren Applikation und benutzt dazu CView und CController.

Page 19: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

13

CObject

Object

CModelCView

CController

MVC

CArchive

Persistence

CSet

Collections CAccountCGiro

CStudentGiroCSavings

Bank

CStringCDateTime

...

Misc

«import»

«import» «import»«import»

«import»

«import»«import»

«import»

CApplication

Application«import»

Abbildung 6: Teilsystemstruktur (Entwurf)

Die Import-Pfeile in Abbildung 6 lassen sich im wesentlichen auf Vererbungs- und Benutzungsbeziehungen abbilden, so dass die folgende Darstellung die Beziehungen zwischen den Klassen der Lösungsidee verdeutlicht. Die grau unterlegten Klassen sind die anwendungsspezifischen, vom Entwickler zu erstellenden, während die restlichen bereits vollständig durch die Klassenbibliothek vorgefertigt sind oder nur noch angepasst werden müssen.

CModelCView

CController

CObject

CSet

CAccount

CString

CDateTime

CArchive

CGiro CSavings

CStudentGiro Abbildung 7: Beziehungen zwischen Klassen (Entwurf)

In der Abbildung wurden nicht alle Klassen von CObject abgeleitet, was aber durchaus möglich ist und lediglich der Übersichtlichkeit wegen weggelassen wurde. Ebenso werden Hilfklassen für Strings und Daten in fast allen Klassen der Kontenhierarchie sowie des MVC-Modells verwendet, aber stellvertretend nur mit CAccount verbunden. Leicht zu erkennen ist in der Darstellung die zentrale Bedeutung der Klasse CModel, die von CController und CView benutzt wird (Darstellung der Benutzeroberfläche) und über CSet eine Anbindung an die applikationsspezifischen Daten (die Bankhierarchie) bietet.. CArchive wird im Lösungsmodell ausschließlich vom Model benutzt, in der Praxis kann die Serialisierung/ Deserialisierung aber auch an die Fachklassen delegiert werden, wodurch weitere Benutzungsbeziehungen entstehen.

Page 20: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

14

Page 21: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

15

Kapitel 4 Realisierung des Lösungsmodells Für die Realisierung der Aufgabenstellung wird die Entwicklungsumgebung Microsoft Visual C++ 6 mit Service Pack 5 unter Windows XP Professional verwendet. Im Lieferumfang enthalten ist die Klassenbibliothek MFC (Microsoft Foundation Classes), die auch hier verwendet wird. Obwohl auch andere Bibliotheken integriert werden können, ist die MFC doch die native für diese IDE und bietet breite Unterstützung für Persistenzhaltung, Architekturinformationen u.v.m. In diesem Kapitel werden besondere Lösungsansätze in der Implementation sowie Methoden der Qualitätssicherung beschrieben.

4.1 Namenskonventionen Für dieses Projekt sollen die Namenskonventionen aus [HR02] verwendet werden — soweit Namen durch die Aufgabenstellung nicht bereits vorgegeben sind.

• Namen beginnen mit einem Großbuchstaben, gefolgt von Kleinbuchstaben (Balance) • bei Zusammensetzungen aus elementaren Namen beginnt jeder Bestandteil mit einem

Großbuchstaben (DateOfCreation) • Hilfsvariablen erhalten beliebig kurze Name (i) • Namen von Konstanten werden durchgängig groß geschrieben (COMMERCIAL) • eigene Datentypen werden mit dem Präfix T gekennzeichnet (TAccountType) • Namen von Klassen erhalten das Präfix C (CDate) • Zeigervariablen wird das Präfix p (Pointer) vorangestellt (pAccount)

Die Teilsysteme werden in der verwendeten Programmiersprache C++ in Übersetzungseinheiten realisiert. Jede Klasse wird (zusammen mit Hilfstypen) in einer CPP-Datei implementiert. Die Deklaration der Schnittstelle erfolgt wie üblich in den sog. Header-Files. Jede Quelltextdatei erhält einen standardisierten Kopf mit Angaben zur Erstellung und zu Verwendung des Teilsystems. //////////////////////////////////////////////////////////////////// // Account.cpp: implementation of the CAccount class. // Author: Christoph Stöpel Date: 04.03.2003 // Version: 2.0 Update: 10.07.2003 //////////////////////////////////////////////////////////////////// Durch Verwendung von Wizards (Assistenten, die Quellcodeerzeugung übernehmen), besonders bei der Erstellung grafischer Oberflächen, sind einige Namen nicht o.g. Konventionen entsprechend. Für diese Bereiche wird die ungarische Notation, wie sie von Microsoft für die Entwicklung mit der MFC propagiert wurde, benutzt. Dabei ist am Variablennamen sowohl ihr Geltungsbereich z.B. durch Präfix g_ (global), m_ (member, Klasse) als auch ihr Typ ablesbar. Eine Instanzvariable Balance vom Typ int wird dementsprechend in GUI-Klassen mit m_nBalance bezeichnet. In diesem Praktikum wurden die Klassen der Kontenhierarchie weit weniger kommentiert als im ersten Beleg. Dies liegt daran, dass Semantik, Vor- und Nachbedingugen von Methoden dieser Klassen mittlerweile als bekannt vorausgesetzt werden und ggf. auch der CEDL-Spezifikation (Anhang) entnommen werden können. Allen anderen Methoden ist in den Implementierungsdateien ein beschreibender Kommentar folgender Form vorangestellt. // Desc: <Beschreibung> // Pre: <Vorbedingungen> // Post: <Nachbedingungen>

Page 22: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

16

4.2 Realisierung/ Implementation In diesem Abschnitt sollen besondere Lösungswege aber auch Anpassungen, die sich durch die Verwendung der Klassenbibliothek MFC ergeben besprochen werden. Die Gliederung ist dabei an das Kapitel „Objektorientierte Programmierung und Wiederverwendung“ aus [HR02] angelehnt.

4.2.1 Allgemeine Bemerkungen Die CEDL-Beschreibung der Aufgabenstellung wurde fast 1 zu 1 in C++ umgesetzt. Einzig für die Parameterspezifizierer in, out und inout existieren keine äquivalenten Schlüsselwörter. Daher wurde die folgende Übertragung vorgenommen: in Parameter als Wert oder konstante Referenz out Rückgabewert von Funktionen für Basistypen oder als Referenzparameter inout Referenzparameter oder Übergabe als Zeiger

Die Umsetzung von public Transfer(inout for: CGiro, in amo:Ordinal, out t: Boolean) ist dementsprechend public: bool Transfer(CGiro& gir, int amo); Weiterhin wurden einige Methoden in ihrer Signatur angepasst oder ganz weggelassen:

• Einige Methoden sollen virtuell gekennzeichnet aber nicht überladen werden. Daher ist es notwendig die Signaturen der Basisklasse beizubehalten (vgl. Abschnitt 4.2.3 RTTI).

• CAccount enthält als einzige Klasse der Kontenhierarchie die nichtvirtuellen Methoden Equal und EqualKey (und den Alias operator==, der EqualKey benutzt). In abgeleitetetm Klassen sind diese nicht nötig, da sie aufgrund des objektorientierten Verarbeitungsmodells von C++ wiederverwendet werden können.

• Die Klasse CRegister wurde ausschließlich für den Konsolentest vollständig implementiert. In der grafischen Oberfläche wird sie durch CGSEBankDoc ersetzt, das in der Applikation nur einmal instanziert wird (singleton). Daher wurden Methoden wie Equal, EqualValue, Copy usw. in diese nicht übernommen. Diese könnten niemals benutzt werden und sind dort somit überflüssig.

• Die geforderte Klasse CDate wurde nicht selbst implementiert und stattdessen COleDateTime aus der Klassenbibliothek benutzt. Die Klasse CAccountType wurde durch eine einfache Enumeration (enum) realisiert und gemäß Namenskonvention in TAccountType umbenannt. Die Anwendung des objektorientierten Paradigmas schien bei diesem sehr einfachen Typ nicht sinnvoll.

• Der Schwerpunkt bei diesem Praktikum wurde auf die programmtechnische Realisierung unter Benutzung einer Klassenbibliothek gelegt. Daher sind die Aspekte einer realen Bank eher als zweitrangig einzuordnen:

o Der Kontostand wird durch einen 32-Bit Integer repräsentiert, was in kommerziellen Anwendungen wahrscheinlich zu ungenau wäre.

o Die Berechnung von Zinsen (CalculateBalance) wurde vereinfacht auf die Berechnung von Tageszinsen zurückgeführt. Im Bankgeschäft wäre eine quartalsweise Betrachtung mit Zinseszinsen genauer.

o Bei einigen Methoden ist die Semantik nicht klar aus der Spezifikation zu entnehmen. CAccount hätte z.B. auch abstrakt implementiert werden können. Wann Operationen wie Auszahlung und Transfer bei den verschiedenen Konten scheitern, ist nicht festgelegt und somit nach eigenem Ermessen verwirklicht.

Page 23: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

17

4.2.2 MVC-Konzept/ Ereignisbehandlung Das MVC-Konzept besteht wie bereits aufgeführt aus drei wesentlichen Bauelementen, die Datenhaltung, Darstellung der Daten und Verarbeitung der Eingaben abstrahieren. Ein ähnliches Modell wird durch die MFC unterstützt. Doch hier sind View und Controller nicht mehr klar getrennt, sondern zu einer Document-View-Architektur (Dokument-Ansicht) verschmolzen. Für dieses Praktikum bedeutet dies insbesondere, dass die View Eingaben entgegennehmen kann und direkt mit dem Model (via CBankView::GetDocument()) kommunizieren kann. Im Gegensatz zum klassichen MVC-Konzept kann auch das Model in begrenztem Maße seine Views benutzen (UpdateAllViews()). Zwar wäre es technisch möglich, eine Klasse CController einzuführen, doch ist die Quellcodegenerierung durch Assistenten auf die Dokument-Ansicht-Architektur ausgelegt und soll daher auch beibehalten bleiben. Damit ergibt sich das folgende reale Modell.

CListView

CBankView CBankDoc

CDocument

CBankApp

CWinApp

CWinThread

CCmdTarget

CObject

CView

CWnd

CAccount

CGiro

CStudentGiroCSavings

COleDateTime

CArchive

as CRegister

CString

CFrameWnd

CMainFrame

CObList

CDocTemplate

CSingleDocTemplate

Abbildung 8: Lösungsmodell mit den MFC

In der Darstellung sind Benutzbeziehungen zu nicht abgeleiteten Klassen wie CArchive und CString teilweise weggelassen, um die Übersichtlichkeit zu erhalten. Tatsächlich werden diese von fast allen Klassen verwendet. Die grau unterlegten Klassen sind bereits mitgeliefert, die restlichen müssen entweder komplett selbst erstellt oder anwendungsspezifisch angepasst werden. Die Funktionalität von CController wird durch Kombination von CBankApp (für Programmstart) und CSingleDocTemplate, das die Bestandteile ausführbar zusammenfasst, nachgebildet. Nachrichten können (und werden) aber auch von der View verarbeitet, so dass eine klare Trennung nicht möglich ist. Das Document-View-Pattern wird in Abb. 8 durch die Bauelemente CBankView (entspricht der geforderten Klasse CView) und CBankDoc (entspricht CModel) dargestellt, die genauso wie CBankApp, von CCmdTarget erben. Dadurch ist es diesen Klassen möglich, sich in die Ereignisverarbeitungskette einzureihen. In der reinen Win32-API müssen Programme eine WindowProc-Funktion registrieren, um per switch-case die verschiedenen Meldungen zu verarbeiten. In den MFC wird die Ereignisbehandlung über sog. Message-Maps realisiert. Diese sind zunächst nur Präprozessordirektiven, die Windows-Nachrichten (WM_*) auf Member-Funktionen abbilden. Beim Kompilieren werden die Makros dann zu Nachrichtentabellen erweitert.

Page 24: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

18

CWnd&CCmdTarget::messageMap&CWnd::_messageEntries[0]

MessageMap Strukturen messageEntries Array Member Funktionen

WM_DRAWITEMWM_CTLCOLOR

...

CWnd::OnDrawItemCWnd::OnCtlColor

...

CView&CWnd::messageMap

&CView::_messageEntries[0] WM_ACTIVATEWM_PAINT

...

CView::OnActivateViewCView::OnDraw

...

CBankView&CView::messageMap

&CBankView::_msgEntries[0] WM_UPDATEWM_PAINT

...

CBankView::OnUpdateCBankView::OnDraw

...Nachricht

Abbildung 9: Konzept der Ereignisbehandlung über Nachrichtentabellen

Eine eingehende Nachricht durchläuft die Nachrichtentabellen beginnend bei der am meisten spezialisierten Klasse der Hierarchie. In diesem Fall also von CBankView bis zu CCmdTarget. Wird beim Durchlauf in einer der Tabellen ein passender Eintrag gefunden, wird die entsprechend zugeordnete Member-Funktion ausgeführt und die Nachricht dann in den meisten Fällen verworfen. In diesem Praktikum werden alle applikationsspezifischen Nachrichten ausschließlich von der View verarbeitet, da nur diese Zugriff auf das Datenmodell hat und für viele andere die Standardimplementierung der MFC ausreicht Wie in Abb. 8 auch zu erkennen ist, erbt die Hauptansicht (CBankView) von CListView. Dadurch wird in der Ansichtsklasse ein Listensteuerelement zu Verfügung gestellt, wie es z.B. vom Windows Explorer bekannt ist. Die detaillierte Ansicht in mehreren Spalten wird erreicht, indem der Stil des Steuerelementes während der Initialisierung auf „Report“ gesetzt wird. Auf Update Nachrichten kann dann reagiert werden, indem jedes Konto im Dokument durch eine eigene Zeile dargestellt wird.

4.2.3 Architekturinformationen/ RTTI Architekturinformationen sind Mittel zur (Selbst-) Beschreibung von Klassen und können sowohl mit Sprachmitteln der Programmiersprache C++ als auch über Mechanismen der Klassenbibliothek bereitgestellt werden. In C++ basieren Architekturinformationen auf RTTI (Laufzeit Typidentifikation) und damit auf virtuellen Methoden und Cast-Operatoren. Dafür mussten die Signaturen einiger Methoden geändert werden, denn virtuelle Methoden dürfen im Zuge der Vererbung ihre Signatur nicht mehr ändern. Dies betrifft die Methoden

• bool Copy(const CAccount& acc); • bool EqualValue(const Caccount& acc);

die in allen Klassen der Kontenhierarchie diese Signatur haben. Daraus ergibt sich aber auch die Notwendigkeit des Typumwandlung (cast). Um auf alle Attribute einer abgeleiteten Klasse

Page 25: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

19

zuzugreifen, muss die Basisklassenzreferenz (oder Zeiger) in eine Referenz auf die abgeleitete Klasse gecastet werden. Fehler können durch die Benutzung des dynamic_cast Operators behandelt werden, der „wahlweise“ eine Exception wirft oder einen NULL-Zeiger liefert. Letztere Variante wird im Praktikum verwendet: bool CGiro::Copy(const CAccount& acc) { const CGiro *pGir = dynamic_cast<const CGiro*>(&acc); if (pGir) { // Zugriff auf CGiro-Attribute return true; }

else return false; // Fehler beim cast } In den MFC werden weitere Architekturinformationen durch das simple Einfügen der Makros DECLARE_* und IMPLEMENT_* zur Verfügung gestellt. In der Bankmanagement-Applikation werden durchgängig die Makros DECLARE_SERIAL und IMPLEMENT_SERIAL genutzt, die die höchste Ebene der Metainformationen darstellen und auch die Persistenzhaltung auf einfache Weise ermöglichen. Die Klassen werden dabei unter anderem um eine Instanz von CRuntimeClass und die Methode GetRuntimeClass erweitert. class CRuntimeClass { public:

LPCSTR m_lpszClassName; // Klassenname int m_nObjectSize; // Größe in Byte … CObject* CreateObject( ); // virtueller Konstruktor BOOL IsDerivedFrom( const CRuntimeClass* pBaseClass) const;

}; Diese Form der Metainformationen wird zum Beispiel bei der Generierung des impliziten Schlüssels von Konten genutzt. Der Schlüssel soll sich hier aus dem Typ des Kontos, seinem Inhaber und der Nummer zusammensetzen, was normalerweise nur durch virtuelle Methoden und Überschreibung in allen Klassen realisierbar wäre. Durch Benutzung der CRuntimeClass Instanz genügt es aber in CAccount eine nicht-virtuelle Methode zu implementieren, wie der folgende Quelltextausschnitt zeigt. CString CAccount::KeyOf() const { CString key; key.Format("%s:%d:%s",

(LPCTSTR)GetRuntimeClass()->m_lpszClassName, AccountNo,(LPCTSTR)Owner); return key; }

4.2.4 Objektkonstruktion Mit Objektkonstruktion ist hier die dynamische gemeint, bei der teilweise nicht einmal der Typ des zu erstellenden Objektes bekannt ist. Da virtuelle Konstrukturen technisch nicht machbar sind, ist diese Art der dynamischen Objektkonstruktion eng mit den Architekturinformationen einer Klasse verbunden.

Page 26: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

20

Die dynamische Objektkonstruktion kann verschiedenartig umgesetzt werden. Möglich sind zum Beispiel Klonierung, Nutzung von Architekturinformationen oder Object Factories. Da die MFC umfangreiche Meta-Informationen über eingebettete Klassen bietet, wird hier eine Kombination aus den ersten beiden Ansätzen genutzt. Der klassische Ansatz der Klonierung fügt jeder Klasse eine virtuelle Methode Generate hinzu, die mit dem Kopierkonstruktor ein Duplikat seiner selbst erzeugt und als Basisklassenzeiger zurückgibt: CAccount* CAccount::Generate() {return new CAccount(*this); } CAccount* CGiro::Generate() {return new CGiro(*this); } … Diese Überschreibung in allen Klassen ist hier nicht nötig, da die MFC mit CRuntimeClass::CreateObject quasi eine Object-Factory mitliefert. Die so erstellte Instanz muss nur noch mit sinnvollen Werten gemäß Vorlage belegt werden, was in einem Aufruf der virtuellen Methode Copy resultiert. Damit wird dasselbe Ergebnis wie oben erreicht, hat aber den Vorteil, dass die Methode nur in der Wurzelklasse der Kontenhierarchie implementiert werden muss: CAccount* CAccount::Generate() const { CAccount *pAcc = static_cast<CAccount*>(

GetRuntimeClass()->CreateObject() );

pAcc->Copy(*this); return pAcc; }

4.2.5 Polymorphe Mengen/ Iteratoren Die Idee polymorpher Mengen, wie sie bereits im Kapitel Lösungsmodell besprochen wurde, wird in der MFC durch die Klasse CObList realisiert. Diese verwaltet Zeiger auf Instanzen die von CObject abgeleitet sind. Die Klasse CRegister kapselt eine Instanz dieser Mengenklasse, wurde aber lediglich für die Konsolentests vollständig implementiert. In der GUI-Applikation übernimmt das Dokument (CBankDoc) dessen Aufgaben, so dass getestete Methoden direkt in diese Klasse kopiert werden. Polymorphe Menge zeichnen sich dadurch aus, dass verschiedene Typen der gleichen Hierarchie verwaltet werden können. So erlaubt auch das Dokument das Einfügen verschiedener Konten, indem die Insert-Methode einen Basisklassenzeiger verwendet, der unterschiedliche Typen referenzieren kann. Die Einfügeoperation erfolgt per Kopie und benutzt die oben erläuterten Mittel der Objektkonstruktion. Der Zugriff von außen dagegen wird über Elementzeiger gewährt. Das ermöglicht speicherschonendes Arbeiten und zudem auch die Ausführung von Instanzmethoden auf Elementen der Menge. Ist vollständige Kapselung erwünscht (z.B. aus Sicherheitsgründen oder in verteilten Systemen), so kann auch hier leicht mit Kopien gearbeitet werden, indem statt des Zeigers einfach ein mit Generate erzeugtes Objekt zurückgegeben wird. Die MFC verwendet zur Durchmusterung seiner Mengenklassen Iteratoren, die denen der STL ähneln. So erlauben die Methoden CObList::GetHeadPosition und CObList::GetNext die Iteration durch die verkettete Objektliste und verwenden dabei eine Variable vom Typ POSITION (Alias für einen generischen Zeiger). Alle Elemente lassen sich mit folgendem Quelltextausschnitt durchlaufen: POSITION pos = Set.GetHeadPosition(); while (pos) DoSomethingWithElement(Set.GetNext(pos));

Page 27: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

21

Obwohl diese Iteratoren bereits genügen würden, sind in diesem Praktikum noch die Methoden GetFirst, GetNext und GetActual implementiert. Dadurch wird die interne Menge nach außen verborgen und kann später ausgewechselt werden, ohne die Schnittstelle anzupassen. Die genannten Methoden benutzen auch eine Variable vom Typ POSITION, verbergen diese aber gemäß Geheimnisprinzip. In der View können dann auch ausschließlich diese Methoden verwendet werden, was u.a. nötig ist wenn sie vom Model die Aufforderung erhält, sich zu aktualisieren: void CBankView::OnUpdate(...) { for (CAccount *pAcc = GetDocument()->GetFirst;

pAcc != NULL; pAcc = GetDocument()->GetNext()) { DisplayInList(pAcc); DoSomethingElse(pAcc); } }

4.2.6 Objektpersistenz Objektpersistenz ist das Aufbewahren eines Programmzustandes über seine Lebenszeit hinaus. In diesem Praktikum ist damit die Speicherung der Models (resp. MFC-Dokuments) auf der Festplatte oder anderen Datenträgern gemeint. Mit der Einbindung der Architekturinformationen über die Makros DECLARE_SERIAL und IMPLEMENT_SERIAL wurden bereits die Vorraussetzungen für eine automatische Persistenzhaltung durch die Klassenbibliothek geschaffen. Es bleibt nur noch die Einführung einer Methode Serialize(CArchive& ar) in die Dokumentklasse. CArchive verfügt über Streamoperatoren, die solange weitere Serialize-Methoden aufruft, bis elementare Datentypen erreicht sind. Daraus ergibt sich die Notwendigkeit Serialize auch in allen Klassen der Kontenhierarchie zu implementieren.

Set.Serialize()RegisterInf.Serialize()

DateOfCreation.Serialize()

acc->Serialize()gir->Serialize()

ar << Balancear << AccountNo

...

...

CBankDoc::Serialize(…)

ar << Balancear << AccountNo

...

ar << Dispoar << ECNo

CAccount::Serialize...

Abbildung 10: Rekursive Serialisierung der Mengenklasse

Im Quelltext ist dies wie folgt umgesetzt: void CBankDoc::Serialize(CArchive& ar) {

// Handle Attributes if (ar.IsStoring()) // Speichern { ar << DateOfCreation; ar << RegisterInformation; } else // oder Laden {

Page 28: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

22

ar >> DateOfCreation; ar >> RegisterInformation; SetCleanup(); // free Mem for Set } // Do recursive Set.Serialize(ar); } Stellvertretend für alle Klassen der Bankhierarchie sollen hier die Implementierungen von CGiro und CAccount gezeigt werden. Das Prinzip ist in allen Methoden gleich: zunächst wird die Basisklasse rekursiv serialisiert, danach die Attribute (siehe hierzu auch die Quelltexte auf CD).

Im Aufruf von CObject::Serialize werden schließlich auch die Metainfomationen von CRuntimeClass abgelegt. Bei der Wiederherstellung von Instanzen kommt dann wieder die dynamische Objektkonstruktion zum Einsatz, bei der zunächst der Typ der anzulegenden Instanz ermittelt und dementsprechend die passende Instanz erzeugt wird (vgl. [HR02], S. 307).

void CGiro::Serialize(CArchive& ar) { CAccount::Serialize(ar); if (ar.IsStoring()) // Speichern { ar << DispoCreditLine; ar << ECNo; ar << ECExpirationDate; } else // oder Laden { ar >> DispoCreditLine; ar >> ECNo; ar >> ECExpirationDate; } }

void CAccount::Serialize(CArchive& ar) { CObject::Serialize(ar); if (ar.IsStoring()) { ar << DateOfCreation; ar << AccountNo; ar << Balance; … } else { ar >> DateOfCreation; ar >> AccountNo; ar >> Balance; … } }

Page 29: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

23

4.3 Testergebnisse Der Test der Implementation ist in 3 wichtige Abschnitte eingeteilt. Jedoch ist keine dieser Methoden geeignet, vollständige Fehlerfreiheit nachzuweisen (es gibt auch keine solche Methode). Die Kombination der Sicherungsschichten soll aber ein höchstmögliches Maß an Softwarequalität gewährleisten.

• Codeinspektion/ Codewalktrough, wird während der Erstellung des Quellcodes durchgeführt und zeichnet sich durch gewissenhaftes Programmieren und ausschließen von logischen Fehlern aufgrund der Erfahrung aus. Debugausgaben (bedingte Kompilierung mit #ifdef _DEBUG, Überschreibung von CObject::Dump) helfen dabei den Programmablauf in verschiedenen Zweigen zu verfolgen.

• Beim rechnergestützten statischen Testen gibt der Compiler dem Entwickler Fehlermeldungen, die rein syntaktischer Natur sein können oder Warnungen aus, die meist auf logische Fehler im Programm hindeuten. Typische Warnungen dieser Art beziehen sich auf „unbenutzte Parameter“ oder „Variablenverwendung vor Definition“.

• Intensiver Bottom-Up-Test, bei dem anhand verschiedener Testfälle wichtige Funktionalität bestätigt werden kann. Dabei wird „von unten nach oben“ getestet, d.h. elementare Bauelemente zuerst und dann darauf basierende.

Der Bottom-Up-Test von Softwarebauelementen verwendet für gewöhnlich extra erstellte Umgebungen, in denen Abhängigkeiten auf das nötigste reduziert sind. Dieses Vorgehen ist in Klassenhierarchien nur bedingt möglich, da abgeleitete Klassen in Testumgebungen wesentliche Funktionalität verlieren können. Einige Vorbemerkungen zu den ausgeführten Tests:

• Get-/ und Setmethoden wurden nicht getestet, da davon ausgegangen werden kann, dass Operationen wie das Belegen und Auslesen von Variablen, sowohl mit Basistypen als auch mit Bibliotheksklassen, ausführlich vom Compilerhersteller verifiziert wurden.

• Basisklassenmethoden, die in abgeleiteten Klassen nicht überschrieben oder durch einfaches Kopieren in andere Klassen eingefügt wurden (CalculateBalance), werden ausschließlich in den Klassen getestet, in denen sie zuerst eingeführt wurden.

Das folgende Framework soll helfen, die nötigen Test zu automatisieren

CTestFrameWorkIUserTest

CTransferTestCRateOfInterestTest

CAccount

CGiro

CStudentGiro CSavings

Abbildung 11: automatisiertes Testen der Klassenhierarchie

Die zentrale Klasse ist dabei CTestFramework, von der lediglich eine Instanz angelegt werden muss, um die verschiedenen Valid-Cases nachzuweisen. Der Konstruktor nimmt zwei Zeiger auf CAccount-Instanzen entgegen, wodurch auch der Test polymorpher Objekte ermöglicht wird. Auf diesen Objekten werden dann Valid Cases geprüft, wie sie in der CEDL-Beschreibung gefordert sind, aber auch eigene Tests (insbesondere zur Persistenzhaltung) ausgeführt.

Page 30: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

24

Die Schnittstelle der Klasse soll nun einen kurzen Überblick über das generelle Testsverfahren der Hierarchie geben. class CTestFramework { private: CAccount *acc1; CAccount *acc2; protected: bool ProveCase(bool value, bool expected = true); public: CTestFramework(); CTestFramework(CAccount *pAcc1, CAccount *pAcc2); virtual ~CTestFramework(); static bool FileExists(CString name); // helper for persist. bool RunCommonTests(); // runs the following test bool TestEquals(); // tests copy, equalvalue, equalkey bool TestNotEquals(); // tests copy, deposit, equalvalue bool TestGenerate(); // tests generate, equal, equalvalue bool TestBalanceChanges(); // tests withdraw, deposit … // Store an Account in file “FileName” bool TestStore(CString FileName, CAccount *acc = NULL); // Load Account from file “FileName” bool TestLoad(CString FileName); bool TestUserDefined(IUserTest& test); // test giro, savings, … }; Die einzelnen Tests sind im wesentlichen gleich aufgebaut. Eine vorgegebene Sequenz wird abgearbeitet und dabei die booleschen Rückgabewerte gespeichert. Die Konjunktion der Rückgabewerte muss dann einem Erwartungswert entsprecht, der durch die Methode ProveCase verifiziert wird. Weichen tatsächlicher und Erwartungswert voneinander ab, wird eine Fehlermeldung ausgegeben und Maßnahmen zur Beseitigung unternommen. Exemplarisch sei im folgenden der Test der Methode Generate aufgeführt, die übrigen sind den Quelltexten zu entnehmen. bool CTestFramework::TestGenerate() { // (1) display test-scenario std::cout << "Testing Generate-Equal-EqualValue... ";

// (2) run test-sequence CAccount *acc = acc2->Generate(); // create a new account bool t1 = acc->Equal(*acc2); // should not(!) have same address bool t2 = acc->EqualValue(*acc2); // but same attributes delete acc; // cleanup mem

// (3) verify results return ProveCase(!t1 && t2); } Zum Test von Methoden, die nicht in CAccount deklariert sind, kann das Framework benutzerdefinierte Sequenzen abarbeiten, denen es möglich ist, die Testobjekte zu casten. Dazu wird

Page 31: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

25

das Interface IUserTest zu Verfügung gestellt, das in Form einer Funktionsklasse implementiert werden muss. class IUserTest { public: virtual bool operator()(CAccount *acc1, CAccount *acc2) = 0; }; Im folgenden ist beispielhaft der automatisierte Test von CGiro dargestellt. Darin wird auch die Strategie der Persistenzhaltungstests deutlich. Eine Instanz wird nur abgespeichert falls noch keine persistente Datei vorhanden ist. Danach wird der Anwender aufgefordert, die Applikation neu zu starten. Nur so kann sichergestellt werden, dass statt der persistenten Daten nicht Inhalte aus dem Arbeitsspeicher des Programms gelesen werden. Nach erfolgtem Neustart wird die vorhandene Datei gefunden, und das gesicherte Objekt wiederhergestellt. Das kann dann manuell mit einem Referenzobjekt verglichen werden. Der Vergleich per EqualValue ist nicht möglich, da sich die Instanzen mindestens im Attribut DateOfCreation unterscheiden. void RunGiroTests() { // […] Create and initialize gir1 and gir2 CTestFramework tester(&gir1, &gir2); cout << "Running Testsuite for CGiro:" << endl << endl; tester.RunCommonTests(); tester.TestUserDefined(CTransferTest()); if (CTestFramework::FileExists("giro.store")) { cout << "Loading from file..." << endl; tester.TestLoad("giro.store"); } else { cout << "Storing, please restart app to load..." << endl; cout << "Reference Object: " << endl; gir2.Show(); tester.TestStore("giro.store", gir2); } } Die graphische Oberfläche wurde schon während der Entwicklung evolutionär getestet. Hierzu wurde ein Register (Datei „test1.gse“ auf CD) mit verschiedenen Konten angelegt und alle gebotenen Funktionen (also Menueinträge, Symbolleisten-Buttons und Hotkeys) in verschiedener Reihenfolge getestet. CRegister wurde modular getestet, d.h. die Valid-Cases in einzelnen Funktionen zusammengefasst. Die Protokolle der Konsolentests sind im folgenden abgedruckt. Die Programmausgabe wird originalgetreu wiedergegeben und wurde lediglich bei doppelten Ausgaben (bei Neustart des Programms zur Persistenzhaltung) gekürzt. Diese Kürzungen sind als solche gekennzeichnet. Aufrufe von Show vor dem Speichern und nach dem Laden sind durch Unterstreichung hervorgehoben. Die Tests der graphischen Oberfläche können leicht anhand der mitgelieferten ausführbaren Datei nachvollzogen werden. Screenshots werden daher hier nicht gezeigt.

Page 32: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

26

Testprotokoll CAccount D:\Projekte\gse2_beleg\class_test\Release>class_test.exe Please choose a class to test: (1) CAccount (2) CGiro (3) CStudentGiro (4) CSavings (5) CRegister (6) Delete persistent files (7) Exit Program >1 Running Testsuite for CAccount: Testing Copy-EqualValue-EqualKey... OK Testing Copy-Deposit-EqualValue... OK Testing Generate-Equal-EqualValue... OK Testing Balance Changes... Balance: 500, Deposit(20) Balance: 520, WithDraw(10) Balance: 510 OK Storing, please restart app to load... Reference Object: CAccount # 1 of B. Bunny created 14.08.2003 12:06:52 Balance: 500 D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CAccount: […] Loading from file... Loaded Object: CAccount # 1 of B. Bunny created 14.08.2003 12:06:52 Balance: 500 Testprotokoll CGiro: D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CGiro: Testing Copy-EqualValue-EqualKey... OK Testing Copy-Deposit-EqualValue... OK Testing Generate-Equal-EqualValue... OK Testing Balance Changes... Balance: 500, Deposit(20) Balance: 520, WithDraw(10) Balance: 510 OK Testing Transfer-EqualValue... Giro1: 600, Giro2: 600 Giro1.Transfer(Giro2, 100) Giro1: 700, Giro2: 500 OK

Page 33: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

27

Storing, please restart app to load... Reference Object: CGiro # 1 of B. Bunny created 14.08.2003 12:13:00 Balance: 500 DispoCreditLine: 0 ECNo: 1 expires 12.12.2006 D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CGiro: […] Loading from file... Loaded Object: CGiro # 1 of B. Bunny created 14.08.2003 12:13:00 Balance: 500 DispoCreditLine: 0 ECNo: 1 expires 12.12.2006 Testprotokolle CStudentGiro D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CStudentGiro: Testing Copy-EqualValue-EqualKey... OK Testing Copy-Deposit-EqualValue... OK Testing Generate-Equal-EqualValue... OK Testing Balance Changes... Balance: 500, Deposit(20) Balance: 520, WithDraw(10) Balance: 510 OK Testing RateOfInterest... Balance: 500 Balance in 6 Months: 506 OK Testing RateOfInterest... Balance: 500 Balance in 12 Months: 512 OK Testing Transfer-EqualValue... Giro1: 600, Giro2: 600 Giro1.Transfer(Giro2, 100) Giro1: 700, Giro2: 500 OK Storing, please restart app to load... Reference Object: CStudentGiro # 1 of B. Bunny created 14.08.2003 12:17:49 Balance: 500 DispoCreditLine: 0 ECNo: 1 expires 12.12.2006 Student ID expires: 12.12.2006 Rate of Interest: 2.5% D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CStudentGiro:

Page 34: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

28

[…] Loading from file... Loaded Object: CStudentGiro # 1 of B. Bunny created 14.08.2003 12:17:49 Balance: 500 DispoCreditLine: 0 ECNo: 1 expires 12.12.2006 Student ID expires: 12.12.2006 Rate of Interest: 2.5% Testprotokolle CSavings: D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CSavings: Testing Copy-EqualValue-EqualKey... OK Testing Copy-Deposit-EqualValue... OK Testing Generate-Equal-EqualValue... OK Testing Balance Changes... Balance: 500, Deposit(20) Balance: 520, WithDraw(10) Balance: 510 OK Storing, please restart app to load... Reference Object: CSavings # 1 of B. Bunny created 14.08.2003 12:21:57 Balance: 500 Rate of Interest: 2.5 D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CSavings: […] Loading from file... Loaded Object: CSavings # 1 of B. Bunny created 14.08.2003 12:21:57 Balance: 500 Rate of Interest: 2.5 Testprotokolle CRegister: D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CRegister: CAccount # 1 of B. Bunny created 14.08.2003 12:25:40 Balance: 1000 CStudentGiro # 1 of B. Bunny created 14.08.2003 12:25:40 Balance: 500 DispoCreditLine: 0 ECNo: 1 expires 12.12.2006 Student ID expires: 12.12.2006 Rate of Interest: 2.5% CAccount # 2 of B. Bunny created 14.08.2003 12:25:40 Balance: 500

Page 35: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

29

Testing Copy-EqualValue-EqualKey... OK Testing Insert-Find-GetActual... OK Testing Scratch-Find-Card...OK Storing, please restart app to load... D:\Projekte\gse2_beleg\class_test\Release>class_test.exe […] Running Testsuite for CRegister: […] Loading from file... Loaded Object: Register SK Potsdam contains 3 Accounts, created 14.08.2003 12:25:40 CAccount # 1 of B. Bunny created 14.08.2003 12:25:40 Balance: 1000 CStudentGiro # 1 of B. Bunny created 14.08.2003 12:25:40 Balance: 500 DispoCreditLine: 0 ECNo: 1 expires 12.12.2006 Student ID expires: 12.12.2006 Rate of Interest: 2.5% CAccount # 2 of B. Bunny created 14.08.2003 12:25:40 Balance: 500 Integrationstest der Benutzeroberfläche Neuanlegen und Hinzufügen von Konten:

1. Programmstart mit leerem Register 2. Konten mit sinnvollen Daten anlegen

a. CAccount b. CGiro c. CStudentGiro d. CSavings

3. Aktualisierung des ListViews prüfen 4. Registerinformation festlegen 5. Daten speichern

Neuanlegen ungültiger Konten:

1. Programmstart mit leerem Register 2. Konten mit Daten anlegen, die Invarianz verletzen oder bereits schlüsselgleich sind 3. Fehlermeldung und Nicht-Aktualisierung der Oberfläche prüfen

Persistenzhaltung:

1. Wiederherstellen eines Registers a. Über Laden-Menüeintrag b. Über Recent-File-Menüeintrag c. Per Doppelklick im Windows-Explorer

2. Anzeige (und Verifikation) der Details aller Konten 3. Anzeige der Registerinformation

Page 36: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

30

Bearbeiten vorhandener Konten:

1. Laden eines gespeicherten Registers 2. Editieren der enthaltenen Konten (alle Typen) 3. Schließversuch des Programms 4. Speichernachfrage bejahen 5. Laden des gespeicherten Registers und Verifikation der geänderten Daten

Kombinationstest:

1. Laden eines gespeicherten Registers 2. Editieren von Konten 3. Hinzufügen mehrerer neuen Konten 4. Löschen von Neuen, Editierten und geladenen Konten 5. Abspeichern des Registers und Verifikation der Daten durch Programmneustart und Laden

Zugriff auf Konten im Register:

1. Laden eines gespeicherten Registers 2. Ein- und Auszahlen (auch ungültiger Beträge) 3. Aktualisierung des ListViews prüfen 4. Speichern des Registers 5. Programmneustart und Laden mit geänderten Kontoständen

Page 37: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

31

.

Page 38: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

32

Page 39: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

33

Kapitel 5 Wertung des erreichten Ergebnisses Für dieses Praktikum sind vorgegebene Bausteine eine Pogrammsystems in der Klassen der Programmiersprache C++ umgesetzt und getestet worden. Dazu wurden verschiedene Techniken der objektorientierten Programmierung wie Vererbung und polymorphe Objekte angewandt. Durch Nachnutzung der Klassenbibliothek MFC konnte auch auf bereits vorhandenes Wissen zurückgegriffen und eine intuitiv bedienbare Windows-Oberfläche erstellt werden. Dadurch waren aber auch Anpassungen nötig, so konnte das MVC-Konzept in seiner klassischen Form nicht umgesetzt werden. Stattdessen wurde das Dokument-Ansicht-Modell verwendet, das View und Controller in einem Bauelement vereint. Durch verschiedene Methoden der Qualitätssicherung kann von weitgehender Fehlerfreiheit ausgegangen werden. Die zur Verfügung gestellte Funktionalität sollte die Anforderungen an ein Kontoverwaltungssystem erfüllen und auch problemlos, z.B. für weitere Kontoarten erweiterbar sein. Weitere mögliche Anpassungen wären:

• Das Hinzufügen eines „echten“ Find-Dialoges. Dieser wurde hier noch weggelassen, da die Darstellung in einer Listenansicht einen schnellen Überblick über allen vorhandenen Konten gewährt und Details jederzeit über die Oberfläche abgerufen werden können (Anbindung der Datenschicht über LVITEM::lParam).

• Einige Operationen von Menüeinträgen können nur auf selektierten Listen-Elementen ausgeführt werden und geben andernfalls Fehlermeldungen aus. Diese Menüeintrage könnte man kontextabhängig (de-) aktivieren oder ausschließlich durch Kontextmenüs zur Verfügung stellen.

• Unterstützung typischer Funktionen wie Einfügen, Kopieren, Ausschneiden, Drucken sowie die Auslieferung innerhalb eines Setup-Programmes. Für diese Belegarbeit aber weder gefordert noch notwendig. (Dennoch sei die Verwendung des Scripts „unregister_app.js“ auf CD angeraten, um Registrierungseinträge der Programms nach der Verwendung zu entfernen)

• Einführung einer Schnittstelle, die typische Methoden wie Equal, Copy usw. kapselt. In diesem Praktikum würde diese allerdings nur in die Vererbungsbeziehung zwischen CObject (MFC) und CAccount eingeordnet, so dass letztere Klasse auch allein als Lieferant der Schnittstelle dienen kann. In der Document-Klasse sind derartige Funktionen aus genannten Gründen überflüssig (vgl. 4.2.1).

• Erweiterung des Programmsystems für Datenverwaltungsschicht, Anwendungsschicht und Präsentationsschicht in verteilten System (GSE III).

Page 40: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

34

Page 41: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-1

Anhang A Die Quelltexte des Praktikums Auf den folgenden Seiten sind die Header-Files der zu entwickelnden Applikation abgedruckt.

A.1 Account.h // Account.h: interface for the CAccount class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_ACCOUNT_H__A663C82E_BD2D_4942_8177_6305AB1FAE14__INCLUDED_) #define AFX_ACCOUNT_H__A663C82E_BD2D_4942_8177_6305AB1FAE14__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 enum TAccountType { PRIVATE, COMMERCIAL }; class CAccount : public CObject { private: CString Owner; TAccountType Type; unsigned int AccountNo; COleDateTime DateOfCreation; protected: int Balance; public: CAccount(); CAccount(unsigned int no, TAccountType typ, CString own, int bal); CAccount(const CAccount& acc); CAccount* Generate() const; virtual ~CAccount(); CString KeyOf() const; bool Equal(const CAccount& acc) const; bool EqualKey(const CAccount& acc) const; virtual bool EqualValue(const CAccount& acc) const; virtual bool ClassInvariant() const; virtual bool Copy(const CAccount& acc); virtual void Serialize(CArchive& ar); virtual void Show() const; unsigned int GetAccountNo() const; COleDateTime GetDateOfCreation() const; TAccountType GetAccountType() const; CString GetOwner() const; int GetBalance() const; void SetAccountType(TAccountType typ); void SetOwner(CString own); bool Deposit(int val); virtual bool WithDraw(int val); CAccount& operator=(const CAccount& acc); bool operator==(const CAccount& acc) const; DECLARE_SERIAL(CAccount) };

Page 42: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-2

#endif // !defined(AFX_ACCOUNT_H__A663C82E_BD2D_4942_8177_6305AB1FAE14__INCLUDED_)

A.2 Giro.h // Giro.h: interface for the CGiro class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_GIRO_H__D4818E70_444E_4BCD_A72B_DFC6E8E76D55__INCLUDED_) #define AFX_GIRO_H__D4818E70_444E_4BCD_A72B_DFC6E8E76D55__INCLUDED_ #include <iostream> #include "Account.h" #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CGiro : public CAccount { private: unsigned int DispoCreditLine; unsigned int ECNo; COleDateTime ECExpirationDate; public: CGiro(); CGiro(unsigned int no, TAccountType typ, CString own, int bal, unsigned int dis, unsigned int eno, COleDateTime exp); CGiro(const CGiro& gir); virtual ~CGiro(); virtual bool EqualValue(const CAccount& acc) const; virtual bool ClassInvariant() const; virtual bool Copy(const CAccount& acc); virtual void Serialize(CArchive& ar); virtual void Show() const; virtual bool WithDraw(int val); bool Transfer(CGiro& gir, unsigned int val); unsigned int GetECNo() const; COleDateTime GetECExpirationDate() const; unsigned int GetDispoCreditLine() const; void RenewECCard(unsigned int eno, COleDateTime exp); void SetDispoCreditLine(unsigned int dis); CGiro& operator=(const CGiro& gir); DECLARE_SERIAL(CGiro) }; #endif // !defined(AFX_GIRO_H__D4818E70_444E_4BCD_A72B_DFC6E8E76D55__INCLUDED_)

Page 43: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-3

A.3 StudentGiro.h // StudentGiro.h: Schnittstelle für die Klasse CStudentGiro. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_STUDENTGIRO_H__CBC03704_CAEB_45FA_A136_9E3324BCCBD3__INCLUDED_) #define AFX_STUDENTGIRO_H__CBC03704_CAEB_45FA_A136_9E3324BCCBD3__INCLUDED_ #include <iostream> #include "Giro.h" #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CStudentGiro : public CGiro { private: double RateOfInterest; COleDateTime StudentIDExpirationDate; public: CStudentGiro(); CStudentGiro(unsigned int no, TAccountType typ, CString own, int bal, unsigned int dis, unsigned int eno, COleDateTime exp, double roi, COleDateTime idexp); CStudentGiro(const CStudentGiro& stu); virtual ~CStudentGiro(); virtual bool EqualValue(const CAccount& acc) const; virtual bool ClassInvariant() const; virtual bool Copy(const CAccount& acc); virtual void Serialize(CArchive& ar); virtual void Show() const; double GetRateOfInterest() const; COleDateTime GetStudentIDExpirationDate() const; void SetRateOfInterest(double roi); void RenewStudentID(COleDateTime idexp); int CalculateBalance(COleDateTime dat) const; CStudentGiro& operator=(const CStudentGiro& stu); DECLARE_SERIAL(CStudentGiro) }; #endif // !defined(AFX_STUDENTGIRO_H__CBC03704_CAEB_45FA_A136_9E3324BCCBD3__INCLUDED_)

A.4 Savings.h // Savings.h: Schnittstelle für die Klasse CSavings. // //////////////////////////////////////////////////////////////////////

Page 44: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-4

#if !defined(AFX_SAVINGS_H__7F8333B8_D02A_449C_AD3F_953EE2C36571__INCLUDED_) #define AFX_SAVINGS_H__7F8333B8_D02A_449C_AD3F_953EE2C36571__INCLUDED_ #include <iostream> #include "Account.h" #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CSavings : public CAccount { private: double RateOfInterest; public: CSavings(); CSavings(int no, TAccountType typ, CString own, int bal, double roi); CSavings(const CSavings& sav); virtual ~CSavings(); virtual bool EqualValue(const CAccount& acc) const; virtual bool ClassInvariant() const; virtual bool Copy(const CAccount& acc); virtual void Serialize(CArchive& ar); virtual void Show() const; double GetRateOfInterest() const; void SetRateOfInterest(double roi); int CalculateBalance(COleDateTime dat) const; CSavings& operator=(const CSavings& sav); DECLARE_SERIAL(CSavings) }; #endif // !defined(AFX_SAVINGS_H__7F8333B8_D02A_449C_AD3F_953EE2C36571__INCLUDED_)

A.5 Register.h // Register.h: interface for the CRegister class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_REGISTER_H__6CE2B6B2_F4AB_4ED4_969F_29D06E3BE7CB__INCLUDED_) #define AFX_REGISTER_H__6CE2B6B2_F4AB_4ED4_969F_29D06E3BE7CB__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <afxcoll.h> #include "Account.h" class CRegister : public CObject { private:

Page 45: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-5

CObList Set; POSITION Cursor; CString RegisterInformation; COleDateTime DateOfCreation; protected: void SetCleanup(); public: CRegister(); CRegister(CString inf); CRegister* Generate() const; virtual ~CRegister(); bool ClassInvariant() const; bool Equal(const CRegister& reg) const; bool EqualValue(const CRegister& reg) const; bool EqualKey(const CRegister& reg) const; bool Copy(const CRegister& reg); void Serialize(CArchive& ar); CString KeyOf() const; bool Find(const CAccount& acc); bool Insert(const CAccount& acc); bool Scratch(); CAccount* GetFirst(); CAccount* GetNext(); CAccount* GetActual() const; int Card(); CString GetRegisterInformation() const; COleDateTime GetDateOfCreation() const; void SetRegisterInformation(CString inf); void Show(); DECLARE_SERIAL(CRegister) }; #endif // !defined(AFX_REGISTER_H__6CE2B6B2_F4AB_4ED4_969F_29D06E3BE7CB__INCLUDED_)

A.6 GSEBank.h // GSEBank.h : main header file for the GSEBANK application // #if !defined(AFX_GSEBANK_H__46F505EE_0161_4235_B1AF_1A02FED6E18B__INCLUDED_) #define AFX_GSEBANK_H__46F505EE_0161_4235_B1AF_1A02FED6E18B__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #ifndef __AFXWIN_H__ #error include 'stdafx.h' before including this file for PCH #endif #include "resource.h" // main symbols

Page 46: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-6

///////////////////////////////////////////////////////////////////////////// // CGSEBankApp: // See GSEBank.cpp for the implementation of this class // class CGSEBankApp : public CWinApp { public: CGSEBankApp(); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CGSEBankApp) public: virtual BOOL InitInstance(); //}}AFX_VIRTUAL // Implementation //{{AFX_MSG(CGSEBankApp) afx_msg void OnAppAbout(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_GSEBANK_H__46F505EE_0161_4235_B1AF_1A02FED6E18B__INCLUDED_)

A.7 GSEBankDoc.h // GSEBankDoc.h : interface of the CGSEBankDoc class // /////////////////////////////////////////////////////////////////////////// #if !defined(AFX_GSEBANKDOC_H__FEDC71F9_FA47_4B1D_BEBF_1BBB39F05277__INCLUDED_) #define AFX_GSEBANKDOC_H__FEDC71F9_FA47_4B1D_BEBF_1BBB39F05277__INCLUDED_ #include <afxcoll.h> #include "Account.h" #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CGSEBankDoc : public CDocument { protected: // create from serialization only CGSEBankDoc(); DECLARE_DYNCREATE(CGSEBankDoc) // Attributes

Page 47: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-7

public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CGSEBankDoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); //}}AFX_VIRTUAL // Implementation public: virtual ~CGSEBankDoc(); CAccount* GetActual() const; CAccount* GetNext(); CAccount* GetFirst(); bool Scratch(); int Card() const; bool Find(const CAccount& acc); bool Insert(const CAccount& acc); void OnExternalChanged(); COleDateTime GetDateOfCreation() const; void SetRegisterInformation(CString inf); CString GetRegisterInformation() const; #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: void SetCleanup(); //{{AFX_MSG(CGSEBankDoc) //}}AFX_MSG DECLARE_MESSAGE_MAP() private: CObList Set; POSITION Cursor; COleDateTime DateOfCreation; CString RegisterInformation; }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_GSEBANKDOC_H__FEDC71F9_FA47_4B1D_BEBF_1BBB39F05277__INCLUDED_)

Page 48: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-8

A.8 GSEBankView.h // GSEBankView.h : interface of the CGSEBankView class // ///////////////////////////////////////////////////////////////////////////// #if !defined(AFX_GSEBANKVIEW_H__597AED3E_3E4C_4A10_9CCD_3A89CEF3807A__INCLUDED_) #define AFX_GSEBANKVIEW_H__597AED3E_3E4C_4A10_9CCD_3A89CEF3807A__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CGSEBankView : public CListView { protected: // create from serialization only CGSEBankView(); DECLARE_DYNCREATE(CGSEBankView) // Attributes public: CGSEBankDoc* GetDocument(); // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CGSEBankView) public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: virtual void OnInitialUpdate(); // called first time after construct virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); //}}AFX_VIRTUAL // Implementation public: virtual ~CGSEBankView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: void CreateListHeaders(); CImageList m_SmallImageList; void ErrorMsg(UINT nID); //{{AFX_MSG(CGSEBankView) afx_msg void OnAccountCreate(); afx_msg void OnAccountDelete(); afx_msg void OnShowDetails(); afx_msg void OnDblclk(NMHDR* pNMHDR, LRESULT* pResult);

Page 49: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-9

afx_msg void OnAccountEdit(); afx_msg void OnDeposit(); afx_msg void OnWithdraw(); afx_msg void OnBankinfo(); afx_msg void OnOnlineUpdate(); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: bool m_bInitialized; }; #ifndef _DEBUG // debug version in GSEBankView.cpp inline CGSEBankDoc* CGSEBankView::GetDocument() { return (CGSEBankDoc*)m_pDocument; } #endif ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_GSEBANKVIEW_H__597AED3E_3E4C_4A10_9CCD_3A89CEF3807A__INCLUDED_)

A.9 ManageDlg.h #if !defined(AFX_MANAGEDLG_H__D759DEC9_DA94_499A_B0C5_F03E25B05E4E__INCLUDED_) #define AFX_MANAGEDLG_H__D759DEC9_DA94_499A_B0C5_F03E25B05E4E__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // ManageDlg.h : header file // #include "Account.h" ///////////////////////////////////////////////////////////////////////////// // CManageDlg dialog class CManageDlg : public CDialog { // Construction public: enum ManageMode { CREATENEW, EDITEXISTING, SHOWEXISTING }; ManageMode m_Mode; CAccount* m_pAccount; COleDateTime m_datStudentExp; COleDateTime m_datECExp; CManageDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CManageDlg) enum { IDD = IDD_DIALOG1 }; int m_nAccountType; int m_nDispo;

Page 50: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-10

UINT m_nECNo; UINT m_nAccountNo; CString m_strOwner; double m_dRateOfInterest; int m_nBalance; CString m_strCreationDate; CString m_strECExp; CString m_strStudExp; //}}AFX_DATA // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CManageDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: // Generated message map functions //{{AFX_MSG(CManageDlg) afx_msg void OnButtonSetecexp(); afx_msg void OnButtonSetstud(); afx_msg void OnSelchangeComboAcctype(); virtual BOOL OnInitDialog(); virtual void OnOK(); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: void SetEditableGUI(); bool CreateSavings(); bool CreateStudentGiro(); bool CreateGiro(); bool CreateAccount(); void ShowAccount(); }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_MANAGEDLG_H__D759DEC9_DA94_499A_B0C5_F03E25B05E4E__INCLUDED_)

A.10 DateChooser.h #if !defined(AFX_DATECHOOSER_H__2EAEE74E_72A8_4B13_8DC1_6BBB4675E388__INCLUDED_) #define AFX_DATECHOOSER_H__2EAEE74E_72A8_4B13_8DC1_6BBB4675E388__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // DateChooser.h : header file // ///////////////////////////////////////////////////////////////////////////// // CDateChooser dialog class CDateChooser : public CDialog

Page 51: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-11

{ // Construction public: COleDateTime m_selDate; CDateChooser(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CDateChooser) enum { IDD = IDD_DIALOG2 }; // NOTE: the ClassWizard will add data members here //}}AFX_DATA // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CDateChooser) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: // Generated message map functions //{{AFX_MSG(CDateChooser) virtual void OnOK(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_DATECHOOSER_H__2EAEE74E_72A8_4B13_8DC1_6BBB4675E388__INCLUDED_)

A.11 InputBox.h #if !defined(AFX_INPUTBOX_H__9FC9D988_7765_4BF2_8AAD_C6F8E9C9052F__INCLUDED_) #define AFX_INPUTBOX_H__9FC9D988_7765_4BF2_8AAD_C6F8E9C9052F__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // InputBox.h : Header-Datei // ///////////////////////////////////////////////////////////////////////////// // Dialogfeld CInputBox class CInputBox : public CDialog { // Konstruktion public: CInputBox(CWnd* pParent = NULL); // Standardkonstruktor // Dialogfelddaten //{{AFX_DATA(CInputBox)

Page 52: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

A-12

enum { IDD = IDD_DIALOG3 }; CString m_strInput; CString m_strPrompt; //}}AFX_DATA // Überschreibungen // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CInputBox) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL // Implementierung protected: // Generierte Nachrichtenzuordnungsfunktionen //{{AFX_MSG(CInputBox) // HINWEIS: Der Klassen-Assistent fügt hier Member-Funktionen ein //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ fügt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. #endif // AFX_INPUTBOX_H__9FC9D988_7765_4BF2_8AAD_C6F8E9C9052F__INCLUDED_

Page 53: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

B-13

Anhang B Abbildungsverzeichnis ABBILDUNG 1: TEILSYSTEMSTRUKTUR DES MVC-KONZEPTS............................................................... 5 ABBILDUNG 2: HAUPTFENSTER DES PROGRAMMSYSTEMS................................................................. 10 ABBILDUNG 3: DIALOG ZUR VERWALTUNG VON KONTEN.................................................................. 11 ABBILDUNG 4: STANDARD EINGABEAUFFORDERUNG.......................................................................... 11 ABBILDUNG 5: DIALOG ZUR EINFACHEN DATUMSAUSWAHL............................................................. 12 ABBILDUNG 6: TEILSYSTEMSTRUKTUR (ENTWURF).............................................................................. 13 ABBILDUNG 7: BEZIEHUNGEN ZWISCHEN KLASSEN (ENTWURF)....................................................... 13 ABBILDUNG 8: LÖSUNGSMODELL MIT DEN MFC .................................................................................... 17 ABBILDUNG 9: KONZEPT DER EREIGNISBEHANDLUNG ÜBER NACHRICHTENTABELLEN........... 18 ABBILDUNG 10: REKURSIVE SERIALISIERUNG DER MENGENKLASSE .............................................. 21 ABBILDUNG 11: AUTOMATISIERTES TESTEN DER KLASSENHIERARCHIE........................................ 23

Page 54: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

C-14

Page 55: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

C-15

Anhang C Literaturverzeichnis [Hor03] HORN, PROF. ERIKA: Vorlesungsmanuskript Grundlagen der Softwareentwicklung II. 2003. [HR02] HORN, ERIKA und THOMAS REINKE: Softwarearchitektur und Softwarebauelemente. Hanser,

München, Wien, 2002. [Lou00]LOUIS DIRK: C/C++ Kompendium. Markt&Technik, München, 2000. [MS03] Verschiedene Autoren: Microsoft Developers Network (MSDN) Library.

http://msdn.microsoft.com/library/default.asp sowie Platform SDK Release October 2002 http://www.microsoft.com/msdownload/platformsdk/

[Pro99] PROSISE JEFF: Programming Windows with MFC Second Edition. Microsoft Press 1999. [Str00] STROUSTRUP, BJARNE: Die C++ Programmiersprache. Professionelle Programmierung.

Addison-Wesley, München, vierte Auflage, 2000. Das Standardwerk zur Programmiersprache C++.

Page 56: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

D-16

Page 57: Praktikumsdokumentation · 2015-09-23 · Universität Potsdam Institut für Informatik Professur Informatik II Lehrveranstaltung Grundlagen der Softwareentwicklung II Prof. Dr. E

D-17

Anhang D Eidesstattliche Erklärung Hiermit erkläre ich an Eides statt und bestätige mit meiner Unterschrift, dass

1. wörtlich aus anderer Quelle übernommene Teile des Beleges deutlich als Zitat gekennzeichnet und mit Quellenangabe versehen sind,

2. sinngemäß aus anderer Quelle übernommene Teile des Beleges mit Quellen-angabe versehen sind,

3. alle übrigen Teile des Beleges, insbesondere die zu entwickelnde Software, ausschließlich von mir ohne inhaltliche oder wörtliche Übernahme von Teilen anderer Werke erarbeitet wurden.

Potsdam, den 20.08.2003

Christoph Stöpel