La loi de Demeter est une règle de conception souvent décrite de la manière suivante : "Ne parlez qu'à vos amis immédiats".
Prenons comme exemple la classe suivante :
class Car
{
public function __construct(
protected Engine $engine,
) {}
public function isRunning(): bool
{
return $this->engine->state->isRunning();
}
}
La méthode isRunning
est une violation de la loi de Demeter car elle manipule une instance de State
provenant d'une de ses instances de classe : Engine
.
Dit de façon plus triviale : «isRunning est dépendant d'une dépendance de ses dépendances».
Ce couplage est délétère pour la composition de vos classes et affectera de manière négative son afferent et son efferent coupling.
La classe Car
, étant directement dépendante de la classe State
, un changement ou une refactorisation de cette dernière impactera à la fois Engine
et Car
, alors que seul Engine
devrait être directement concerné.
Une violation de la loi de Demeter est souvent synonyme d'un problème de conception.
Voyons désormais comment refactoriser ce code pour respecter la loi de Demeter.
class Car
{
public function __construct(
protected Engine $engine,
) {}
public function isRunning(): bool
{
return $this->engine->isRunning();
}
}
class Engine
{
public function __construct(
protected State $state,
) {}
public function isRunning(): bool
{
return $this->state->isRunning();
}
}
class State
{
public function isRunning(): bool
{
return true;
}
}
En respectant cette nouvelle architecture, chaque classe est parfaitement découplée et ne parle qu'à ses amis immédiats, il n'y a pas de dépendance superflue.
Il sera désormais plus facile de faire évoluer la classe Car
car cette dernière n'est plus dépendante de la structure, et de l'état, de ses dépendances.
Tester cette classe Car
sera également plus aisé qu'auparavant car seule la classe Engine
nécessitera la création d'une doublure.
software entities should not depend on things they don’t directly use.