89 votes

Y a-t-il des alternatives viables au modèle Singleton de GOF?

Avouons-le. Le modèle Singleton est un sujet hautement controversé avec des hordes de programmeurs des deux côtés de la clôture. Il y a ceux qui pensent que le Singleton n'est rien de plus qu'une variable globale glorifiée, et d'autres qui jurent par le modèle et l'utilisent sans cesse. Je ne veux pas que la controversé du Singleton soit au cœur de ma question, cependant. Chacun peut se livrer à une bataille et voir qui gagne pour tout ce que je sais. Ce que j'essaie de dire, c'est que je ne crois pas qu'il y ait une seule réponse correcte et je n'essaie pas intentionnellement de provoquer des querelles partisanes. Je suis simplement intéressé par les alternatives au singleton lorsque je pose la question :

Y a-t-il des alternatives spécifiques au modèle Singleton du GOF ?

Par exemple, de nombreuses fois où j'ai utilisé le modèle Singleton dans le passé, je suis simplement intéressé à préserver l'état/les valeurs d'une ou plusieurs variables. Cependant, l'état/les valeurs des variables peuvent être conservés entre chaque instantation de la classe en utilisant des variables statiques au lieu d'utiliser le modèle Singleton.

Quelles autres idées avez-vous ?

ÉDIT : Je ne veux vraiment pas que cela devienne un autre poste sur "comment utiliser correctement le singleton." Encore une fois, je cherche des moyens de l'éviter. Pour le fun, ok ? Je suppose que je pose une question purement académique à voix haute de bande-annonce de film, "Dans un univers parallèle où il n'y a pas de singleton, que pourrions-nous faire ?"

93voto

Rasmus Faber Points 24195

Pour comprendre la bonne manière de contourner les Singletons, vous devez comprendre ce qui ne va pas avec les Singletons (et l'état global en général) :

Les Singletons masquent les dépendances.

Pourquoi est-ce important ?

Parce que si vous cachez les dépendances, vous avez tendance à perdre la trace du degré de couplage.

Vous pourriez argumenter que

void purchaseLaptop(String numeroCarteCredit, int prix){
  CreditCardProcessor.getInstance().debit(numeroCarteCredit, montant);
  Cart.getInstance().addLaptop();
}

est plus simple que

void purchaseLaptop(CreditCardProcessor processeurCarteCredit, Panier panier, 
                    String numeroCarteCredit, int prix){
  processeurCarteCredit.debit(numeroCarteCredit, montant);
  panier.addLaptop();
}

mais au moins le deuxième API indique clairement qui sont les collaborateurs de la méthode.

Ainsi, la solution pour contourner les Singletons n'est pas d'utiliser des variables statiques ou des localisateurs de services, mais de transformer les classes Singleton en instances, qui sont instanciées dans le contexte où elles ont du sens et injectées dans les composants et méthodes qui en ont besoin. Vous pouvez utiliser un framework IoC pour gérer cela, ou le faire manuellement, mais l'important est de vous débarrasser de votre état global et de rendre les dépendances et les collaborations explicites.

74voto

Jacek Szymański Points 1862

Alex Miller dans "Patterns I Hate" cite ce qui suit :

"Quand un singleton semble être la réponse, je trouve qu'il est souvent plus sage de :

  1. Créer une interface et une implémentation par défaut de votre singleton
  2. Construire une seule instance de votre implémentation par défaut au "sommet" de votre système. Cela peut être dans une config Spring, ou dans du code, ou défini de différentes manières selon votre système.
  3. Passer la seule instance à chaque composant qui en a besoin (injection de dépendance)

14voto

seuvitor Points 199

La meilleure solution que j'ai trouvée est d'utiliser le modèle de conception d'usine pour construire des instances de vos classes. En utilisant ce modèle, vous pouvez assurer qu'il n'y a qu'une seule instance d'une classe partagée entre les objets qui l'utilisent.

Je pensais que cela serait compliqué à gérer, mais après avoir lu cet article de blog "Où sont passés tous les singletons ?", cela semble si naturel. Et, en bonus, cela aide beaucoup à isoler vos tests unitaires.

En résumé, que devez-vous faire ? Chaque fois qu'un objet dépend d'un autre, il recevra une instance de celui-ci uniquement via son constructeur (pas de nouveau mot-clé dans votre classe).

class NeedyClass {

    private ExSingletonClass exSingleton;

    public NeedyClass(ExSingletonClass exSingleton){
        this.exSingleton = exSingleton;
    }

    // Ici se trouve du code qui utilise l'objet exSingleton
}

Et ensuite, l'usine.

class FactoryOfNeedy {

    private ExSingletonClass exSingleton;

    public FactoryOfNeedy() {
        this.exSingleton = new ExSingletonClass();
    }

    public NeedyClass buildNeedy() {
        return new NeedyClass(this.exSingleton);
    }
}

Comme vous n'instancierez votre usine qu'une seule fois, il n'y aura qu'une seule instanciation d'exSingleton. Chaque fois que vous appelez buildNeedy, la nouvelle instance de NeedyClass sera associée à exSingleton.

J'espère que cela vous sera utile. Veuillez signaler toute erreur.

8voto

Kai Points 219

Spring ou tout autre conteneur IoC fait raisonnablement bien ce travail. Puisque les classes sont créées et gérées en dehors de l'application elle-même, le conteneur peut rendre des classes simples singletons et les injecter là où c'est nécessaire.

8voto

Thomas Owens Points 45042

Vous ne devriez pas vous efforcer d'éviter tout motif. L'utilisation d'un motif est soit une décision de conception, soit un ajustement naturel (il se met simplement en place). Lorsque vous concevez un système, vous avez le choix d'utiliser un motif ou de ne pas l'utiliser. Cependant, vous ne devriez pas vous efforcer d'éviter quoi que ce soit qui est ultimement un choix de conception.

Je n'évite pas le Pattern Singleton. Soit il est approprié et je l'utilise, soit il n'est pas approprié et je ne l'utilise pas. Je crois que c'est aussi simple que ça.

L'adéquation (ou le manque d'adéquation) du Singleton dépend de la situation. C'est une décision de conception qui doit être prise et les conséquences de cette décision doivent être comprises (et documentées).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X