Accueil / Tutoriels / Facade

Facade

Publié le 31 Mars 2025
Conception

Facade (façade en français) est un design pattern structurel qui fournit une interface simplifiée et unifiée à un ensemble de classes complexes. Son objectif est de réduire la complexité et d’améliorer la lisibilité du code en cachant les détails d’implémentation derrière une interface plus simple.

Principe

L’objectif va être de créer une classe unique (la façade) qui sert de point d’entrée pour interagir avec des classes sous-jacentes. Ainsi, on masque la complexité de ces classes en offrant une API plus claire aux utilisateurs, on améliore la maintenabilité du code en réduisant les dépendances tout en facilitant les évolutions futures.

Exemples d’utilisation du pattern Facade

Gérer l’authentification des utilisateurs

Sur une application web, gérer l’authentification nécessite plusieurs étapes comme vérifier les identifiants, générer une session, récupérer les informations de l’utilisateur, etc..

Sans Facade, le client doit interagir avec chaque service correspondant à une étape dans le processus d’authentification. Avec une Façade, on interagit avec une seule classe sans se soucier des interactions entre les classes sous-jacentes. La maintenance est également facilitée car si l’on doit modifier un service, le client n’a pas besoin d’être modifié.

API pour interagir avec des services tiers

Lorsqu’on intègre un service de paiement comme Paypal ou Stripe, l'utilisation d’une interface nous évite la complexité de gérer des étapes de validation et de vérification de paiement. Si l’on veut changer de moyen de paiement, seule la Facade devra être modifiée.

Points d’attentions

Une Façade peut devenir un gigantesque fourre-tout qui regroupe trop de responsabilités. Elle devient alors trop difficile à maintenir et à tester. Il vaut mieux dans ce cas découper la Façade en plusieurs sous-façades chacune ayant sa responsabilité dédiée.

En masquant trop de détails, la Façade limite la flexibilité des classes sous-jacentes. Il faut utiliser Facade judicieusement en offrant si besoin un accès direct aux classes sous-jacents et ne pas cacher inutilement des fonctionnalités qui pourraient être utiles.

Une Façade mal conçue peut créer un couplage fort entre les classes sous-jacentes. Si jamais une classe est modifiée, cela peut impacter toute la Façade. L’utilisation de l’injection de dépendances permet de prévenir ce phénomène de couplage et de rendre la Façade plus modulaire.

Par définition, la Façade cache la complexité du code ce qui ici est le but recherché, mais qui peut poser problème quand on souhaite comprendre ou déboguer les classes sous-jacentes. L’ajout de logs pour retracer les différentes étapes lors des appels aux services internes aidera à mieux comprendre la logique du code implémenté.

Implémenter le pattern Facade

L’implémentation va consister à créer une interface simplifiée qui masquera les détails de plusieurs classes ou services. L’idée est de réduire les dépendances entre les composants en fournissant un point d’entrée unique.

Exemple d'utilisation de Facade en Go

Pour un site web, les utilisateurs doivent s’authentifier pour accéder à leurs comptes. Le processus implique par exemple de vérifier les utilisateurs, générer un token d’authentification et de stocker la session utilisateur.


package auth

import "fmt"

type AuthService struct{}

func (a *AuthService) Authenticate(email, password string) bool {
   fmt.Println("Vérification des identifiants...")
   return email == "user@example.com" && password == "securepassword"
}


package auth

import "fmt"

type SessionService struct{}

func (s *SessionService) StoreSession(email, token string) {
   fmt.Println("Session stockée en cache pour", email)
}


package auth

import "fmt"

type TokenService struct{}

func (t *TokenService) GenerateToken(email string) string {
   fmt.Println("Génération du token JWT...")
   return "jwt_token_123"
}


package auth

type AuthFacade struct {
   authService    AuthService
   tokenService   TokenService
   sessionService SessionService
}

func NewAuthFacade() *AuthFacade {
   return &AuthFacade{
      authService:    AuthService{},
      tokenService:   TokenService{},
      sessionService: SessionService{},
   }
}

func (f *AuthFacade) Login(email, password string) string {
   if !f.authService.Authenticate(email, password) {
      return "Erreur d'authentification"
   }

   token := f.tokenService.GenerateToken(email)
   f.sessionService.StoreSession(email, token)
   return token
}


package main

import (
   "fmt"
   "/designPatterns/facade/auth"
)

func main() {
   authFacade := auth.NewAuthFacade()
   token := authFacade.Login("user@example.com", "securepassword")

   fmt.Println("Token généré:", token)
}

Le même exemple en PHP


namespace Practice\DesignPatterns\Facade;

class AuthService
{
   public function authenticate($email, $password)
   {
       echo "Vérification des identifiants...\n";

       return $email === "user@example.com" && $password === "securepassword";
   }
}


namespace Practice\DesignPatterns\Facade;

class SessionService
{
   public function storeSession($email, $token)
   {
       echo "Session stockée en cache pour $email\n";
   }
}


namespace Practice\DesignPatterns\Facade;

class TokenService
{
   public function generateToken($email)
   {
       echo "Génération du token JWT...\n";

       return "jwt_token_123";
   }
}


namespace Practice\DesignPatterns\Facade;

class AuthFacade
{
   private AuthService    $authService;
   private TokenService   $tokenService;
   private SessionService $sessionService;

   public function __construct()
   {
       $this->authService    = new AuthService();
       $this->tokenService   = new TokenService();
       $this->sessionService = new SessionService();
   }

   public function login($email, $password)
   {
       if (!$this->authService->authenticate($email, $password)) {
           return "Erreur d'authentification";
       }

       $token = $this->tokenService->generateToken($email);
       $this->sessionService->storeSession($email, $token);

       return $token;
   }
}


declare(strict_types=1);

use Practice\DesignPatterns\Facade\AuthFacade;

require "./vendor/autoload.php";

$authFacade = new AuthFacade();
$token = $authFacade->login("user@example.com", "securepassword");

echo "Token généré: $token\n";

Conclusion

J'espère que grâce à cet article vous êtes désormais plus à l'aise avec le design pattern Facade. Vous pouvez retrouver mon article sur les patrons de conception ou les autres tutoriels sur Adapter, Prototype, Decorator, Strategy et Visitor.