Le design pattern Facade
Description
L’objectif du design pattern Facade est de regrouper les interfaces d’un ensemble d’objets dans une interface unifiée rendant cet ensemble plus simple à utiliser.
Exemple
Nous voulons offrir la possibilité d’accéder au système de vente de véhicule en tant que service web. Le système est architecturé sous la forme d’un ensemble de composants possédant chacun leur propre interface comme :
-
Le composant Catalogue ;
-
Le composant GestionDocument ;
Il est possible de donner l’accès à l’ensemble de l’interface de ces composants aux clients du service web mais cette démarche présente deux inconvénients majeurs :
-
Certaines fonctionnalités ne sont pas utiles aux clients du service web comme les fonctionnalités d’affichage du catalogue.
-
L’architecture interne du système répond à des exigences de modularité et d’évolution qui ne font pas partie des besoins des clients du service web.
Le design pattern Facade résout ce problème en proposant l’écriture d’une interface unifiée d’un plus haut niveau d’abstraction. Une classe est chargée d’implémenter cette interface unifiée en utilisant les composants du système.
Cette solution est illustrée à la figure 14.1. La classe WebServiceAuto offre une interface aux clients du service web. Cette classe et son interface constituent une façade vis-à-vis de ces clients.
L’interface de la classe WebServiceAuto...
Structure
1. Diagramme de classes
La figure 14.2 détaille la structure générique du design pattern Facade.
Figure 14.2 - Structure du design pattern Facade
2. Participants
Les participants au design pattern Facade sont les suivants :
-
Facade (WebServiceAuto) et son interface constituent la partie abstraite exposée aux clients du système. Cette classe possède des références vers les classes et composants constituant le système et dont les méthodes sont utilisées par la façade pour implémenter l’interface unifiée.
-
Les classes et composants du système (GestionDocument et Catalogue) implémentent les fonctionnalités du système et répondent aux requêtes de la façade. Elles n’ont toutefois pas besoin de la façade pour travailler.
3. Collaborations
Les clients communiquent avec le système au travers de la façade qui se charge, à son tour, d’invoquer les classes et composants du système. La façade ne peut pas se limiter à transmettre des appels. Elle doit aussi réaliser l’adaptation entre son interface et l’interface des objets du système au moyen de code spécifique. Le diagramme de séquence de la figure 14.3 illustre cette adaptation sur un exemple où du code spécifique à la façade doit être...
Domaines d’application
Le design pattern Facade est utilisé dans les cas suivants :
-
Pour fournir une interface simplifiée d’un système complexe. L’architecture d’un système peut être basée sur de nombreuses petites classes, lui offrant une bonne modularité et des capacités d’évolution. Cependant ces bonnes propriétés du système n’intéressent pas ses clients qui ont besoin d’un accès simple qui répond à leurs exigences.
-
Pour diviser un système en sous-systèmes, la communication entre sous-systèmes étant mise en œuvre grâce aux façades.
-
Pour systématiser l’encapsulation de l’implémentation d’un système vis-à-vis de l’extérieur.
Exemple en PHP
Nous reprenons l’exemple du service web que nous allons simuler à l’aide d’un petit programme PHP. Nous donnons d’abord le code source des composants du système et pour commencer celui de la classe ComposantCatalogue et de son interface CatalogueInterface, ainsi que la classe Vehicule.
La base de données constituant le catalogue est remplacée par un tableau d’objets de la classe Vehicule. La méthode retrouveVehicules effectue la recherche d’un ou de plusieurs véhicules en fonction de leur prix à l’aide d’une simple boucle foreach.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Facade;
interface CatalogueInterface
{
public function retrouveVehicules(float $prixMin, float $prixMax):
array;
}
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Facade;
class ComposantCatalogue implements CatalogueInterface
{
protected array $vehicules;
public function __construct(array $vehicules)
{
$this->vehicules = $vehicules;
}
public function retrouveVehicules(float $prixMin, float $prixMax):
array
{
$resultat = [];
foreach ($this->vehicules as $vehicule) {
...