Implémentation du Building Pattern en JS sans classes

Building Pattern in Javascript
Building Pattern in Javascript

Les modèles de conception sont une partie vitale du développement logiciel. Ils décrivent des problèmes communs et des solutions. Ce pattern s’appelle le builder pattern. Comme le dit Wikipedia, c’est :

«un modèle de conception conçu pour fournir une solution flexible à divers problèmes de création d’objets dans la programmation orientée objet»

https://en.wikipedia.org/wiki/Builder_pattern

Cependant, ce pattern ne s’applique pas seulement aux langages orientés objet. Il peut être réalisé en JavaScript sans classes.

Comment fonctionne ce pattern ?

L’objectif du Building Pattern est de rationaliser le processus de création d’objet.
Il est différent du factory pattern sur 2 points : Il est utile lorsque le processus de création est complexe et nécessite un nombre arbitraire d’entrées.
Un exemple célèbre est la classe StringBuilder en Java, qui est utilisée pour construire des chaînes :

class Main {
  public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();
    String info = 
      sb.append("Version: ")
        .append(VersionSignleton.getVersion())
        .append(" running on: ")
        .append(System.getProperty("os.arch"))
        .toString();
    
    System.out.println(info);
  }
}

Étant donné la nature de la POO du Building Pattern, vous pouvez penser que pour l’implémenter, vous devez utiliser des classes.
C’est tout le contraire: ce modèle est parfaitement valable pour les langages fonctionnels tels que JavaScript, grâce à la délégation prototypique et à la liaison this.

Construction de Lego

Implémentation du Building Pattern en JavaScript

Pour implémenter le Building Pattern, il faut utiliser les fonctions constructeur, le mot-clé new et la liaison this.
Ces fonctionnalités n’ont rien à voir avec les classes, leur comportement n’est pas lié aux classes et elles ont été introduites bien avant les classes.
Comme cas d’utilisation pour le Building Pattern, imaginez les 2 choses suivantes :

  • Effectuer un grand nombre de requêtes HTTP courantes sur le même serveur avec le même en-tête.
  • Simplifier l’API.

Observez ce code :

function executeWithFetch(request) {
  // EXERCISE FOR THE READER
}

function executeWithAxios(request) {
  // EXERCISE FOR THE READER
}

function ClientBuilder() {
  return {
    forBaseUrl: function(baseUrl) {
      this.baseUrl = baseUrl;
      return this;
    }
    
    withHeaders: function(headers) {
      this.headers = headers;
      return this;
    }
    
    usingFetch: function() {
      this.executor = executeWithFetch;
      return this;
    }
  
    usingAxios: function() {
      this.executor = executeWithAxios;
      return this;
    }
  
    build: function() {
      return new Client(this.baseUrl, this.headers, this.executor);
    }
  }
}

function Client(baseUrl, headers, executor) {
  this.baseUrl = baseUrl;
  this.headers = headers;
  this.executor = executor;
  
  this.post = function(endpoint, data) {
    const url = `${this.baseUrl}${endpoint}`;
    return this.executor({
      url,
      data,
      method: 'POST',
      headers: this.headers
    });
  }

  this.get = function(endpoint, params) {
    const url = `${this.baseUrl}${endpoint}`;
    return this.executor({
      url,
      params,
      method: 'GET',
      headers: this.headers
    });
  }
}

Tout d’abord, notez la fonction ClientBuilder. Il renvoie un objet qui contient toute la logique de construction.

Il expose les fonctions forBaseUrl, withHeaders, usingFetch, usingAxios, et build.
Les fonctions pour spécifie le comportement souhaité, puis utilisez build pour obtenir le client complet.
La fonction Client est une fonction constructeur, qui accepte baseUrl, headers, et executor, la lie via this et expose les fonctions post et get.

Il faut ensuite utiliser ces fonctions comme ceci :

const client = ClientBuilder()
  .forBaseUrl('https://some-api.com/api/')
  .withHeaders({Authorization: 'Bearer ABACABA'})
  .usingAxios()
  .build();

client.post('UpdateData', {data: 'new data'});

Qu’avez-vous pensé de cette article ?