La loi de Demeter

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 class Car 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 class : Engine.

Dit de façon plus triviale : «IsRunning est dépendant d'une dépendance de ses dépendances».

image.png

Ce couplage est délétère pour la composition de vos class et affectera de manière négative son afferent et son efferent coupling.

Car étant directement dépendant de la class State, un changement ou une refactorisation de cette dernière impactera à la fois Engine et Car, alors que seul Engine devrait être directement concerné, la loi de Demeter est souvent synonyme d'un probleme 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 class est parfaitement découplée et ne parle qu'à ses amis immédiats, il n'y a pas de dépendance superflue.

image.png

Il est désormais plus facile de faire évoluer la class Car, cette dernière n'étant plus dépendante de la structure, et de l'état, de ses dépendances.

Tester cette class Car est également plus aisé qu'auparavant car seule la class Engine nécessitera d'une doublure.