Proxy

La programmation avec design patterns

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com
Programmation orientée aspect (AOP) base tout son fonctionnement sur ce qu'on appelle les proxy. Il s'agit des objets qui englobbent d'autres objets et qui sont donc invoqués avant les objets natifs. Ce contrôle serait impossible sans le design pattern nommé Proxy.

Le design pattern Proxy (en français connu sous le nom délégation) fonctionne de la même manière que les serveurs proxy de cache, comme par exemple Varnish. Dans cette analogie avec les serveurs, la classe réelle (celle que l'utilisateur appelle) est représentée par le serveur web (Apache par exemple). Le serveur de cache comme Varnish, joue ici le rôle de proxy. C'est lui qui intercepte toutes les requêtes des clients et, dans cette situation spécifique, vérifie s'il faut renvoyer un fichier frais (directement depuis Apache) ou un fichier placé dans le cache. Ce procédé a pour but d'accélérer le temps de chargement des pages par l'économie de génération des ressources.

Dans la programmation le gain de l'utilisation du Proxy est aussi de nature de ressources. Une classe Proxy englobbe la classe réelle. Elle peut donc la contrôler et décider combien de fois cette dernière doit être initialisée ou quelles méthodes doivent être exposées à l'exécution. Les proxies servent aussi à surcharger le comportement d'une fonction. Cela trouve son utilité dans Aspect Oriented Programming (AOP, programmaton orientée aspect), expliquée brièvement dans l'article Programmation Orientée Aspect. Elle favorise l'ajout des proxies pour étendre le comportement d'une méthode. On peut ainsi exécuter une fonction supplémentaire avant la fin de la méthode ou aussi bien faire un traitement supplémentaire dans le cas d'une exception.

Si l'on recherche l'illustration dans le monde réel et non-informatique, on retrouve proxy dans tout ce qui est représentation physique de quelque chose. La télécommande est une sorte de proxy de boutons d'un poste de télévision. Les boutons de la télécommande permettent de faire exactement la même chose que ceux placés sur le poste. La différence répose dans le fait qu'on ne doit pas se déplacer physiquement pour, par exemple, changer de chaîne.

D'après cette description on peut trouver les acteurs qui participent dans Proxy :
- subject (sujet) : l'interface qui représente les service du vrai sujet.
- real subject (vrai sujet) : la classe représentée par proxy et implémentant l'interface du sujet.
- proxy : la classe qui implémente l'interface du sujet et possède une référence au vrai sujet. Elle peut être d'une nature : protectrice (déterminer qui peut accéder au vrai sujet), intelligente (par exemple : chargement intelligent du vrai sujet, ajout des fonctionnalités), virtuelle (chargement du vrai sujet seulement quand c'est nécessaire pour économiser des ressources), distante (fournit la représentation locale d'un objet situé réellement sous une autre adresse physique, Java RMI se base sur ce proxy).

Exemple du design pattern Proxy
Dans notre exemple on implémentera un système AOP minifié. Le but de l'exercice consiste à rajouter une méthode supplémentaire pendant l'invocation de la méthode d'origine de la classe Waiter.

//subject
interface RestaurantEmployee{
public void work();
}

//real subject
class Waiter implements RestaurantEmployee{
private final String name;

public Waiter(final String name){
this.name=name;
}

@Override
public void work(){
System.out.println(this.name+" > I got your order. Thanks !");
}
}

Le sujet et le vrai sujet ne font que leur travail. L'interface (sujet) définit l'action possible par le vrai sujet. Quant à ce dernier, il définit comment cette action sera exécutée. En occurrence il s'agit d'une prise de commande d'un serveur. Il "informe" le client que la commande a bien été prise en compte.


// proxy
class WaiterProxy implements RestaurantEmployee{
private Waiter waiter;

@Override
public void work(){
System.out.println("Waiter can't get the order before my action.");
System.out.println("I'm updating the order statistics in our history. Now the waiter can do his job.");
this.waiter=new Waiter("Marc Andre");
this.waiter.work();
}
}

En ce qui concerne le proxy, on voit qu'il implémente la même classe que le vrai sujet. Cependant, le proxy fait quelques choses supplémentaires. Tout d'abord, il dit que le serveur ne peut pas prendre la commande du client car le proxy doit d'abord mettre à jour ses statistiques. Ce n'est qu'après cette opération que le serveur est appelé à la table du client pour noter la commande.


final RestaurantEmployee employee=new WaiterProxy();
employee.work();

Le code client utilise la classe proxy. Le résultat de ce code est le suivant :


Waiter can't get the order before my action.
I'm updating the order statistics in our history. Now the waiter can do his job.
Marc Andre > I got your order. Thanks !


On a vu que le design pattern Proxy est très utile dans les situations où on a besoin d'étendre les fonctionnalités d'un objet sans être obligés de réecrire toute son implémentation. Proxy permet également un meilleure contrôle sur les ressources de l'application. Dans notre exemple on a vu que l'instance de la classe Waiter a été initialisée qu'après le travail fait par WaiterProxy (deux appels du System.out.println()). On pourrait même aller plus loin et définir quel type de client peut appeler le client. La décision serait alors prise par la classe de proxy.
Bartosz KONIECZNY 08-09-2013 17:39 design patterns
Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil MySQL

Vous rencontrez un problème lors de la suppression d'un élément ou d'une table liée à des contraintes des clés étrangères. L'une des solution peut être l'annulation de la vérification de ces contraintes.


-- Au début on indique à MySQL de ne pas vérifier les contraintes des clés étrangères
SET FOREIGN_KEY_CHECKS=0;
-- Ensuite on passe à l'opération de suppression d'une table
DROP TABLE ma_table;
-- A la fin (ou au moment voulu) on restaure la vérification des contraintes
SET FOREIGN_KEY_CHECKS=1;

Vous pouvez en savoir plus sur FOREIGN_KEY_CHEKS dans la documentation du MySQL.