8

これは、しばらくの間私を悩ませてきた問題です。私はこれらのパターンのいくつかについてまだかなり新しいので、用語のいずれかを間違って使用した場合は、私を許してください (そして私を修正してください)。

私の方法論

ゲームエンジンを作りました。私のゲーム エンジンのすべてのオブジェクトは、制御の反転を使用して依存関係を取得します。これらの依存関係はすべてプロトコルを実装しており、ブートストラップ フェーズ以外ではプロジェクト内で直接アクセスされることはありません。これらのオブジェクトを取得するために、サービス ロケーターの概念があります。サービス ロケーターの仕事は、特定のプロトコルに準拠するオブジェクトを見つけて返すことです。これはファクトリによく似ていますが、依存関係も処理する必要があります。

サービス ロケータにサービスを提供するために、サービス指定子と呼ばれるものがあります。サービス ロケータは、プロジェクト内のすべてのサービス指定子を認識しており、オブジェクトが要求されると、提供されたプロトコルに準拠するオブジェクトのインスタンスをそれぞれから取得しようとします。このオブジェクトは呼び出し元に返されます。このセットアップの素晴らしい点は、サービス指定子がサービス ロケーターについても認識しているため、依存関係がある場合は、サービス ロケーターにそれらの特定の依存関係を問い合わせるだけです。

例を挙げると、HighScoreManager というオブジェクトがあります。HighScoreManager は PHighScoreManager プロトコルを実装します。PHighScoreManager のインスタンスが必要な場合はいつでも、以下を呼び出して取得できます。

id<PHighScoreManager> highScoreManager = [ServiceLocator resolve: @protocol(PHighScoreManager)];

したがって、制御の反転。ただし、ほとんどの場合、これを行う必要さえありません。ほとんどのクラスはサービス指定子に配置されているためです。依存関係として PHighScoreManager が必要な場合は、サービス ロケータを通じて取得されます。したがって、私は制御の反転に対してフラットなアプローチをとっています。

私の問題

ゲーム エンジンのコードを共有したいので、スタティック ライブラリとしてコンパイルしました。これは他のすべての場合にうまく機能しますが、サービスロケーターでは少し扱いに​​くいようです. 問題は、一部のサービスがゲームごとに変更されることです。上記の例では、あるゲームのスコアは時間であり、別のゲームではポイントである可能性があります。したがって、HighScoreManager は、PScore オブジェクトの作成方法を指示する PHighScoreCreator のインスタンスに依存します。

PHighScoreCreator を HighScoreManager に提供するには、ゲームのサービス指定子が必要です。これを達成するために考えられる唯一の方法は、リフレクションの Cocoa バージョンを使用することでした。いろいろ調べてみたところ、クラスは NSBundle で発見できることがわかりましたが、現在のバンドルを取得する方法はないようです。したがって、サービス指定子を検索できるようにするには、ゲーム ロジックを独自のバンドルにコンパイルし、エンジンにこのバンドルを検索してロードさせる必要があります。これを行うには、エンジン コードとゲーム ロジック バンドルの両方を格納する 3 番目のプロジェクトを作成する必要がありますが、実際には、エンジンの静的ライブラリを使用するゲーム プロジェクトだけが必要です。

私の本当の質問

結局のところ、私の質問は

  1. Cocoa Touch で達成しようとしていることを行うためのより良い方法はありますか、または
  2. サービス指定子プロトコルに準拠するクラスをメイン バンドルから検出する方法はありますか?

質問を読んでくれてありがとう。

-らせん

4

2 に答える 2

1

Objective-C runtimeの関数を使用する必要があるようです。まず、 を介して利用可能なすべてのクラスのリストを取得できますobjc_getClassList。次に、すべてのクラスを繰り返し処理し、それらがプロトコルに準拠しているかどうかをclass_conformsToProtocol. +conformsToProtocol:ランタイムにはこのセレクターをサポートしないクラスがあるため、ここではメッセージを使用しないでください。

于 2010-08-30T20:40:38.747 に答える
1

見て:

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

これらを使用すると、実行時にさまざまなバンドルをプログラムで操作できます。作業するバンドルを取得したら、探している特定のクラスを見つけるために採用できる戦略がいくつかあります。例えば:

  1. バンドル識別子を取得します — これは @"com.example.GameEngineClient" のような NSString になります。
  2. 最後のドットより前のすべてを削除するか、すべてのドットをアンダースコアなどに置き換えてから、定義済みのプロトコル名を追加することにより、正当な Objective-C クラス名に変換します。たとえば、上記のプロトコルは、@"GameEngineClient_PHighScoreManager" のような文字列になる場合があります。
  3. NSClassFromString() を使用して、プロトコルのバンドルの指定されたクラスを取得します。

これで、指定したプロトコルを実装する、バンドル作成者によって提供されたクラスのインスタンスを作成できます。

Objective-C ランタイムは素晴らしいものです。

于 2010-08-14T01:26:12.560 に答える