Kategorien

Softwaretechnik

Die letzte Lernzusammenfassung dieses Monats dreht sich um das Thema Softwaretechnik. Dabei wird es um die Herangehensweise an Softwareprojekte und die Modellierung der Software gehen.

Inhalt:
1 – Grundlagen
2 – Arbeitsmodelle für Softwareprojekte
3 – Statische Modellierung
4 – Dynamische Modellierung
5 – Gesamtbetrachtung
6 – Systemarchitektur
7 – Design Patterns
8 – Datenbankanbindung

1 – Grundlagen

Die Softwaretechnik, in diesem Fall die Objektorientierte Softwareentwicklung (OOSE), wurde geboren, als sich Ende der 60er Jahre herauskristallisierte, dass das bis dahin übliche intuitive Vorgehen an seine Grenzen stieß. Man ließ sich deswegen von den Ingenieurswissenschaften inspirieren (phasenweise Entwicklung, Muster) und versuchte so, ein wenig Ordnung ins Chaos zu bringen.

Softwaretechnik wird folgendermaßen definiert:

Softwaretechnik bzw. Software-Engineering ist die technische und organisatorische Disziplin zur systematischen Herstellung und Wartung von Softwareprodukten, die zeitgerecht und innerhalb vorgegebener Kostenschranken hergestellt und modifiziert werden.

Ziele der Softwaretechnik sind Software von hoher Qualität und Beherrschung der Kosten und Entwicklungszeit. Wie jedem aus dem Alltag bekannt ist, klappt das auch heute noch eher selten. Umso mehr ein Grund, sich mit der Softwaretechnik zu beschäftigen.

Für Software lassen sich zahlreiche Qualitätskriterien formulieren:

  1. Korrektheit: Software erfüllt die in der Spezifikation beschriebenen Anforderungen. Der Nachweis ist nur mit formalen Methoden möglich.
  2. Zuverlässigkeit: Die Wahrscheinlichkeit, dass die Software eine gewünschte Funktion in einer bestimmten Zeit erfüllt. Fehler sollten selten sein und, wenn vorhanden, dann nur schwach (ohne große Wirkung).
  3. Robustheit: Die Software sollte sinnvoll auf Fehler reagieren, die in der Umgebung auftreten (z.B. Bedienfehler der Nutzer).
  4. Benutzerfreundlichkeit: Einfache Erlernbarkeit und Bedienbarkeit.
  5. Wartbarkeit: Fehler sollten einfach zu lokalisieren und zu beheben sein. Außerdem sollte die Software einfach zu ändern und zu erweitern sein.
  6. Performanz: Angemessenes Laufzeitverhalten und Speicherbedarf.
  7. Dokumentation: Für Benutzer und Entwickler wichtig.
  8. Portabilität: Die Software sollte auf andere Rechner übertragbar sein.

Bei einem objektorientierten Softwaresystem handelt es sich um eine Menge von Objekten, die sich gegenseitig Nachrichten schicken. Der Empfang einer Nachricht löst eine Operation des empfangenden Objekts aus. Ein Objekt ist eine Instanz einer Klasse. Man könnte auch sagen: Eine Klasse beschreibt eine Menge von Objekten mit gemeinsamen Merkmalen. Objekte bestehen aus Attributen, Operationen und Beziehungen zu anderen Objekten. Der Zustand eines Objekts wird durch die aktuellen Attributwerte und Beziehungen zu anderen Objekten bestimmt. Der Systemzustand ist folglich der Zustand aller zu einem Zeitpunkt existierenden Objekte.

Der Vorteil einer objektorientierten Modellierung besteht darin, dass Objekte der realen Welt auf ein objektorientiertes System abgebildet werden können. Objektorientierte Techniken können auf verschiedenen Ebenen der Systementwicklung eingesetzt werden, von Analyse, über den Entwurf bis hin zum Programm selbst. Durch die Objektorientierung bleibt auch bei größeren Projekten der Überblick besser erhalten. Außerdem sind objektorientierte Systeme einfach erweiterbar und wartbar und man kann evtl. einzelne Teile davon bei anderen Projekten wiederverwenden.

