Wie zu vermeiden, Service-Locator Anti-Pattern?

Ich versuche zu entfernen, einen Service Locator von einer abstrakten Klasse, aber ich bin mir nicht sicher, was zu ersetzen. Hier ist ein Pseudo-Beispiel, was ich habe:

public abstract class MyController : Controller
{
    protected IKernel kernel;
    public MyController(IKernel kernel) { this.kernel = kernel); }

    protected void DoActions(Type[] types)
    {

        MySpecialResolver resolver = new MySpecialResolver(kernel);
        foreach(var type in types)
        {
            IMyServiceInterface instance = resolver.Get(type);
            instance.DoAction();
        }
    }
}

Den problem mit dieser ist, dass die instanciator einer abgeleiteten Klasse muss nicht wissen, welche Bindungen die kernel haben muss, um zu halten MySpecialResolver aus eine Ausnahme zu werfen.

Könnte dies an sich unlösbar, denn ich weiß nicht von hier, die Typen, die ich lösen müssen. Die abgeleiteten Klassen sind verantwortlich für die Erstellung der types parameter, aber Sie sind nicht hardcoded überall. (Die Arten werden basierend auf dem Vorhandensein der Attribute, die tief in der abgeleiteten Klasse Komposition, Hierarchie) an.

Habe ich versucht zu reparieren, das mit lazy loading Delegierten, aber bisher habe ich noch keine saubere Lösung.

Update

Gibt es wirklich hier zwei Probleme, das eine ist, dass die IoC-Containers übergeben wird, der controller fungiert als service-locator. Dieser ist leicht zu entfernen-Sie können verschieben die Position nach oben oder unten auf dem Aufruf-stack mit allen möglichen Techniken.

