私のソフトウェアは、1 つまたは複数のデバイスを制御します。プログラム フローは、使用可能なすべてのインターフェイスでデバイスを検索し、IDevice
見つかった各デバイスのタイプのオブジェクトをインスタンス化するようなものです。ここで言うと、これらのオブジェクトはすべて実行時に設定する必要があります。
Autofac を使用して依存関係の逆転 (DI) を取得するには、最初にすべてを設定する必要があります。実行時に何かを使用する場合は、「ファクトリ」を使用します。それでは、例を掘り下げてみましょう。
プログラムの開始は次のようになります。
class Program
{
static void Main(string[] args)
{
var container = ContainerConfig.Configure();
using (var scope = container.BeginLifetimeScope())
{
var app = scope.Resolve<IApplication>();
app.Run();
}
}
}
「アプリケーション」が解決されるとすぐに、開始時にわかっているすべての設定が行われます。その後、アプリケーションが開始され ( app.Run()
)、デバイスが検索され、見つかったすべてのデバイスのリストが設定されます。デバイスをセットアップするには、基本的に(そしてここに問題があります)「デバイス」を介してインスタンス化される「クラスごとに1つ」という一連の「ファクトリ」が必要です。
class Application : IApplication
{
readonly Device.Factory _deviceFactory;
readonly Log.Factory _logFactory;
readonly DateTime.Factory _dateTimeFactory;
readonly Incident.Factory _incidentFactory;
public Application(Device.Factory deviceFactory, Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory)
{
_deviceFactory = deviceFactory;
_logFactory = logFactory;
_dateTimeFactory = dateTimeFactory;
_incidentFactory = incidentFactory;
}
public void Run()
{
List<string> listOfDeviceIds = SearchAllDevices();
List<IDevice> listOfDevices = new List<IDevice>;
foreach(string deviceId in listOfDeviceIds)
{
listOfDevices.Add(deviceFactory(_logFactory, _dateTimeFactory, incidentFactory);
}
}
}
「デバイス」には、何かを追跡するロガーが含まれています。この例では、時間とインシデントを記録します。そのため、新しいログが設定されるとすぐに、いくつかのファクトリを注入する必要があります。
public class Device : IDevice
{
public delegate Device Factory(Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory);
readonly DateTime.Factory _dateTimeFactory;
readonly Incident.Factory _incidentFactory;
readonly Log.Factory _logFactory;
List<Log> ListOfLogs = new List<Log>();
public Device(Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory)
{
_dateTimeFactory = dateTimeFactory;
_incidentFactory = incidentFactory;
_logFactory = logFactory;
}
public AddLog()
{
ListOfLogs().Add(_logFactory(_dateTimeFactory(), _incidentFactory() ));
}
}
public class Log()
{
public delegate Log Factory();
public IDateTime DateTime() { get; }
public IIncident Incident() { get; }
public Log(IDateTime dateTime, IIncident incident)
{
DateTime = dateTime;
Indicent = incident;
}
}
public DateTime : IDateTime
{
public delegate DateTime Factory();
//...
}
public Indicent : IIndicent
{
public delegate Indicent Factory();
//...
}
さて、これは実際にはもっと多くのものを統合するデバイス クラスのほんの一部です。そして、それは今再び乱雑になっているということです。
「デバイス」をインスタンス化するときに設定される約 30 個以上のサブクラスがあります。したがって、それらは実行時に設定されるため、「デバイス」のコンストラクターを介して提供する必要がある「ファクトリー」がすべて必要になります。要点がわかると思います。
どのように対処しますか?それともまた間違った道を進んでいますか?すべてへの依存を逆転させようとして、何かを誤解していませんか?
もう 1 つのポイントは、インターフェイスと autofac がキーワードである、ストーリー全体がテスト可能になろうとしているということです。しかし、ファクトリを使用するときは常にそれ自体のクラスを使用する必要があり、そのインターフェイスを参照として使用することはできません。その時点で DI は実装されていません。... ?
public class MyClass : IMyClass
{
public delegate MyClass Factory();
// ...
}
MyClass.Factory
それを使用すると、代わりにIMyClass.Factory
次のものが必要になります。
class Main()
{
MyClass.Factory _myClassFactory;
Main(MyClass.Factory myClassFactory)
{
_myClassFactory = myClassFactory;
}
foo ()
{
IMyClass myInstance = myClassFactory();
}
}