Es gibt 3 Bereiche der Softwaretechnik. Das sind…

  1. Software-Entwicklung: Anforderungsanalyse, Entwurf, Implementierung, Wartung und Dokumentation
  2. Qualitätssicherung: Code-Inspection, Test, Validierung, Verifikation
  3. Projektmanagement: Planung, Koordination, Kontrolle

2 – Arbeitsmodelle

Es gibt einige Modelle, wie man an Softwareprojekte herangeht. Alle haben ihre Vor- und Nachteile. So wirklich begeistert mich keines davon.

Zum einen gibt es das Wasserfallmodell. Es beschreibt Softwareentwicklung als sequentielle Abfolge: Anforderungsanalayse -> Entwurf -> Implementierung -> Test -> Wartung & Einsatz. Der Nachteil des Wasserfallmodells ist, dass der Kunde das Produkt erst ganz am Ende validieren kann. Außerdem ist ein streng sequentielles Vorgehen gar nicht möglich, da Anforderungen sich manchmal ändern und Fehler oft erst später erkannt werden.

Die einzelnen Phasen möchte ich näher erläutern:

  • Anforderungsanalyse: Sie dreht sich um die Frage “Was soll das System leisten?”. Sie basiert auf einer Anforderungsspezifikation, die der Entwickler mit dem Kunden (vertraglich) vereinbart. Sie dient als Grundlage für die weitere Entwicklung und legt z.B. eine grobe Terminplanung und Rahmenbedingungen fest.
  • Entwurf: Hier steht die Frage “Wie lösen wir das?” im Mittelpunkt. Der Entwurf legt die Systemarchitektur fest und spezifiziert einzelne Systemkomponenten. Ergebnis der Phase ist eine Entwurfsbeschreibung.
  • Implementierung: Der Entwurf wird in einer Programmiersprache codiert.
  • Test: einzelne Komponenten (Unit Tests), schrittweises Zusammenfügen der Einzelkomponenten mit jeweiligem Integrationstest, Systemtest und schließlich Abnahmetest.
  • Wartung: besteht aus Fehlerbeseitigung nach Inbetriebnahme und Änderung und Erweiterung des Systems. Sie verursacht 67% der Kosten (davon 40% zum Verständnis existierender Programme)

Eine weitere Herangehensweise bietet das Iterative Modell. Hier wiederholen sich die Phasen nach einem Durchlauf wieder: Analyse -> Entwurf -> Implementierung ->Test / Wartung -> Analyse -> …. Am Ende jedes Zyklus steht eine Version, die die vorherige verbessert und erweitert (sog. “evolutionäres Prototyping”). Vorteilhaft ist auch der häufige Kundenkontakt. Das Risiko besteht darin, dass die neu hinzukommenden Teile wegen der Anforderungen nicht zu den bestehenden passen.  Eine spezielle Ausprägung des Iterativen Modells ist der Unified Process (anwendungsfall-getrieben).

Ähnlich dazu ist das prototyp-orientierte Modell. Hier wird nur mit Prototypen agiert und diese mit den Wünschen des Kunden abgeglichen. Nachteilig ist allerdings, dass lange Zeit nur eine eingeschränkte Funktionalität angeboten werden kann, die Ergebnisse selten robust sind und schlechte Performanz haben.

Etwas bekannter ist auch XP, “Extreme Programming”. Dabei setzt man sich meist mit einem zweiten Entwickler an einen Rechner (4 Augen sehen mehr und schneller Fehler als zwei). XP ist test-getrieben. Es wird das einfachste implementiert, das funktioniert, das System restrukturiert (Refactoring) und dann getestet.

Schließlich gibt es noch das Spiralmodell, desssen Grundidee die Risikobeherrschung ist. Es beginnt mit einem Life-Cycle-Plan, und spiraliert dann nach außen über die Sektoren Risikoanalyse, der jeweils ein Prototyp folgt, Entwicklung und Validierung, Planung der nächsten Phasen, die ein Review enthält, und dem Festlegen von Zielen, Varianten, Bedingungen und Einschränkungen. Meines Erachtens zu kompliziert, um wirklich genutzt zu werden.

3 – Statische Modellierung

Ein statisches Modell beschreibt strukturelle und datenbezogene Eigenschaften, ein dynamisches Modell dagegen das Verhalten der Objekte, deren Zustandsänderungen und Interaktionen. Die Notation nutzt UML (Unified Modeling Language).

