Grundlagen der Informatik I “Programmierung”

Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”

22.08.2013 Aufrufe

4.1.1 Analyse und Gestaltung Softwaresysteme werden nur selten losgelöst von einem konkreten Bezug zur realen Welt erstellt. Deshalb besteht die wesentliche Aufgabe beim Entwurf von Softwaresystemen fast immer darin, den für die Problemstellung relevanten Ausschnitt der realen Welt zu modellieren. Softwareentwickler stehen also vor der Aufgabe, einen Bezug zwischen der realen Welt und der Denkwelt von Computeralgorithmen herstellen zu müssen. Das verlangt zum einen, den vorgesehenen Einsatzbereich des Softwareproduktes und das zugehörige Umfeld sowie eventuelle Nebenwirkungen des Softwareeinsatzes zu verstehen, und zum anderen, einen derartigen Teil der realen Welt auf formale Modelle zu reduzieren, was zwangsläufig eine drastische Beschränkung der Sicht der realen Welt mit sich bringen wird. Informatiker befinden sich daher immer in einer Doppelrolle. Einerseits sind sie Entdecker der Gesetzmäßigkeiten des Umfelds, das sie modellieren und durch ihr Softwareprodukt beeinflussen wollen. Anderseits sind sie aber auch Gestalter (oder Erfinder) eines Modells, das den relevanten Ausschnitt der Welt wiederspiegelt und durch das entstehende Produkt wieder eine Rückwirkung auf die reale Welt – zum Beispiel auf Arbeitsabläufe innerhalb eines Betriebs – haben wird. Sie als zukünftige Informatiker müssen sich dieser Doppelrolle immer bewußt sein. Ihre Aufgaben und Ihre Verantwortung geht weit über die reine Technik (das Codieren eines Programms) hinaus: Sie müssen die bestehende Welt und natürlich auch die Problemstellung analysieren und sich dafür entscheiden, wie Sie sie durch Ihr Softwareprodukt gestalten wollen. Erst danach können Sie an eine konkrete Implementierung denken. Dementsprechend ist der Entwurf eines Softwaresystems in zwei prinzipiellen Schritten auszuführen: 1. Am Anfang eines Entwurfs steht die Analyse der Leistungen, die das Programm an seine Klienten erbringen soll. Ergebnis der Analyse ist eine Reihe von Attributen, Methoden und Funktionen, die der Anwender abrufen kann. Jede einzelne Leistung entspricht einer Routine, deren Wirkung über ihren Kontrakt beschrieben ist. Das Gesamtangebot an Leistungen des Systems wird üblicherweise als Schnittstelle bezeichnet. 1 Für jede einzelne Leistung wird ihr Kontrakt bestimmt und für das Gesamtprogramm die Zusicherungen, die alle Prozeduren als Nachbedingung garantieren – also die Invariante. Damit ist die äußere Sicht des Programms (Grobspezifikation) abgeschlossen und der inhaltliche Teil des Pflichtenhefts definiert: Es ist vollständig festgelegt, was das Programm leisten soll. Diese Aufgabe muß meist in Kooperation mit Spezialisten aus den Anwendungsbereichen geschehen, da den Informatikern meist die notwendige Kompetenz fehlt. Das befreit Informatiker allerdings nicht von der Pflicht, sich in die Denkweise der entsprechenden Dispziplinen einzuarbeiten. 2. Der nächste Schritt ist der kreative Anteil am Entwurf. Man überlegt sich, wie die einzelnen Angebote realisiert werden können. Die Beschreibung davon nennt man Feinspezifikation. Das Grundprinzip ist dabei eine Zerlegung des Systems in unabhängige kooperierende Komponenten (Separation of Concerns), also die Frage, welche Objekte benötigt werden, um die geforderten Leistungen mit geringem Aufwand zu beschreiben. Hierzu muß man versuchen, Objekte zu spezifizieren, aus deren Merkmalen man die geforderten Leistungen zusammenbauen kann. Zur Durchführung dieser Schritte ist eine Menge Einfallsreichtum und Begabung und vor allem auch eine Menge von Erfahrung und Training erforderlich. Dennoch lassen sich – zumindest für den zweiten Schritt – ein paar allgemeine Leitlinen angeben, die ein erfolgreiches Vorgehen fördern. Hierzu wollen wir zunächst noch einmal die Grundmerkmale der objektorientierten Vorgehensweise resümieren. 1 Ist der Klient ein Anwender (im Gegensatz zu Systemen, bei dem der Klient wiederum ein technisches Systems ist, wie z.B. bei ABS-Systemen, Waschmaschinen, autonomen Waffensystemen), dann wird er nicht direkt diese Routinen aufrufen sondern wird ein Menü sehen, das die einzelnen Routinen kennzeichnet. Die aktuellen Parameter werden dann innerhalb eines Dialogs abgefragt. In diesem Fall nennt man die Schnittstelle Benutzerschnittstelle (User Interface) und seine Darstellung Benutzeroberfläche.

