Possibilité d'utiliser un singleton avec un constructeur non défini par défaut dans C #?
-
23-08-2019 - |
Question
Je suis en œuvre un cadre de notification pour un de mes projets. Comme je veux que ce soit très générique, l'utilisateur peut utiliser plusieurs couches de transport, de sorte qu'il n'a pas vraiment besoin de se soucier de l'utilisation d'une méthode de livraison (permet de dire WCF) ou d'une autre (par exemple ActiveMQ). L'interface utilisateur a accès est évidemment indépendante de la méthode de délivrance (WCF ou ActiveMQ). Pourtant, les deux classes (consommateurs et producteurs) met en œuvre des singletons, de sorte qu'ils utilisent effectivement des constructeurs par défaut (signification, aucun paramètre). Mon problème est que je voudrais avoir un paramètre, la méthode de livraison que l'utilisateur veut utiliser. Mais pour autant que je sache, singleton utiliser uniquement des constructeurs par défaut? ce qui est normal, comme il devrait y avoir aucun point d'utiliser singletons avec des paramètres. Alors, quelles sont mes options ici? ne pas créer un singleton? créer une méthode pour définir la méthode de livraison?
Merci beaucoup pour votre aide,
Sebastian
La solution
Vous pouvez certainement avoir des paramètres avec singletons, sauf au lieu de passer le paramètre dans un constructeur, vous passez dans la méthode getInstance (). Votre constructeur doit être substituée privée bien sûr pour une véritable mise en œuvre singleton. Mon exemple est écrit en Java, mais applique pour C # ainsi.
Exemple:
Singleton s = Singleton.getInstance(42);
Dans le code Singleton:
private Singleton() {
}
private Singleton(int num) {
//set num
}
public getInstance(int num) {
//singleton code (calls the private non-default constructor if an object
//does not already exist)
}
Autres conseils
Il y a des cadres d'injection de dépendance comme Spring.Net qui pourrait vous aider. Vous pouvez passer efficacement un paramètre dans un fichier de configuration pour votre constructeur de singletons.
Lien vers un exemple Spring Framework
Puis-je suggérer que si vous avez deux comportements différents nécessaires de votre singleton que vous voudrez peut-être sous-classe. De cette façon, vous obtenez le comportement que vous voulez en appelant le singleton du comportement de la classe que vous voulez.
Vous pouvez le faire facilement avec un cadre d'injection de dépendance. J'ai une construction similaire dans mon projet actuel en utilisant MEF. Tout ce qui est nécessaire est d'utiliser les options d'injection de constructeur, et d'ajouter que l'assemblage et le montage de dépendance demandé au catalogue, et il les fils correctement.
Une autre option est d'avoir une certaine forme de fonction d'initialisation qui prend votre option, et construit l'instance singleton. Au lieu de construire sur un premier accès, vous pouvez construire pendant l'appel d'initialisation. L'inconvénient est que vous devez vous assurer d'initialiser votre singleton avant de l'utiliser (généralement au démarrage du programme, en utilisant un fichier de configuration).
Une option similaire, mais moins sujette aux erreurs, est d'avoir juste le singleton initialize paresseux, et lui donner une option « par défaut ». Permettre à l'appelant de définir une propriété statique pour modifier l'option est construite, donc si elle est définie avant la construction du singleton, vous aurez un défaut différent. Cela peut être source de confusion, cependant, car encore une fois, vous devez vous assurer que vous définissez la propriété avant d'accéder au singleton, ou vous aurez un comportement inattendu.
Je sais qu'il est tard pour répondre à la question initiale, mais je viens d'avoir ce problème et voici comment je l'ai résolu. Peut-être pas idéal, mais il semble fonctionner. J'ai créé une méthode Init qui doit être appelé avant d'essayer d'utiliser l'instance singleton.
public void Init(/*parameters*/)
{
if (_isInitialized)
{
throw new InvalidOperationException("Component is already initialized!");
}
//do your work here
}
Tout autre accès à l'instance singleton (propriétés get, set, appels de méthode) va lancer une exception opération non valide indiquant que l'objet n'a pas été initialisé.
Je pense que cela fait ce que je dois, est moins déroutant que GetInstance (params) parce qu'il n'y a pas de risque de malentendu ce que fait la méthode. L'inconvénient est qu'il ne sera pas jeter des erreurs de temps de compilation, mais la première course sans l'initialisation fait va lancer une exception, il devrait être assez bon.