I. Introduction▲
Un design pattern décrit une solution standard, utilisable dans la conception de logiciels, à des questions classiques et récurrentes.
Les patrons de conception les plus connus sont au nombre de vingt-trois : Abstract factory, Builder, Factory, Prototype, Singleton, Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy, Memento, Strategy, Command, Chain of responsability, Interpreter, Iterator, Mediator, Template, Visitor, State et Observer. On les classe généralement en trois familles : Création, Structure et Comportement. Ils sont désignés sous le nom de « Gang of Four » (GOF) en référence aux quatre créateurs du concept.
Cet article vous redonne les points clés pour bien comprendre/utiliser les patterns les plus utiles. Il vous propose surtout de télécharger des mémentos à imprimer vous-même au bureau.
Le mémento vous est offert sous licence « Creative Commons CC BY-NC-SA 3.0 FR ». Vous êtes libre de partager (reproduire, distribuer et communiquer) cette œuvre. Ce n'est pas de la publicité. C'est un cadeau pour lequel je ne demande aucune contrepartie. Toutefois, si vous appréciez ce mémento et si vous l'utilisez/distribuez, ça nous fera plaisir de le savoir. Consultez les FAQ pour en savoir plus.
I-A. Patterns par ordre alphabétique▲
Voici tous les patterns de cet article, classés par ordre alphabétique :
I-B. Patterns par famille▲
I-C. Mises à jour▲
La première version de ce document a été écrite avec un seul pattern : le singleton. D'autres patterns (et les mémentos associés) seront ajoutés au fur et à mesure.
29 janvier 2014 : création du document (avec seulement le Singleton)
II. Design patterns▲
II-A. Singleton▲
II-A-1. Principe▲
Le singleton permet de s'assurer qu'il n'existe qu'une seule instance d'une classe dans un environnement et pour une durée d'exécution donnés.
Points clés :
- instance privée et statique ;
- constructeur privé ;
- méthode d'accès publique et statique.
public
class
DogService {
private
static
DogService instance;
private
DogService
(
) {
...
}
public
static
DogService getInstance
(
) {
if
(
instance ==
null
) {
instance =
new
DogService
(
);
}
return
instance;
}
public
void
truc
(
) {
...
}
...
}
DogService dogService =
DogService.getInstance
(
);
dogService.truc
(
);
II-A-2. Synchronisation▲
Dans un contexte multithread, l'utilisation du pattern Singleton nécessite des précautions pour limiter les problèmes d'accès concurrents. Il faut synchroniser les appels et les initialisations.
public
static
synchronized
DogService getInstance
(
) {
if
(
instance ==
null
) {
instance =
new
DogService
(
);
}
return
instance;
}
Malheureusement, on paie le coût de la synchronisation, réalisée grâce au mot-clé « synchronized », à chaque appel et non pas seulement au premier (i.e. initialisation).
Des variantes (plus ou moins efficaces) permettent d'assurer la synchronisation ; vous en retrouverez une sélection ci-dessous. Je vous recommande également/vivement de consulter l'article de Christophe Jollivet intitulé « Le Singleton en environnement Multithread » dont je me suis allègrement inspiré pour écrire cet article.
II-A-2-a. Double-checked locking▲
public
static
DogService getInstance
(
) {
if
(
instance ==
null
) {
synchronized
(
DogService.class
) {
if
(
instance ==
null
) {
instance =
new
DogService
(
);
}
}
}
return
instance;
}
La théorie semble parfaite et de nombreux sites Web recommandent cette solution. Le DCL n'apporte pourtant aucune garantie que cela fonctionnera. Ceci n'est pas inhérent à un bogue de la JVM mais au modèle de mémoire qui autorise l'écriture dans le désordre (« out-of-order writes »).
II-A-2-b. Mot-clé volatile▲
private
static
volatile
DogService instance;
Là encore, c'est une « fausse bonne idée ». Dans les anciennes JVM, ça n'offre pas de garantie. Cela fonctionne dans les nouvelles versions, mais provoque un flush complet du registre du processeur. Le gain de performance recherché en n'utilisant pas la synchronisation est alors nul.
II-A-2-c. Thread local▲
public
class
DogService {
private
static
final
ThreadLocal tl =
new
ThreadLocal
(
);
private
static
DogService instance;
private
DogService
(
) {
...
}
public
static
DogService getInstance
(
) {
if
(
tl.get
(
) ==
null
) {
synchronized
(
DogService.class
) {
if
(
instance ==
null
) {
instance =
new
DogService
(
);
}
tl.set
(
Boolean.TRUE);
}
}
return
instance;
}
}
Défaut : l'utilisation du thread local est un peu lente.
II-A-2-d. Initialisation statique▲
private
static
final
DogService instance =
new
DogService
(
);
L'initialisation est faite au lancement, même si le service n'est finalement jamais utilisé.
II-A-2-e. Inner class▲
public
class
DogService {
private
static
class
InstanceHolder {
public
static
final
DogService instance =
new
DogService
(
);
}
private
DogService
(
) {
...
}
public
static
DogService getInstance
(
) {
return
InstanceHolder.instance;
}
}
Le chargement des classes est « thread-safe » ; la classe encapsulée n'est initialisée que lors de l'appel de la méthode.
II-A-2-f. Enum▲
public
enum
DogService {
INSTANCE;
public
static
DogService getInstance
(
) {
return
INSTANCE;
}
}
final
DogService service =
DogService.getInstance
(
);
// ou comme un enum
final
DogService service =
DogService.INSTANCE;
L'emploi d'un enum permet de prendre en compte le cas de la sérialisation facilement et empêche complètement l'initialisation par réflexion.
II-A-3. JSR330▲
Des frameworks d'injection (CDI, Spring, Guice, etc.) savent initialiser une variable comme un singleton.
@Singleton
public
class
DogService {
...
}
public
class
UneClasse {
@Inject
private
DogService service;
...
}
...
Dans une application professionnelle, il est fort probable que vous utiliserez une bibliothèque comme Spring dont le Singleton est le « scope » par défaut. Avec ce type de framework, on n'a pas besoin (et on ne doit pas) programmer soi-même le Singleton.
II-A-4. Mémento▲
Téléchargez gratuitement le fichier « memento_singleton.pdf » (461 Ko) pour l'imprimer au bureau.
III. Tous les mémentos▲
IV. Conclusion▲
Et voilà... Revenez de temps en temps pour découvrir les nouveaux mémentos qui seront ajoutés.
Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : 9 commentaires
V. Remerciements▲
J'adresse de grands remerciements aux personnes qui ont contribué à l'écriture de cet article ainsi qu'aux mémentos associés, en particulier à Mickael BARON, Julien, Logan, Michel Dirix, Nicolas et Philippe DUVAL.
VI. Annexes▲
VI-A. Liens▲
Retrouvez quelques design pattern sur Developpez.com :
https://smeric.developpez.com/java/uml/
Article de Christophe Jollivet, intitulé « Le Singleton en environnement Multithread » :
https://christophej.developpez.com/tutoriel/java/singleton/multithread/
VI-B. Liens perso▲
VI-C. FAQ▲
VI-C-1. Comment imprimer les mémentos au bureau ?▲
Les mémentos doivent être imprimés sur du papier au format A4 avec une orientation paysage. Cela est déjà configuré dans les fichiers PDF, mais je vous conseille de vérifier que le pilote de votre imprimante le respecte.
La plupart des imprimantes vont essayer de mettre le document à l'échelle, car les fichiers PDF des mémentos sont conçus pour rogner les marges au maximum. Dans la fenêtre des options d'impression, il faudra donc désactiver la mise à l'échelle. En général, il suffit de cocher (ou de décocher selon que c'est une négation ou une option) la mise à l'échelle.
Il faudra aussi demander une impression recto verso sur bord court. Le réglage par défaut est généralement d'imprimer sur bord long, ce qui convient aux documents à orientation en portrait, mais pas aux mémentos, qui sont orientés en paysage.
VI-C-2. Comment plier les mémentos imprimés ?▲
Les mémentos sont constitués de trois volets qu'il va falloir plier. Il existe deux façons de plier un document constitué de trois volets : en zigzag ou en enroulé.
Pour les mémentos offerts sur cette page, il convient de faire un pliage enroulé (ou fermé). Une fois plié, le volet 3 se retrouve à l'intérieur.
Il y a une petite ligne en pointillé en bas du verso.
Il faut replier le premier volet du mémento sur cette ligne, ce qui créera le premier pli (entre les volets 1 et 2).
Si vous être droitier, je vous conseille de tenir le mémento à l'envers, de sorte que la petite ligne en pointillé soit en haut. Pour pourrez ainsi utiliser votre main droite pour replier le premier volet. Remettez ensuite le document à l'endroit pour faire le second pli.
Pour obtenir le second pli (entre les volets 2 et 3), il suffit de replier le morceau restant à l'intérieur en se servant du premier pli comme butée. Le second pli devrait alors se faire au niveau de la petite ligne en pointillé.
VI-C-3. Que permet la licence CC BY-NC-SA 3.0 FR ?▲
La licence Creative Commons vous demande de respecter trois points : attribution, pas d'utilisation commerciale et pas d'œuvre dérivée. Si vous souhaitez modifier ce mémento, par exemple pour l'utiliser dans une de vos plaquettes ou pour ajouter votre logo, il vous suffit de me contacter et j'aurai le plaisir de vous accompagner et de vous offrir (gratuitement) une version utilisable et plus pratique.
VI-C-4. Peut-on commander des mémentos déjà imprimés et pliés ?▲
Oui c'est possible. Notre objectif n'est pas de gagner de l'argent grâce aux mémentos. Nous les rédigeons, car notre passion est le développement et que nous souhaitons la partager et la rendre simple. Nous pouvons imprimer les mémentos sur du papier épais, les plier et vous les envoyer. Dans ce cas, nous vous demanderons juste une petite participation aux frais d'envoi.
VI-C-5. Peut-on redistribuer les mémentos ?▲
La réponse la plus simple serait de dire « oui ». Toutefois, au lieu de distribuer vous-même les mémentos, je vous invite à donner l'adresse de ce document. Les visiteurs pourront ainsi profiter des prochaines mises à jour.
VI-C-6. Comment peut-on vous soutenir ?▲
Le mieux est de parler de nous en donnant l'adresse de cette page à vos contacts. Nous avons également toujours besoin de sponsors qui nous permettraient, par exemple, de consacrer plus de temps à la création et à l'amélioration de contenus de qualité.
Nous avons également besoin de vos retours. Ils nous aident à améliorer nos publications. Nous sommes preneurs des critiques positives et négatives, des remarques et des bonnes idées.