Das Gesetz von Demeter (LoD), auch als „Prinzip der geringsten Kenntnis“ bekannt, ist ein Konzept in der Softwareentwicklung, das besagt, dass ein Objekt nur mit seinen direkten Nachbarn kommunizieren sollte. Es soll verhindern, dass Objekte zu viel über die inneren Details anderer Objekte wissen. In der objektorientierten Programmierung fördert dieses Gesetz eine lose Kopplung und schützt vor unnötigen Abhängigkeiten zwischen den Komponenten.
Was ist das Gesetz von Demeter?
Das Gesetz von Demeter wurde 1987 von Karl J. Lieberherr und Ian Holland formuliert. Es empfiehlt, dass ein Objekt nur mit seinen „direkten Freunden“ kommuniziert, also mit:
- Den Objekten, die es selbst erstellt hat.
- Den Objekten, die ihm als Argumente übergeben wurden.
- Den Objekten, die es direkt besitzt.
- Den Objekten, die in seiner eigenen Rückgabewerte enthalten sind.
Das Gesetz stellt sicher, dass ein Objekt so wenig wie möglich über andere Objekte wissen muss. Es soll verhindern, dass Objekte zu stark miteinander verbunden sind, was zu einer engen Kopplung und schwieriger wartbarem Code führen kann.
Beispiel: Verletzung des Gesetzes von Demeter
Ein klassisches Beispiel für eine Verletzung des Gesetzes von Demeter ist die sogenannte „Trainwreck“-Syntax. Hierbei ruft ein Objekt eine Methode des Objekts eines anderen Objekts auf. Dies führt zu unübersichtlichem und schwer wartbarem Code.
Beispiel in C++ – Verletzung des Gesetzes von Demeter:
class Address {
public:
std::string getStreet() { return street; }
private:
std::string street;
};
class Person {
public:
Address* getAddress() { return &address; }
private:
Address address;
};
class Company {
public:
Person* getPerson() { return &person; }
private:
Person person;
};
void printStreet(Company& company) {
std::cout << company.getPerson()->getAddress()->getStreet() << std::endl; // Verletzung des Gesetzes
}
In diesem Beispiel ruft die Methode printStreet()
auf einer Kette von Objekten Methoden auf, die das Gesetz von Demeter verletzen. Das führt zu einer engen Kopplung zwischen den Klassen Company
, Person
und Address
. Wenn sich die Implementierung einer dieser Klassen ändert, müssen alle anderen Klassen möglicherweise auch geändert werden.
Einhaltung des Gesetzes von Demeter in C++
Um das Gesetz von Demeter einzuhalten, sollte ein Objekt nicht Methoden von Objekten aufrufen, die es nur indirekt kennt. Stattdessen sollte es eine Methode bereitstellen, die die gewünschte Information in einer abstrahierten Form liefert. Ein Beispiel zeigt, wie dies korrekt umgesetzt wird:
Beispiel in C++ – Einhaltung des Gesetzes von Demeter:
class Address {
public:
std::string getStreet() { return street; }
private:
std::string street;
};
class Person {
public:
std::string getStreet() {
return address.getStreet();
}
private:
Address address;
};
class Company {
public:
Person* getPerson() { return &person; }
private:
Person person;
};
void printStreet(Company& company) {
std::cout << company.getPerson()->getStreet() << std::endl; // Einhaltung des Gesetzes
}
In diesem Beispiel wird die Kette der Aufrufe vereinfacht, indem Person
die Methode getStreet()
direkt bereitstellt. Dadurch müssen die Details der Address
-Klasse nicht mehr von außen zugänglich gemacht werden.
Vorteile des Gesetzes von Demeter
1. Bessere Wartbarkeit:
Da Objekte weniger von den Implementierungsdetails anderer Objekte abhängen, wird der Code einfacher zu verstehen und zu warten.
2. Geringere Kopplung:
Das Gesetz fördert eine lose Kopplung zwischen den Komponenten des Systems. Änderungen in einer Klasse erfordern weniger Änderungen in anderen Klassen.
3. Einfacheres Testen:
Objekte, die das Gesetz von Demeter befolgen, sind leichter zu testen, da sie in der Regel besser isoliert sind. Unit-Tests können ohne umfangreiche Test-Doubles durchgeführt werden.
4. Erhöhte Flexibilität:
Durch das Minimieren von Abhängigkeiten wird der Code flexibler und erweiterbar. Neue Funktionalitäten können leichter hinzugefügt werden, ohne bestehende Teile des Systems zu beeinträchtigen.
Beispiel:
Wenn die Klasse Person
geändert wird, um mehr Details zu speichern, kann Company
weiterhin problemlos auf Person
zugreifen, solange die Schnittstellen konsistent bleiben.
Nachteile des Gesetzes von Demeter
1. Übermäßige Schnittstellen:
Das Gesetz von Demeter kann dazu führen, dass mehr Methoden und Schnittstellen erforderlich sind, um die gewünschten Informationen zu extrahieren. Dadurch wird der Code potenziell komplexer.
2. Geringere Leistung:
In einigen Fällen kann das Einhalten des Gesetzes zu zusätzlichem Overhead führen, da mehr Methodenaufrufe notwendig sind. Dies kann in performancekritischen Anwendungen problematisch sein.
3. Einschränkung bei der Verwendung von „Komplexen Strukturen“:
Das Gesetz von Demeter schränkt die Nutzung komplexer Objektstrukturen ein, die oft direkte Zugriffe auf innere Details erfordern. In einigen Fällen könnte eine Lockerung dieser Regel sinnvoll sein, um den Code effizienter zu gestalten.
Weitere Verbesserung durch das Gesetz von Demeter
Es gibt zusätzliche Techniken, die helfen, das Gesetz von Demeter noch konsequenter anzuwenden. Eine Möglichkeit ist, zusätzliche Abstraktionen einzuführen, die den Zugriff auf die Objektstrukturen steuern. Hier könnte man zusätzliche Design Patterns wie das Facade Pattern verwenden, um den Zugang zu komplexen Objekten zu abstrahieren.
Beispiel – Anwendung des Facade Patterns:
class AddressFacade {
public:
AddressFacade(Person& person) : person(person) {}
std::string getStreet() { return person.getStreet(); }
private:
Person& person;
};
void printStreet(Company& company) {
AddressFacade facade(*company.getPerson());
std::cout << facade.getStreet() << std::endl; // Vereinfachter Zugang
}
In diesem Beispiel wird das Facade Pattern verwendet, um den Zugang zu Address
zu abstrahieren. Dadurch wird der Code noch sauberer und das Gesetz von Demeter besser eingehalten.
Fazit
Das Gesetz von Demeter spielt eine zentrale Rolle beim Design wartbarer Software. Es fördert eine lose Kopplung und schützt vor übermäßigen Abhängigkeiten. Die Anwendung des Gesetzes führt zu besser wartbarem und testbarem Code. Es hat jedoch auch Nachteile, wie die Notwendigkeit zusätzlicher Schnittstellen und einen möglichen Performance-Overhead. Trotz dieser Nachteile ist das Gesetz von Demeter ein wichtiger Baustein für sauberen, flexiblen und gut strukturierten Code, der langfristig leicht zu pflegen ist. In C++ ist es besonders wichtig, bei der Anwendung des Gesetzes den Überblick zu behalten und sicherzustellen, dass der Code sowohl gut strukturiert als auch performant bleibt.
Auch lesenswert: Design Pattern und Fünf Anforderungen von Bertrand Meyer