Kürzlich habe ich Mark Seemanns Artikel über Service Locator Anti-Pattern gelesen .
Der Autor weist auf zwei Hauptgründe hin, warum ServiceLocator ein Anti-Pattern ist:
API-Verwendungsproblem (mit dem ich vollkommen
einverstanden bin) Wenn die Klasse einen Service Locator verwendet, ist es sehr schwierig, ihre Abhängigkeiten zu erkennen, da die Klasse in den meisten Fällen nur einen PARAMETERLESS-Konstruktor hat. Im Gegensatz zu ServiceLocator macht der DI-Ansatz Abhängigkeiten explizit über Konstruktorparameter verfügbar, sodass Abhängigkeiten in IntelliSense leicht erkennbar sind.Wartungsproblem (was mich
verwirrt ) Betrachten Sie das folgende Beispiel
Wir haben eine Klasse 'MyType', die einen Service Locator-Ansatz verwendet:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Jetzt möchten wir der Klasse 'MyType' eine weitere Abhängigkeit hinzufügen.
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
Und hier beginnt mein Missverständnis. Der Autor sagt:
Es wird viel schwieriger zu sagen, ob Sie eine bahnbrechende Änderung einführen oder nicht. Sie müssen die gesamte Anwendung verstehen, in der der Service Locator verwendet wird, und der Compiler wird Ihnen nicht helfen.
Aber warten Sie eine Sekunde, wenn wir den DI-Ansatz verwenden, würden wir eine Abhängigkeit mit einem anderen Parameter im Konstruktor einführen (im Fall einer Konstruktorinjektion). Und das Problem wird immer noch da sein. Wenn wir möglicherweise vergessen, ServiceLocator einzurichten, vergessen wir möglicherweise, eine neue Zuordnung in unseren IoC-Container einzufügen, und der DI-Ansatz hätte das gleiche Laufzeitproblem.
Auch der Autor erwähnte über Unit-Test-Schwierigkeiten. Aber haben wir nicht Probleme mit dem DI-Ansatz? Müssen wir nicht alle Tests aktualisieren, die diese Klasse instanziiert haben? Wir werden sie aktualisieren, um eine neue verspottete Abhängigkeit zu übergeben, nur um unseren Test kompilierbar zu machen. Und ich sehe keine Vorteile aus diesem Update und dem Zeitaufwand.
Ich versuche nicht, den Service Locator-Ansatz zu verteidigen. Aber dieses Missverständnis lässt mich denken, dass ich etwas sehr Wichtiges verliere. Könnte jemand meine Zweifel zerstreuen?
UPDATE (ZUSAMMENFASSUNG):
Die Antwort auf meine Frage "Ist Service Locator ein Anti-Pattern" hängt wirklich von den Umständen ab. Und ich würde definitiv nicht vorschlagen, es von Ihrer Werkzeugliste zu streichen. Dies kann sehr praktisch sein, wenn Sie mit Legacy-Code arbeiten. Wenn Sie das Glück haben, ganz am Anfang Ihres Projekts zu stehen, ist der DI-Ansatz möglicherweise die bessere Wahl, da er einige Vorteile gegenüber Service Locator bietet.
Und hier sind die Hauptunterschiede, die mich überzeugt haben, Service Locator nicht für meine neuen Projekte zu verwenden:
- Am offensichtlichsten und wichtigsten: Service Locator verbirgt Klassenabhängigkeiten
- Wenn Sie einen IoC-Container verwenden, werden wahrscheinlich alle Konstruktoren beim Start gescannt, um alle Abhängigkeiten zu überprüfen und Ihnen sofort Feedback zu fehlenden Zuordnungen (oder falscher Konfiguration) zu geben. Dies ist nicht möglich, wenn Sie Ihren IoC-Container als Service Locator verwenden
Für Details lesen Sie ausgezeichnete Antworten, die unten gegeben werden.