Prinzipien objektorientierten Designs sind Prinzipien, die zu gutem objektorientierten Design führen sollen. Sie wurden neben anderen von Robert C. Martin, Bertrand Meyer und Barbara Liskov publiziert und propagiert. Viele Techniken der Objektorientierung wie Entwurfsmuster, Domain-driven Design oder Dependency Injection basieren auf diesen Prinzipien objektorientierten Designs.

Für eine Gruppe dieser Prinzipien wurde von Robert C. Martin das Akronym “SOLID” geprägt. Diese Prinzipien gemeinsam angewandt führt laut Robert C. Martin zu einer höheren Wartbarkeit und somit Lebensdauer von Software. Diese Prinzipien sind das “Single Responsibility Prinzip”, das “Open-Closed Prinzip”, das “Liskovsches Substitutionsprinzip”, das “Interface Segregation Prinzip” und das “Dependency Inversion Prinzip”.

Darüber hinaus gibt es noch eine Reihe weiterer mehr oder weniger bekannter Prinzipien objektorientierten Designs wie Design by contract oder das Gesetz von Demeter. Eine Sonderstellung unter den Prinzipien objektorientierten Designs haben die sogenannten Packaging Prinzipien, da diese sich alle mit der Gruppierung von Klassen zu Packages beschäftigen.

SOLID-Prinzipien Single-Responsibility-Prinzip

Das Single-Responsibility-Prinzip besagt, dass jede Klasse nur eine einzige Verantwortung haben solle. Verantwortung wird hierbei als „Grund zur Änderung“ definiert:

Mehr als eine Verantwortung für eine Klasse führt zu mehreren Bereichen, in denen zukünftige Änderungen notwendig werden können. Die Wahrscheinlichkeit, dass die Klasse zu einem späteren Zeitpunkt geändert werden muss, steigt zusammen mit dem Risiko, sich bei solchen Änderungen subtile Fehler einzuhandeln. Dieses Prinzip führt in der Regel zu Klassen mit hoher Kohäsion, in denen alle Methoden einen starken gemeinsamen Bezug haben.

Open-Closed-Prinzip

Das Open-Closed-Prinzip besagt, dass Software-Einheiten (hier Module, Klassen, Methoden usw.) Erweiterungen möglich machen sollen (dafür offen sein), aber ohne dabei ihr Verhalten zu ändern (ihr Sourcecode und ihre Schnittstelle sollte sich nicht ändern). Es wurde 1988 von Bertrand Meyer folgendermaßen formuliert:

Eine Erweiterung im Sinne des Open-Closed-Prinzips ist beispielsweise die Vererbung. Diese verändert das vorhandene Verhalten einer Klasse nicht, erweitert sie aber um zusätzliche Funktionen oder Daten. Überschriebene Methoden verändern auch nicht das Verhalten der Basisklasse, sondern nur das der abgeleiteten Klasse. Folgt man weiter dem Liskovschen Substitutionsprinzip, verändern auch überschriebene Methoden nicht das Verhalten, sondern nur die Algorithmen.

Liskovsches Substitutionsprinzip

Das Liskovsche Substitutionsprinzip (LSP) oder Ersetzbarkeitsprinzip fordert, dass eine Instanz einer abgeleiteten Klasse sich so verhalten muss, dass jemand, der meint, ein Objekt der Basisklasse vor sich zu haben, nicht durch unerwartetes Verhalten überrascht wird, wenn es sich dabei tatsächlich um ein Objekt eines Subtyps handelt. Es wurde 1993 von Barbara Liskov und Jeannette Wing formuliert.Barbara H. Liskov, Jeannette M. Wing: Family Values: A Behavioral Notion of Subtyping. Pittsburgh 1993. In einem nachfolgenden Artikel wurde es folgendermaßen formuliert:

Damit ist garantiert, dass Operationen vom Typ Superklasse, die auf ein Objekt des Typs Subklasse angewendet werden, auch korrekt ausgeführt werden. Dann lässt sich stets bedenkenlos ein Objekt vom Typ Superklasse durch ein Objekt vom Typ Subklasse ersetzen. Objektorientierte Programmiersprachen können eine Verletzung dieses Prinzips, die aufgrund der mit der Vererbung verbundenen Polymorphie auftreten kann, nicht von vornherein ausschließen. Häufig ist eine Verletzung des Prinzips nicht auf den ersten Blick offensichtlich.Lahres, Rayman: Praxisbuch Objektorientierung. Seiten 153–189, siehe Literatur

Interface-Segregation-Prinzip

