依存性注入を使用するときに、インターフェースと具象クラスの間に1対1の関係があることで罪を犯してきました。インターフェイスにメソッドを追加する必要がある場合、インターフェイスを実装するすべてのクラスを壊してしまいます。
ILogger
これは単純な例ですが、クラスの1つにを注入する必要があると仮定しましょう。
public interface ILogger
{
void Info(string message);
}
public class Logger : ILogger
{
public void Info(string message) { }
}
このような1対1の関係を持つことは、コードの臭いのように感じます。実装は1つしかないのでInfo
、単一のクラス専用のインターフェイスを作成する代わりに、クラスを作成してメソッドを仮想としてマークし、テストでオーバーライドする場合、潜在的な問題はありますか?
public class Logger
{
public virtual void Info(string message)
{
// Log to file
}
}
別の実装が必要な場合は、Info
メソッドをオーバーライドできます。
public class SqlLogger : Logger
{
public override void Info(string message)
{
// Log to SQL
}
}
これらの各クラスに、リークのある抽象化を作成する特定のプロパティまたはメソッドがある場合、基本クラスを抽出できます。
public class Logger
{
public virtual void Info(string message)
{
throw new NotImplementedException();
}
}
public class SqlLogger : Logger
{
public override void Info(string message) { }
}
public class FileLogger : Logger
{
public override void Info(string message) { }
}
基本クラスを抽象としてマークしなかった理由は、別のメソッドを追加したい場合でも、既存の実装を壊さないためです。たとえば、メソッドFileLogger
が必要な場合は、既存のを壊さずDebug
に基本クラスを更新できます。Logger
SqlLogger
public class Logger
{
public virtual void Info(string message)
{
throw new NotImplementedException();
}
public virtual void Debug(string message)
{
throw new NotImplementedException();
}
}
public class SqlLogger : Logger
{
public override void Info(string message) { }
}
public class FileLogger : Logger
{
public override void Info(string message) { }
public override void Debug(string message) { }
}
繰り返しますが、これは単純な例ですが、いつインターフェイスを使用する必要がありますか?