4.1.2 Grundideen des objektorientierten Entwurfs Bei einem reinen objektorientierten Vorgehen, wie es durch die Programmiersprache Eiffel unterstützt wird, ist zu beachten, daß Klassen der einzige Strukturierungsmechanismus für Systeme sind. Sie sind unabhängige Einheiten, obwohl sie durch Benutzung und Vererbung miteinander verbunden sein können. Aus Sicht der Programmiersprache liegen alle Klassen auf der gleichen Ebene und dürfen – genau wie Routinen – nicht geschachtelt werden. Diese Eigenständigkeit von Softwareteilen ist wesentlich für Wiederverwendbarkeit und einer der wichtigsten Unterschiede zu den gängigen blockstrukturierten Sprachen. Eine Klasse kann als ein Lager von Dienstleistungen (exportierten features) angesehen werden, die auf den Exemplaren eines Datentyps verfügbar sind. Diese Dienste werden allen Kunden, die sie überhaupt benutzen dürfen, gleichermaßen zur Verfügung gestellt: • Es gibt keine Operationen mit höherer oder niedriger Bedeutung, insbesondere keine Hauptfunktion – selbst dann, wenn bestimmte Dienste häufiger in Anspruch genommen werden als andere. • Es gibt keine Vorschriften über die Reihenfolge, in der Dienstleistungen aufgerufen werden dürfen. Die Reihenfolge mag zwar bei der eigentlichen Ausführung eines Systems von großer Bedeutung sein. Es wäre jedoch ein Fehler, diese Reihenfolge schon bei der Deklaration der entsprechenden Dienstleistungen einzufrieren. Die Festlegung einer solchen Reihenfolge ist ausschließlich Sache der Kunden. Natürlich gibt es Gründe festzulegen, daß eine Operation wie das Herausnehmen von Elementen aus einer Liste nur ausgeführt werden kann, wenn zuvor eine andere Operation – das Einfügen von mindestens einem Element – stattgefunden hat. Dies ist aber eine Vorbedingung für die Ausführbarkeit der Operation und sollte auch als solche formuliert werden. Es liegt dann in der Verantwortung des Kunden, was er damit macht. Eine Folge dieses Prinzips ist, daß es keine Gründe gibt, die Anzahl der features einer Klasse zu beschränken. Hat eine Operation einen logischen Bezug zu dieser Klasse, so kann man sie hinzufügen, auch wenn unklar ist, ob sie von vielen Kunden benötigt wird. 2 Das Problem, daß eine Klasse eine unüberschaubare Größe bekommen kann, ist verhältnismäßig gering, da eine zu große Anzahl von Dienstleistungen (ein zu breites Spektrum im Lager) selten stört, da man sich bei der Betrachtung von Informationen auf die features beschränken kann, die man tatsächlich braucht. Einzig die Suche nach noch unbekannten, aber eventuell brauchbaren features wird durch eine zu große Anzahl von features etwas erschwert. Anders ist es beim Code einer einzelnen Routine. Dieser sollte kurz und überschaubar bleiben, was aber bei der objektorientierten Sichtweise von Routinen als wohldefinierte Einzeldienstleistung selten ein Problem werden wird. Aufgrund der Hervorhebung des Wiederverwendbarkeitsaspektes eignen Klassen sich besonders für einen Entwurfsstil, der sich stark auf bereits existierende Module stützt (“Bottom-up Entwurf”). 3 Die Stärke der objektorientierten Programmierung liegt in der Aktivierung fertiger Programmteile. Deshalb lohnt es, sich mit vordefinierten Klassen der Eiffel-Basisbibliothek und gegebenenfalls auch anderer Bibliotheken vertraut zu machen und neu zu entwickelnden Klassen möglichst allgemein zu gestalten, damit sie später auch in anderen Lösungen verwendet werden können. 2Das Problem, daß hierdurch beim Zusammensetzen eines Systems viel unbenutzter Code erzeugt wird, kann durch den Eiffel-Optimierer gelöst werden. 3Natürlich kann man den Entwurf nicht losgelöst von der eigentlichen Problemstellung durchführen. Ein reiner “Top-Down Entwurf”, wie er früher favorisiert wurde, konzentriert sich aber zu sehr auf das Problem und man muß wichtige Entscheidungen über die Softwarestruktur in einer Phase fällen, in der das Bild noch sehr vage ist und Wesentliches von Unwesentlichem noch nicht getrennt werden kann. Dadurch – und vor allem durch Vernachlässigung der Tatsache, daß es bereits Lösungen für ähnlich gelagerte Problemstellungen geben kann – wird der Entwickler von der Komplexität des Problems geradezu erschlagen und Fehlentscheidungen werden gravierende Folgen auf das entstehende Produkt haben. Top-Down Entwicklung von Programmen bietet sich erst während der Implementierungsphase an, nachdem die Struktur des Gesamtsystems bereits so weit untergliedert ist, daß jedes Teilproblem überschaubar ist.

