PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Programmierprinzipien: Law of Demeter

with 14 comments

Professor Ian Holland hat zu Beginn der objektorientierten Zeit (1989) bereits eine wichtige Richtlinie definiert, die die lose Kopplung von Klassen sicherstellen soll: Das „Gesetz von Demeter“ (Law of Demeter, LoD).

Wenn man Klassen soweit es geht voneinander trennt, sind sie übersichtlicher, besser wartbar und testbar, leichter weiterzuentwickeln und wiederzuverwenden. Umgangssprachlich könnte man es beschreiben als „Sprich nur mit deinen nächsten Freunden“ und „Verrate keine Geheimnisse, die andere nichts angehen“.

Ein Praxisbeispiel:

class Order
{
	public $orderStatus = 0;

	public function changeOrderStatus($newStatus, $customer)
	{
		$this->orderStatus = $newStatus;

		if ($newStatus == 3) {
			$this->sendEmail(
					$customer->getData()->getContactInformation()->getEmail(),
					'New Order Status: ' . $newStatus
			);
		}
	}
}

Wer bei diesem Code keine Bauchschmerzen hat, sollte unbedingt weiterlesen. Wenn wir darauf nun die Regeln des LoD loslassen, sehen wir die Probleme.

Eine Klassenmethode sollte nur folgende andere Methoden verwenden:

  • Methoden der eigenen Klasse
  • Methoden der übergebenen Parameter
  • Methoden der mit eigenen Klasse assoziierten Klassen
  • Methoden von Objekten, die die Methode selbst erzeugt hat

Die Zeile 11 wäre also verboten, da sie eine zu enge Kopplung bzw. ein zu großes Wissen über andere Klassen voraussetzt. Lösung wäre hier, nicht das ganze Kundenobjekt an die Methode zu übergeben, sondern nur die für hier wichtigen Kontaktinformationen.

Außerdem verstößt der Code gegen das Geheimnisprinzip, da das Attribut $orderStatus public ist und man so den Status ändern könnte ohne eine Email zu versenden.

Wenn wir einen Test für die oben beschriebene Methode schreiben möchten, müssen wir vorher erst ein Kundenobjekt erzeugen, darin Daten hinterlegen, Kontaktinformationen usw. Doch eigentlich würden die Kontaktinformationen reichen für den Test, das Kundenobjekt ansich ist uns eigentlich egal, da es nicht genutzt wird. Auch Testen wird also durch lose Kopplung einfacher.

Besser wäre z.B. der folgende Code.

class Order
{
	private $_orderStatus = 0;

	public function changeOrderStatus($newStatus, $customerInformation)
	{
		$this->_orderStatus = $newStatus;

		if ($newStatus == 3) {
			$this->_sendEmail(
					$customerInformation->getEmail(),
					'New Order Status: ' . $newStatus
			);
		}
	}
}

Oder man macht es wie im unten stehenden Beispiel. Darin ist auch das Prinzip „Tell don’t ask“ abgebildet, welches besagt, dass man lieber Befehle gibt als Informationen abzufragen:

class Order
{
	private $_orderStatus = 0;

	public function changeOrderStatus($newStatus, $customer)
	{
		$this->_orderStatus = $newStatus;

		if ($newStatus == 3) {
			$customer->sendEmail('New Order Status: ' . $newStatus);
		}
	}
}

Wir geben also dem Kundenobjekt den Befehl, eine Email zu versenden (an den Kunden). Dann ersparen wir uns das Abfragen von Informationen, und wir müssen nicht wissen, wie im Kundenobjekt die Email-Adresse abgespeichert wird. Änderungen der Kundenklasse sind so also viel einfacher und problemloser machbar. Die Klasse Order kümmert sich also hauptsächlich um seine eigenen Dinge, und überlässt alles was den Kunden betrifft wenn es geht der Kundenklasse. Stichwort ist da das Single Responsibility Principle bzw. das  „Eine-Verantwortlichkeit-Prinzip„.

Um nochmal schnell die 4 Prinzipien an Code darzustellen, hier die erlaubten Methodenaufrufe:

Methoden der eigenen Klasse:

class A
{
    public function method1() {
        $this->method2();
    }

    public function method2() {
    }
}

Methoden der Parameter:

