Vous êtes sur la page 1sur 7

Design pattern

1- Dfinition
Pattern :
Un pattern ou modle, est un moyen daccomplir quelque chose, un moyen datteindre un
objectif, une technique.
Design pattern :
En gnie logiciel, un patron de conception (Design pattern) est une solution gnrique
dimplmentation rpondant un problme spcifique. En gnral, un patron de conception dcrit
une structure de classes utilisant des interfaces, et sapplique donc des dveloppements logiciels
utilisant la programmation oriente objet.
Un pattern de conception est un modle qui utilise des classes et leurs mthodes dans un langage
orient objet. Les patterns de conception interviennent un niveau au-dessus du code et indiquent
typiquement comment atteindre un but en nutilisant que quelques classes. Un pattern reprsente
une ide, et non une implmentation particulire.
De manire analogue un patron de couture, le patron de conception dcrit les grandes lignes
dune solution, qui peuvent ensuite tre modifies et adaptes en fonction des besoins.
Ils ont une influence sur larchitecture logicielle dun systme informatique.

2- Classification
Ensemble de patrons de conception :
-

Gang of Four (ou GoF : Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides)
Les patrons GRASP (General Responsability Assignment Software Patterns or Princeples)
cres par Craig Larman
Les patrons dentreprise (Entreprise Design Pattern) crs par Martin Fowler
Autres (inversion de contrle, injection de dpendances)

3- Patrons du Gang of Four


Ces patrons de conception sont classs en 3 catgories :
-

Les patrons de cration : dcrivent comment rgler les problmes dinstanciation de


classes, cest--dire de cration et de configuration dobjets (objet en unique exemplaire
par exemple)
Les patrons de structure : dcrivent comment structurer les classes afin davoir le
minimum de dpendance entre limplmentation et lutilisation dans diffrents cas
Les patrons de comportement : dcrivent une structure de classes pour le comportement
de lapplication (rpondre un vnement par exemple)

3-1- Patrons de cration


Un patron de cration permet de rsoudre les problmes lis la cration et la configuration
dobjets.

3-1-1- Singleton
Il est utilis quand la classe ne peut tre instancie quune seule fois.
Le singleton doit tre implment avec prcaution dans les applications multi-thread. Si 2
processus lgers excutent en mme temps la mthode de cration alors que lobjet unique nexiste
pas encore, il faut absolument sassurer quun seul crera lobjet, et que lautre obtiendra une
rfrence vers ce nouvel objet.
Description du problme :
Certaines applications possdent des classes qui doivent tre instancies une seule et unique
fois. Cest par exemple le cas dune classe qui implmenterait un pilote pour un priphrique, ou
encore un systme de journalisation. En effet, instancier deux fois une classe servant de pilote une
imprimante provoquerait une surcharge inutile du systme et des comportements incohrents.
On peut alors se demander comment crer une classe, utilise plusieurs fois au sein de la
mme application, qui ne pourra tre instanci quune seule fois ?
Une premire solution, rgulirement utilise, est dinstancier la classe ds le lancement de
lapplication dans une variable globale (cest--dire une variable accessible depuis nimporte quel
emplacement du programme). Cependant cette solution doit tre vite car en plus denfreindre le
principe dencapsulation, elle comporte de nombreux inconvnients. En effet, rien ne garantit quun
dveloppeur ninstanciera pas une deuxime fois la classe la place dutiliser la variable globale
dfinie. De plus, on est oblig dinstancier les variables globales ds le lancement de lapplication et
non la demande (ce qui peut avoir un impact non ngligeable sur la performance de lapplication).
Enfin, lorsquon arrive plusieurs centaines de variables globales, le dveloppement devient
rapidement ingrable surtout si plusieurs programmeurs travaillent simultanment.
Dfinition de la solution :
Lobjectif est dajouter un contrle sur le nombre dinstances que peut retourner une classe.
La premire tape consiste empcher les dveloppeurs dutiliser le ou les constructeur(s) de
la classe pour linstancier. Pour cela, il suffit de dclarer priv tous les constructeurs de la classe.
Une fois cette tape accomplie, il est possible dinstancier cette classe uniquement depuis ellemme.
Nous allons construire un pseudo constructeur. Pour cela, il faut dclarer une mthode
statique qui retournera un objet correspondant au type de la classe. Lavantage de cette mthode par
rapport un constructeur, est que lon peut contrler la valeur que lon va retourner. Le fait que cette
mthode soit dclare statique permet de lappeler sans possder dinstance de cette classe. A noter
que par convention, ce pseudo constructeur est nomm getInstance.

