Subsysteme können auf
verschiedene komplementäre Arten verwendet werden, um das System in Einheiten zu unterteilen, die
-
unabhängig voneinander angeordnet, konfiguriert und bereitgestellt werden können,
-
die unabhängig voneinander entwickelt werden können, solange die Schnittstellen unverändert bleiben,
-
die unabhängig voneinander auf mehreren verteilten Rechenknoten eingesetzt werden können,
-
die unabhängig voneinander geändert werden können, ohne andere Teile des Systems zu beeinträchtigen.
Subsysteme eignen sich somit ideal für die Modellierung von Komponenten, den austauschbaren Assemblierungseinheiten in
der komponentenbasierten Entwicklung, die größer sind als eine einzelne Designklasse.
Außerdem können Subsysteme
-
das System in Einheiten einteilen, die eine eingeschränkte Sicherheit für die Schlüsselressourcen gewährleisten,
-
vorhandene Produkte oder externe Systeme im Design darstellen.
Eine komplexe Analyseklasse wird einem Designsubsystem zugeordnet, wenn sie Verhalten zu enthalten scheint, das nicht
in der Zuständigkeit einer einzelnen Designklasse allein liegen kann. Eine komplexe Designklasse kann auch zu einem
Subsystem werden, wenn sie wahrscheinlich in Form einer Gruppe kollaborierender Klassen implementiert wird.
Subsysteme sind außerdem ein probates Mittel, um Teile des Systems zu identifizieren, die unabhängig von einem anderen
Team entwickelt werden. Wenn die kollaborierenden Designelemente zusammen mit ihren Kollaborationen vollständig in
einem Paket enthalten sein können, kann ein Subsystem eine stärkere Form der Kapselung unterstützen als ein einfaches
Paket. Inhalt und Kollaborationen in einem Subsystem sind vollständig hinter einer oder mehreren Schnittstellen
isoliert, so dass der Client des Subsystems nur von der Schnittstelle abhängig ist. Der Designer des Subsystems ist
damit vollständig von externen Abhängigkeiten isoliert. Der Designer (bzw. das Designerteam) muss festlegen, wie die
Schnittstelle realisiert wird, aber er hat völlige Freiheit, das interne Subsystemdesign zu ändern, ohne damit externe
Abhängigkeiten zu beeinträchtigen. In großen Systemen mit weitgehend unabhängigen Teams ist dieser Grad von
Entkopplung, kombiniert mit der Architekturumsetzung durch formale Schnittstellen ein schlagkräftiges Argument für die
bevorzugte Wahl von Subsystemen gegenüber einfachen Paketen.
Das Designsubsystem wird verwendet, um diese Kollaborationen so zu kapseln, dass den Clients des Subsystems das interne
Design des Subsystems völlig verborgen bleibt, selbst wenn sie die vom Subsystem bereitgestellten Services nutzen. Wenn
die an einer Kollaboration teilnehmenden Klassen/Subsysteme nur mit einander interagieren, um eine klar definierte
Menge von Ergebnissen zu liefern, sollten die Kollaboration und die kollaborierenden Designelemente in einem Subsystem
gekapselt werden.
Diese Regel kann auch auf Untergruppen von Kollaborationen angewendet werden. Kollaborationen können vollständig oder
teilweise und überall gekapselt und vereinfacht werden. Auf diese Weise wird das Design verständlicher.
Hinweise
Hinweis
|
Details
|
Optionalität erkennen
|
Wenn eine bestimmte Kollaboration (oder untergeordnete Kollaboration) optionales Verhalten darstellt,
schließen Sie sie in ein Subsystem ein. Features, die entfernt, aktualisiert oder ersetzt werden
können, müssen unabhängig davon betrachtet werden.
|
Benutzerschnittstelle des System betrachten
|
Wenn die Benutzerschnittstelle relativ unabhängig von den Entitätsklassen im System ist (d. h.
Benutzerschnittstelle und Entitätsklassen können und werden unabhängig von einander geändert),
erstellen Sie Subsysteme, die horizontal integriert werden. Gruppieren Sie zusammengehörige
Grenzklassen der Benutzerschnittstelle in einem Subsystem und zusammengehörige Entitätsklassen in einem
anderen Subsystem.
|
Wenn die Benutzerschnittstelle und die Entitätsklassen eng miteinander gekoppelt sind (d. h. eine
Änderung in einem Teil löst eine Änderung im anderen aus), erstellen Sie Subsysteme, die vertikal
integriert werden. Schließen Sie zusammengehörige Grenz- und Entitätsklassen in ein gemeinsames
Subsystem ein.
|
Akteure anschauen
|
Trennen Sie Funktionalität, die von zwei unterschiedlichen Akteuren verwendet werden, da jeder Akteur
die Anforderungen an das System unabhängig ändern kann.
|
Erstellen Sie Subsysteme, um den Zugriff auf ein externes System oder eine externe Einheit zu kapseln.
|
Kopplung und Kohäsion zwischen Designelementen betrachten
|
Eng miteinander gekoppelte oder kohäsive Klassen/Subsysteme kollaborieren und stellen gemeinsam eine
Gruppe von Services zur Verfügung. Fassen Sie eng miteinander gekoppelte Elemente in Subsystemen
zusammen und trennen Sie Elemente, die nur lose gekoppelt sind. Manchmal kann eine lose Kopplung
verhindert werden, indem die Klassen in kleinere Klassen mit kohäsiveren Zuständigkeiten aufgeteilt
oder Subsysteme entsprechend partitioniert werden.
|
Substitution anschauen
|
Wenn mehrere Servicestufen für eine bestimmte Funktionalität angegeben sind (z. B. hohe, mittlere und
niedrige Verfügbarkeit), stellen Sie jede Servicestufe als separates Subsystem dar, von denen jedes
dieselben Schnittstellen realisiert. Auf diese Weise sind die Subsysteme gegeneinander austauschbar.
|
Verteilung anschauen
|
Obwohl
es mehrere Instanzen eines Subsystems geben kann, die auf unterschiedlichen Knoten ausgeführt werden
können, ist es in vielen Architekturen nicht möglich, dass eine Instanz einer Komponente auf mehrere
Knoten verteilt wird. Wenn Subsystemverhalten auf mehrere Knoten verteilt werden muss, wird empfohlen,
das Subsystem in kleinere Subsysteme (die jeweils eine Komponente darstellen) mit einer
eingeschränkteren Funktionalität zu zerlegen.
Bestimmen Sie die Funktionalität für jeden Knoten und erstellen Sie für genau diese Funktionalität ein
neues Subsystem. Auf diese Weise können Sie die Zuständigkeiten und zugehörigen Elemente des
ursprünglichen Subsystems entsprechend verteilen.
Die neuen Subsysteme sind Interna des ursprünglichen Subsystems.
|
Nachdem Sie das Design in Subsysteme unterteilt haben, aktualisieren Sie die Anwendungsfallrealisierungen entsprechend.
Designsubsysteme werden mit UML-Komponenten modelliert. Dieses Konstrukt unterstützt die folgenden
Modellierungsmöglichkeiten:
-
Sie kann Klassen gruppieren, um ein Teil eines Systems mit größerer Unterteilung zu definieren.
-
Sie kann die sichtbaren Schnittstellen von der internen Implementierung abgrenzen.
-
Sie kann Instanzen haben, die zur Laufzeit ausgeführt werden.
Beachten Sie die folgenden Hinweise:
-
Jedes Designsubsystem muss einen Namen und eine Kurzbeschreibung erhalten.
-
Die Zuständigkeiten der ursprünglichen Analyseklasse müssen auf das neu erstellte Subsystem übertragen werden.
Verwenden Sie die Beschreibung des Subsystems, um die Zuständigkeiten zu dokumentieren.
Anmerkung: UML 2.0 definiert außerdem einen Stereotyp für Komponenten mit dem Namen <<Subsystem>>, der
darauf hinweist, dass diese Komponente beispielsweise für die Darstellung großer Strukturen verwendet werden kann. Ein
RUP-Designsubsystem kann eine große Struktur sein oder nicht. Beides ist aus der RUP-Perspektive ein Designsubsystem.
Der Softwarearchitekt muss entscheiden, ob beispielsweise Komponenten, die sich aus Komponenten zusammensetzen, als
<<Subsysteme>> bezeichnet werden.
Wenn ein vorhandenes Produkt Schnittstellen exportiert, d. h. Operationen (und möglicherweise Rezeptionen), aber ansonsten alle Details der Implementierung verdeckt, kann
es in der logischen Sicht als Subsystem modelliert werden. Beispiele für Produkte, die das System verwendet und die Sie
unter Umständen mit einem Subsystem darstellen können, sind:
-
Datenübertragungssoftware (Middleware),
-
Unterstützung für Datenbankzugriffe (Unterstützung für RDBMS-Zuordnung),
-
anwendungsspezifische Produkte.
Einige vorhandene Produkte wie Sammlungen von Typen und Datenstrukturen (z. B. Stacks, Listen und Warteschlangen)
lassen sich besser als Pakete darstellen, da sie mehr als Verhalten aufdecken, und es ist gerade der Inhalt des Pakets,
der wichtig und hilfreich ist, und nicht das Paket an sich, das einfach nur ein Container ist.
Gemeinsame Dienstprogramme wie Mathematikbibliotheken können als Subsysteme dargestellt werden, wenn sie lediglich
Schnittstellen exportieren. Ob dies jedoch erforderlich oder sinnvoll ist, richtet sich nach der Designerbeurteilung
der zu modellierenden Elemente. Subsysteme sind objektorientierte Konstrukte (da sie modellierte Komponenten sind). Ein
Subsystem kann Instanzen haben (wenn der Designer es entsprechend angibt). UML unterstützt außerdem die Modellierung
von Gruppen globaler Variablen und Prozeduren in Dienstprogrammen. Ein Dienstprogramm (utility) ist ein Stereotyp einer Klasse.
Dienstprogramme haben keine Instanzen.
Wenn Sie das Subsystem für die Darstellung des Produkts definieren, müssen Sie auch eine oder mehrere Schnittstellen
definieren, um die Produktschnittstellen darzustellen.
Designsubsysteme (die als UML-Komponenten modelliert werden) unterscheiden sich von Paketen in ihrer Semantik. Ein
Subsystem stellt Verhalten über eine oder mehrere Schnittstellen bereit, die es realisiert. Pakete stellen kein
Verhalten bereit. Sie sind lediglich Container für Elemente, die Verhalten bereitstellen.
Der Grund für die Verwendung eines Subsystems anstelle eines Pakets ist der, dass ein Subsystem seinen Inhalt kapselt
und Verhalten nur über seine Schnittstellen bereitstellt. Dies hat im Gegensatz zu einem Paket den Vorteil, dass Inhalt
und internes Verhalten eines Subsystems flexibel geändert werden können, solange die Schnittstellen des Subsystems
konstant bleiben. Subsysteme sind außerdem 'austauschbare Designelemente'. Wenn zwei
<<Realisierungskomponenten>> dieselben Schnittstellen (oder <<Spezifikationskomponente>>)
realisieren, sind sie gegeneinander austauschbar.
Um sicherzustellen, dass Subsysteme austauschbare Elemente im Modell sind, müssen einige Regeln beachtet werden:
-
Ein Subsystem sollte so wenig wie möglich Verhalten offen legen. Idealerweise sollte kein Element in einem
Subsystem 'öffentlich' sichtbar sein, so dass kein Element außerhalb des Subsystems von der Existenz eines
bestimmten Elements im Subsystem abhängig ist. Es gibt diverse Ausnahmen:
-
In einigen Technologien können die Externa eines Subsystems nicht als UML-Schnittstelle modelliert werden.
Eine Java-Schnittstelle wird beispielsweise als stereotypierte Klasse modelliert.
-
Das Subsystemdesign kann erfordern, dass Klassen anstelle von UML-Schnittstellen offen gelegt werden.
Beispielsweise kann eine Delegierungs- oder Zugriffsklasse verwendet werden, um eine komplexe Kollaboration
anderer Klassen zu verbergen. Sie könnten hier auch ein herkömmliches Paket verwenden. Mit einem Subsystem
können Sie allerdings die Zielsetzung untermauern, Verhalten zu kapseln und interne Details zu verdecken.
-
Wenn die Externa eines Subsystems keine UML-Schnittstellen sind, ist es häufig hilfreich, die sichtbaren Elemente
des Subsystems in einem Diagramm (das Sie beispielsweise "Externe Sicht" nennen könnten) zu zeigen.
-
Ein Subsystem muss seine Abhängigkeiten von Subsystemschnittstellen (und für die zuvor beschriebenen Sonderfälle
von öffentlich sichtbaren Elementen des Subsystems) definieren. Außerdem können mehrere Subsysteme Schnittstellen-
oder Klassendefinitionen gemeinsam nutzen. In diesem Fall 'importieren' diese Subsysteme den Inhalt der Pakete, die
die gemeinsamen Elemente enthalten. Dies ist häufiger der Fall bei Paketen der unteren Schichten in der
Architektur, um sicherzustellen, dass gemeinsame Definitionen von Klassen, die zwischen Subsystemen ausgetauscht
werden müssen, konsistent definiert sind.
Im Folgenden sehen Sie ein Beispiel für Subsystem- und Paketabhängigkeiten:
Subsystem- und Paketabhängigkeiten im Designmodell
Die UML ([UML04]) definiert Folgendes:
Es existieren verschiedene UML-Standardstereotypen für Komponenten, z. B. <<Spezifikation>>
(Specification) und <<Realisierung>> (Realization) für die Modellierung von Komponenten mit eindeutigen
Spezifikations- und Realisierungsdefinitionen, wobei eine Spezifikation mehrere Realisierungen haben kann.
Eine Komponente mit dem Stereotyp <<Spezifikation>> spezifiziert eine Domäne von Objekten, ohne die
physische Implementierung dieser Objekte zu definieren. Sie enthält nur bereitgestellte und erforderliche
Schnittstellen und in ihrer Definition keine realisierenden Klassen und Unterkomponenten.
Eine Komponente mit dem Stereotyp <<Realisierung>> (Realization) spezifiziert eine Domäne von Objekten
und definiert außerdem die physische Implementierung dieser Objekte. Beispielsweise enthält eine Komponente mit dem
Stereotyp <<Realisierung>> (Realization) nur realisierende Klassen und Unterkomponenten, die Verhalten
implementieren, das von einer gesonderten Komponente <<Spezifikation>> (Specification) spezifiziert
wird.
Die Trennung von Spezifikation und Realisierung lässt im Wesentlichen zwei separate Beschreibungen des Subsystems zu.
Die Spezifikation dient als Vertrag, der alles definiert, was ein Client wissen muss, um das Subsystem verwenden zu
können. Die Realisierung wird detailliert im internen Design beschrieben, das den Implementierer anleitet. Wenn Sie
mehrere Realisierungen unterstützen möchten, erstellen Sie separate "Realisierungssubsysteme" und zeichnen Sie eine
Realisierung von jedem Realisierungssubsystem zum Spezifikationssubsystem.
Wenn der interne Zustand und das Verhalten des Subsystems relativ einfach sind, kann es ausreichen, das Subsystem mit
den offen gelegten Schnittstellen, Zustandsdiagrammen für die Beschreibung des Verhaltens und beschreibendem Text zu
spezifizieren.
Für komplexere interne Zustände und Verhalten können Analyseklassen verwendet werden, um das Subsystem auf einer
höheren Abstraktionsebene zu spezifizieren. Für große Systeme mit Systemen kann die Spezifikation eines Subsystems auch
Anwendungsfälle enthalten. Weitere Informationen hierzu finden Sie im Whitepaper Developing Large-Scale Systems with the Rational Unified Process.
Eine von der Realisierung gesonderte detaillierte Spezifikation kann in den folgenden Situationen äußerst hilfreich
sein:
-
Der interne Zustand oder das Verhalten der Subsystemrealisierung ist komplex, und die Spezifikation muss so einfach
wie möglich ausgedrückt werden, damit sie von den Clients effektiv genutzt werden kann.
-
Das Subsystem ist eine wiederverwendbare "Assemblierungskomponente", die für die Integration in mehrere Systeme
bestimmt ist (siehe Konzept:
Komponente).
-
Die Interna des Subsystems werden voraussichtlich von unterschiedlichen Organisationen entwickelt.
-
Es müssen mehrere Implementierungen des Subsystems erstellt werden.
-
Das Subsystem wird voraussichtlich durch eine andere Version ersetzt, die signifikante interne Änderungen ohne
Änderungen am extern sichtbaren Verhalten aufweist.
Die Verwaltung einer separaten Spezifikation bedeutet jedoch Aufwand, weil sichergestellt werden muss, dass die
Realisierung des Subsystems mit der Spezifikation kompatibel ist. Die Kriterien dafür, wann und ob gesonderte
Spezifikations- und Realisierungsklassen und Kollaborationen erstellt werden sollen, müssen in den projektspezifischen Richtlinien definiert werden.
Eine Spezifikation muss ihre Abhängigkeiten definieren. Es handelt sich hierbei um die Schnittstellen und sichtbaren
Elemente aus anderen Subsystemen und Paketen, die in allen kompatiblen Realisierungen des Subsystems verfügbar sein
müssen.
Eine Realisierung kann zusätzliche Abhängigkeiten haben, die vom Designer oder Implementierer eingeführt werden.
Beispielsweise könnte eine Dienstprogrammkomponente verwendet werden, um die Implementierung zu vereinfachen, aber die
Verwendung dieser Dienstprogrammkomponente ist ein Detail, die den Clients nicht offen gelegt werden muss. Diese
zusätzlichen Abhängigkeiten müssen im Rahmen der Realisierung in einem separaten Diagramm erfasst werden.
Eine vollständig detaillierte Spezifikation definiert alles, was ein Client benötigt, um das Subsystem verwenden zu
können. Das bedeutet, dass die offen gelegten Schnittstellen und alle öffentlich sichtbaren Elemente so präzisiert
werden müssen, dass sie dem Code 1:1 entsprechen. Analyseklassen, die eingeführt werden, um das Subsystemverhalten zu
spezifizieren, sollten auf einer hohen Abstraktionsebene bleiben, da sie von allen Subsystemrealisierungen unabhängig
bleiben sollen.
Die Realisierungselemente eines Subsystems müssen eng am Code ausgerichtet sein.
Weitere Informationen zu diesem Thema finden Sie in Technik: Zuordnung von Design zu Code.
Modellierung
Designsubsysteme können als UML-2.0-Komponenten oder als UML-1.5-Subsysteme modelliert werden. Diese Konstrukte
unterstützen nahezu dieselben Modellierungsmöglichkeiten wie Modularität, Kapselung und Instanzen, die zur Laufzeit
ausgeführt werden können.
Schauen Sie sich die folgenden zusätzlichen Hinweise zu diesen Modellierungsoptionen an:
-
UML-1.5-Subsystem enthalten explizit die Begriffe "Spezifikation" und "Realisierung" (siehe Definition im Abschnitt
Subsystemspezifikation und -realisierung oben). Die
UML-2.0-Komponenten unterstützen die Begriffe Spezifikation (in Form einer oder mehrerer bereitgestellter und
erforderlicher Schnittstellen) und Realisierung (interne Implementierung, die sich aus einer oder mehreren Klassen
und Unterkomponenten zusammensetzt, die das Verhalten realisieren).
-
UML-1.5-Subsysteme sind auch Pakete. UML-2.0-Komponenten haben Paketmerkmale, d. h. sie können eine potenziell
umfangreiche Menge von Modellelementen enthalten und importieren.
Im Großen und Ganzen sind diese Notationen jedoch gegeneinander austauschbar. Ob Designsubsysteme als
UML-1.5-Subsysteme oder UML-2.0-Komponenten dargestellt werden, ist eine Entscheidung, die in den projektspezifischen Richtlinien für Ihr Projekt dokumentiert werden
muss.
Wenn Ihr Tool für visuelle Modellierung UML-1.5-Pakete, aber keine UML-1.5-Subsysteme unterstützt, kann ein Paket mit
dem Stereotyp <<Subsystem>> für die Beschreibung eines Subsystems verwendet werden.
Einschränkungen für Subsystemabhängigkeiten
Die Einschränkungen und Erläuterungen aus dem Abschnitt Einschränkungen für Subsystemabhängigkeiten gelten gleichermaßen auch
für Designsubsysteme, die als UML-1.5-Subsysteme modelliert werden.
Im Folgenden sehen Sie ein Beispiel für Subsystem- und Paketabhängigkeiten in UML 1.5:
Subsystem- und Paketabhängigkeiten im Designmodell
Subsystemspezifikation und -realisierung
UML 1.5 definiert Folgendes:
Der Inhalt eines Subsystems wird in zwei Untergruppen eingeteilt: 1) Spezifikationselemente und 2)
Realisierungselemente. Die Spezifikationselemente werden zusammen mit den Operationen und Rezeptionen des
Subsystems verwendet, um eine abstrakte Spezifikation des von den Realisierungselementen bereitgestellten
Verhaltens zu formulieren. Die Sammlung der Realisierungselemente modelliert die Interna der Verhaltenseinheit des
physischen Systems.
Die Trennung von Spezifikation und Realisierung lässt im Wesentlichen zwei separate Beschreibungen des Subsystems zu.
Die Spezifikation dient als Vertrag, der alles definiert, was ein Client wissen muss, um das Subsystem verwenden zu
können. Die Realisierung wird detailliert im internen Design beschrieben, das den Implementierer anleitet.
Eine Option für die Modellierung von Spezifikationen und Realisierungen, falls diese nicht direkt von der
Modellierungsumgebung unterstützt werden, ist die, in jedes Subsystem zwei Pakete, Spezifikation und Realisierung, zu
stellen.
Eine Motivation für Spezifikationen ist die Unterstützung mehrerer Realisierungen. Dies wird in UML 1.x nicht direkt
unterstützt. Wenn Sie mehrere Realisierungen mit UML-1.5-Subsystemen unterstützen möchten, müssen Sie separate
"Realisierungssubsysteme" erstellen und eine Realisierung von jedem Realisierungssubsystem zum Spezifikationssubsystem
zeichnen.
Im Wesentlichen sind die für Spezifikation und Realisierung in UML 2.0 geltenden Richtlinien auch hier (siehe Verwendung, Abhängigkeiten und Beziehung zur Implementierung).
Zusätzliche Informationen
Lesen Sie auch den Artikel Unterschiede zwischen UML 1.x und UML 2.0.
|