Das ist ein Problem, das mich schon seit einiger Zeit nervt. Ich bin immer noch ziemlich neu mit einigen dieser Muster, also musst du mir vergeben (und mich korrigieren), wenn ich einen der Begriffe falsch verwende.
Meine Methodik
Ich habe eine Spiele-Engine erstellt. Alle Objekte in meiner Game-Engine verwenden eine Inversion der Kontrolle, um Abhängigkeiten zu erhalten. Diese Abhängigkeiten implementieren alle Protokolle und werden nie direkt im Projekt aufgerufen, außer während der Bootstrap-Phase. Um diese Objekte zu bekommen, habe ich das Konzept eines Service Locators. Die Aufgabe des Service-Locators besteht darin, ein Objekt zu finden, das einem bestimmten Protokoll entspricht, und es zurückzugeben. Es ist viel wie eine Fabrik, aber es sollte auch die Abhängigkeiten handhaben.
Um die Dienste dem Service Locator zur Verfügung zu stellen, habe ich Service-Spezifizierer, die ich nenne. Der Service-Locator kennt alle Service-Spezifizierer im Projekt, und wenn ein Objekt angefordert wird, versucht er, eine Instanz eines Objekts, das dem bereitgestellten Protokoll entspricht, von jedem von ihnen zu erhalten. Dieses Objekt wird dann an den Aufrufer zurückgegeben. Was an diesem Setup cool ist, ist, dass der Service-Spezifizierer auch einen Service-Locator kennt. Wenn er also Abhängigkeiten hat, fragt er nur den Service-Locator nach diesen spezifischen Abhängigkeiten.
Um ein Beispiel zu geben, habe ich ein Objekt namens HighScoreManager. HighScoreManager implementiert das PHighScoreManager-Protokoll. Wenn eine Instanz von PHighScoreManager erforderlich ist, kann sie jederzeit durch Aufrufen von
abgerufen werden %Vor%So, Umkehrung der Kontrolle. In den meisten Fällen ist dies jedoch nicht einmal notwendig, da sich die meisten Klassen in einem Dienstspezifizierer befinden. Wenn einer PHighScoreManager als Abhängigkeit benötigt wird, wird er über den Dienstlocator abgerufen. Daher habe ich einen netten, flachen Ansatz zur Inversion der Kontrolle.
Mein Problem
Da der Code aus meiner Spiele-Engine geteilt werden soll, habe ich ihn als statische Bibliothek kompiliert. Das funktioniert super für alles andere, scheint aber mit dem Service Locator etwas knifflig zu werden. Das Problem ist, dass sich einige Dienste von Spiel zu Spiel ändern. In meinem obigen Beispiel könnte eine Punktzahl in einem Spiel eine Zeit sein und in einer anderen könnten es Punkte sein. Daher hängt der HighScoreManager von einer Instanz von PHighScoreCreator ab, die angibt, wie ein PScore-Objekt erstellt wird.
Um den HighScoreManager mit PHighScoreCreator auszustatten, benötige ich einen Service Specifier für mein Spiel. Die einzige Möglichkeit, dies zu erreichen, war die Cocoa-Version von Reflexionen. Nachdem ich gegraben hatte, fand ich heraus, dass Klassen über NSBundle auffindbar waren, aber es scheint, dass es keine Möglichkeit gibt, das aktuelle Paket zu bekommen. Wenn ich also in der Lage sein möchte, meine Service-Spezifizierer zu suchen, müsste ich meine Spiellogik in ein eigenes Paket zusammenstellen und dann die Engine dieses Paket durchsuchen und laden lassen. Um dies zu tun, müsste ich ein drittes Projekt erstellen, das sowohl den Engine-Code als auch das Game-Logik-Paket enthält, während ich in Wirklichkeit nur ein Spiele-Projekt hätte, das die Engine-Static-Bibliothek verwendet.
Meine wahre Frage
Nach all dem ist meine Frage
Danke für die Hilfe und die Zeit, um die Frage zu lesen.
-helixed
Sehen Sie sich an:
Damit können Sie zur Laufzeit programmatisch mit den verschiedenen Bundles interagieren. Sobald Sie ein Bündel haben, mit dem Sie arbeiten können, gibt es eine Reihe von Strategien, die Sie anwenden könnten, um die spezifische (n) Klasse (n) zu finden, die Sie suchen. Zum Beispiel:
Nun können Sie eine Instanz der vom Paketautor bereitgestellten Klasse erstellen, die das von Ihnen angegebene Protokoll implementiert.
Die Objective-C-Laufzeit ist eine schöne Sache!
Klingt so, als müssten Sie die Funktionen des Objective-C verwenden Laufzeit Zuerst können Sie eine Liste aller verfügbaren Klassen über objc_getClassList
erhalten. Dann können Sie über alle Klassen iterieren und prüfen, ob sie Ihrem Protokoll mit class_conformsToProtocol
entsprechen. Sie sollten hier keine +conformsToProtocol:
-Meldungen verwenden, da es in der Laufzeit Klassen gibt, die diesen Selektor nicht unterstützen.
Tags und Links objective-c cocoa inversion-of-control nsbundle service-locator