Das Interface-Segregation-Prinzip dient dazu, zu große Interfaces aufzuteilen. Die Aufteilung soll gemäß den Anforderungen der Clients an die Interfaces gemacht werden – und zwar derart, dass die neuen Interfaces genau auf die Anforderungen der einzelnen Clients passen. Die Clients müssen also nur mit Interfaces agieren, die das und nur das können, was die Clients benötigen. Das Prinzip wurde von Robert C. Martin 1996 folgendermaßen formuliert:

Mit Hilfe des Interface-Segregation-Prinzips ist es möglich eine Software derart in entkoppelte und somit leichter refaktorisierbare Klassen aufzuteilen, dass zukünftige fachliche oder technische Anforderungen an die Software nur geringe Änderungen an der Software selbst benötigen.

Dependency-Inversion-Prinzip

Das Dependency-Inversion-Prinzip beschäftigt sich mit der Reduktion der Kopplung von Modulen. Es besagt, dass Abhängigkeiten immer von konkreteren Modulen niedriger Ebenen zu abstrakten Modulen höherer Ebenen gerichtet sein sollten. Es wurde von Robert C. Martin erstmals im Oktober 1994 beschrieben und später folgendermaßen formuliert:

Damit ist sichergestellt, dass die Abhängigkeitsbeziehungen immer in eine Richtung verlaufen, von den konkreten zu den abstrakten Modulen, von den abgeleiteten Klassen zu den Basisklassen. Damit werden die Abhängigkeiten zwischen den Modulen reduziert und insbesondere zyklische Abhängigkeiten vermieden.

Weitere Prinzipien Neben der von Robert C. Martin propagierten SOLID-Gruppe von Prinzipien Objektorientierten Designs sind noch folgende Prinzipien als Prinzipien Objektorientierten Designs bekannt:

Gesetz von Demeter

Das Gesetz von Demeter (englisch: Law of Demeter, kurz: LoD) besagt im Wesentlichen, dass Objekte nur mit Objekten in ihrer unmittelbaren Umgebung kommunizieren sollen. Dadurch soll die Kopplung in einem Softwaresystem verringert und dadurch die Wartbarkeit erhöht werden.

Das Gesetz wurde von Karl J. Lieberherr und Ian Holland 1989 im Paper Assuring Good Style for Object-Oriented Programs folgendermaßen beschrieben:

Durch die formale Spezifikation lässt sich das Gesetz von Demeter leicht als automatisch geprüfte Softwaremetrik umsetzen. Es bietet sich somit zur Früherkennung von Kopplungsproblemen an.

Design by Contract

Das Design-by-contract-Prinzip, englisch für Entwurf gemäß Vertrag, auch Programming by Contract genannt, hat das reibungslose Zusammenspiel einzelner Programmmodule durch die Definition formaler „Verträge“ zur Verwendung von Schnittstellen, die über deren statische Definition hinausgehen zum Ziel. Entwickelt und eingeführt wurde es von Bertrand Meyer mit der Entwicklung der Programmiersprache Eiffel.

Das reibungslose Zusammenspiel der Programmmodule wird durch einen „Vertrag“ erreicht, der beispielsweise bei der Verwendung einer Methode einzuhalten ist. Dieser besteht aus Vorbedingungen (englisch precondition), also den Zusicherungen, die der Aufrufer einzuhalten hat Nachbedingungen (englisch postcondition), also den Zusicherungen, die der Aufgerufene einhalten wird, sowie den Invarianten (englisch class invariants), quasi dem Gesundheitszustand einer Klasse.

Der Einsatz des Design-by-Contract-Prinzips führt zu sicherer und weniger fehleranfälliger Software, da eine Verletzung des Vertrages zu einem sofortigen Fehler (Fail-Fast) bereits in der Softwareentwicklungsphase führt. Weiters kann die explizite Definition des Vertrages als Form der Dokumentation des Verhaltens des entsprechenden Moduls gesehen werden. Das wiederum führt zu einer besseren Erlernbarkeit und Wartbarkeit der Software.

Datenkapselung

Datenkapselung (engl. encapsulation), nach David Parnas auch bekannt als information hiding, ist nach Bertrand Meyer ein weiteres Prinzip objektorientierten Designs. Es beschreibt das Verbergen von Daten oder Informationen vor dem Zugriff von außen. Der direkte Zugriff auf die interne Datenstruktur wird unterbunden und erfolgt stattdessen über definierte Schnittstellen. Die in der Objektorientierung verwendeten Zugriffsarten (private, protected, …) sowie eine Reihe von Entwurfsmustern – beispielsweise Facade – unterstützen bei der Umsetzung der Datenkapselung.

