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)
