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 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».

image.png

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.

image.png

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.