4.1.2 Grundideen des objektorientierten Entwurfs<br />

Bei einem reinen objektorientierten Vorgehen, wie es durch die Programmiersprache Eiffel unterstützt wird,<br />

ist zu beachten, daß Klassen <strong>der</strong> einzige Strukturierungsmechanismus für Systeme sind. Sie sind unabhängige<br />

Einheiten, obwohl sie durch Benutzung und Vererbung miteinan<strong>der</strong> verbunden sein können. Aus Sicht <strong>der</strong><br />

Programmiersprache liegen alle Klassen auf <strong>der</strong> gleichen Ebene und dürfen – genau wie Routinen – nicht<br />

geschachtelt werden. Diese Eigenständigkeit von Softwareteilen ist wesentlich für Wie<strong>der</strong>verwendbarkeit und<br />

einer <strong>der</strong> wichtigsten Unterschiede zu den gängigen blockstrukturierten Sprachen.<br />

Eine Klasse kann als ein Lager von Dienstleistungen (exportierten features) angesehen werden, die auf den<br />

Exemplaren eines Datentyps verfügbar sind. Diese Dienste werden allen Kunden, die sie überhaupt benutzen<br />

dürfen, gleichermaßen zur Verfügung gestellt:<br />

• Es gibt keine Operationen mit höherer o<strong>der</strong> niedriger Bedeutung, insbeson<strong>der</strong>e keine Hauptfunktion –<br />

selbst dann, wenn bestimmte Dienste häufiger in Anspruch genommen werden als an<strong>der</strong>e.<br />

• Es gibt keine Vorschriften über die Reihenfolge, in <strong>der</strong> Dienstleistungen aufgerufen werden dürfen.<br />

Die Reihenfolge mag zwar bei <strong>der</strong> eigentlichen Ausführung eines Systems von großer Bedeutung sein. Es<br />

wäre jedoch ein Fehler, diese Reihenfolge schon bei <strong>der</strong> Deklaration <strong>der</strong> entsprechenden Dienstleistungen<br />

einzufrieren. Die Festlegung einer solchen Reihenfolge ist ausschließlich Sache <strong>der</strong> Kunden.<br />

