Les singletons immuables / apatrides sont-ils mauvais?

12

Dernièrement, il y a eu une sorte de révolution contre les singletons, mais y a-t-il quelque chose qui ne va pas s'ils sont apatrides?

Je connais le discours sur la surutilisation et tout ... cela s'applique à tout, pas seulement aux singletons.

m3th0dman
la source
1
Non. Les singletons ne sont en principe pas mauvais, ils sont juste massivement surutilisés.
Bart van Ingen Schenau
3
qu'entendez-vous par dernièrement?
Manoj R
5
@Joachim Sauer: Pourquoi auriez-vous besoin de remplacer; s'il est sans état, vous pouvez le tester correctement.
m3th0dman
1
Si vous avez un singleton sans état, vous avez essentiellement une classe d'utilité statique, qui a tendance à devenir l'anti-modèle God Class. Vous pouvez généralement utiliser des méthodes statiques à la place dans le contexte dans lequel elles sont utilisées (ou mieux encore: utiliser des méthodes d'extension en C #).
Spoike
1
Copie

Réponses:

12
  > Are immutable/stateless singletons bad?
  • Non s'ils ne dépendent pas d'autres systèmes externes.
    • Exemple: une Stringutility qui échappe au HTML dans une chaîne.
    • Raison: Dans les tests, il n'est pas nécessaire de le remplacer par un simulateur / simulateur.
  • Oui si votre singleton immuable / sans état dépend d'autres systèmes / services externes et si vous souhaitez effectuer des tests non testés (test dans l'isolement)
    • Exemple: un service qui dépend d'un Web-Calculateur de Taxe Externe.
    • Raison: Pour effectuer des tests avec ce service (isolément), vous devez simuler / simuler les systèmes / services externes.

Pour plus de détails, voir l'architecture-oignon


  • Les singleton-s peuvent rendre les tests unitaires (isolés) plus difficiles / impossibles et
  • les dépendances / couplages cachés peuvent être considérés comme un problème, comme expliqué par @yBee

Je ne vois pas d'autres raisons pour lesquelles je n'utilise pas de singletons.

k3b
la source
Vous devrez toujours vous moquer de ce service Web externe si vous voulez tester votre classe, même s'il ne s'agit pas d'un singleton (sans état).
m3th0dman
@ m3th0dman je suis d'accord
k3b
10

Cela dépend toujours de l'utilisation. Je pense que la révolution vient du fait que chaque programmeur apprend ce modèle comme le modèle orienté objet. La plupart oublient de penser où cela a du sens et où ce n'est pas le cas.
Ceci, bien sûr, est vrai pour chaque modèle. En utilisant simplement des modèles, vous ne créez pas un bon code ou un bon logiciel.

Si vous avez un singleton sans état, pourquoi ne pas utiliser une classe proposant uniquement des méthodes statiques (ou utiliser une classe statique)?

Voici quelques articles concernant les variables globales et les singletons en général.

Je ne serais pas aussi strict que l'auteur, mais il montre que pour la plupart des cas où vous pensez avoir besoin d'un singleton, vous n'en avez pas vraiment besoin.

StampedeXV
la source
1
Pourquoi ne pas utiliser une classe avec des méthodes statiques? L'héritage par exemple ...
m3th0dman
3
@ m3th0dman: Cela ne semble pas être un bon endroit pour l'héritage.
Billy ONeal
@BillyONeal Vous pouvez dire que quelque chose est bon ou mauvais pour l'héritage si vous connaissez le modèle de domaine, ce qui doit être modélisé de cette façon ...
m3th0dman
2
@ m3th0dman: Euh, non. Je peux être assez positif sans rien savoir du modèle de domaine. L'hérédité concerne le comportement polymorphe. Mais en tant que singleton, vous n'allez pas avoir un comportement polymorphe.
Billy ONeal
1
@ m3th0dman: Parce que pour obtenir l'objet singleton, il faut spécifier le nom du singleton sur le site d'appel. Ce qui signifie que vous n'utilisez pas de comportement polymorphe. Ce qui signifie que la composition est beaucoup plus flexible que l'héritage.
Billy ONeal
7

