警告、長い投稿が先です。
私は最近これについてよく考えていて、ここで満足のいく解決策を見つけるのに苦労しています. 例では C# と autofac を使用します。
問題
IoC は、ステートレス サービスの大きなツリーを構築するのに最適です。サービスを解決し、メソッド呼び出しにのみデータを渡します。偉大な。
場合によっては、データ パラメーターをサービスのコンストラクターに渡したいことがあります。それが工場の目的です。サービスを解決する代わりに、そのファクトリを解決し、パラメーターを指定して create メソッドを呼び出してサービスを取得します。もう少し作業がありますが、OKです。
時々、サービスを特定のスコープ内の同じインスタンスに解決したいと考えています。AutofacInstancePerLifeTimeScope()は非常に便利な機能を提供します。これにより、実行サブツリー内の同じインスタンスに常に解決できます。良い。
また、両方のアプローチを組み合わせたい場合もあります。コンストラクターにデータパラメーターが必要で、インスタンスのスコープが設定されています。これを達成するための満足のいく方法は見つかりませんでした。
ソリューション
1.メソッドの初期化
データをコンストラクターに渡す代わりに、Initializeメソッドに渡すだけです。
インターフェース:
interface IMyService
{
void Initialize(Data data);
void DoStuff();
}
クラス:
class MyService : IMyService
{
private Data mData;
public void Initialize(Data data)
{
mData = data;
}
public void DoStuff()
{
//...
}
}
登録:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
使用法:
var myService = context.Resolve<IMyService>();
myService.Init(data);
// somewhere else
var myService = context.Resolve<IMyService>();
初めてサービスを解決して Initialize を呼び出した後、同じコンテキスト内で問題なく解決し、初期化された同じインスタンスを取得できます。Initialize呼び出す前に使用できないオブジェクトがあるという事実は好きではありません。Initialize() を呼び出す前に、インスタンスが解決されて別の場所で使用される危険性があります。
2.ホルダーパターン
これは、データ オブジェクトへの参照を保持するパターンであり、データ オブジェクト自体を注入する代わりに、ホルダー オブジェクトを注入します。
インターフェース:
interface IMyService
{
void DoStuff();
}
クラス:
class MyService : IMyService
{
private Data mData;
public MyService(IDataHolder dataHolder)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
登録:
builder.RegisterType<MyService>().As<IMyService>();
builder.RegisterType<DataHolder>().As<IDataHolder>().InstancePerLifetimeScope();
使用法:
var holder = context.Resolve<IDataHolder>();
holder.Data = data;
// somewhere else
var myService = context.Resolve<IMyService>();
インスタンスを保持する責任を別のクラスに移したので、これは少し良くなりました。他のサービスでもホルダーを使用できるようになりました。その他の利点は、必要に応じてホルダー内のデータをホットスワップできることです。コードが難読化され、テスト中にモックしなければならない別のインターフェイスが追加されるという事実は好きではありません。
3.コンテナにインスタンスを保持させる
インターフェース:
interface IMyService
{
void DoStuff();
}
クラス:
class MyService : IMyService
{
private Data mData;
public MyService(Data data)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
登録:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
使用法:
var myServiceFactory = context.Resolve<Func<Data, IMyService>>();
myServiceFactory(data);
// somewhere else
var myService = context.Resolve<IMyService>();
それは正しい。autofac が保存してくれるので、ファクトリ コールの結果はどこにも保存しません。これは、コードを読む人にとってはかなり驚くべきことです。autofac がこのように使用されることを意図していたのかどうかはわかりません。これの良いところは、インスタンスを保持するための追加の初期化メソッドも追加のクラスも必要ないことです。
質問
これについてどう思いますか?実行時のデータ パラメーターと有効期間のスコープを使用して状況をどのように処理しますか? より良いアプローチがありませんか?