P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ SCAN MY NETWORK AND DIE Articles | Connexion
 
~Singleton et Proxy

 Présentation

Dans l'introduction nous faisions connaissance avec les motifs de conception, ou Design Patterns. Dorénavant nous étudierons dans chaque cours un ou deux motifs dans l'une des trois catégories précisées précédemment. Notre étude se portera sur un motif créateur et un motif structurel. La premier motif de conception étudié se nomme Singleton et le second Proxy.
 Sommaire


 Le motif Singleton

Le design pattern Singleton se voit regroupé au sein des motifs de création. Il s'agit en réalité d'un motif de "non-création". En programmation orientée objet, il existe de nombreuses circonstances au cours desquelles il convient de ne posséder qu'une seule et unique instance d'une classe donnée. Un programme ne doit proposer par exemple qu'un seul gestionnaire de cache.

L'implémentation de ce motif peut bénéficier de trois approches possibles. Ces trois approches ont en commun l'emploi de membres statiques de classe. La première approche repose sur le principe des exceptions. Analysons le listing d'une implémentation possible d'un gestionnaire de cache :

public class CacheManager {
  protected static boolean isInstanceAlive = false;

  public CacheManager() throws SingletonException {
    if (isInstanceAlive)
      throw new SingletonException("instance de CacheManager deja active");
    else
      isInstanceAlive = true;
    System.out.println("Le cache a ete cree avec succes.");
  }

  public void finalize() {
    isInstanceAlive = false;
  }
}
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Lors de l'appel du constructeur, nous vérifions au préalable qu'aucune instance n'existe déjà. L'existence d'une instance se détermine par la valeur de la variable logique "isInstanceAlive". Si une instance a déjà été créée, le constructeur émet une exception pour le signaler. L'utilisation d'une exception est rendue obligatoire par l'impossibilité d'un constructeur de renvoyer une valeur.

La seconde approche possible pour implémenter le modèle Singleton consiste à prendre exemple sur la classe java.lang.Math. Java offre en effet un mot clé particulier interdisant l'héritage d'une classe. Il s'agit du mot clé "final". En créant une classe "final" ne contenant que des méthodes statiques, vous vous assurez de l'impossibilité d'en créer une instance.

Il se révèle possible de créer des instances de la classe. Néanmoins, chaque instance possédera le même comportement que les autres, puisque l'héritage sera interdit. Cette approche pêche par sa difficulté d'adaptation lorsque l'on souhaite retirer le principe du Singleton. Un exemple simple de ce procédé peut être :

final class FinalCacheManager
{
  static void printCacheContent() {
    System.out.println("Le contenu du cache est le suivant : <vide>");
  }
}
       
      
JextCopier dans Jext
La troisième et dernière approche rappelle le principe de la fabrique. Il s'agit de réaliser une méthode statique garantissant l'impossibilité de créer deux instances de la classe. L'avantage de cette dernière manière de procéder réside dans la possibilité de laisser de côté le traitement des exceptions. Ceci a pour effet bénéfique de rendre le code plus léger à rédiger et à comprendre. Remplacez donc le constructeur de la classe CacheManager par une méthode telle que celle-ci :

public static StaticCacheManager getInstance()
{
  if (isInstanceAlive)
    return null;
  else {
    isInstanceAlive = true;
    return new StaticCacheManager();
  }
}
       
      
JextCopier dans Jext
Le principe du Singleton amène deux conséquences importantes. En premier lieu, l'héritage d'un singleton se voit possible (hormis dans le cadre de la seconde approche) mais difficile dans la mesure où la classe de base ne doit pas avoir été instanciée. Ensuite, vous pouvez tout à fait décider d'étendre le Singleton pour permettre la création de quelques instances au lieu d'une seule.


 Le motif Proxy

Le motif de conception intitulé Proxy désigne un motif structurel. Six autres motifs de conception structurels existent :
  • Le motif Adapter
  • Le motif Bridge
  • Le motif Composite
  • Le motif Decorator
  • Le motif Facade
  • Le motif Flyweight
Un Proxy représente un moyen de fournir une représentation simplifiée d'un objet complexe. Typiquement, le Proxy permet d'offrir un substitut à un objet en chargement. Durant le chargement, le Proxy utilise ses propres méthodes. Une fois le chargement fini, les méthodes du Proxy délèguent leurs actions aux méthodes de l'objet. A l'aide d'un Proxy, une application peut ainsi remettre à plus tard le chargement d'un objet, lorsqu'il sera réellement nécessaire.

Nous allons pour notre part écrire un Proxy d'image. Les navigateurs Internet affichent toujours un rectangle symbolisant les images en cours de chargement. Nous sommes ici en présence du principe du Proxy. L'exemple de notre étude dessinera ainsi un rectangle à l'écran en l'attente du chargement d'une image.

L'exemple se compose de deux classes : MainProxy, le programme principal contenant une fenêtre Swing, et ImageProxy, le Proxy à proprement parler. Lors de la création de la fenêtre, MainProxy crée une instance de ImageProxy qui hérite de JPanel. Le rôle de ImageProxy consiste à lancer le chargement d'une image et à afficher un rectangle rouge de la taille de l'image lors dudit chargement. Héritant de JPanel, ImageProxy propose une méthode de dessin nommée paint(). C'est au cour de cette méthode que nous allons effectuer le travail. Si le chargement a atteint son terme, l'image se voit dessinée à l'écran. Dans le cas contraire, un simple rectangle rouge apparaît alors. Le chargement de l'image se voit réalisé par l'intermédiaire de l'objet MediaTracker. Voici le code de la fonction paint() :

public void paint(Graphics g) {
  // l'image a été chargée
  if (tracker.checkID(0))
  {
    width = img.getWidth(frame);
    height = img.getHeight(frame);
    g.setColor(Color.lightGray);
    g.fillRect(0, 0, width, height);
    g.drawImage(img, 0, 0, frame);
  } else {
    // image en attente
    g.setColor(Color.red);
    g.drawRect(0, 0, width - 1, height - 1);
  }
}
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Afin de vous permettre de remarquer l'affichage du rectangle, notre Proxy utilise un thread supplémentaire pour forcer le ralentissement de l'affichage. Au préalable, l'image se voit placée en queue de chargement dans le MediaTracker, voir ici :

tracker = new MediaTracker(f);
img = Toolkit.getDefaultToolkit().getImage(imageName);
tracker.addImage(img, 0);

check = new Thread(this);
check.start();

try
{
  tracker.waitForID(0, 1);
} catch (InterruptedException ie) { }
       
      
JextCopier dans Jext
Le thread intitulé "check" va provoquer une boucle d'attentes de une seconde tant que l'image n'aura pas été chargée définitivement. A la suite de quoi elle sera affichée.

Les motifs de conception Proxy trouvent également leur utilité dans la conservation de copies d'objets gourmands en mémoire. Si votre programme demande la création d'une seconde instance d'un tel objet, le Proxy peut décider de ne pas effectuer une copie immédiatement. Il utilise simplement l'objet original. Si jamais des modifications se voient appliquées à la seconde instance potentielle, le Proxy les applique sur une nouvelle instance. Le programmeur se voit en mesure de gagner beaucoup de temps machine dans des applications faisant appel à de gros objets qui ne sont pas nécessairement modifiés après création.

Vous retrouverez en annexe les exemples complets de nos deux motifs.



Notre application de Proxy.



Le fameux ouvrage du Gang Of Four.


 Annexes




par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006



 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE