Inhalt Abbildung PDF Source OO-Designkurs
 |<    <     >    >|  Generated by CoCoDiL

3.4 Objektorientierte Designprinzipien

Es gibt wahrscheinlich kein komplexeres Programm das nicht gegen mindestens einer der folgenden Designprinzipien vertösst. Man sollte die Designprinzipien nicht als Bibel, aber trotzdem ernst nehmen.

3.4.1 Das Single Responsibility Prinzip SRP

Was ist an dieser Klasse problematisch?.


Abb. 3.3: Klasse die das SRP Prinzip verletzt

Die Klasse in der obigen Abbildung weiss zuviel.

In der Anfangszeit der Objektorientierung hat man fehlerhaft gemeint, ein Domain Objekt weiss selber wie es sich abspeichert, wie es sich selber an der Benutzungsoberfläche darstellt usw.

Wenn man in der obigen Klasse Employee statt in ein XML-Stream in eine Datenbank abspeichert, muss die Klasse Employee geändert werden. Das SRP sagt, dass verschiedene Verantwortlichkeiten in verschiedenen Klassen implementiert werden soll.


Abb. 3.4: Klassen die das SRP Prinzip berücksichtigen

3.4.2 Das Open Closed Prinzip OCP

Das Open Closed Prinzip besagt, dass es möglich sein sollte ein Modul zu erweitern, ohne es selber verändern zu müssen.

SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION.

Betrachte folgendes Klassendiagramm:


Abb. 3.5: Verletzung Open Closed Prinzip

Im Client verdoppelt die Methode changeMySalary() meinen Gehalt. Schliesslich habe ich es verdient.

public void changeMySalary(){
    ConcreteDatabase database = ConcreteDatabase.soleInstance();
    String personalIdKlausMeucht = "4711";
    Employee ich = database.readEmployee(personalIdKlausMeucht);
    ich.setSalary(ich.getSalary() * 2);
    database.saveEmployee(ich);
}

Diese Methode zeigt allerdings, dass ich eine Gehaltserhöhung nicht verdient habe. (Übersehen wir mal die Verwendung von singleton und des MagicValues 4711)

Es ist schwer einen Unittest für diese Methode zu schreiben, da die Klasse Client und ConcreteDatabase fest miteinander verkoppelt sind.

Ein Unittest mit der Verwendung einer konkreten Datenbank ist nicht sinnvoll, da das Schreiben auf die Datenbank Zeit kostet und die Unittests unabhängig von der Datenbank sein soll.

Sinnvoll wäre es die ConcreteDatabase mit einer simulierten Datenbank aus Softwarebasis auszutauschen. Da der Client und ConcreteDatabase eng miteinander gekoppelt sind, kann ich die Datenbank nicht austauschen. Der Client ist nicht offen gegenüber einen Austausch der Datenbank.

Eine Möglichkeit für die Entkopplung ist die Verwendung von Interfaces. Der Client sollte nicht von einer konkreten Implementierung, sondern nur von einer Schnittstelle abhängig sein. Damit kann man die konkrete Implementierung austauschen.

Im folgenden Beispiel ist der Client offen gegenüber einer neuen Datenbankklasse. Ein Unittest kann nun sehr einfach die Datenbank austauschen.


Abb. 3.6: Offen gegenüber Austausch der Datenbank

Die Methode changeMySalary() sieht folgendermassen aus.

public void changeMySalary(){
    I_Database database = DataseFactory.getConcreteDatabase();
    String personalIdKlausMeucht = "4711";
    Employee ich = database.readEmployee(personalIdKlausMeucht);
    ich.setSalary(ich.getSalary() * 2);
    database.saveEmployee(ich);
}

3.4.3 The Liskov Substitution Prinzip LSP

Unterklassen sollen anstelle ihrer Oberklassen einsetzbar sein. Unterklassen sollten Methoden von Oberklassen immer erweitern, aber nicht wegnehmen.Vermeide es Methoden der Oberklassen durch leere Implementierungen zu überschreiben. Beim Überschreiben von Methoden aus einer Oberklasse sollte sichergestellt sein, dass die Unterklasse in jedem Fall für die Oberklasse einsetzbar bleibt.

Beipsiel für Verletzung des Liskov Prinzips:


Abb. 3.7: Verletzung Liskov Prinzip

Obwohl wir alle aus dem Mathematik Unterricht wissen, dass ein Quadrat ein Rechteck ist; ist es problematisch ein Quadrat als Unterklasse von Rechteck zu implementieren. Das Problem liegt darin dass ein Quadrat Eigenschaften eines Rechtecks nicht erweitert sonder einschränkt. In der Methode tueEtwas müsste man um korrekt zu sein, abfragen ob ein Rechteck in Wirklichkeit ein Quadrat ist.

D.h der Client muss Wissen über die Unterklassen von Rechteck haben und dies verstösst neben dem Liskov Prinzip auch das Open-Closed Prinzip

3.4.4 The Dependency Inversion Principle DIP

Nutzer einer Dienstleistung sollten möglichst von Abstraktionen (d.h abstrakten Klassen oder Interfacaes) , nicht aber von konkreten Implementierungen abhängig sein. Abstraktionen sollten auf keinen Fall von konkreten Implementierungen abhängig sein.

3.4.5 The Interface Segregation Principle ISP

Clients sollten nicht von Diensten abhängig, die sie nicht benötigen. Interfaces gehören ihren Clients, nicht den Klassenhierarchien, die diese Interfaces implementieren. Entwerfen Sie Schnittstellen nach den Clients, die diese Schnittstellen brauchen.


Abb. 3.8: Interface Segregation Principle
Inhalt Abbildung PDF Source OO-Designkurs
 |<    <     >    >|  Generated by CoCoDiL