2011-10-20 11 views
2

抽象的な依存関係の具体的な実装について説明しているわけではないので、これが実際にDIとして認定されるかどうかはわかりません。私はちょうど必要な期間のものを注入することについて話しています。マルチレベルのDIリファクタリング

私のゲームエンジンでは、ゲームの状態(メニュー、ステージ選択、ゲーム内、カットシーンなど)を処理する部分をクリーンアップしたいと考えています。これらのすべてが共通のインターフェースを実装しています。しかし、彼らのうちの1つは、ゲーム内の現在のレベルとして具体的に参照されています。

私のプロジェクトには現在、ゲームを通してアクセスされている現在のレベルの参照が43個あります。たとえば、Game.CurrentGame.CurrentMap.Somethingです。リファレンスは、スクリーン、エンティティ、ビヘイビアコンポーネント、メインフォーム(デバッグツール用)であっても参照できます。

私は必要なものすべてを注入することでこのリファレンスを取り除きたいと思っています。しかし、CurrentMap自体は望ましい依存性ではなく、他のものはその下にアクセスされています。私の初期の計画は、それぞれの場所に行き、実際に使用されているものを見つけ出し、そのクラスのコンストラクタにパラメータを追加して注入することです。これは1レベル上の別の依存関係を導入するので、すべてが終了するまでプロセスを繰り返します。しかし、この問題は、依存関係を直接使用していない場所を含め、より多くのコンストラクタパラメータを導入することになります。多くのクラスは依存関係を受け入れるだけで、その下にある別のオブジェクトにそれを渡すことができます。

これに代わるクリーンな方法は何ですか?

答えて

2

ここでは、依存関係がオブジェクトのいくつかのレイヤーを通って実際に必要な場所に移動するシナリオについて説明しています。これは起こる必要はありません。

オブジェクトが依存関係を作成すると、この問題が発生します。オブジェクトに依存関係が指定されている場合は、ファクトリまたはDIコンテナ(これは単なるファクトリなファクトリです)によって必要になります。この問題は発生しません。したがって、この問題を回避するには、各クラスがゲームロジックやクラスの作成に関係するかどうかを判断する必要があります。

電流レベルを必要とし、オブジェクトbにはないcオブジェクトcやオブジェクトを呼び出している、あなたがオブジェクトbを呼び出すオブジェクトaを、持っているとしましょう。

間違った方法はnew C(level);bから呼び出すことです。あなたが指摘したように、bはレベルについて知る必要がないので、状況が悪くなっているようです。あなたは依存性注入を十分に行っていません。 b内にcを作成する代わりに、bのコンストラクタでcを尋ねてください。今すぐクラスbは約cしか知らず、levelについて何も知らない。

Miskoは、工場でのコードこの優れたhttp://misko.hevery.com/2009/03/30/collaborator-vs-the-factory/ここに私ができるより

を説明したが、次のようになります。

Level level = new Level(); 
C c = new C(level); 
B b = new B(c); 
A a = new A(b); 

クラスBは、それが直接の協力者(c)だとに依存しません知っていますLevel。私たちは工場で物を作っているので、オブジェクトグラフの葉をオブジェクトグラフに通す必要はありません。

クラスBcを作成する責任を負っていた場合は、クラスcのインスタンスを作成する方法についてすべてを知る必要があります。これは間違っています。

+0

+1何かを注入して他の何かのコンストラクタに渡すことができ、それを直接使っていないと思ったら、代わりに何かを渡すことを考えていなければなりません。 –

+0

「単に「b」のコンストラクタでそれを求めてください」ということを明確にすることはできますか?それはそれを求めているので、 'b'はまだ' c'について知っているように聞こえる。コードサンプルを渡すことができますか? – Tesserex

1

Castle Windsor、Structuremap、UnityなどのDIフレームワークを使用してみてください(他にも完全に安定しているものがたくさんあります)。

あなたが記述している問題は、これらのフレームワークを解決することをだけ問題ではありませんが、それは彼らがほぼ完全に排除することを摩擦の種の大部分です。

依存関係は具体的な実装であり、より高いレベルの抽象概念ではないということは無関係です。通常、私は現在の状態を追跡するサービスを注入

IOC/DI: Is Registering a Concrete Type a Code Smell?

0

public interface IGameStateTracker 
{ 
    Game CurrentGame {get;} 
    GameMap CurrentMap {get;} 
} 

あなたが唯一のコンストラクタでこのサービスを注入する必要があります(本当にあなたに頼ま)この質問を参照してください。それを直接必要とするクラス。私は、あなたが直接それを必要としないクラスに物事を注入する必要があることが分かっている理由を完全には理解していないのではないかと思います。これは、適切なDIパターンを使用していないというサインかもしれません。この問題の例を示すためにいくつかのコードサンプルを提供できますか?

DIフレームワークを使用したPhil Sandlerの2番目のポイントです。それは人生をはるかに簡単にするでしょう。しかし、最初は間違ったDIパターンを使用して補完することはできません。