Der verlinkte Wikipedia-Artikel erklärt so ziemlich alles wichtige, deswegen werde ich davon absehen die entsprechenden Klassen- und Objektdiagramme durchzukauen. Die Beziehungen zwischen Klassen möchte ich allerdings herausgreifen. Darunter befinden sich die Möglichkeiten…

  • Komposition: symbolisiert durch ausgefüllte Raute. Das Teil ist existenzabhängig vom Ganzen, wird erst nach ihm erzeugt und mit ihm gelöscht.
  • Aggregation: symbolisiert durch leere Raute. Gesamtheit-Teil-Beziehung.
  • Abhängigkeit: symbolisiert durch gestrichelte Linie plus Pfeil. Änderungen im Ziel verursachen mglw. Änderungen im abhängigen Element.
  • Vererbung: symbolisiert durch Linie mit leerer Pfeilspitze. Dabei ist die Oberklasse A die Generalisierung der Unterklasse B bzw. B die Spezialisierung von A. Es herrscht das Substitutionsprinzip, d.h. statt einem Objekt der Oberklasse kann ein Objekt der Unterklasse genutzt werden.
  • Schnittstellen: symbolisiert durch “<<interface>>” im Körper. Nutzende Klassen verbinden mit einem (gestrichelten) Pfeil, realisierende Klassen verbinden mit einer gestrichelten Linie mit leerer Pfeilspitze. Auch bei Schnittstellen herrscht das Substitutionsprinzip: Statt dem Interface-Typ kann auch die realisierende Klasse genommen werden. Schnittstellen sind ein wichtiges Strukturierungsmittel für flexible Softwarearchitekturen.