Linguistic-Modular-Units-Prinzip

Das Linguistic-Modular-Units-Prinzip (englisch für Prinzip linguistisch-modularer Einheiten) besagt, dass Module durch syntaktische Einheiten der verwendeten Sprache – sei es eine Programmier-, Design- oder Spezifikationssprache – repräsentiert werden müssen. Im Falle einer Programmiersprache müssen Module durch separat voneinander kompilierbare Einheiten dieser gewählten Programmiersprache repräsentiert werden:

Self-Documentation-Prinzip

Das Self-Documentation-Prinzip (englisch für Selbstdokumentierungsprinzip) besagt, dass alle Informationen zu einem Modul in diesem selbst enthalten sein sollten. Damit wird gefordert, dass der Code entweder selbst für sich spricht (d. h. keine weitere Dokumentation nötig hat) beziehungsweise die technische Dokumentation möglichst nahe beim Sourcecode (beispielsweise bei der Verwendung von Javadoc) liegt. Dadurch wird einerseits gewährleistet, dass die technische Dokumentation dem Code entspricht und andererseits, dass die Komplexität des Codes so gering ist, dass keine komplexe Dokumentation nötig ist:

Uniform-Access-Prinzip

Das Uniform-Access-Prinzip (englisch für Prinzip des gleichartigen Zugriffes) fordert, dass auf alle Services eines Modules mittels einer gleichartigen Notation zugegriffen werden kann – ohne dass dadurch preisgegeben wird, ob die Services dahinter auf Datenbestände zugreifen, oder Berechnungen durchführen. Services sollten also nach außen nicht bekanntgeben, wie sie ihre Serviceleistung erbringen, sondern nur was ihre Serviceleistung ist:

Single-Choice-Prinzip

Das Single-Choice-Prinzip besagt, dass verschiedene Alternativen (beispielsweise von Daten oder Algorithmen) in einem Softwaresystem in nur einem einzigen Modul abgebildet werden sollten. Beispielsweise unterstützt das Entwurfsmuster Abstrakte Fabrik dieses Prinzip, indem in der Fabrik einmal aus einem Set an Alternativen entschieden wird, welche Klassen und welche Algorithmen zu verwenden sind. Diese Entscheidung muss an keiner weiteren Stelle im Programm mehr getroffen werden:

Persistence-Closure-Prinzip

Das Persistence-Closure-Prinzip besagt, dass Persistenzmechanismen Objekte mit all ihren Abhängigkeiten speichern und auch wieder laden müssen. Damit ist sichergestellt, dass Objekte ihre Eigenschaften durch Speichern und darauffolgendes Laden nicht verändern.

Command-Query-Separation-Prinzip

Das Command-Query-Separation-Prinzip (CQS) besagt, dass eine Methode entweder als Abfrage () oder als Kommando ( (auch oder genannt)) implementiert werden soll. Eine Abfrage muss hierbei Daten zurückliefern und darf keine Nebeneffekte auf dem beobachtbaren Zustand des Systems aufweisen, während ein Kommando beobachtbare Nebeneffekte aufweist und keine Daten zurückliefert.

Principle of Least Surprise

Das Principle of Least Surprise () ist eigentlich ein Prinzip in der Software-Ergonomie, der Mensch-Computer-Interaktion und dem Interfacedesign. Es wird aber oft auch auf den Quellcode erweitert und betrifft im objektorientierten Design die Benennung von Variablen, Funktionen, Methoden, Parameter, Klassen und dergleichen. Sie sollen derart benannt werden, dass deren Funktion und mögliche Seiteneffekte alleine aus dem Namen klar erkenntlich sind.

Packaging-Prinzipien Die folgenden von Bertrand Meyer und Robert C. Martin definierten Prinzipien beschäftigen sich mit der Frage, wie man Klassen zu Modulen (Packages) zusammenführen sollte. Sie führen insbesondere zu einer hohen Kohäsion innerhalb der Module und geringen Kopplung zwischen den Modulen.

Reuse-Release-Equivalence-Prinzip

Das Reuse-Release-Equivalence-Prinzip bezieht sich auf die Struktur von Packages im Sinne eines Moduls als kleinste Einheit eines Releases. Es gibt vor, dass sich Packages nur aus Klassen zusammensetzen dürfen, von denen entweder alle, oder gar keine zur Wiederverwendung gedacht sind.