Natürlich gibt es Gründe festzulegen, daß eine Operation wie das Herausnehmen von Elementen aus<br />

einer Liste nur ausgeführt werden kann, wenn zuvor eine an<strong>der</strong>e Operation – das Einfügen von mindestens<br />

einem Element – stattgefunden hat. Dies ist aber eine Vorbedingung für die Ausführbarkeit <strong>der</strong><br />

Operation und sollte auch als solche formuliert werden. Es liegt dann in <strong>der</strong> Verantwortung des Kunden,<br />

was er damit macht.<br />

Eine Folge dieses Prinzips ist, daß es keine Gründe gibt, die Anzahl <strong>der</strong> features einer Klasse zu beschränken.<br />

Hat eine Operation einen logischen Bezug zu dieser Klasse, so kann man sie hinzufügen, auch wenn unklar ist,<br />

ob sie von vielen Kunden benötigt wird. 2 Das Problem, daß eine Klasse eine unüberschaubare Größe bekommen<br />

kann, ist verhältnismäßig gering, da eine zu große Anzahl von Dienstleistungen (ein zu breites Spektrum im<br />

Lager) selten stört, da man sich bei <strong>der</strong> Betrachtung von Informationen auf die features beschränken kann,<br />

die man tatsächlich braucht. Einzig die Suche nach noch unbekannten, aber eventuell brauchbaren features<br />

wird durch eine zu große Anzahl von features etwas erschwert.<br />

An<strong>der</strong>s ist es beim Code einer einzelnen Routine. Dieser sollte kurz und überschaubar bleiben, was aber<br />

bei <strong>der</strong> objektorientierten Sichtweise von Routinen als wohldefinierte Einzeldienstleistung selten ein Problem<br />

werden wird.<br />

Aufgrund <strong>der</strong> Hervorhebung des Wie<strong>der</strong>verwendbarkeitsaspektes eignen Klassen sich beson<strong>der</strong>s für einen<br />

Entwurfsstil, <strong>der</strong> sich stark auf bereits existierende Module stützt (“Bottom-up Entwurf”). 3 Die Stärke <strong>der</strong><br />

objektorientierten Programmierung liegt in <strong>der</strong> Aktivierung fertiger Programmteile. Deshalb lohnt es, sich<br />

mit vordefinierten Klassen <strong>der</strong> Eiffel-Basisbibliothek und gegebenenfalls auch an<strong>der</strong>er Bibliotheken vertraut<br />

zu machen und neu zu entwickelnden Klassen möglichst allgemein zu gestalten, damit sie später auch in<br />

an<strong>der</strong>en Lösungen verwendet werden können.<br />

2Das Problem, daß hierdurch beim Zusammensetzen eines Systems viel unbenutzter Code erzeugt wird, kann durch den<br />

Eiffel-Optimierer gelöst werden.<br />

3Natürlich kann man den Entwurf nicht losgelöst von <strong>der</strong> eigentlichen Problemstellung durchführen. Ein reiner “Top-Down<br />

Entwurf”, wie er früher favorisiert wurde, konzentriert sich aber zu sehr auf das Problem und man muß wichtige Entscheidungen<br />

über die Softwarestruktur in einer Phase fällen, in <strong>der</strong> das Bild noch sehr vage ist und Wesentliches von Unwesentlichem noch<br />

nicht getrennt werden kann. Dadurch – und vor allem durch Vernachlässigung <strong>der</strong> Tatsache, daß es bereits Lösungen für ähnlich<br />

gelagerte Problemstellungen geben kann – wird <strong>der</strong> Entwickler von <strong>der</strong> Komplexität des Problems geradezu erschlagen und<br />

Fehlentscheidungen werden gravierende Folgen auf das entstehende Produkt haben. Top-Down Entwicklung von Programmen<br />

bietet sich erst während <strong>der</strong> Implementierungsphase an, nachdem die Struktur des Gesamtsystems bereits so weit unterglie<strong>der</strong>t<br />

ist, daß jedes Teilproblem überschaubar ist.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!