Open Closedの原則に違反しないように、これが実際にどのように行われるかを理解しようとしています。
URL を受け取り、html を文字列として返すファイルをダウンロードする 1 つの関数を持つ HttpFileDownloader というクラスがあるとします。このクラスは、関数を 1 つだけ持つ IFileDownloader インターフェイスを実装します。したがって、コード全体で IFileDownloader インターフェイスへの参照があり、IFileDownloader が解決されるたびに HttpFileDownloader のインスタンスを返す IoC コンテナーがあります。
その後、しばらく使用すると、その時点でサーバーがビジー状態になり、例外がスローされることがあることが明らかになります。これを回避するために、例外が発生した場合は 3 回自動再試行し、各再試行の間に 5 秒待機することにしました。
そこで、最大 3 ループの for ループで HttpFileDownloader を使用し、各ループ間で 5 秒間待機する 1 つの関数を持つ HttpFileDownloaderRetrier を作成します。HttpFileDownloadRetrier の「再試行」機能と「待機」機能をテストできるように、HttpFileDownloaderRetrier コンストラクターに IFileDownloader を取得させることで、HttpFileDownloader 依存関係を注入しました。
したがって、IFileDownloader のすべての解決で HttpFileDownloaderRetrier が返されるようにします。しかし、そうすると、HttpFileDownloadRetrier の IFileDownloader 依存関係は、HttpFileDownloader ではなく、それ自体のインスタンスを取得します。
したがって、IFileDownloaderNoRetry という名前の HttpFileDownloader 用の新しいインターフェイスを作成し、HttpFileDownloader を変更してそれを実装できることがわかります。しかし、それは、Open Closed に違反する HttpFileDownloader を変更していることを意味します。
または、IFileDownloaderRetrier という名前の HttpFileDownloaderRetrier 用の新しいインターフェイスを実装してから、IFileDownloader の代わりにそれを参照するように他のすべてのコードを変更することもできます。しかし、繰り返しになりますが、他のすべてのコードで Open Closed に違反しています。
それで、私はここで何が欠けていますか?既存のコードを変更せずに、既存の実装 (ダウンロード) を実装の新しいレイヤー (再試行と待機) でラップするにはどうすればよいですか?
それが役立つ場合のコードは次のとおりです。
public interface IFileDownloader
{
string Download(string url);
}
public class HttpFileDownloader : IFileDownloader
{
public string Download(string url)
{
//Cut for brevity - downloads file here returns as string
return html;
}
}
public class HttpFileDownloaderRetrier : IFileDownloader
{
IFileDownloader fileDownloader;
public HttpFileDownloaderRetrier(IFileDownloader fileDownloader)
{
this.fileDownloader = fileDownloader;
}
public string Download(string url)
{
Exception lastException = null;
//try 3 shots of pulling a bad URL. And wait 5 seconds after each failed attempt.
for (int i = 0; i < 3; i++)
{
try { fileDownloader.Download(url); }
catch (Exception ex) { lastException = ex; }
Utilities.WaitForXSeconds(5);
}
throw lastException;
}
}