Ist ServiceLocator ein anti-pattern?
Kürzlich habe ich gelesen Mark Seemann Artikel über den Service Locator anti-pattern.
Autor weist hauptsächlich zwei Gründe, warum ServiceLocator ist ein anti-Muster:
- API-Nutzung-Problem (was ich völlig in Ordnung)
Wenn die Klasse beschäftigt ein Service locator ist es sehr schwer zu erkennen, Ihre Abhängigkeiten, wie in den meisten Fällen-Klasse hat nur einen PARAMETERLOSEN Konstruktor.
Im Gegensatz ServiceLocator, DI-Ansatz explizit aussetzen Abhängigkeiten per Konstruktor-Parameter also, die Abhängigkeiten sind einfach gesehen, in IntelliSense. - Wartung Problem (das verwirrt mich)
Betrachten Sie das folgende zB
Wir haben eine Klasse 'MyType', die mit einem Service-locator-Ansatz:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Nun wollen wir hinzufügen, eine andere Abhängigkeit zu der Klasse 'MyType'
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
//new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
Und hier ist, wo mein Unverständnis beginnt. Der Autor sagt:
Wird es viel schwieriger zu sagen, ob Sie die Einführung einer brechen ändern oder nicht. Sie müssen verstehen, dass die gesamte Anwendung, in denen der Service-Locator verwendet wird, und der compiler ist nicht zu helfen.
Aber warten Sie eine Sekunde, wenn wir mit DI-Ansatz, würden wir die Einführung einer Abhängigkeit mit einem anderen parameter im Konstruktor (bei der constructor injection). Und das problem wird noch da sein. Wenn wir vielleicht vergessen, um das setup ServiceLocator, dann können wir vergessen, fügen Sie eine neue Zuordnung in unserer IoC-container und DI-Ansatz würde die gleiche Laufzeit-problem.
Außerdem Autor erwähnt über unit-test Schwierigkeiten. Aber, nicht wir haben Probleme mit der DI-Ansatz? Nicht wir müssen aktualisieren Sie alle tests wurden Instanziierung dieser Klasse? Wir werden aktualisiert und vermitteln ein neues verspottet Abhängigkeit nur um unseren test kompilierbar. Und ich sehe keine Vorteile von diesem update und Zeit verbringen.
Ich versuche nicht zu verteidigen Service-Locator-Ansatz. Aber dieses Missverständnis machen mich denken, dass ich etwas zu verlieren sehr wichtig. Könnte jemand zerstreuen meine Zweifel?
UPDATE (ZUSAMMENFASSUNG):
Die Antwort auf meine Frage "Ist das Service-Locator-ein anti-pattern" hängt nun wirklich von den Umständen ab. Und ich definitiv nicht empfehlen kann, ist zu überqueren, es aus der Werkzeug-Liste. Es könnte sehr nützlich sein, wenn Sie beginnen, den Umgang mit legacy-code. Wenn Sie Glück genug, um am Anfang Ihr Projekt dann bei der DI-Ansatz wäre die bessere Wahl, da es einige Vorteile gegenüber den Service-Locator.
Und hier sind die wichtigsten Unterschiede, die mich überzeugt, nicht die Nutzung des Service Locator für meine neuen Projekte:
- Die meisten offensichtlich und wichtig: Service Locator blendet Klasse Abhängigkeiten
- Wenn Sie Verwendung einigen IoC-container, wird es wahrscheinlich Scannen Sie alle Konstruktor beim Start überprüft alle Abhängigkeiten und geben Ihnen sofortiges feedback auf fehlende mappings (oder falsche Konfiguration); dies ist nicht möglich, wenn Sie Ihre IoC-container als Service Locator
Für details Lesen Sie hervorragende Antworten, die sind unten angegeben.
Du hast Recht, es hängt davon ab. In großen Android-apps, zum Beispiel, so weit die Menschen waren sehr zurückhaltend mit DI wegen der Leistung Bedenken, die auf low-spec-mobile-Geräte. In solchen Fällen müssen Sie eine Möglichkeit finden, noch schreiben von testbarem code, und ich würde sagen, Service Locator ist ein gut-genug Ersatz in diesem Fall. (Hinweis: die Dinge können sich ändern für Android, wenn die neuen Dolch 2.0 DI-framework ist ausgereift genug.)
Beachten Sie, dass, da diese Frage schon gepostet hat, gibt es ein update auf Mark Seemann Service Locator ist ein Anti-Pattern-post - beschreibt, wie service-locator gegen OOP durch Aufbrechen der Kapselung, das ist seine beste argument noch (und der eigentliche Grund für all die Symptome, die er verwendet, werden alle vorherigen Argumente). Update 2015-10-26: Das grundlegende problem mit dem Service Locator ist, dass es gegen Kapselung.
InformationsquelleAutor davidoff | 2014-04-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie definieren Muster als anti-mustern, nur weil es einige Situationen, wo es nicht passt, dann JA, es ist ein anti-pattern. Aber mit dieser Argumentation alle Muster wäre auch anti-Muster.
Stattdessen müssen wir schauen, ob es gültige Verwendungen der Muster und für den Service Locator gibt es verschiedene Anwendungsfälle. Aber lassen Sie uns beginnen, indem man die Beispiele, die Sie gegeben haben.
Den Wartungs-Alptraum mit dieser Klasse ist, dass die Abhängigkeiten ausgeblendet sind. Wenn Sie erstellen und verwenden Sie diese Klasse:
Du nicht verstehen, dass es Abhängigkeiten, wenn Sie ausgeblendet sind mit service-Standort. Nun, wenn wir statt dependency injection:
Können Sie direkt vor Ort die Abhängigkeiten und können nicht verwenden Sie die Klassen vor befriedigend.
In einer typischen line-of-business-Anwendung, die Sie sollten vermeiden, die Verwendung von service-Standort für den jeweiligen Anlass. Sollte es sein, die Muster zu verwenden, wenn es keine anderen Optionen.
Ist das pattern ein anti-pattern?
Nicht.
Beispielsweise inversion of control Container nicht funktionieren würde, ohne service-Standort. Es ist, wie Sie lösen die services intern.
Aber ein viel besseres Beispiel ist ASP.NET MVC und WebApi. Was denken Sie, macht die dependency injection möglich in den Controller? Das stimmt -, service-Standort.
Ihre Fragen
Gibt es noch zwei weitere schwerwiegende Probleme:
Mit Konstruktor-Injektion mit Hilfe eines Containers, die Sie bekommen, kostenlos.
Das ist wahr. Aber mit Konstruktor-Injektion, die Sie nicht Scannen die gesamte Klasse, um herauszufinden, welche Abhängigkeiten fehlen.
Und einige bessere Container auch überprüft alle Abhängigkeiten beim Start (durch das Scannen aller Konstruktoren). Also mit diesen Behältern erhalten Sie die runtime-Fehler direkt, und nicht auf einige spätere zeitliche Punkt.
Nicht. Da Sie nicht über die eine Abhängigkeit zu einer statischen service-locator. Haben Sie versucht, um parallele tests arbeiten mit statischen Abhängigkeiten? Es ist nicht Spaß.
Ihre einzige argument für den Service-Locator nicht als ein anti-pattern ist: "inversion of control Container nicht funktionieren würde, ohne service-Standort". Dieses argument ist jedoch ungültig, da der Service Locator wird über die Absichten und nicht um die mechanik, wie bereits erläutert, klar hier von Mark Seemann: "EIN DI-container gekapselt in einer Komposition Root ist nicht ein Service-Locator - es ist eine Infrastruktur-Komponente."
Web-API nicht verwenden Service-Standort für die DI in Controller. Es nicht, DI an alle. Was es tut, ist: Es gibt Ihnen die option zum erstellen Ihrer eigenen ControllerActivator Durchgang in der Configuration Services. Von dort aus können Sie eine Zusammensetzung root, ob es einen Reinen DI oder Container. Auch mischen Sie die Verwendung von Service-Standort, als Bestandteil Ihrer Muster, mit der definition von "Service-Locator-Muster." Mit dieser definition, Zusammensetzung Stamm-DI -, könnte erwogen werden, ein "Service-Locator-Muster." Der springende Punkt, die definition ist umstritten.
Ich möchte darauf hinweisen, dass dies eine allgemein gute Antwort, ich habe gerade kommentiert, eine irreführende Punkt, den Sie gemacht.
DI und SL sind beide Darstellungen des IoC. SL ist einfach die falsch Weg, es zu tun. Ein IoC-container könnte SL, oder es könnte DI. Es hängt davon ab, wie es verdrahtet. Aber SL ist schlecht, schlecht, schlecht. Es ist eine Weise des Versteckens der Tatsache, dass Sie eng Kupplung alles zusammen.
InformationsquelleAutor jgauffin
Möchte ich auch darauf hinweisen, dass, WENN Sie das refactoring von legacy-code, der den Service-Locator-Muster ist nicht nur ein anti-pattern, aber es ist auch eine praktische Notwendigkeit. Niemand ist jemals mit einem Zauberstab über Millionen von Zeilen code und plötzlich alle, der code wird DI bereit. Also, wenn Sie wollen, um zu starten Einführung von DI zu einem bestehenden code-Basis, ist es oft der Fall, dass Sie die Dinge ändern werden DI-Dienste langsam, und der code, die Verweise, die diese Dienste oft NICHT DI-Dienste. Damit DIESE services müssen die Service-Locator, um Instanzen dieser Dienste, die Sie HABEN umgewandelt worden, um die Verwendung DI.
Also bei der Umgestaltung großen legacy-Anwendungen zu nutzen beginnen DI-Konzepte, ich würde sagen, dass ist nicht nur Service-Locator NICHT ein anti-pattern, aber es ist der einzige Weg, um schrittweise gelten DI-Konzepte, um die code-Basis.
InformationsquelleAutor jwells131313
Sich aus der Prüfung Sicht -, Service-Locator ist schlecht. Sehen Misko Hevery Google Tech Talk schöne Erklärung mit Beispielen http://youtu.be/RlfLCWKxHJ0 ab minute 8:45. Ich mochte seine Analogie: wenn Sie $25, erfragen Sie bitte direkt bei Geld, anstatt Ihre Brieftasche aus, wo das Geld entnommen werden soll. Er vergleicht auch die Service-Locator mit einem Heuhaufen, der die Nadel, die Sie brauchen, und weiß, wie man es abrufen. - Klassen mit Service Locator sind schwer zu Wiederverwendung, weil es.
InformationsquelleAutor user3511397
Gibt es 2 verschiedene Gründe, warum mit service locator ist schlecht in dieser Hinsicht.
Schlicht und einfach: Eine Klasse mit einem service locator es ist schwieriger wiederzuverwenden als eine, die akzeptiert Ihre Abhängigkeiten über den Konstruktor.
InformationsquelleAutor NightOwl888
Mein wissen ist nicht gut genug, um zu beurteilen, aber im Allgemeinen denke ich, dass, wenn etwas hat eine Verwendung in einer bestimmten situation, es nicht notwendigerweise bedeutet, es kann nicht sein, ein anti-pattern. Vor allem, wenn man mit 3rd-party-Bibliotheken, die Sie nicht haben die volle Kontrolle über alle Aspekte und Sie können am Ende mit die nicht beste Lösung.
Hier ist ein Absatz von Adaptive Code Via C#":
InformationsquelleAutor Siavash Mortazavi
Der Autor Gründe dafür, dass "der compiler wird dir nicht helfen" - und es ist wahr.
Wenn Sie geruhen, eine Klasse, werden Sie wollen, sorgfältig auswählen, seine Schnittstelle werden unter anderem die Ziele zu machen, wie unabhängig, wie ... wie es Sinn macht.
Durch, dass der client akzeptieren, den Verweis auf einen service (eine Abhängigkeit) durch explizite Schnittstelle, die Sie
Du hast Recht, dass DI hat seine Probleme /Nachteile, aber die genannten Vorteile überwiegen Sie bei weitem ... IMO.
Du hast Recht, das mit DI gibt es eine Abhängigkeit eingeführt, die in der Schnittstelle (Konstruktor) - aber das ist hoffentlich der Abhängigkeit, die Sie brauchen, und dass Sie möchten, machen Sie sichtbar und überprüfbar ist.
Die "statische " Informationen'/'compile-time checking' - argument ist ein Strohmann. @Davidoff hingewiesen hat, DI ist genauso anfällig für Laufzeitfehler. Ich möchte noch hinzufügen, dass moderne IDEs bieten tooltip Ansichten des Kommentar/Zusammenfassung Informationen für die Mitglieder, und sogar diejenigen, die nicht, jemand noch auf der Suche in der Dokumentation, bis Sie nur 'wissen' die API. Dokumentation ist die Dokumentation, ob ein erforderlicher parameter des Konstruktors oder einer Bemerkung über das konfigurieren einer Abhängigkeit.
Gedanken über die Umsetzung / Programmierung und Qualitätssicherung - die Lesbarkeit des Codes entscheidend ist, insbesondere zur definition der Schnittstelle. Wenn Sie das tun können ohne automatische Kompilier-Zeit überprüft und, wenn Sie angemessen kommentieren / dokumentieren Sie Ihre Schnittstelle, dann denke ich, kann man zumindest teilweise Abhilfe der Nachteile der versteckten Abhängigkeit auf eine Art Globale variable mit nicht leicht erkennbar / vorhersehbar Inhalte. Ich würde sagen, Sie brauchen gute Gründe, um diesem Muster überwiegen die Nachteile.
InformationsquelleAutor Zrin
Ja, service locator ist ein anti-pattern gegen Kapselung und solid.
InformationsquelleAutor Alireza Rahmani Khalili