Le chaînage des méthodes pour un code plus concis

Le design pattern Fluent Interface est beaucoup utilisé si on vient du monde JavaScript avec la librairie jQuery. C’est peut-être cette librairie qui a démocratisé ce patron de conception dans le développement web. Elle consiste à ajouter à chaque méthode d’une classe ou d’un objet le fait de renvoyer la classe afin d’utiliser plusieurs méthodes à partir d’un même appel. L’objectif principal est d’avoir un code plus concis et plus facile à lire.

Cependant avec ce système les méthodes ne peuvent plus renvoyer de valeur de contrôle comme true ou false afin de vérifier le bon fonctionnement du programme. Ce patron de conception est à utiliser sur les méthodes ne devant pas renvoyer des données comme les setters ou sur les méthodes ne nécessitant pas de vérification. Il ne faut pas l’utiliser si la méthode doit par exemple envoyer un email afin de retourner true ou false si l’email est bien envoyé. Chaque programmeur doit bien réfléchir à l’implémentation de ce design pattern dans les classes pour ne pas provoquer l’effet inverse en rendant le code plus compliqué.

Le design pattern Fluent Design permet d'écrire du code plus concis
Le design pattern Fluent Design pour un code plus concis

Exemple d’un chaînage de méthodes en PHP

L’exemple ci-dessous en PHP présente une simple classe Person qui affiche le nom complet après avoir enregistré le nom et le prénom. Les 2 fonctions setFirstName et setLastName utilisent le chaînage de méthodes en renvoyant à chaque fois la classe Person. Cette façon d’écrire le code permet d’appeler ces méthodes sur le même objet.

<?php
class Person {
    private string $firstname = '';
    private string $lastname = '';
    public function setFirstName(string $value):Person {
        $this->firstname = $value;
        return $this;
    }
    public function setLastName(string $value):Person {
        $this->lastname = $value;
        return $this;
    }
    public function getName():string {
        return $this->firstname . ' ' . $this->lastname;
    }
}
$person = new Person();
$person->setFirstName('Franck')->setLastName('Thilliez');
echo $person->getName(); // Franck Thilliez

Optimisation du Fluent Interface en PHP

En PHP comme dans d’autres langages de programmation, il est possible d’appeler les propriétés d’une classe de façon dynamique. Les développeurs PHP peuvent optimiser leurs codes en créant un setter personnalisé fonctionnant avec le principe du chaînage de méthode. L’exemple ci-dessous permet d’optimiser le nombre de méthodes dans la classe Person grâce à une fonction setter globale qui enregistre les propriétés si elles existent.

<?php
class Person {
    private string $firstname = '';
    private string $lastname = '';
    public function set(string $name, $value):Person {
        if (isset($this->$name)) {
            $this->$name = $value;
        }
        return $this;
    }
    public function getName():string {
        return $this->firstname . ' ' . $this->lastname;
    }
}
$person = new Person();
$person->set('firstname', 'Olivier')->set('lastname', 'Norek');
echo $person->getName(); // Olivier Norek

Malheureusement il n’est pas possible d’utiliser la méthode magique __set de PHP pour créer un chaînage de méthode. En effet la définition de cette dernière oblige à renvoyer void ce qui empêche l’utilisation du design pattern Fluent Interface. Mais il est tout à fait possible de créer ses propres getter et setter pour exploiter les données de la classe. Dans l’exemple ci-dessous le getter utilise la nouvelle instruction match apparu en PHP 8 similaire au switch mais avec comme principale particularité qu’elle renvoie une valeur.

<?php
class Person {
    private array $data = [];
    public function set(string $name, $value):Person {
        $this->data[$name] = $value;
        return $this;
    }
    public function get(string $name):?string {
        return match ($name) {
            'fullname'  => $this->data['firstname'] . ' ' . $this->data['lastname'],
            default     => null
        };
    }
}
$person = new Person();
$person->set('firstname', 'Cédric')->set('lastname', 'Sire');
echo $person->get('fullname'); // Cédric Sire

Un design pattern exploitable dans tous les langages

Le design pattern Fluent Interface peut s’utiliser dans tous les langages de programmation. En JavaScript on peut utiliser ce patron de conception exactement de la même façon qu’en PHP. L’exemple JavaScript ci-dessous reprend la même classe Person que dans l’exemple PHP afin de reproduire ce patron de conception.

class Person {
    data = [];
    set(name, value) {
        this.data[name] = value
        return this
    }
    get(name) {
        switch (name) {
            case 'fullname':
                return this.data['firstname'] + ' ' + this.data['lastname']
            default:
                return null
        }
    }
}
let author = new Person();
author.set('firstname', 'Michael').set('lastname', 'Connelly');
console.log(author.get('fullname')); // Michael Connelly

Le design pattern Fluent Interface permet de rendre son code source plus concis pour le développement. C’est un patron de conception très utilisé par les développeurs web qui a été démocratisé par la librairie jQuery. Pour plus d’informations, il y a la page Wikipédia qui contient de nombreux exemples dans différents langages de programmation C#, Java, Python, etc.