Академический Документы
Профессиональный Документы
Культура Документы
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-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.
Ce design pattern est tout indiqu pour implmenter des services qui :
-
Un singleton basique
Un simple enchanement de rflexions permet de dduire les caractristiques d'une classe
Singleton :
-
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.
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 !
Ainsi, toute instance dsrialise du Singleton sera remplace par notre instance unique.