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)