これは、Doc Brownに対する補完的な回答になることと、質問にまだ関連しているDinaizの未回答のコメントに回答することを目的としています。
おそらく必要なのは、DIを行うためのフレームワークです。複雑な階層を持つことは、必ずしも悪い設計を意味するわけではありませんが、Dに直接注入するのではなく、TimeFactoryボトムアップ(AからD)を注入する必要がある場合、おそらく依存性注入の方法に何か問題があります。
シングルトン?結構です。必要なイスタンスが1つだけの場合、アプリケーションコンテキスト全体で共有します(Infector ++のようにDIにIoCコンテナを使用するには、TimeFactoryを単一のイスタンスとしてバインドする必要があります)。すでにC ++ 11になっていますか?リークフリーアプリケーションを無料で入手できます):
Infector::Container ioc; //your app's context
ioc.bindSingleAsNothing<TimeFactory>(); //declare TimeFactory to be shared
ioc.wire<TimeFactory>(); //wire its constructor
// if you want to be sure TimeFactory is created at startup just request it
// (else it will be created lazily only when needed)
auto myTimeFactory = ioc.buildSingle<TimeFactory>();
IoCコンテナの良い点は、タイムファクトリをDに渡す必要がないことです。クラス「D」がタイムファクトリを必要とする場合は、クラスDのコンストラクタパラメータとしてタイムファクトリを置くだけです。
ioc.bindAsNothing<A>(); //declare class A
ioc.bindAsNothing<B>(); //declare class B
ioc.bindAsNothing<D>(); //declare class D
//constructors setup
ioc.wire<D, TimeFactory>(); //time factory injected to class D
ioc.wire<B, D>(); //class D injected to class B
ioc.wire<A, B>(); //class B injected to class A
ご覧のとおり、TimeFactoryの注入は1回のみです。「A」の使用方法 非常に簡単で、すべてのクラスが注入され、メインでビルドされ、またはファクトリでインスタンス化されます。
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
クラスAを作成するたびに、Dまでのすべての依存関係が自動的に(遅延インスタンス化)注入され、DにはTimeFactoryが注入されます。大量のボイラープレートコードを削除する): "new / delete"を呼び出す必要はありません。アプリケーションロジックをグルーコードから分離できるため、これは非常に重要です。
Dは、Dのみが持つことができる情報を持つTimeオブジェクトを作成できます。
それは簡単です。TimeFactoryには「作成」メソッドがあり、別の署名「create(params)」を使用するだけで完了です。依存関係のないパラメーターは、多くの場合この方法で解決されます。また、追加のボイラープレートを追加するだけなので、「文字列」や「整数」などを注入する義務がなくなります。
誰が誰を作成しますか?IoCコンテナーはインスタンスとファクトリーを作成し、ファクトリーは残りを作成します(ファクトリーは任意のパラメーターで異なるオブジェクトを作成できるため、ファクトリーの状態は実際には必要ありません)。IoCコンテナーのラッパーとしてファクトリーを引き続き使用できます。一般的に、IoCコンテナーのインジェクションは非常に悪く、サービスロケーターの使用と同じです。一部の人々は、IoCコンテナーをファクトリでラップすることで問題を解決しました(これは厳密には必要ではありませんが、コンテナーによって階層が解決され、すべての工場の保守がさらに容易になるという利点があります)。
//factory method
std::unique_ptr<myType> create(params){
auto istance = ioc->build<myType>(); //this code's agnostic to "myType" hierarchy
istance->setParams(params); //the customization you needed
return std::move(istance);
}
また、依存関係の注入を乱用しないでください。単純型はクラスのメンバーまたはローカルスコープの変数になります。これは当たり前のように思えますが、それを許可するDIフレームワークがあったからといって、人々が "std :: vector"を注入しているのを見ました。デメテルの法則を常に覚えておいてください:「本当に必要なものだけを注入してください」