Das zweite Problem ist die schwierige, wie können Sie sicherstellen, dass der controller hat die erforderlichen Leistungen, wenn die Anforderungen nicht ausgesetzt, die erst zur Laufzeit. Es sollte gewesen offensichtlich von Anfang an: das kannst du nicht! Sie werden immer abhängig sein von entweder dem aktuellen Status des service locator oder den Inhalt einer Sammlung. In diesem speziellen Fall keine Menge hantieren jemals Behebung des Problems beschrieben, in dieser Artikel mit staticly typisierte Abhängigkeiten. Ich denke, dass das, was ich werde zu tun ist die übergabe eines Lazy-array in dem controller-Konstruktor und eine Ausnahme werfen, wenn eine erforderliche Abhängigkeit fehlt.

  • Ähm, ich weiß, das ist nicht die trendige Antwort, aber Service Locator ist nicht ein anti-pattern. Es ist eine alternative zu der Verwendung von einem IoC-container, aber Sie können dependency injection mit ein (es ist ein bisschen seltsam, injizieren von Abhängigkeiten in Dienst-Lage-Klassen, aber nicht unmöglich). Das heißt, wenn Sie einen IoC-container, und dann mit einem Service-Locator sowie würde wahrscheinlich qualifizieren als code smell.
  • Wie es aussieht, bist du mit mvc und möglicherweise Windsor, aber ich bin mir nicht sicher - wenn ja, können Sie commonservicelocator.codeplex.com und dann irgendwo in der Application_Start-call ServiceLocator.SetLocatorProvider(() => { return new WindsorServiceLocator(_container); });DependencyResolver.SetResolver(ServiceLocator.Strom); Dann dies wird Ihnen ermöglichen, zu injizieren und Ihre Abhängigkeiten in den controller-Konstruktoren. Andere Container unterstützt werden, aber ich habe nur verwendet Windsor für diese
  • Paul, können Sie hinzufügen, ein Beispiel für die abgeleitete Klasse Attribut Abhängigkeit? Sind die Attribute der abgeleiteten controller und die daraus abgeleiteten controller-Abhängigkeiten?
  • diese basieren auf den abgeleiteten Controller-Eigenschaften-befindet sich in einer anderen assembly. So, während die benötigten Abhängigkeiten sind technisch statischen zur build-Zeit, wird der Netto-Effekt ist, dass Sie nicht bekannt sind, um den IoC-container oder unit-test, bis der controller instanziiert wurde.
  • Macht Sinn. Meine Antwort kann immer noch mit dieser situation umzugehen. Wir können starten einer chat-Sitzung, wenn Sie wollen, mehr zu besprechen.
  • Paul, Sie sollten wirklich posten Sie Ihre Lösung (mit code, vorzugsweise als Antwort und akzeptieren es. Ihr update nur irgendwie ließ uns hängen. Ich bin mir nicht sicher, ich Stimme mit deiner Lösung, aber es ist Ihr Vorrecht zu entscheiden.
  • Ich weiß nicht wirklich einverstanden mit Ihrer Antwort...wie @chrischris sagte, es klingt wie Sie Ihre Basis-controller hat zu viele Aufgaben und sollten Sie diesen service-Aufrufe an den richtigen stellen. Aber Sie haben das Letzte Wort.
  • was ich geschrieben habe, ist die Lösung, die ich mit gestartet. Ich mochte es nicht, also fragte ich die Frage hier. Ich will nicht zu posten/zu akzeptieren, eine irreführende Antwort. Ich bin mir nicht sicher, ob es eine Lösung gibt, führt meine (zugegebenermaßen etwas willkürlich) Ziele für den oben genannten Gründen. Architektur-Probleme sind nicht immer sofort klar, also für den moment ich werde versuchen, das zu machen, was ich habe, zu arbeiten und wieder diese Frage mal ich hab ein klareres Verständnis von den Auswirkungen.
  • fair genug. Ich hoffe, Sie finden die richtige Lösung für Ihre situation.
  • Obwohl es ein "Anti-Muster", ich habe es nützlich gefunden, die passieren in der Kernel-Schnittstelle, vor allem, wenn es darum geht zu testen und Ninject.Mock und pass in eine Mock version des Kernels.
  • Was wollen Sie erreichen? Möchte einfach nur eine Liste der Instanzen des angegebenen Typen? Warum ist Ihre Steuerung haben etwas zu tun mit den Typen und nicht die Rolle-Schnittstellen?
  • Aus irgendeinem Grund war es nicht immediently mir klar, fast ein Jahr her, als ich diese Frage gestellt, aber es ist keine Lösung für dieses problem. Der Grund dafür ist, dass in diesem Fall der controller ist eine abstrakte Basisklasse, die einfach NICHT WISSEN, welche Dienste es müssen erst zur Laufzeit. Sehen Sie, wo die DoAction Methode wird immer eine Liste der Typen? Der controller kann nicht wissen, zur compile-Zeit, welche Arten es wird schließlich zur Verfügung gestellt werden, wie diese durch die Unterklassen. Ohne dieses wissen ist es unmöglich zu vermeiden, das problem von einer falsch initialisiert service-locator.
  • es ist keine missbräuchliche Verwendung eines service locator, wenn Sie wirklich tun service Lage. DoActions(Type[] types) ist ein text-Buch-Beispiel von service-Standort. Der service locator ist eine grundlegende Muster, die keine alternativen, außer schlechte Implementierungen des service-locator. Der service locator ist ein elementarer Baustein aller IOC-Container. Das service locator pattern ist nicht ein anti-pattern, und ich vehement widersprechen Mark Seemann mit seinem deklarieren, dass es so wäre. Falsche Anwendung des Musters ist die anti-pattern.
  • "Service-Position" sollte bei der Zusammensetzung root. Der Begriff "anti-pattern" ist nicht eine intrinsische, absolute Eigenschaft kann man Rational argumentieren, etwas, das 'ist' oder 'ist nicht', sondern ein zugeschrieben, basierend auf der menschlichen Beobachtung und Erfahrung. In diesem Fall kann ich persönlich bezeugen, um die Gefahren der Streuung service locator-Aufrufe, wie diese in der gesamten Anwendung.
  • mit großer macht kommt große Verantwortung. Der service locator wird als lose gekoppelt als code können Sie immer werden (kurz -, null-Kopplung, was bedeutet, dass keinerlei Interaktionen), die Locator-Punkte willkürlich wäre in der Tat gefährlich sein. Nur weil Messer gefährlich sind, bedeutet nicht, Sie machen jedes Messer ein Messer in butter, obwohl Sie müssen ein steak-Messer. Einfachstes Beispiel ist Validator.Validate(obj) dass nicht Richtlinien-basierte Validierung, basierend auf den Inhalt von obj. Das kann einfach nicht sein fertig in der Zusammensetzung root kurzen kleben voodoo in den container.

InformationsquelleAutor Paul | 2011-07-26
Schreibe einen Kommentar