Die einzelnen Elemente können verschiedene Sichtbarkeiten haben: öffentlich = für alle sichtbar (+name), privat = nur innerhalb der Klasse (-name), protected = in der Klasse und ihren Subklassen und außerhalb des Pakets, wenn Klasse öffentlich (#name) und schließlich komponenten-privat = nur innerhalb des Pakets (~name), was bei Java die Grundeinstellung ist.

Zur statischen Modellierung gehört auch die Betrachtung der Use-Cases (Anwendungsfälle). Dabei nehmen Aktoren gegenüber einem System eine Rolle ein. Die Anwendungsfälle beschreiben die Interaktionen zwischen den beteiligten Aktoren und sind auf eine bestimmte Aufgabe bezogen. Definiert ist ein Use-Case folgendermaßen:

Ein Anwendungsfall ist eine Menge von verhaltensverwandten Sequenzen von Transaktionen, die durch ein System ausgeführt werden und ein messbares Ergebnis liefern.

Sonderlich viel schlauer ist man nach der Definition allerdings nicht. Bei der Erstellung eines Use-Case-Modells geht man so vor:
- Bestimmung der Aktoren, die mit dem System interagieren
- Bestimmung der Anwendungsfälle aufgrund der von Aktoren gewünschten Aufgaben
- Erstellung eines Use-Case-Diagramms
- Beschreibung der Anwendungsfälle nach dem Schema: Name, Kurzbeschreibung, Vorbedingung, Nachbedingung, Standardablauf, Alternativabläufe und evtl. Aktivitätsdiagramm.

4 – Dynamische Modellierung

Zur Modellierung des dynamischen Verhaltens verwendet man Interaktionsdiagramme, Aktivitätsdiagramme und Zustandsdiagramme.

Die Dynamik ist stark von Ereignissen bestimmt. Es gibt 5 Arten von Ereignissen:

  1. Signal Event: Empfang eines Signals (z.B. “Knopf gedrückt”).
  2. Call Event: Aufruf einer Operation (z.B. konto.einzahlen(50)…).
  3. Change Event: Eine Bedingung wird wahr (z.B. when (temperatur < 0)…).
  4. Time Event: Ablauf einer Zeitvorgabe (z.B. after(5sec)…).
  5. Completion Event: Beendigung einer Aktivität (z.B. “Internetseite geladen”).

Zustandsdiagramm

Ein Zustandsdiagramm besteht aus einem Graph, dessen Knoten Zustände und dessen Kanten Transitionen sind. Die Transitionen werden bestimmt durch Ereignisse, die noch durch Bedingungen (Guards) und Aktivitäten ergänzt werden können. Die Bedingungen müssen nach Durchlaufen der Transition noch gelten.

Aktivitäten, die während eines Zustands ablaufen, können entweder als selbstbezogene Transition oder als innere Aktivität modelliert werden. Spezielle Aktivitäten sind entry (immer eingangs, nicht unterbrechbar), exit (immer ausgangs, n.u.), do (u.) und defer. Ein verzögertes Ereignis e, das mit e/defer markiert ist, aber im Zustand keine ausgehende Transition hat, wird aufbewahrt und erst dann verarbeitet, wenn sich das Objekt in einem anderen Zustand mit dieser Möglichkeit befindet.

Komplexe, sequentielle Unterzustände können mit einer umschließenden Box markiert werden. Wie normale Zustandsdiagramme können auch sie Start- und Endpunkt haben. Parallele Unterzustände markiert man mit horizontalen gestrichelten Linien, zwischen denen sich die nebenläufigen Zustände befinden.

Ein Zustand, dem eine Aktivität zugeordnet ist und der nur durch ein (evtl. bedingtes) Completion Event verlassen werden kann, heißt Aktivitätszustand. Ein Zustand, dem keine Aktivität zugeordnet ist, heißt stabiler Zustand oder inaktiver Zustand.

Aktivitätsdiagramme

Aktivitätsdiagramme dienen zur Darstellung des Ablaufs von Geschäftsprozessen, Use-Cases (s.u.) oder von Operationen. Ein Aktivitätsdiagramm ist ein gerichteter Graph, dessen Knoten Aktionen, Kontrollstrukturen und Daten sind, und dessen Kanten die Abläufe beschreiben. Aktivitätsdiagramme sehen ähnlich aus wie Zustandsdiagramme.

Fallunterscheidungen/Bedingungen modelliert man entweder durch Entscheidungsknoten (meist als Raute) oder durch einen Fork, dessen ausgehende Kanten die entsprechenden Bedingungen beinhalten (wie Guards bei ZD).

Interaktionsdiagramme

Interaktionsdiagramme sind entweder Kommunikationsdiagramme oder Sequenzdiagramme (SD). Beide Diagramme stellen i.W. die selbe Information dar.

Sequenzdiagramme heben die zeitliche Reihenfolge hervor, in der Nachrichten zwischen den Objekten versandt und empfangen werden. Sie verlaufen von oben nach unten (entlang der “Lebenslinie” der Objekte). Synchrone Nachrichten haben einen geschlossenen Pfeil, asynchrone einen offenen. Aktivierte Objekte haben ein fortlaufendes Rechteck auf ihrer Lebenslinie, das bei synchronen Nachrichten weiterläuft, solange auf die Rückgabe des Steuerungsfokus (gestrichelter offener Pfeil) gewartet wird. Alternative Abläufe (z.B. bei einer Fallunterscheidung) können durch ein entsprechendes überspannendes Feld markiert werden, das die entsprechenden Fälle nacheinander aufführt.

Kommunikationsdiagramme heben die strukturellen Beziehungen aller an einer Interaktion beteiligten Objekte hervor. Die zeitliche Reihenfolge wird durch fortlaufende Nummern dargestellt.

5 – Gesamtbetrachtung

Die Analysephase besteht aus den Abschnitten
1. Use-Case-Analyse
2. Entwicklung eines statischen Modells (Klassendiagramme)
3. Entwicklung eines dynamischen Modells (Interaktions-, Zustands-, Aktivitätsdiagramme)
4. Validieren, Überarbeiten und Erweitern der Modelle

Die in der Analyse erarbeiteten Dokumente (Use-Case-Modelle, Problembeschreibungen) dienen als Grundlage für die Entwicklung eines statischen Modells. Ihr Ziel ist ein Klassendiagramm (noch ohne Operationen). Dafür sind folgende Schritte notwendig:

  1. Klassen identifizieren (Personen, Organisationen, Gegenstände, …)
  2. Assoziationen bestimmen (konzeptionelle Verbindung, Besitzverhältnis, …)
  3. Attribute identifizieren
  4. Vererbung einführen (durch Generalisierung und Spezialisierung)
  5. Modell überarbeiten (fehlende Klassen, Typen, Multiplizitäten, …)

Die Use-Case-Beschreibungen und das statische Modell sind schließlich der Input für den Entwurf von Interaktionsdiagrammen. Dazu identifiziert man die an einem Anwendungsfall beteiligten Objekte und die Nachrichten, die sie austauschen. Für jeden Anwendungsfall bzw. dessen Szenarien erstellt man dann ein oder mehrere Interaktionsdiagramme (i.d.R. Sequenzdiagramme).

Aufbauend auf den Interaktionsdiagrammen kann man dann Zustands- und Aktivitätsdiagramme entwickeln. Für jede Klasse mit “interessantem Verhalten” erstellt man ein Zustandsdiagramm.

Interessantes Verhalten heißt, dass das Objekt einen nicht-trivialen (=zustandsabhängigen) Lebenszyklus hat, d.h.:
1. Es gibt mindestens ein Ereignis, das in Abhängigkeit vom Objektzustand unterschiedliche Reaktionen auslösen kann.
2. Mindestens ein Ereignis wird in bestimmten Zuständen ignoriert bzw. kann dort nicht auftreten.

Bei der Konstruktion eines Zustandsdiagramms ist wie folgt vorzugehen:

  1. Ein SD wählen, das eine typische Interaktion für ein Objekt der betrachteten Klasse zeigt (i.A. Primärszenario).
  2. Der Lebenslinie des Objekts folgen und daraus eine Kette von Zuständen und Transitionen bilden, sodass
    - inaktive Phasen sind stabile Zustände
    - aktive Phasen sind Aktivitätszustände (Aufruf von lokalen Operationen)
    - eintreffende Ereignisse modelliert man durch Transitionen von stabilen Zuständen in Akt.zustände
    - Beendigung einer Aktivität ist eine Transition mit einem Completion Event von einem Akt.zustand in einen stabilen Zustand
  3. Zyklen für sich wiederholende Folgen bilden.
  4. Bei weiteren SDs für Objekte der betrachteten Klasse den Aktivitätszustand finden, wo die Sequenz vom bisherigen Verhalten abweicht und die neue Folge als Alternative an diesen Zustand anhängen.
  5. Konstruiere Aktivitätsdiagramme für lokale Operationen, die in Aktivitätszuständen aufgerufen werden (siehe 2.)
  6. Zustandsdiagramm verfeinern durch Einfügen von Bedingungen bei Transitionen, die von Aktivitätszuständen ausgehen.
  7. Sekundärszenarien integrieren, soweit nötig.

Nun kann man zum Objektentwurf ansetzen und …

  1. Operationen hinzufügen (aus den Sequenz- und Aktivitätsdiagrammen ersichtlich)
  2. Assoziationen ausrichten
  3. Zugriffsrechte bestimmen (dabei Attribute und Rollennamen nicht öffentlich)
  4. Mehrfachvererbung auflösen (durch Einführung von Schnittstellen)
  5. Wiederverwendung von Klassen einführen (durch Spezialisierung und Delegation)

Delegation bedeutet dabei, ein Attribut der verwendenden Klasse mit einer Referenz auf die Instanz der wiederzuverwendenden Klasse zuzugreifen.

Wenn man nun will, dass der Objektentwurf das im Zustandsdiagramm beschriebene Verhalten realisiert, kann man dies mit einer der folgenden Möglichkeiten bewerkstelligen:

  1. Prozedurgesteuert: Ereignisse werden durch erzwungene Benutzereingaben realisiert (geht nur, wenn Objekt an der Systemgrenze). Nachteil: unflexibel.
  2. Fallunterscheidung: Enumeration für die stabilen Zustände, explizites Zustandsattribut für betrachtete Klasse, zustandsabhängige Operationen durch Fallunterscheidung nach derzeitigem Zustand (siehe Attribut) realisieren. Nachteil: Bei neuen Zuständen muss jede Operation erweitert werden.
  3. Zustandsobjekte: Jedes Objekt hat ein zugehöriges Zustandsobjekt. Der Aufruf einer zustandsabhängigen Operation wird an das Zustandsobjekt delegiert, das dann die gewünschte Aktivität ausführt. Bei Zustandsänderung wird ein neues Zustandsobjekt erzeugt und mit dem Basisobjekt verbunden. Nachteil: Bei neuen Operationen muss jeder Zustand erweitert werden. Siehe Design-Pattern State.
  4. Zustandsmaschine: Alle Größen im Zustandsdiagramm (Zustände, Ereignisse, Transitionen, Aktivitäten) werden durch Objekte dargestellt. Ereignisse werden von einem Event-Handle (spezielle Operation) interpretiert. Das gesamte Zustandsdiagramm wird dann durch eine verzeigerte Objektstruktur repräsentiert.

6 – Systemarchitektur

Die Systemarchitektur beschreibt die Gesamtstruktur des Softwaresystems durch Subsysteme (Pakete und Komponenten) und Beziehungen zwischen diesen Subsystemen. Dabei gelten folgende Grundregeln:

  1. Hohe Kohärenz: Zusammenfassung zusammengehörender Teile eines Systems in einem Subsystem.
  2. Geringe Kopplung: Wenige Abhängigkeiten zwischen den einzelnen Subsystemen.

Der Vorteil davon ist, dass einzelne Teile dadurch leicht änderbar und austauschbar sind.

Gebräuchlich sind auch Schichtenarchitekturen, bekannt z.B. das OSI-Modell. Bei geschlossenen Architekturen darf eine Schicht nur auf die direkt darunterliegende Schicht zugreifen, ansonsten redet man von offenen Architekturen. Wenn verschiedene Schichten auf verschiedenen Rechnern sind, spricht man von Client-Server-Systemen. Eine Schicht kann selbst aus Subsystemen bestehen. Für die Softwaretechnik ist v.a. die 3-Schichten-Architektur für betriebliche Informationssysteme von Belang:

  1. Benutzerschnittstelle
  2. Anwendungskern
  3. Datenbankschnittstelle
  4. Datenbank

Die Datenbank wird nicht zum System dazugerechnet. Ein “Thick-Client” hat 1 und 2 auf dem selben Rechner, ein “Thin-Client” (z.B. eine Web-Anwendung) hat 1 und 2 auf unterschiedlichen Rechnern. Die Betrachtung der 3-Schichten-Architektur führt zum Model-View-Controller-Muster (MVC), einem Verbund von Entwurfsmustern bzw. Design Patterns.

7 – Design Patterns

Um MVC wirklich zu verstehen, muss man ein paar Muster kennen. Entwurfsmuster wurden geschaffen, um für oft wiederkehrende Probleme, die zueinander ähnlich sind, eine standardisierte Lösung zu haben. Sie haben den Vorteil, dass die Lösungsprinzipien wiederverwendbar sind, man damit Entwürfe abstrakt dokumentieren kann und Entwickler damit ein gemeinsames Vokabular zur leichteren Verständigung haben.

Man kann die gängigen Entwurfsmuster in drei Klassen unterteilen:

  1. Creational Patterns: befassen sich mit der Erzeugung von Objekten. Beispiele sind Abstract Factory oder Singleton.
  2. Structural Patterns: strukturelle Komposition von Objekten. Beispiele sind Adapter, Facade oder Composite.
  3. Behavioral Patterns: Interaktion von Objekten und Verteilung von Verantwortlichkeiten. Beispiele sind Iterator, Observer, Template Method, State oder Strategy.

Davon möchte ich einige herausgreifen. Zuerst die Abstract Factory. Sie stellt eine Schnittstelle zum Erzeugen mehrerer zusammengehöriger oder verwandter Objekte zur Verfügung, ohne dass dazu die konkreten Objektklassen benötigt werden.

Klassendiagramm der Abstract Factory

Klassendiagramm der Abstract Factory

Auch wichtig ist das Composite-Pattern. Es erlaubt, sowohl einzelne als auch zusammengesetzte Objekte einer Baumstruktur einheitlich zu behandeln. Es wird zum Beispiel für die GUI-Komponenten (AWT/Swing) in Java genutzt.

Klassendiagramm des Composite-Musters

Klassendiagramm des Composite-Musters

Ein weiteres wichtiges Muster ist das State-Pattern. Es ermöglicht, dass ein Objekt sein Verhalten in Abhängigkeit von seinem Zustand ändern kann. Damit eignet es sich zur Realisierung von Zustandsdiagrammen via Zustandsobjekte.

Klassendiagramm des State-Musters

Klassendiagramm des State-Musters

Eines der wichtigsten und häufigsten Muster ist Observer. Es arbeitet wie ein Newsletter-Verteiler: Wenn es etwas neues über das observierte Objekt gibt, dann schickt es an alle Angemeldeten eine Änderungsnotiz.

Klassendiagramm des Observer-Musters

Klassendiagramm des Observer-Musters

Das vorhin genannte MVC ist eine Kombination aus Mustern, genauer gesagt eine Vereinigung von Observer, Strategy und Composite:

  • View und Controller implementieren Strategy. Alle Entscheidungen über das Verhalten delegiert View an Controller. View bleibt so entkoppelt vom Model, mit dem nur der Controller interagiert.
  • View selbst kann als Composite modelliert werden, z.B. indem jede Anzeigenkomponente (z.B. Fenster) ein Kompositum oder ein Blatt (z.B. Button) ist. Eine Aktualisierung des Views ruft einfach die entsprechende Funktion im Wurzelknoten auf, der dann entsprechend dem Muster den Aufruf weiterreicht.
  • Das Observer-Muster findet beim Model seine Anwendung. Interessierte Objekte werden bei Zustandsänderungen des Models informiert. So könnte man bspw. mehrere Views an ein Model binden.

MVC dient, wie bereits genannt, zur Implementierung der 3-Schichten-Architektur. Dabei dient View als Benutzerschnittstelle, Controller als Anwendungskern und Model als Datenbankanbindung. Diese Äquivalenz ist allerdings in Fachkreisen umstritten und wird von vielen Programmierern unterschiedlich gehandhabt (siehe dazu auch die Diskussionen im eher schlechten Wikipedia-Artikel).

Die “Kommunikation” im MVC spielt sich folgendermaßen ab:

  1. V->M – attach(): V bindet sich als Observer an M.
  2. V->C – handleEvent(): Der Nutzer hat im Interface ein Event ausgelöst, die View reicht es an den Controller weiter.
  3. C->V – manipulate(): C manipuliert V (z.B. ein Dialog “Bitte Warten…”).
  4. C->M – service(): C weist M an, entsprechende Daten zu ändern.
  5. M->V – update(): M schickt eine Änderungsnotiz an seine Observer.
  6. V->M – getData(): V holt sich die neuen Daten.
  7. V – showData(): V zeigt dem Nutzer die aktualisierte Sicht auf die Daten.

8 – Datenbankanbindung

Es kann vorkommen, dass man Objekte in einer Datenbank speichern will. Das Objektmodell kann man folgendermaßen auf Tabellen/Relationen abbilden:

  • Bei der Abbildung von Klassen wird für jede Klasse ein Primärschlüsselattribut eingeführt.
  • Bei Multiplizität A* – *B (viele zu viele) erstellt man eine eigene Relation mit den Schlüsseln von A und B.
  • Bei Multiplizität A* – (0..1)B bindet man den Schlüssel von B als Fremdschlüssel in A ein.
  • Bei Multiplizität 0..1 – 0..1 nimmt man den Schlüssel der einen als Fremdschlüssel in die andere Relation auf.
  • Bei Vererbung hat man wie gehabt eine Tabelle pro Klasse, muss allerdings beachten, dass bei Anfragen, die Objekte der Unterklassen betreffen, ggf. Einträge in mehreren Relationen berücksichtigt werden. Man könnte auch in die Tabellen der Unterklassen die geerbten Attribute eintragen. Wenn sich allerdings die Oberklasse ändert, müssen auch die Unterklassen geändert werden. Eine dritte Möglichkeit ist, eine Tabelle für alle zu nutzen. Dann muss man allerdings an manchen Stellen NULL-Werte eintragen.

Der Rückweg (genannt Materialisierung) funktioniert umgekehrt analog.

So, das war’s erstmal wieder… genug Stoff zu lernen!

Artikel drucken Artikel drucken

1 comment to Softwaretechnik

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>