Accueil /  Blog / Symfony / 5 Design Patterns que vous avez utilisé au quotidien avec Symfony

5 Design Patterns que vous avez utilisé au quotidien avec Symfony

Publié le vendredi 5 juillet 2024

Lorsque nous développons avec Symfony, nous utilisons souvent des design patterns sans même nous en rendre compte.
Dans cet article, nous présenterons cinq design patterns issus de Symfony, et illustrés de leur code source.

Disclaimer : Les exemples ont volontairement été simplifiés pour une meilleure compréhension, les liens de la documentation officielle vous seront fournis à chaque point afin que vous puissiez aller plus loin.

1. Le pattern Factory

Le pattern Factory propose une interface pour la création d'objets au sein d'une classe parente, tout en déléguant aux sous-classes le choix des types d'objets à créer.

Qui ne connait pas encore le composant Form de Symfony ?

Avant l’avènement des APIs, il a été pendant longtemps le composant obligatoire dans toutes les applications web.

Mais saviez-vous qu'il était conçu à partir du pattern Factory ? C'est dans la class FormFactory que nous pouvons voir l'implémentation de ce pattern.

Voici 2 des méthodes les plus utilisés de cette classe :

class FormFactory implements FormFactoryInterface
{
    public function create($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = [])
    {
        $builder = $this->createBuilder($type, $data, $options);
        return $builder->getForm();
    }

    public function createBuilder($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = [])
    {
        return $this->builderFactory->createBuilder($type, $data, $options);
    }
}

2. Le pattern Strategy

Le pattern Strategy permet de définir une famille d'algorithmes, de les encapsuler et de les rendre interchangeables.

Dans Symfony, beaucoup de composants utilisent ce pattern, un des plus connus est le composant HttpClient.

Dans ce composant il est possible de définir une stratégie de Retry en cas d'échec de la requête. Il est implémenté dans la class RetryableHttpClient

class RetryableHttpClient implements HttpClientInterface, ResetInterface
{
    use AsyncDecoratorTrait;

    private RetryStrategyInterface $strategy;
    private array $baseUris = [];

    /**
     * @param int $maxRetries The maximum number of times to retry
     */
    public function __construct(
        HttpClientInterface $client,
        ?RetryStrategyInterface $strategy = null,
        private int $maxRetries = 3,
        private ?LoggerInterface $logger = null,
    ) {
        $this->client = $client;
        $this->strategy = $strategy ?? new GenericRetryStrategy();
    }

Grace au respect de l'interface RetryStrategyInterface il est possible de définir la stratégie retry que vous souhaitez adopter pour votre client http.

Si vous souhaitez voir une présentation plus complète de ce pattern, je vous invite à lire notre article sur le sujet.

3. Le pattern Observer

Le pattern Observer permet à un objet (le sujet) de notifier d'autres objets (les observateurs) des changements d'état.

Dans Symfony, ce pattern est couramment utilisé via le composant EventDispatcher et son point d'entrée principal.

class EventDispatcher implements EventDispatcherInterface
{
    private array $listeners = [];
    private array $sorted = [];

    public function dispatch(object $event, string $eventName = null): object
    {}

    public function getListeners(string $eventName = null): array
    {}

    public function addListener(string $eventName, callable $listener, int $priority = 0)
    {}

    public function removeListener(string $eventName, callable $listener)
    {}
}

4. Le pattern Decorator

Le pattern Decorator permet d'ajouter dynamiquement des comportements à un objet. Dans Symfony, le pattern est par exemple utilisé dans le composant HttpKernel, plus précisément pour géré le Cache avecla classe HttpCache.

class HttpCache implements HttpKernelInterface
{
    private $kernel;
    private $store;

    public function __construct(HttpKernelInterface $kernel, StoreInterface $store)
    {
        $this->kernel = $kernel;
        $this->store = $store;
    }

    public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true): Response
    {}

    private function lookup(Request $request): bool
    {}
}

Si vous souhaitez en savoir plus sur ce pattern je vous invite à lire notre article sur le sujet.

5. La chaîne de responsabilité

Le pattern Chaine de responsabilité permet à une requête de passer à travers une chaîne d'objets jusqu'à ce qu'un objet puisse la traiter. Dans Symfony, une implémentation de ce pattern existe notamment dans le composant Cache via la classe ChainAdapter

Le ChainAdapter permet de combiner plusieurs adaptateurs de cache. Il tente de récupérer un élément de chaque adaptateur dans l'ordre jusqu'à ce qu'il trouve l'élément. Lors de l'enregistrement d'un élément, il écrit dans tous les adaptateurs configurés.

class ChainAdapter implements CacheItemPoolInterface
{
    private $adapters;

    public function __construct(array $adapters, $defaultLifetime = 0)
    {}

    public function getItem($key)
    {}

    public function save(CacheItemInterface $item)
    {}

    public function deleteItem($key)
    {}
}

Si vous souhaitez en savoir plus sur ce pattern je vous invite à lire notre article sur le sujet.

Suivez notre actualité en avant première. Pas plus d’une newsletter par mois.