APIにクラスがあり、詳細を検証してログに記録することを目的とした静的メソッドがあります。 ILoggerインターフェイスを挿入する方法についてのガイダンスをお願いします。
public class ValidateDataInAPI
{
public static bool IsValid(string data)
{
//do something
If(error)
{
_logger.Error("Log error as implemented by caller");
}
}
}
私が正しく理解していれば、ILoggerのインスタンスを静的メソッドに挿入したいと思います。おそらくすでに理解しているように、依存性メソッドが静的である場合、依存性注入を「通常の方法」で利用することはできません。
ここで探しているのは サービスロケーターパターン です。
StructureMap IoCコンテナーを使用すると(ただし、実際には任意のコンテナーを使用できます)、それを配線するための構成は次のようになります。
For<ILogger>().Use<SomeLoggerImplementation>();
実装すると、呼び出しコードは次のようになります。
public class ValidateDataInAPI
{
private static ILogger Logger
{
// DependencyResolver could be any DI container here.
get { return DependencyResolver.Resolve<ILogger>(); }
}
public static bool IsValid(string data)
{
//do something
If(error)
{
Logger.Error("Log error as implemented by caller");
}
}
}
これはアンチパターンと見なすことができ、利便性だけでなく、明確な正当性がある場合にのみ使用する必要があることを指摘したいと思います。
依存性注入の全体的な考え方は、呼び出し元のコードのコンストラクターに依存性を注入して、クラスのすべての依存性を外部に公開することです。
これにより、コードの可読性が向上するだけでなく(内部に隠された「驚き」がない)、テスト性も向上します。ユニットテストプロジェクトでIoCコンテナを構成したくないですか?依存性注入を正しい方法で使用すると、この必要性がなくなり、コードを単体テストするときに作業が大幅に楽になります。
依存性注入の概念に精通していない場合は、 このリンク を使用して開始することができます。そこにはたくさんの情報があります。
依存性注入を使用すると、呼び出しコードは次のようになります。
public class ValidateDataInAPI : IValidateDataInAPI
{
private readonly ILogger _logger;
// Since the dependency on ILogger is now exposed through the class's constructor
// you can easily create a unit test for this class and inject a mock of ILogger.
// You will not need to configure your DI container to be able to unit test.
public ValidateDataInAPI(ILogger logger)
{
_logger = logger;
}
public bool IsValid(string data)
{
//do something
If(error)
{
_logger.Error("Log error as implemented by caller");
}
}
}
同様に、検証クラスにインターフェースを定義することで、その検証クラスをAPIクラスに挿入できます。
public interface IValidateDataInAPI
{
bool IsValid(string data);
}
Validatorクラスをモックできるようになりました。これにより、APIクラスをより簡単に単体テストできます。
そうは言っても、IsValidメソッドを静的に保つ必要がある場合は、サービスロケーターパターンがおそらく最適な方法です。