Wie kann ich das Service-Locator-Muster in Cocoa Touch über mehrere Projekte hinweg implementieren?

8

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

  1. Gibt es einen besseren Weg, um das zu tun, was ich in Cocoa Touch erreichen möchte, oder
  2. ?
  3. Gibt es eine Möglichkeit, aus dem Hauptpaket Klassen zu ermitteln, die meinem Service Specifier-Protokoll entsprechen?

Danke für die Hilfe und die Zeit, um die Frage zu lesen.

-helixed

    
LandonSchropp 06.08.2010, 02:47
quelle

2 Antworten

1

Sehen Sie sich an:

  • + [NSBundle mainBundle];
  • + [NSBundle bundleForClass:];
  • + [NSBundle bundleWithIdentifier:];
  • + [NSBundle allBundles];
  • + [NSBundle allFrameworks];

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:

  1. Abrufen der Paket-ID - dies ist ein NSString wie @ "com.example.GameEngineClient".
  2. Verwandeln Sie es in einen legalen Objective-C-Klassennamen, indem Sie alles vor dem letzten Punkt entfernen oder alle Punkte durch Unterstriche oder was auch immer ersetzen und dann einen vordefinierten Protokollnamen anhängen. Ihr Protokoll von oben könnte zum Beispiel eine Zeichenfolge wie @ "GameEngineClient_PHighScoreManager" ergeben.
  3. Mit NSClassFromString ().
  4. erhalten Sie die designierte Klasse des Bundles für Ihr Protokoll

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!

    
Kaelin Colclasure 14.08.2010 01:26
quelle
1

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.

    
Sven 30.08.2010 20:40
quelle