Il n'y a rien qu'un singleton sans état immuable ne puisse faire qu'une classe statique ne peut pas.

Il n'y a tout simplement aucune raison d'ajouter le niveau de complexité supplémentaire que crée -> Instance (), tandis que l'appel simple à une méthode statique sera plus clair, plus conservateur en termes de ressources et probablement plus rapide.

Ce n'est pas qu'ils se trompent. C'est qu'il y a une meilleure façon de le faire. Il existe des scénarios où des singletons normaux ("avec état") sont la bonne voie à suivre. Le mal avec le singleton est qu'ils sont souvent maltraités, avec les mêmes mauvais résultats que les variables globales, mais il existe des cas spécifiques où l'utilisation d'un singleton est tout simplement correcte. Il n'y a pas de tels cas pour les apatrides.

SF.
la source
Je parie que vous pouvez construire des cas où un Singleton a des avantages. Selon le scénario et le langage de programmation éventuellement (par exemple en profitant du chargement paresseux).
StampedeXV
1
@StampedeXV: Oui, certainement un singleton avec état. Un apatride et immuable - je serais vraiment curieux d'entendre des exemples mais je ne retiens pas mon souffle.
SF.
D'accord, vous avez raison. J'ai généralisé un peu votre réponse. Pour les apatrides immuables, je ne vois aucun avantage non plus.
StampedeXV
1
Avec des classes qui n'ont que des fonctions statiques, vous ne pouvez pas utiliser l'héritage / polymorphisme qui est une grande limite ...
m3th0dman
1
Il n'y a rien qu'un singleton sans état immuable ne puisse faire qu'une classe statique ne peut pas. bien, les méthodes statiques ne peuvent pas implémenter une interface, ce qu'un singleton pourrait
Michal M
3

Le principal problème avec le singleton est qu'il cache les dépendances et le couplage spécialement lorsqu'il est utilisé dans un scénario de préoccupations transversales. Voir Singletons sont des menteurs pathologiques ou Pourquoi les singletons sont mauvais pour une lecture plus approfondie.

De l'autre côté, un état moins singleton, s'il n'est pas abusé, peut être utile et améliorer les performances. Prenons un exemple:

interface Interface
{
    void Method();
}

class StatelessSingleton : Interface
{
    public static readonly StatelessSingleton Instance = new StatelessSingleton();
    private StatelessSingleton() { }

    public void Method() { }
}

class User
{
    public User(Interface i) { /* ... */ }
}

Ici, le StatelessSingleton agit comme implémentation par défaut de l'interface et est placé dans le constructeur User. Il n'y a pas de couplage codé en dur ni de dépendances cachées. Nous ne sommes pas en mesure d'utiliser une classe statique en raison de l'interface sous-jacente, mais il n'y a aucune raison de créer plusieurs instances d'une valeur par défaut. C'est pourquoi un singleton apatride semble être un choix approprié.

Cependant, nous devrions peut-être utiliser un autre modèle pour une implémentation par défaut:

class Implementation : Interface
{
    private readonly Action _method;

    public Implementation()
    {
        _method = new Action(() => { /* default */ });
    }

    public Implementation(Action custom)
    {
        _method = custom;
    }

    public void Method()
    {
        _method();
    }
}

Il atteint les performances par rapport à StatelessSingleton mais constitue une implémentation générique de l'interface. Une solution similaire est utilisée par l' interface IProgress .

Encore une fois, pourquoi permettre de créer plusieurs implémentations de comportement par défaut? Pourtant, nous pouvons combiner les deux:

class Implementation : Interface
{
    public readonly Implementation Default = new Implementation();

    private readonly Action _method;

    private Implementation()
    {
        _method = new Action(() => { /* default */ });
    }

    public Implementation(Action custom)
    {
        _method = custom;
    }

    public void Method()
    {
        _method();
    }
}

En conclusion, je crois qu'il y a des endroits (comme les défauts représentés) où les singletons sont utiles. La définition principale de Singleton indique qu'il ne permet pas de créer plusieurs instances d'une classe. C'est comme l'énergie nucléaire. Peut produire une énergie ou une bombe. Cela dépend de l'homme.

yBee
la source