Rappel : le design pattern Singleton


Le Singleton rpond deux exigences :
-

garantir qu'une unique instance d'une classe donne sera cre


offrir un point d'accs universel cette instance.

Ce design pattern est tout indiqu pour implmenter des services qui :
-

sont fonctionnellement uniques au sein de l'application (ex: systme de logging centralis,


gestion de la configuration...)
doivent pouvoir tre appels par toutes les couches de l'application. Il serait en effet peu
pratique de passer une rfrence au service toutes les classes devant l'utiliser.

Voyons maintenant comment on l'implmente en Java.

Un singleton basique
Un simple enchanement de rflexions permet de dduire les caractristiques d'une classe
Singleton :
-

Afin de garantir l'unicit du Singleton, il est ncessaire de contrler strictement son


processus d'instanciation. Il faut donc interdire tout code extrieur d'utiliser l'oprateur
"new" et de crer des instances supplmentaires. Pour cela, il suffit de dclarer un
constructeur de visibilit "priv" (voir le Java Quiz #1).
Consquence : pour obtenir une rfrence sur une instance du Singleton, le code appelant
devra obligatoirement passer par une mthode utilitaire au lieu du constructeur. Cette
mthode sera ncessairement statique, car cet instant, le code appelant ne dispose
encore d'aucune rfrence sur l'instance du singleton, et ne peut donc accder qu' ses
membres statiques.

La mthode utilitaire tant statique, elle ne peut accder qu'aux proprits galement
statiques de la classe. L'instance unique devra donc tre statique aussi.

Voici donc la version minimale du Singleton :


1. /**
2. * Implmentation simple d'un singleton.
3. * L'instance est cre l'initialisation.
4. */
5. public class Singleton
6. {
7.
/** Constructeur priv */
8.
private Singleton()
9.
{}
10.
11.
/** Instance unique pr-initialise */
12.
private static Singleton INSTANCE = new Singleton();
13.
14.
/** Point d'accs pour l'instance unique du singleton */
15.
public static Singleton getInstance()
16.
{
return INSTANCE;
17.
}
18. }

Lazy-loading
Dans l'implmentation ci-dessus, l'instance du Singleton est automatiquement cre au dmarrage de
l'application.
Bien qu'il s'agisse de la meilleure solution dans la plupart des cas, il peut arriver que l'on souhaite
retarder l'initialisation de l'instance jusqu'au premier appel de "getInstance()". Cela se justifie par
exemple si le programme n'a pas systmatiquement besoin des services du singleton.
Implmentation basique
Voici l'implmentation la plus frquente :
1. public class Singleton
2. {
3.
/** Constructeur priv */
4.
private Singleton()
5.
{}
6.
7.
/** Instance unique non prinitialise */
8.
private static Singleton INSTANCE = null;
9.
10.
/** Point d'accs pour l'instance unique du singleton */
11.
public static Singleton getInstance()
12.
{
13.
if (INSTANCE == null)
14.
{
INSTANCE = new Singleton();
15.
}
16.
return INSTANCE;
17.
}
18. }

Cette
implmentation
semble
correcte

premire
vue.
Pourtant, elle est extrmement dangereuse en environnement multithread, car deux threads
peuvent excuter le test simultanment et crer ainsi chacun une instance du singleton. Elle doit
donc tre absolument proscrite.

Synchronisation globale
Afin de rsoudre ce problme de concurrence des threads, on peut videmment synchroniser la
mthode "getInstance()" :
1. public class Singleton
2. {
3.
/** Constructeur priv */
4.
private Singleton()
5.
{}
6.
7.
/** Instance unique non prinitialise */
8.
private static Singleton INSTANCE = null;
9.
10.
/** Point d'accs pour l'instance unique du singleton */
11.
public static synchronized Singleton getInstance()
12.
{
13.
if (INSTANCE == null)
14.
{
INSTANCE = new Singleton();
15.
}
16.
return INSTANCE;
17.
}
18. }

Le problme est ainsi rsolu, mais au prix d'une pnalit sur les performances. Si le singleton est
accd souvent (systme de log...), le ralentissement de l'application peut tre important.
Synchronisation locale
Si l'on est attentif, on s'aperoit que la synchronisation n'est requise qu'au moment exact de la
cration de l'instance. Ne pourrait-on donc pas distinguer supprimer la synchronisation globale sur la
mthode, et ne l'appliquer que dans le cas o l'instance doit tre cre ?
1. public class Singleton
2. {
3.
/** Constructeur priv */
4.
private Singleton()
5.
{}
6.
7.
/** Instance unique non prinitialise */
8.
private static Singleton INSTANCE = null;
9.
10.
/** Point d'accs pour l'instance unique du singleton */
11.
public static Singleton getInstance()
12.
{
13.
if (INSTANCE == null)
14.
{
15.
synchronized(Singleton.class)
16.
{
17.
if (INSTANCE == null)
18.
{
INSTANCE = new Singleton();
19.
}
20.
}
21.
}
22.
return INSTANCE;
23.
}
24. }

Hlas, cette solution, appele "double-checked locking", ne fonctionne pas non plus.

Technique du Holder
En revanche, une technique fonctionne correctement : la technique dite du "Holder".
Elle repose sur l'utilisation d'une classe interne prive, responsable de l'instanciation de l'instance
unique du Singleton.
1. public class Singleton
2. {
3.
/** Constructeur priv */
4.
private Singleton()
5.
{}
6.
7.
/** Holder */
8.
private static class SingletonHolder
9.
{
10.
/** Instance unique non prinitialise */
11.
private final static Singleton instance = new
Singleton();
12.
}
13.
14.
/** Point d'accs pour l'instance unique du singleton */
15.
public static Singleton getInstance()
16.
{
17.
return SingletonHolder.instance;
18.
}
19. }

Cette technique joue sur le fait que la classe interne ne sera charge en mmoire que lorsque
l'on y fera rfrence pour la premire fois, c'est--dire lors du premier appel de "getInstance()" sur la
classe Singleton. Lors de son chargement, le Holder initialisera ses champs statiques et crera donc
l'instance unique du Singleton.
Cerise sur le gteau, elle fonctionne correctement en environnement multithread et ne
ncessite aucune synchronisation explicite !

Srialisation des singletons


Pour finir, rappelez-vous qu'il existe une seconde faon d'instancier des objets : par
dsrialisation.
Si votre Singleton implmente java.io.Serializable, il faut absolument empcher que sa
dsrialisation n'entrane la cration de nouvelles instances. Pour cela, la javadoc indique que la
mthode "readResolve()" permet de remplacer tout objet dsrialis par un objet personnalis.

Utilisons cela notre avantage :


1. public class Singleton implements Serializable
2. {
3.
/** Constructeur priv */
4.
private Singleton()
5.
{}
6.
7.
/** Instance unique pr-initialise */
8.
private static Singleton INSTANCE = new Singleton();
9.
10.
/** Point d'accs pour l'instance unique du singleton */
11.
public static Singleton getInstance()
12.
{
return INSTANCE;
13.
}
14.
15.
/** Scurit anti-dsrialisation */
16.
private Object readResolve() {
17.
return INSTANCE;
18.
}
19. }

Ainsi, toute instance dsrialise du Singleton sera remplace par notre instance unique.