Law of Demeter (LoD) Um das Law of Demeter (Gesetz von Demeter) in
der Softwareentwicklung geht es im achten Wissenshäppchen. Inhalt
Das Law of Demeter sagt aus, dass eine Methode nur Zugriff auf die
folgenden Objekte/Methoden haben sollte: Andere Instanzmethoden in
ihrer eigenen Klasse Ihre Parameter Methoden in Objekten, die sie
selbst erzeugt Globale Variablen Eine einfache andere Definition
lautet: Verkette keine Methodenaufrufe ("method chaining"). Oder:
Verwende nicht mehr als einen ., wenn du auf etwas zugreifst. Ein
anderer Name für das LoD ist "Prinzip des geringsten Wissens"
("principle of least knowledge"). Der Name stammt von Demeter,
einer griechischen Göttin. Der "Erfinder" des Prinzips entwickelte
in den 80er-Jahren ein System mit diesem Namen. Erklärung Vorweg:
Globale Variablen waren in den 80ern hip, heute nicht mehr. Bitte
verwende sie am besten gar nicht. Je mehr "Punkte" in einer
Aufrufhierarchie auftreten, desto mehr Kenntnis hat eine Komponente
vom "Innenleben" der aufgerufenen Komponenten. Je mehr Kenntnis
eine Komponente über die von ihr verwendeten Komponenten hat, desto
stärker bindet sie sich an diese. Wenn sich die genutzten
Komponenten ändern, muss sie sich mit ändern bzw. ist kaputt. Das
verletzt das Geheimnisprinzip und die Kapselung, nach der wir
eigentlich in der Objektorientierung arbeiten wollen. Je mehr
solcher Abhängigkeiten eine Methode hat, desto schwerer ist sie zu
verstehen und zu testen. Code, der sich an das LoD hält, gilt auch
als "schüchtern", weil er "nur mit seinen Freunden spricht".
Beispielcode Um an den Gesamtbeitrag einer Versicherungspolice zu
kommen, ist die Kenntnis über die darin enthaltenen versicherten
Personen und deren Tarife nötig. Da es sich dabei jeweils um Listen
handelt, ist sogar noch ein "Flachklopfen" der Strukturen nötig.
Der Code sieht vielleicht cool aus, ist aber stark an die
Strukturen gekoppelt. Das heißt, ein Test müsste sehr viel Aufwand
betreiben, um die nötigen Strukturen zu schaffen (z.B. mit Mocks).
class Tarif def initialize(name) @name = name end def beitrag
123.45 end end class VersichertePerson def initialize(name) @name =
name @tarife = [ Tarif.new("KFZ"), Tarif.new("Hausrat") ] end def
tarife @tarife end end class Versicherungspolice def initialize
@versicherte_personen = [ VersichertePerson.new("Stefan Macke"),
VersichertePerson.new("Klaus Meyer") ] end def versicherte_personen
@versicherte_personen end end # cool, aber schwer verständlich,
anfällig für Anpassungen und auch schwer zu testen puts
Versicherungspolice.new .versicherte_personen .flat_map { |vp|
vp.tarife } .inject(0){|summe,tarif| summe + tarif.beitrag } Um
dies zu vermeiden, können die einzelnen Klassen von ihren inneren
Strukturen abstrahieren und stellen simple Zugriffsmethoden für die
gewünschten Ergebnisse bereit. Der finale Aufruf sieht nun schon
fast langweilig aus. Dafür liegt die fachliche Berechnungslogik da
wo sie hingehört: in den jeweiligen Klassen und nicht beim
Aufrufer. class Tarif def initialize(name) @name = name end def
beitrag 123.45 end end class VersichertePerson def initialize(name)
@name = name @tarife = [ Tarif.new("KFZ"), Tarif.new("Hausrat") ]
end def beitragssumme @tarife.inject(0){|summe,tarif| summe +
tarif.beitrag } end end class Versicherungspolice def initialize
@versicherte_personen = [ VersichertePerson.new("Stefan Macke"),
VersichertePerson.new("Klaus Meyer") ] end def gesamtbeitrag
@versicherte_personen.inject(0){|summe,vp| summe + vp.beitragssumme
} end end # langweilig, aber einfach zu verstehen und zu testen
puts Versicherungspolice.new.gesamtbeitrag Vorteile Der Code wird
verständlicher, weil nicht mehrere Strukturen bekannt sein müssen.
Fachliche Logik landet evtl. eher da, wo sie hingehört. Anstatt
externen Komponenten Zugriff auf die inneren Daten zu geben, werden
Abstraktionen geschaffen. Die Komponenten sind unabhängiger
voneinander und lassen sich leichter testen. Große Test-Setups mit
vielen Mocks, die weitere Mocks zurückgeben, lassen sich vermeiden.
Interne Änderungen an verwendeten Komponenten wirken sich nicht auf
deinen Code aus. Du hast also weniger Anpassungsaufwand. Nachteile
Wenn du die Regel exakt befolgen möchtest, musst du womöglich recht
viel Boilerplate-Code schreiben, z.B. simple Getter, die an
Instanzvariablen delegieren. Wenn sich die verwendeten Strukturen
selten ändern, ist der zusätzliche Aufwand vermutlich unnötig.
Literaturempfehlungen Zu diesem Wissenshäppchen gibt es ein
separates Kapitel in einem meiner absoluten Lieblingsbücher zur
Softwareentwicklung: The Pragmatic Programmer*. Es ist vor Kurzem
in der 20-Jahre-Edition neu aufgelegt worden, aber das Law of
Demeter ist immer noch Thema. * Links Permalink zu dieser
Podcast-Episode RSS-Feed des Podcasts Gesetz von Demeter –
Wikipedia Law Of Demeter Demeter’s Law: Don’t talk to strangers!
Kommentare (0)
Melde dich an, um einen Kommentar zu schreiben.