私は オープン/クローズの原則を説明するこのコード例 を見つけました。
原則を適用する前のコード:
_public class Logger
{
public void Log(string message, LogType logType)
{
switch (logType)
{
case LogType.Console:
Console.WriteLine(message);
break;
case LogType.File:
// Code to send message to printer
break;
}
}
}
public enum LogType
{
Console,
File
}
_
そしてリファクタリングされたコード:
_public class Logger
{
IMessageLogger _messageLogger;
public Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
public interface IMessageLogger
{
void Log(string message);
}
public class ConsoleLogger : IMessageLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
public class PrinterLogger : IMessageLogger
{
public void Log(string message)
{
// Code to send message to printer
}
}
_
Logger
クラスをプライベートIMessageLogger
インスタンスで保持する理由を教えてください。私は単にそれを避けるでしょう:
_public interface ILogger
{
public void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
public class PrinterLogger : ILogger
{
public void Log(string message)
{
// Code to send message to printer
}
}
_
私が考えることができる唯一の理由は、Logger
クラスを使用した提案された解決策では、このクラスをクライアントコードで引き続き参照できますが、すべてのLog(msg)
呼び出しを変更して削除する必要があるためですLogType
引数。
新しいLogger
クラスにそれ以上のコードが含まれていない限り、この例は不自然に思われます。しかし、具体的なIMessageLogger
から独立したコードを使用して、クラスがさらにいくつかのメソッドを取得するとします。次に例を示します。
public class Logger
{
// ...
public void LogFormatted(string formatString, string[] parameters )
{
string message = string.Format(formatString, parameters);
_messageLogger.Log(message);
}
}
次に、プログラムをDRYに保ちながら、この追加コードを1か所に実装できるクラスを用意することは理にかなっています。
ここで見るパターンは、古典的な「戦略」パターンです。これは、IMessageLogger
をILoggingStrategy
に、派生クラスをConsoleLoggingStrategy
およびPrinterLoggingStrategy
に名前を変更すると明らかになります。
これはOCPのデモンストレーションでもあります。これは、Logger
とIMessageLogger
(またはILoggingStrategy
)を再利用可能なライブラリ(またはフレームワーク)に入れ、新しいIMessageLogger
の派生は、そのlibを使用するアプリケーションコードに常駐できます。したがって、たとえばLogger
のような新しい戦略のようなものを追加したい場合、CloudLoggingStrategy
classを含むlibを変更する必要はありません。ただし、元のコードでは、Logger
クラスを含むlibをそのような拡張機能に合わせて変更する必要があります。