L'Alternative à Singleton

nous avons une classe qui contient des informations de configuration pour l'application. Il sert à être un singleton. Après une révision architecturale, on nous a dit d'enlever le singleton. Nous avons constaté certains avantages de ne pas utiliser singleton dans les essais unitaires, car nous pouvons tester différentes configurations en même temps.

sans singleton, nous devons passer l'instance partout dans notre code. C'est si bordélique qu'on a écrit un emballage de singleton. Maintenant nous portons le même code pour PHP et .NET, je me demande s'il y a un meilleur motif que nous pouvons utiliser pour l'objet de configuration.

110
demandé sur John Mill 2009-08-19 19:21:34

13 réponses

Le Google blog Test a une série d'entrées d'éviter de Singleton (afin de créer de code de tests). Cela peut peut-être vous aider:

le dernier article explique en détail comment déplacer la création de nouveaux objets dans une usine, de sorte que vous pouvez éviter d'utiliser des singletons. La peine de lire pour vous.

bref, nous déplaçons tous les nouveaux opérateurs dans une usine. Nous regroupons tous les objets de semblable à vie dans une seule usine.

126
répondu FrankS 2012-01-18 21:18:20

la meilleure façon est d'utiliser un modèle D'usine à la place. Lorsque vous construisez une nouvelle instance de votre classe (dans l'usine), vous pouvez insérer les données 'globales' dans l'objet nouvellement construit, soit comme référence à une seule instance (que vous stockez dans la classe usine), soit en copiant les données pertinentes dans le nouvel objet.

tous vos objets contiennent alors les données qui habitaient dans le singleton. Je ne pense pas qu'Il ya beaucoup de différence dans l'ensemble, mais il peut rendre votre code plus facile à lire.

15
répondu gbjbaanb 2009-08-19 15:27:36

je pourrais dire l'évidence ici, mais y a-t-il une raison pour laquelle vous ne pouvez pas utiliser un cadre d'injection de dépendances tel que Spring ou Guice ? (Je crois que le printemps est aussi disponible pour .NET).

de cette façon, le framework peut contenir une seule copie des objets de configuration, et vos beans (services, DAOs, n'importe quoi) n'ont pas à s'inquiéter de le chercher.

C'est l'approche que j'ai d'habitude, prends!

5
répondu 2009-08-19 15:28:56

Si vous utilisez Spring , vous pouvez simplement créer une fève. Par défaut (ou si vous définissez explicitement scope="singleton" ) une seule instance de la fève est créée et cette instance est retournée chaque fois que la fève est utilisée dans une dépendance ou récupérée via getBean() .

vous obtenez l'avantage de l'instance simple, sans le couplage du modèle Singleton.

4
répondu CoverosGene 2009-08-19 15:30:04

l'alternative est de passer dans ce dont vous avez besoin au lieu de demander un objet pour des choses.

4
répondu koen 2009-08-19 15:30:26

n'accumule pas de responsabilités à un seul objet de configuration car il se termine par un très grand objet à la fois difficile à comprendre et fragile.

par exemple, si vous avez besoin d'un autre paramètre pour une classe particulière, vous changez l'objet Configuration , puis vous recompilez toutes les classes qui l'utilisent. C'est quelque peu problématique.

essayez de refactoriser votre code pour éviter un commun, global et grand Configuration objet. Transmettre uniquement les paramètres requis aux classes de clients:

class Server {

    int port;

    Server(Configuration config) {
        this.port = config.getServerPort();
    } 

}

doit être remanié pour:

 class Server {

    public Server(int port) {
       this.port = port;
    }
 }

un l'injection de dépendance cadre aidera beaucoup ici, mais il n'est pas strictement nécessaire.

4
répondu dfa 2009-08-19 15:33:17

Vous pouvez accomplir le même comportement de singleton en utilisant des méthodes statiques. Steve yegge l'explique très bien dans ce post.

1
répondu Youssef 2009-08-19 15:35:38

est-ce qu'une classe qui ne contient que des méthodes et des champs statiques est possible? Je ne suis pas sûr de savoir exactement quelle est votre situation, mais ça pourrait valoir le coup d'examiner.

0
répondu Thomas Owens 2009-08-19 15:24:05

dépend de ce que l'outillage/les cadres etc.. sont utilisés. Avec les outils d'injection de dépendances / ioc, on peut souvent obtenir des performances/optimisations singleton en demandant au conteneur di/ioc d'utiliser un comportement singleton pour la classe requise - (comme une interface IConfigSettings) en ne créant qu'une seule instance de la classe. Cela pourrait encore être substitué à l'essai

alternativement on pourrait utiliser une usine pour créer la classe et retourner la même instance chaque fois que vous le demandez - mais pour les tests il pourrait retourner une version stubbed / mocked

0
répondu saret 2009-08-19 15:30:17

examiner la possibilité de faire la configuration comme interface de rappel. Ainsi, votre code sensible à la configuration ressemblera à:

MyReuseCode.Configure(IConfiguration)

Système-code d'initialisation regardez:

Library.init(MyIConfigurationImpl)
0
répondu Dewfy 2009-08-19 15:31:09

vous pouvez utiliser un framework d'injection de dépendances pour soulager la douleur de passer dans l'objet de configuration. Un décent est ninject qui a l'avantage d'utiliser le code plutôt que xml.

0
répondu Colin Gravill 2009-08-19 15:34:11

peut-être pas très propre non plus, mais vous pourriez peut-être passer les bits d'information que vous voulez avoir changé à la méthode qui crée le singleton -- au lieu d'utiliser

public static Singleton getInstance() {
    if(singleton != null)
        createSingleton();
        return singleton;
    }
}

vous pouvez appeler createSingleton(Information info) directement au démarrage de l'application (et dans les méthodes d'installation des tests unitaires).

0
répondu Roland Ewald 2013-01-03 08:47:44

les Singleton ne sont pas mauvais mais le dessin est défectueux. J'ai une classe que je ne veux créer qu'une seule instance pendant l'exécution mais que je veux créer plusieurs instances isolées pendant les tests unitaires pour assurer des résultats déterministes.

DI en utilisant le ressort, etc, est une très bonne option, mais pas la seule.

-1
répondu codematrix 2012-10-10 19:56:13