class A
{
    public function method1(B $b) {
        $b->method2();
    }
}
class B
{
    public function method2() {
    }
}

Methoden assoziierter Klassen:

class A
{
    private $b;
    public function method1() {
        $this->b->method2();
    }
}
class B
{
    public function method2() {
    }
}

Methoden selbst erzeugter Objekte:

class A
{
    public function method1() {
        $b = new B();
        $b->method2();
    }
}
class B
{
    public function method2() {
    }
}

Weitere Informationen zum LoD gibts im deutschen oder englischen Artikel in der Wikipedia. Oder direkt im Paper des Professors (PDF).

Written by Michael Kliewe

Dezember 2nd, 2009 at 9:02 am

14 Responses to 'Programmierprinzipien: Law of Demeter'

Subscribe to comments with RSS or TrackBack to 'Programmierprinzipien: Law of Demeter'.

  1. Sehr interessant beschrieben. Da werde ich gleich mal schauen ob ich mich überall an Demeter halte.

    Bastian

    2 Dez 09 at 09:16

  2. Schöner Artikel, danke 😉

    ghost

    2 Dez 09 at 09:17

  3. […] Dieser Eintrag wurde auf Twitter von justb81, Michael Kliewe erwähnt. Michael Kliewe sagte: Neuer Blogeintrag: Programmierprinzipien: Law of Demeter ( http://www.phpgangsta.de/655 ) […]

  4. Sehr schön,

    halten sich nicht viele dran. Für alle die das nicht wissen, es ist nicht ein Prinzip in PHP, sondern in allen objektorientierten Sprachen!

    Das müsste man noch erwähnen 😉

    Daumen hoch

  5. Super interessant. Habe bisher natürlich noch die vom „Law of Demeter“ gehört, außer vielleicht im Bioladen bei den Möhren. 😀

    Danke, Sterne: 5

    Matthias

    3 Dez 09 at 10:25

  6. […] Anwendungen live debuggen kann ohne Performance Verlust. Allerdings noch MacOS und Solaris only. Programmierprinzipien: Law of Demeter | PHP Gangsta – Der PHP Blog Wenn man Klassen soweit es geht voneinander trennt, sind sie übersichtlicher, besser wartbar und […]

  7. Hi,

    welches Plugin verwendest du fürs Syntax Highlighting?

    MfG
    Simon

    Simon

    16 Dez 09 at 13:18

  8. Achja, fast hätte ich es vergessen:
    Sehr interessanter Artikel!

    Simon

    16 Dez 09 at 13:24

  9. Ich nutze „SyntaxHighlighter Evolved“

    Michael Kliewe

    16 Dez 09 at 16:45

  10. Danke!
    Das funktioniert auch…

    Aber wie kriegst du die Einrückung hin?
    Manuell?

    Wenn ich den Code einfach einfüge, ist die komplette Einrückung weg 🙁

    MfG
    Simon

    Simon

    30 Dez 09 at 10:21

  11. Ahh,
    wenn ich es im HTML-Modus einfüge, dann gehts.

    Vielen Dank für den Plugin-Tipp!

    Wenn das mal keine Verlinkung wert ist 😉
    Ich schreibe demnächst einen Artikel darüber.

    Bis dann und nochmal danke!
    Simon

    Simon

    30 Dez 09 at 10:24

  12. Ja genau, im HTML-Modus funktioniert es. Nicht ideal, aber es geht immerhin, habe vorher 1-2 andere Plugins ausprobiert und da ging es garnicht.

    Michael Kliewe

    30 Dez 09 at 10:33

  13. […] durch Zufall einen Artikel gefunden, bei dem so ein Plugin zum Einsatz kommt. Ich rede von “Programmierprinzipien: Law of Dementer” auf dem Blog von PHPGangsta. In den Kommentaren habe ich den Autor gefragt, was er denn für […]

  14. Ich habe bestimmt 5 Plugins ausprobiert, keines hat es so perfekt wie dieses gemacht.

    Hab jetzt einen Artikel darüber gecshrieben: http://www.net-developers.de/blog/2009/12/30/syntaxhighlighter-fur-wordpress-gefunden/

    MfG
    Simon

    Simon

    30 Dez 09 at 10:50

Leave a Reply

You can add images to your comment by clicking here.