Les « patrons de con­cep­tion », également appelés design patterns en anglais, aident les dé­ve­lop­peurs dans la pro­gram­ma­tion orientée objet avec des patrons éprouvés pour résoudre les tâches de pro­gram­ma­tion. Une fois qu’un modèle approprié a été trouvé parmi les quelques soixante-dix patrons de con­cep­tion, il est adapté à chaque cas in­di­vi­duel. Toutefois, l’approche générale du patron reste la même. Le patron de con­cep­tion Singleton est très puissant, mais il est considéré comme une relique de la pro­gram­ma­tion orientée objet. Vous ap­pren­drez dans notre guide ce qu’il peut néanmoins faire, où et comment l’utiliser.

Qu’est-ce que le singleton pattern ?

Le singleton pattern ap­par­tient à la catégorie des patrons de création. Son but est d’éviter qu’une classe ne crée plus d’un objet. Pour ce faire, on crée l’objet souhaité dans une classe propre, puis on le récupère sous forme d’instance statique. Le singleton est l’un des patrons les plus simples, mais les plus puissants dans le dé­ve­lop­pe­ment de logiciels.

Citation

Le « Gang of Four » (GfO), une équipe de pro­gram­meurs des États-Unis, à propos du singleton pattern : « S’assurer qu’une classe ne dispose que d’une unique instance, et fournir un point d’accès global à celle-ci. »]

Quelles sont les pro­prié­tés du singleton pattern ?

Une fois que l’instance d’une classe a été créée à l’aide du patron de con­cep­tion Singleton, il garantit qu’elle ne reste réel­le­ment qu’avec cette seule instance. Le singleton rend cette classe glo­ba­le­ment ac­ces­sible dans le logiciel. Il existe dif­fé­rentes méthodes pour cela dans les langages de pro­gram­ma­tion. Pour s’assurer qu’il reste avec une seule instance unique, il faut empêcher les uti­li­sa­teurs de créer de nouvelles instances. Pour ce faire, le cons­truc­teur doit déclarer le patron comme « privé ». De cette façon, seul le code du Singleton peut ins­tan­cier le Singleton lui-même. Cela garantit qu’un seul et même objet peut atteindre l’uti­li­sa­teur. Si cette instance existe déjà, aucune nouvelle n’est créée. Voici un exemple de singleton possible :

public class Singleton {
	private static Singleton instance; // protégé contre l’accès externe et statique
	private Singleton() {} // constructeur privé avec protection d’accès externe
	public static Singleton getInstance() { // méthode publique, appel par code
		if (instance == nul) { // seulement si aucune instance n’existe, en créer une nouvelle
			instance = new Singleton();
		}
		return instance;
	}
}

Singleton pattern : re­pré­sen­ta­tion UML

En langage de mo­dé­li­sa­tion unifié, en bref UML (Unified Modeling Language), le singleton complet est constitué d’un seul objet, car il n’y a qu’une seule instance d’une classe à créer.

Il n’est pas possible de changer quoi que ce soit de l’extérieur dans le singleton créé. C’est exac­te­ment le but de l’uti­li­sa­tion du singleton Pattern.

Avantages et in­con­vé­nients du patron de con­cep­tion singleton

Coup d’œil sur les avantages

Un singleton peut être écrit ra­pi­de­ment et fa­ci­le­ment car il n’est pas peuplé d’in­nom­brables variables (globales). Il englobe sa création et peut donc également exercer un contrôle précis sur le moment et la manière dont on y accède. Un singleton pattern existant peut être dérivé en utilisant des sous-classes pour remplir de nouvelles fonc­tion­na­li­tés. L’uti­li­sa­tion qui en est faite est décidée de manière dynamique. Enfin, un singleton est créé exac­te­ment au moment où il est né­ces­saire, cette fonction est appelée Lazy Loading. Le processus d’ins­tan­cia­tion d’un singleton avant qu’il ne soit né­ces­saire s’appelle Eager Loading.

Coup d’œil sur les in­con­vé­nients

