Les normes de conception (Design Pattern) concrétisent des abstractions efficaces pour des développements courants.
Une classe Singleton fournit une instance unique d'un objet d'usage général, comme une connexion, avec une méthode getInstance() qui peut porter un nom spécifique.
Les approches statique et singleton ne doivent pas être mélangées. Dans une approche singleton, la plupart des méthodes doivent être liées à l'instance créée. Ceci peut par exemple permettre à la classe de fournir un pool d'objets au lieu d'un objet unique sans changement de code pour les objets utilisateurs.
System
propose un ensemble de méthodes statiques
Runtime
est une classe singleton qui propose une méthode
getRuntime()
pour obtenir un objet runtime
doté de nombreuses propriétés et méthodes.
L'initialisation d'une classe singleton peut être longue et est souvent gérée dans un Thread séparé. Elle ne bloque alors pas la suite de l'application. L'obtention d'une instance doit en revanche attendre qu'un objet pleinement fonctionnel soit disponible.
Une utilisation classique est la fourniture d'une connexion à une base de données.
Connection
par
la méthode MaConnexion.getInstance().
Si la connexion a eu le temps de s'établir, l'obtention est immédiate,
sinon il faut attendre un peu
%class%
par le nom de la classe à créer.
Pour installer ce snippet dans JBuilder
snippets
Fichier | Nouveau...
)
ajouter un snippet
(clic droit)
"Singleton"
), le source ("Singleton.snippet"
) et une icône
//<Exclude> //<Target text="Nom de classe" pattern=%class% default=Singleton1> //<Package> //</Exclude> /** * Implémentation générique de la norme de conception (design pattern) Singleton.<br> * Il importe de ne pas rendre statiques les données qui dépendent de l'instance.<p> * La méthode statique <a href="#getInstance()">getInstance()</a> * renvoie une instance unique et prête à fonctionner pour l'objet. * P. Larreya, Janvier 2001 */ public class %class% implements Runnable { static private %class% instance; private Thread thread; private Object data; // donnée fournie à titre d'exemple /** * Lee constructeur d'un singleton ne doit pas être appelé directement. * Initialiser et passer par <a href="#getInstance()">getInstance()</a> * pour obtenir un objet. */ private %class%(Object data) { this.data = data; } /** * Initialisation à appeler avant tout <code>getInstance()</code> * <ul> * <li><code>synchonized</code> bloque <code>getInstance()</code> * <li>création et lancement d'un thread d'initialisation * <li>sortie de la méthode. <code>getInstance()</code> peut être appelée * <li>lors de l'appel, <code>getInstance()</code> attend la fin du * thread d'initialisation. *</ul> */ public static synchronized void init(Object data) { if (instance != null) { // ou initialiser au premier appel throw new RuntimeException("%class%.init() : déjà initialisé."); } instance = new %class%(data); instance.initInstance(); } private void initInstance() { thread = new Thread(this); thread.start(); } /** * Renvoie l'instance unique et prête à fonctionner */ public static synchronized %class% getInstance() { if (instance == null) { throw new RuntimeException("%class%: pas initialisé."); } try { instance.thread.join(); // initialisation terminée. } catch (InterruptedException ex) { System.out.println("Interruption pendant l'obtention d'un %class%"); ex.printStackTrace(); } return instance; } /** * Taches d'initialisation d'une instance, réalisée dans un thread séparé. */ public void run() { // coder ici l'initialisation d'une instance singleton } /** * Texte affichable */ public String toString() { return this.getClass().getName()+": "+data.toString(); } }
Le mécanisme d'initialisation avec un découpage en init()
et
initInstance()
n'est pas directement lié à la notion de singleton
mais s'inspire d'une approche utilisée par les initialisations CORBA.
Patrick Larreya, Janvier 2001, Février 2006.