Injection de dépendance et modèle de conception Singleton

Comment Pouvons-nous identifier quand utiliser l'injection de dépendance ou le modèle singleton. J'ai lu dans beaucoup de sites Web où il est dit "utiliser l'injection de dépendance plutôt que le modèle singleton". Mais je ne suis pas sûr d'être entièrement d'accord avec eux. Pour mes projets à petite ou moyenne échelle je vois certainement l'utilisation de singleton pattern simple.

par exemple Logger. Je pourrais utiliser Logger.GetInstance().Log(...) Mais, au lieu de cela, pourquoi ai-je besoin d'injecter chaque classe que je crée, avec le logger exemple?.

64
demandé sur Bozho 2010-04-18 19:55:20

7 réponses

Si vous voulez vérifier ce qui est enregistré dans un test, vous avez besoin d'injection de dépendance. De plus, un bûcheron est rarement un simple bûcheron - généralement vous avez un bûcheron par chacun de votre classe.

Regardez cette présentation sur la conception orientée objet pour la testabilité et vous verrez pourquoi les Singleton sont mauvais.

le problème avec les singletons est qu'ils représentent un état global qui est difficile à prédire, surtout dans les tests.

ont à l'esprit qu'un objet peut être de facto singleton mais encore être obtenu via dépendance-injection, plutôt que via Singleton.getInstance() .

Je ne fais qu'énumérer quelques points importants soulevés par Misko Hevery dans sa présentation. Après l'avoir regardé, vous obtiendrez pleine perspective sur la raison pour laquelle il est préférable d'avoir un objet définir ce que ses dépendances sont, mais pas définir un moyen comment créer eux.

51
répondu Bozho 2010-04-18 16:00:50

Singletons sont comme le communisme: ils ont tous les deux un son génial sur le papier, mais exploser avec des problèmes dans la pratique.

le motif singleton met un accent disproportionné sur la facilité d'accès aux objets. Il évite complètement le contexte en exigeant que chaque consommateur utilise un objet Appdomaine-scoped, ne laissant aucune option pour varier les implémentations. Il intègre les connaissances d'infrastructure dans vos cours (l'appel à GetInstance() ) tout en ajoutant exactement zéro puissance expressive. Il diminue en fait votre pouvoir expressif, parce que vous ne pouvez pas changer l'implémentation utilisée par une classe sans la changer pour tous d'entre eux. Vous ne pouvez tout simplement pas ajouter des pièces uniques de fonctionnalité.

aussi, lorsque la classe Foo dépend de Logger.GetInstance() , Foo cache effectivement ses dépendances aux consommateurs. Cela signifie que vous ne pouvez pas pleinement comprendre Foo ou l'utiliser avec confiance à moins que vous lisez sa source et découvrez qu'elle dépend de Logger . Si vous n'avez pas la source, cela limite votre capacité à comprendre et à utiliser efficacement le code dont vous dépendez.

le modèle singleton, tel qu'il est mis en œuvre avec des propriétés/méthodes statiques, n'est guère plus qu'un piratage autour de la mise en œuvre d'une infrastructure. Il vous limite de multiples façons tout en n'offrant aucun avantage discernable sur les alternatives. Vous pouvez l'utiliser comme vous le souhaitez, mais comme il il ne devrait jamais s'agir d'une pratique recommandée.

77
répondu Bryan Watts 2010-04-18 19:09:06

D'autres ont très bien expliqué le problème avec les singletons en général. Je voudrais juste ajouter une remarque sur le cas spécifique de l'Enregistreur. Je suis d'accord avec vous sur le fait que ce n'est généralement pas un problème d'accéder à un Logger (ou au Logger racine, pour être précis) en tant que singleton, via une méthode statique getInstance() ou getRootLogger() . (sauf si vous voulez voir ce qui est enregistré par la classe que vous testez - mais d'après mon expérience, je ne peux pas me souvenir de tels cas où cela était nécessaire. Puis de nouveau, pour les autres, ce serait peut-être plus préoccupante).

IMO habituellement, un enregistreur simple n'est pas un souci, car il ne contient aucun état pertinent à la classe que vous testez. C'est, de l'enregistreur, l'état (et de ses éventuelles modifications) ont aucun effet sur l'état de la classe testée. Cela ne rend donc pas vos tests unitaires plus difficiles.

l'alternative serait d'injecter le logger via le constructeur, à (presque) chaque classe de votre application. Pour la cohérence des interfaces, il faut l'injecter même si la classe en question n'enregistre rien à l'heure actuelle - l'alternative serait que lorsque vous découvrez à un moment donné que maintenant vous devez Logger quelque chose de cette classe, vous avez besoin d'un logger, donc vous avez besoin d'ajouter un paramètre de constructeur pour DI, cassant tout le code client. Je n'aime pas ces deux options, et je pense que l'utilisation de DI pour la journalisation serait juste compliquer ma vie afin de se conformer à une règle théorique, sans aucun bénéfice concret.

donc ma ligne de fond est: une classe qui est utilisé (presque) universellement, mais ne contient pas l'état pertinent à votre application, peut être mis en œuvre en toute sécurité comme Singleton .

13
répondu Péter Török 2010-04-18 22:25:05

c'est surtout, mais pas entièrement à propos des tests. Les Singleton étaient populaires parce qu'il était facile de les consommer, mais il y a un certain nombre d'inconvénients à Singleton.

  • difficile à tester. Ce qui veut dire comment je m'assure que l'enregistreur fasse la bonne chose.
  • difficile à tester. Ce qui signifie que si je teste le code qui utilise l'enregistreur, mais ce n'est pas l'objet de mon test, je dois quand même m'assurer que mon env de test supporte l'enregistreur
  • parfois vous ne voulez pas un singlton, mais plus de flexibilité

DI Vous donne la consommation facile de vos classes dépendantes - il suffit de le mettre dans le constructeur args, et le système fournit pour vous - tout en vous donnant l'essai et la flexibilité de construction.

7
répondu Scott Weinstein 2010-04-18 16:10:38

le seul moment où vous devriez utiliser un Singleton au lieu d'une Injection de dépendance est si le Singleton représente une valeur immuable, telle que List.Vide ou similaire (en supposant des listes immuables).

Le gut check pour un Singleton doit être "aurais-je être bien si c'était une variable globale au lieu d'un Singleton?"Si ce n'est pas le cas, vous utilisez le modèle Singleton pour décrire une variable globale, et vous devriez envisager une approche différente.

1
répondu kyoryu 2010-04-18 22:19:38

vient de vérifier l'article Monostate - c'est une alternative astucieuse à Singleton, mais il a quelques propriétés de wierd:

class Mono{
    public static $db;
    public function setDb($db){
       self::$db = $db;
    }

}

class Mapper extends Mono{
    //mapping procedure
    return $Entity;

    public function save($Entity);//requires database connection to be set
}

class Entity{
public function save(){
    $Mapper = new Mapper();
    $Mapper->save($this);//has same static reference to database class     
}

$Mapper = new Mapper();
$Mapper->setDb($db);

$User = $Mapper->find(1);
$User->save();

N'est pas ce genre d'effrayant-parce que le Mapper dépend vraiment de la connexion à la base de données pour effectuer save () - mais si un autre mapper a été créé avant - il peut ignorez cette étape dans l'acquisition de ses dépendances. Bien que soigné, il est aussi un peu bordélique, n'est-ce pas?

1
répondu sunwukung 2010-04-24 13:19:10
0
répondu topright gamedev 2017-05-23 10:31:33