L’uti­li­sa­tion effrénée du singleton conduit dans les faits à un état similaire à la pro­gram­ma­tion pro­cé­du­rale (c’est-à-dire non orientée objet) et peut conduire à un code source dé­fec­tueux. La dis­po­ni­bi­lité globale de patrons de con­cep­tion singleton présente des dangers lorsque des données sensibles sont traitées avec eux. Si des mo­di­fi­ca­tions sont apportées au singleton, il n’est pas possible de retracer les parties du programme qui sont affectées. Cela rend la main­te­nance des logiciels plus difficile car les dys­fonc­tion­ne­ments ne peuvent être repérés qu’avec dif­fi­culté. La dis­po­ni­bi­lité globale rend également difficile la sup­pres­sion du singleton, puisque les com­po­sants d’un logiciel peuvent toujours s’y référer. Dans les ap­pli­ca­tions com­por­tant de nombreux uti­li­sa­teurs (ap­pli­ca­tions multi-uti­li­sa­teurs), un seul singleton peut réduire les per­for­mances, car il re­pré­sente un goulot d’étran­gle­ment pour les données.

Le patron de con­cep­tion singleton dans « la vraie vie »

Le singleton est gé­né­ra­le­ment utilisé lorsque des tâches ré­cur­rentes doivent être ef­fec­tuées dans le cadre d’une routine de programme. Il s’agit notamment des données à écrire dans un fichier, par exemple pour des fichiers logs ou des travaux d’im­pres­sion qui doivent être écrits de manière répétée dans une seule mémoire tampon d’im­pri­mante. Comme les pilotes et les mé­ca­nismes de cache ont toujours les mêmes processus, le singleton pattern est souvent utilisé là aussi.

Comme il est très difficile de tester le singleton pattern, nous il­lus­trons ici son fonc­tion­ne­ment en prenant l’exemple du bureau d’une petite en­tre­prise dans laquelle plusieurs employés utilisent une seule im­pri­mante. Un exemple proche de la pratique est présenté dans la série de tutoriels de design pattern réalisé par Daniel H. Jacobsen. C’est sur cette base que le patron de con­cep­tion Singleton suivant a été conçu :

Lorsqu’un uti­li­sa­teur envoie une demande à l’im­pri­mante, le singleton pose la « question » suivante : « Un objet Im­pri­mante existe-t-il déjà ? Sinon, créez-en un. » Ce problème est résolu par une dé­cla­ra­tion avec la condition if/then (return im­pri­mante == null ?). Pour empêcher l’accès et donc les mo­di­fi­ca­tions, les variables in­di­vi­duelles et l’im­pri­mante sont réglées sur « privé » et non « public ».

Public class Imprimante {
	private static Imprimante imprimante;
	private int nombre de pages;
	private imprimante() {
	}
	public static imprimante getInstance() {
		return imprimante== null ? 
				imprimante = nouvelle imprimante() : 
				imprimante ;
	}
	public void print(String text){
		System.out.println(text +
			"\n" + "nombre de pages imprimées aujourd’hui" + ++ nombrepages+
				"\n" + "---------") ;
	}
}

Ensuite, les employés de la branche sont « en­cap­su­lés ». Les chaînes de ca­rac­tères des noms, de la position et de l’activité dans l’en­tre­prise sont également réglées sur « privé ».

public class Employee {
	private final String nom;
	private final String position; 
	private final String activite;
	public Employe(String name, String position, String activite) {
		this.nom = nom;
		this.position = position;
		this.activite= activite;
	}
	public void printCurrent activite (){
		Imprimante imprimante = imprimante getInstance();
		imprimante.print("Employe: " + name+ "\n" +
			"Position: " + position + "\n" +.
			"Activite: " + activite + "\n");
	}
}

Enfin, les deux sin­gle­tons sont inclus dans une routine de sortie.

Public class Main {
	public static void main(String[] args) {
		Employe andre = nouvel employe ("André",
				"patron",
				"Gère la branche") ;
		employee julie = new employee ("Julie",
				"conseillère" ,
				"conseille les clients en cas de réclamation");
		employe tom = nouvel employe ("Tom",
				"vendeur",
				" vend les produits");
		employee stephanie = new employee ("Stéphanie",
				"développeuse",
				"maintient l’informatique dans la succursale");
		employe matthieu = new employe ("Matthieu",
				"comptable",
				"Comptabilité financière de la succursale");
		andre.printCurrentactivite();
		julie.printCurrentactivite();
		tom.printCurrentactivite();
		stephanie.printCurrentactivite();
		matthieu.printCurrentactivite();
	}
}
Aller au menu principal