Le modèle pour créer des singletons semble être quelque chose comme: Cependant, mon problème est comment accompagnez-vous une classe comme celle-ci si le constructeur Singleton fait quelque chose qui n'est pas un seul test par exemple appelle le service externe, la recherche JNDI, etc. p> Je penserais que je pourrais le refroidir comme: p> public class Singleton {
private static Singleton instance;
private Singleton(){
}
public synchronized static Singleton getInstance()
{
if(instance == null)
instance = new Singleton();
return instance;
}
//for the unit tests
public static void setInstance(Singleton s)
{
instancce = s;
}
}
5 Réponses :
Vous pouvez utiliser le Modèle d'usine pour créer le singleton et changer les implémentations en fonction de l'everironment. p>
ou, évitez d'utiliser le motif singleton et utilisez Injection de dépendance à la place. P>
Vous pouvez utiliser un énumé comme un singleton dire que votre singleton fait quelque chose d'indésirable dans des tests unitaires, vous pouvez; p> Printing a class reference
clazz = class ClassInitMain$Singleton
Using an enum value
class ClassInitMain$Singleton initialised
L'instance sera chargée même via une référence à .class code>, mais non initialisé.
@Lewbloch Il pourrait y avoir JVMS où cela se produit, mais l'option Oracle JVM 8, 112 ne le fait pas.
Pas correcte. Le JLS explique. Le type se charge sur la référence au .class code> littéral, évidemment, sinon le littéral ne serait pas en mémoire de référencer en premier lieu. Cela chargera le type, mais ne l'initialise pas. Vous avez probablement confondu le chargement et l'initialisation.
Référence au .class code> en soi était toujours suffisante pour charger un type, mais selon les JLS revenant au moins Java 1.4, n'a jamais été censé déclencher une initialisation de type. Avant Java 1.5, Sun JVMS avait un bug dans lequel de telles références ont en fait déclencher une initialisation de type. Ils ont corrigé ce bogue dans Java 5, et comme cette fonctionnalité a fonctionné selon les spécifications.
@Lewbloch hmmm. Je l'ai reformulé car il était confus que j'avoue.
Vous pouvez injecter la dépendance à l'instance singleton, remplacer le getInstance () à partir du code de test de l'unité, utilisez la programmation orientée de l'aspect pour intercepter l'appel de la méthode et renvoyer un objet différent, ou utilisez un outil comme jmockit qui vous permet de vous moquer à peu près tout, y compris la statique, les classes finales, les constructeurs et toutes les choses que les gens disent normalement sont" plus abandonnés. " p>
Une approche que j'ai prise dans des systèmes hérités (où je voulais faire quelque chose de tester avec un impact minimal sur l'architecture du système) consistait à modifier les méthodes d'usine (GetInstance) pour vérifier une propriété système pour une autre implémentation que je voudrais instancier à la place. Ceci a été réglé sur un objet alternatif et faux dans la suite de tests d'unité. P>
comme pour le "verrouillage double vérifié est cassé", ce n'est plus vraiment vrai, si vous utilisez le mot clé volatile, et Java> = 1.5. Il a été cassé (même avec volatile) avec 1,4 et plus tôt, mais si vous savez que votre code ne sera exécuté que des JVM récentes, je ne m'inquiéterais pas. Mais je n'utiliserais pas non plus un singleton de toute façon: avoir un conteneur DI / COO gérer le cycle de vie de l'objet résoudrait à la fois vos problèmes (test de test de testeur et d'un goulot d'étranglement synchronisé) beaucoup plus élégamment. P>
Hmm J'aime l'idée d'une propriété système qui pourrait signaler pour tester un appareil. Idéalement, il serait agréable de changer pour ne pas utiliser le singleton, mais que c'est un peu au-dessus de moi, une grande base de code ancienne et un pas de temps pour re-factor :(.
Que diriez-vous de vous initialiser paresseux dans la phase de construction où vous exécutez les tests d'unité. Ensuite, vous modifiez le code à l'initialisation en ligne avant qu'il ne soit compilé pour la distribution. P>
Votre code de production est initialisé en ligne, sauf lors de vos tests. Peut-être que cette divergence BTW Code de production et de test pourrait introduire des bogues, mais qui? P>
(Bien sûr, si c'est une solution, nous laissons une phase de construction + outil faire le travail. Je vois cela facilités avec Maven et DP4J ). P>
Le verrouillage à double coché est cassé dans chaque langue, pas seulement Java.
J'ai tendance à éviter les singletons, mais vous pouvez utiliser le modèle de titulaire juste bien si vous en avez besoin, comme recommandé dans Josh Bloch's Efficace Java EM>: P> public class Foo
{
static class Holder
{
static final Foo instance = new Foo();
}
public static Foo getInstance()
{
return Holder.instance;
}
private Foo()
{
}
// ...
}
Bien que j'ai mentionné la solution de classe de titulaire à la mise en œuvre de singletons, c'est presque toujours survenue. L'approche la plus simple, la plus fiable et presque toujours correcte consiste à définir une énumération avec une seule constante, car @Peter Lawrey a souligné.
Vous avez identifié un inconvénient du motif singleton: il vous enferme dans une implémentation spécifique de l'interface Singleton. Oui, vous pouvez vous contourner de différentes manières, très terriblement laid. Demandez-vous plutôt si vous avez vraiment besoin d'un singleton du tout.
Pourquoi auriez-vous déjà besoin d'initialisation paresseuse dans ce que Java fournit déjà automatiquement à chaque type?