PHP : La loi de Déméter en quelques exemples

La loi de Déméter (LoD en anglais, pour Law of Demeter) est un principe de design de systèmes dits « orientés objet ». Son principe élémentaire tient en une phrase :

« Ne parle qu’à tes amis »

Ce principe de conception orientée objet à été évoqué pour la première fois en 1987 à la Northeastern University de Boston (Massachussets) par Ian Holland qui travaillait alors sur un projet du nom de Demeter. Le but de cette « loi » est de maintenir un couplage laĉhe entre les classes.

Ce que permet LoD

LoD nous donne pour principe la chose suivante :

Une méthode dans un objet donné doit seulement invoquer les méthodes des types d’objets suivants : l’objet lui-même, ses objets paramètres, les objets qu’il crée, les objets qu’il a en composition

L’objet lui-même


class A {
    public function __construct() {
        $this->_faireUnTruc();
    }

    protected function _faireUnTruc() {}
}

L’objet instance de A sera autorisé à appeler ses propres fonctions (tout de même…)

Ses paramètres


class B {
    public function faireQuelqueChose() {}
}

class A {
    public function __construct(B $b) {
        $b->faireQuelqueChose();
    }

    protected function _faireUnTruc() {}
}

N’importe quel objet créé dans la classe

class C {
    public function faireDesMiracles() {}
}

class A {
    public function __construct() {
        		$c = new C;
        		$c->faireDesMiracles();
    }
}

Les objets en composition

class D {
    public function faireAutreChose() {}
}

class A {
    private $_d;

    public function __construct() {
        $c = new D;
    }

    public function faireDesChoses() {
        $this->_d->faireAutreChose();
    }
}

Ce qui remet en cause LoD

class C {
    public function faireBeaucoupDeChoses() {}
}

class B {
    private $_c;

    public function __construct(C $c) {
        $this->_c = $c;
    }

    public function getC() {
        return $this->_c;
    }
}

class A {
    private $_d;

    public function __construct() {
        $c = new C;
        $b = new B($c);
        $b->getC()->faireBeaucoupDeChoses();
    }
}

Dans cet exemple, ce n’est pas le chaînage des méthodes en lui-même qui pose un problème mais le fait que A fasse appel à C à travers B. Idéalement, A fait appel à B qui lui, délègue le service demandé à C de sorte que nous n’aurions plus que :

$b->faireBeaucoupDeChoses();

et


class B {
    private $_c;

    public function __construct(C $c) {
        $this->_c = $c;
    }

    public function faireBeaucoupDeChoses() {
        return $this->_c->faireBeaucoupDeChoses();
    }
}

Ici, chaque classe parle à ses amis les plus proches (A à B, B à C) et Déméter n’en sera pas offusquée !

Pour en savoir plus…

Un billet du blog d’Avdi Grimm (anglais)

La page du projet Demeter (anglais)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.