Abhängigkeitsinjektion und Singleton. Sind das zwei völlig unterschiedliche Konzepte?

17

Ich habe gehört, dass ich die Abhängigkeitsinjektion über Singleton für meinen Kollegen verwendet habe. Ich kann immer noch nicht erkennen, ob es sich um zwei orthogonale Muster handelt, die gegeneinander ausgetauscht werden können. Oder ist DI eine Methode, um das Singleton-Muster testbar zu machen?

Bitte schauen Sie sich das folgende Code-Snippet an.

    IMathFace obj = Singleton.Instance;

    SingletonConsumer singConsumer = new SingletonConsumer(obj);

    singConsumer.ConsumerAdd(10,20);

Der SingletonConsumerakzeptiert einen Parameter vom Typ IMathFace. Anstatt intern auf die Singleton-Klasse zuzugreifen, SingletonConsumerwird die Singleton-Instanz vom Aufrufer übergeben. Ist dies ein gutes Beispiel für die Verwendung von Singleton-Klassen über die Abhängigkeitsinjektion?

Logeeks
quelle
Können Sie mir bitte sagen, wie DI den Singleton ersetzen kann?
7
Singleton ist ein Entwurfsmuster. DI / IoC ist eine Technik.
Dave
2
DI kann Singleton nicht mehr ersetzen, als eine Banane einen Vergaser ersetzen könnte. Das sind völlig andere Konzepte.
Dave
Mein Beispiel ist also gültig.
1
Ja, es kann aber auf Kosten der Verkapselung kommen (die gilt auch für Nicht-Singleton) zu sehen: stackoverflow.com/questions/1005473/...

Antworten:

17

Ich denke, er meinte, dass Sie Abhängigkeitsinjektion verwenden sollten, um eine einzelne Instanz des Dienstes zu injizieren, anstatt die klassische Singleton-Implementierung mit einem statischen Accessor zu verwenden MySingleton.Instance .

public class MySingleton
{
    public static MySingleton Instance{get{...}};
}

Bei der klassischen Singleton-Implementierung hängt Ihr gesamter Code davon ab, dass dieser Dienst ein Singleton ist. Sie programmieren diese Annahme grundsätzlich fest in konsumierenden Code, wann immer Sie sie verwenden MySingleton.Instance.

Andererseits erhalten Sie mit DI eine Instanz des Dienstes, die an Ihren Konstruktor übergeben und dort gespeichert wird. Dass es nur eine einzige Instanz dieses Dienstes gibt, ist ein Implementierungsdetail. Sie können es leicht ändern, um dem konsumierenden Code eine andere Instanz zu geben. Auf diese Weise haben Sie eine Klasse / Schnittstelle, die zufällig von einer einzelnen Instanz implementiert wird, anstatt zu erzwingen, dass es nur eine Instanz gibt.

Dies ist nützlich, wenn Sie beispielsweise eine Scheinimplementierung des Dienstes zum Testen wünschen oder wenn verschiedene Teile des Programms unterschiedliche Konfigurationen dieses Dienstes benötigen.

CodesInChaos
quelle
4

Ja, du hast recht. Anstatt über den Singleton auf das Objekt zuzugreifen, übergeben Sie einen Verweis darauf, sodass Sie eine Konstruktorinjektion verwenden.

Andere weisen darauf hin, dass diese Begriffe nicht miteinander zusammenhängen. Das Konsumieren einer Singleton-Instanz ist nichts Besonderes, da es dem Objekt, in das Sie injizieren, egal ist, woher das injizierte Objekt stammt.

Wiktor Zychla
quelle
2

Es gibt einen Fall, in dem das Singleton-Muster und DI / IoC die Injektion eines Singleton schneiden.

Die meisten DI-Frameworks können so konfiguriert werden, dass sie eine einzelne Instanz eines injizierten Objekts instanziieren. Jedes Consumer-Objekt, das eine Instanz eines solchen Objekts anfordert, erhält dieselbe einzelne Instanz. Diese Instanz ist per Definition ein Singleton. Das war's schon mit der Überlappung im Konzept.

Dave
quelle
1

Die Verwirrung hier ist, dass zwei Konzepte zusammengeführt wurden: der Singleton und der statische Accessor / Gateway zur Singleton-Instanz.

Wie Sie zu Recht festgestellt haben, schlägt Ihr Kollege vor, die Abhängigkeit einzuschleusen, anstatt direkt über Singleton.Instance(statisches Gateway) darauf zuzugreifen.

Der Grund dafür, dass dies mit dem Singleton-Muster eigentlich nichts zu tun hat, ist, dass dasselbe DI-Konzept auch für die Instanziierung eines Nicht-Singleton-Objekts mit gilt new Foo(). Die Abhängigkeit wird unabhängig davon injiziert, ob es sich um eine Singleton-Implementierung handelt.

Jay
quelle