Procuration
Intention
La Procuration est un patron de conception structurel qui vous permet d’utiliser un substitut pour un objet. Elle donne le contrôle sur l’objet original, vous permettant d’effectuer des manipulations avant ou après que la demande ne lui parvienne.
Problème
Pourquoi vouloir maîtriser l’accès à un objet ? Voici un exemple : vous avez un énorme objet qui consomme beaucoup de ressources, mais vous n’en avez besoin que de temps en temps.
Vous pouvez recourir à l’instanciation paresseuse : créer l’objet uniquement lorsque vous en avez besoin. Vous devrez implémenter une initialisation différée dans tous les clients pour l’objet concerné. Malheureusement, vous allez vous retrouver avec beaucoup de code dupliqué.
Dans le meilleur des mondes, nous voudrions mettre ce code directement dans la classe de l’objet, mais ce n’est pas toujours possible. La classe pourrait par exemple faire partie d’une application externe non modifiable.
Solution
Ce patron de conception vous propose de créer une classe procuration qui a la même interface que l’objet du service original. Vous passez ensuite l’objet procuration à tous les clients de l’objet original. Lors de la réception d’une demande d’un client, la procuration crée l’objet du service original et lui délègue la tâche.
Mais quel est son intérêt ? Si vous voulez lancer un traitement avant ou après avoir appliqué la logique principale de la classe, la procuration peut intervenir sans modifier cette dernière. Elle implémente la même interface que la classe originale, et peut donc être passée en paramètre à n’importe quel client qui attend l’objet du service original.
Analogie
Une carte de crédit est une procuration pour un compte bancaire, qui est une procuration pour une liasse de billets. Ils implémentent la même interface : tous deux peuvent être utilisés pour effectuer un paiement. Le consommateur apprécie grandement, car il n’a pas besoin de garder une grosse somme en liquide sur lui. Le commerçant est également très heureux, car les transactions sont versées électroniquement vers son compte en banque, sans courir le risque d’égarer son dépôt ou de se le faire voler sur le chemin de la banque.
Structure
-
L’Interface Service déclare l’interface du service. La procuration doit implémenter cette interface afin de pouvoir se déguiser en objet du service.
-
Le Service est une classe qui fournit la logique métier dont vous voulez vous servir.
-
La Procuration est une classe dotée d’un attribut qui pointe vers un objet service. Une fois que la procuration a lancé tous ses traitements (instanciation paresseuse, historisation des logs, vérification des droits, mise en cache, etc.), elle envoie la demande à l’objet du service.
En général, les procurations gèrent le cycle de vie de leurs objets service.
-
Le Client passe par la même interface pour travailler avec les services et les procurations. Il est ainsi possible de passer une procuration à n’importe quel code qui attend un objet service.
Pseudo-code
L’exemple suivant montre comment le patron de conception Procuration nous aide à utiliser l’instanciation paresseuse et la mise en cache pour intégrer une librairie YouTube externe.
La librairie nous fournit une classe pour télécharger des vidéos. Malheureusement, elle n’est pas très efficace. Si l’application client demande une même vidéo à plusieurs reprises, la librairie va la télécharger encore et encore, plutôt que de la mettre en cache après la première utilisation.
La classe procuration implémente la même interface que l’outil de téléchargement original et délègue tout le travail à ce dernier. En revanche, elle garde la trace de tous les fichiers téléchargés et retourne les données du cache lorsque l’application fait plusieurs fois appel à la même vidéo.
Possibilités d’application
La procuration possède de nombreux usages. Passons en revue les plus populaires.
Instanciation paresseuse (procuration virtuelle). À utiliser lorsque l’objet du service est très consommateur en ressources système car il est actif en permanence, mais vous n’en avez pas tout le temps besoin.
Vous pouvez différer l’initialisation de l’objet plutôt que de le créer au lancement de l’application.
Vérification des droits (procuration de protection). Si vous avez besoin de limiter l’accès de vos clients à l’objet du service, par exemple si vos objets sont des parties cruciales d’un système d’exploitation et que les clients sont différentes applications lancées (dont certaines sont malveillantes).
La procuration peut ne transmettre une demande à l’objet du service que si les identifiants du client remplissent certains critères.
Lancement local d’un service distant (procuration à distance). L’objet du service se situe sur un serveur distant.
Dans ce cas, la procuration envoie la demande par le réseau en s’occupant de gérer tous les détails compliqués de la gestion du réseau.
Demande de logs (procuration de logs). Pour garder un historique des demandes passées auprès de l’objet du service.
La procuration peut garder la trace de toutes les demandes passées au service.
Mettre en cache les résultats des demandes (procuration de cache). Si vous voulez mettre en cache les résultats des demandes faites au client et gérer le cycle de vie de ce cache, principalement lorsque les résultats sont imposants.
La procuration peut gérer la mise en cache des demandes récurrentes qui retournent toujours le même résultat. Les paramètres des demandes peuvent servir de clé.
Référencement intelligent. Si vous voulez vous débarrasser d’un objet très consommateur en ressources lorsqu’aucun client ne l’utilise.
La procuration peut garder la trace des clients qui ont récupéré une référence vers l’objet du service ou vers ses résultats. De temps en temps, la procuration peut faire le tour des clients et vérifier s’ils sont toujours actifs. Si la liste des clients est vide, la procuration peut supprimer l’objet du service afin de libérer des ressources.
Elle peut également savoir si le client avait modifié l’objet du service. Les objets non modifiés peuvent ensuite être réutilisés par les autres clients.
Mise en œuvre
-
Si le service n’a pas encore d’interface, créez-en une pour rendre la procuration et les objets du service interchangeables. Il n’est pas toujours possible d’extraire l’interface de la classe du service, car vous devez effectuer des modifications pour que tous les clients du service utilisent cette interface. Heureusement, nous avons un plan B. Transformez la procuration en sous-classe de la classe service, afin qu’elle hérite de l’interface du service.
-
Créez la classe procuration. Elle doit inclure un attribut qui stocke la référence au service. En général, les procurations créent et gèrent le cycle de vie de leurs services. En de rares occasions, un service est passé à la procuration par le biais d’un constructeur du client.
-
Mettez en place les méthodes de la procuration et leur fonctionnement. Dans la plupart des cas, la procuration doit déléguer le travail à l’objet du service après avoir lancé ses traitements.
-
Réfléchissez à l’implémentation d’une méthode de création qui décide si votre client doit utiliser directement le service ou passer par la procuration. Il peut s’agir d’une méthode statique toute simple ou d’une classe procuration avec une méthode fabrique complète.
-
Envisagez également l’implémentation d’une instanciation paresseuse pour l’objet du service.
Avantages et inconvénients
- Vous pouvez contrôler l’objet du service sans que le client ne s’en aperçoive.
- Vous pouvez gérer le cycle de vie de l’objet du service si les clients ne s’en occupent pas.
- La procuration fonctionne même si l’objet du service n’est pas prêt ou pas disponible.
- Principe ouvert/fermé. Vous pouvez ajouter de nouvelles procurations sans toucher au service ou aux clients.
- Le code peut devenir plus complexe puisque vous devez y introduire de nombreuses classes.
- La réponse du service peut mettre plus de temps à arriver.
Liens avec les autres patrons
-
Avec Adaptateur, vous accédez à un objet existant via une interface différente. Avec Procuration, l’interface reste la même. Avec Décorateur, vous accédez à l’objet via une interface améliorée.
-
La Façade et la Procuration ont une similarité : ils mettent en tampon une entité complexe et l’initialisent individuellement. Contrairement à la façade, la procuration implémente la même interface que son objet service, ce qui les rend interchangeables.
-
Le Décorateur et la Procuration ont des structures similaires, mais des intentions différentes. Ces deux patrons sont bâtis sur le principe de la composition, où un objet est censé déléguer certains traitements à un autre. La différence est qu’en principe, la procuration gère elle-même le cycle de vie de son objet service, alors que la composition des décorateurs est toujours contrôlée par le client.