3

これはもっと理論的な質問です。ロギングは、ロギングを主な目的としないクラス内に存在する必要がありますか?

これは、数値の計算を実行するものすべての簡単なインターフェイスです。

public interface ICalculation { 
    public int calculate(int number); 
}

これは、計算を実行し、いくつかのロギングを行うICalculationインターフェースの実装です。これは非常に実用的なアプローチだと思います。コンストラクターが計算のドメインで通常は見られないものを受け入れることを除けば、インラインロギングは間違いなく邪魔になりません。

public class ReallyIntenseCalculation : ICalculation {
    private readonly ILogger log;

    public ReallyIntenseCalculation() : this(new DefaultLogger()) {
    }

    public ReallyIntenseCalculation(ILogger log) {
        this.log = log;
        log.Debug("Instantiated a ReallyIntenseCalculation.");
    }

    public int calculate(int number) {
        log.Debug("Some debug logging.")
        var answer = DoTheDirtyWork(number);
        log.Info(number + " resulted in " + answer);
        return answer;
    }

    private int DoTheDirtyWork(int number) {
        // crazy math happens here
        log.Debug("A little bit of granular logging sprinkled in here.");
    }
}

ReallyIntenseCalculationからすべてのロギングコードを削除した後、コードには明確な単一責任のように見えるものが含まれるようになりました。

public class ReallyIntenseCalculation : ICalculation {

    public int calculate(int number) {
        return DoTheDirtyWork(number);
    }

    private int DoTheDirtyWork(int number) {
        // crazy math happens here
    }
}

さて、ReallyIntenseCalculationの内部ログ機能を削除しました。その機能を外部化する方法をどのように見つけることができますか。デコレータパターンを入力します。

ICalculationを装飾するクラスを作成することで、ログをミックスに戻すことができますが、そうすると、ReallyIntenseCalculationのプライベートメソッド内で行われていたより詳細なログの一部が損なわれます。

public class CalculationLoggingDecorator : ICalculation {
    private readonly ICalculation calculation;
    private readonly ILogger log;

    public CalculationLoggingDecorator(ICalculation calculation, ILogger log) {
        this.calculation = calculation;
        this.log = log;
        log.Debug("Instantiated a CalculationLoggingDecorator using " + calculation.ToString());
    }

    public int calculate(int number) {
        log.Debug("Some debug logging.")
        var answer = calculation.calculate(number);
        log.Info(number + " resulted in " + answer);
    }
}

ロギングデコレータを持つことのその他の考えられる長所と短所は何ですか?

4

3 に答える 3

3

議論の余地があると思います。ロギングがその単一責任の一部である場合があります。

とはいえ、アスペクト指向プログラミングが扱う横断的関心事の観点から考えていると思います。実際、ロギングコードはAOPの標準的な例です。アスペクト#のようなAOPフレームワークを検討することをお勧めします。

このようなことを行うことの利点は、もちろん、分解可能性、再利用、および関心の分離です。

于 2009-11-25T17:42:51.137 に答える
3

これは分野横断的な懸念事項であるというジェイソンの意見に同意します。

関数は実際には 1 つの関数のみを実行する必要があります。これにより、コードが読みやすくなり、テストが容易になります。たとえば、ログ ファイルがいっぱいで単体テストが失敗した場合、メソッド内でログ記録をテストしていないため、混乱を招きます。

ここでは AOP が最良の選択であり、.NET の場合は PostSharp が最良のオプションである可能性があります。

AOP が適切なオプションでない場合は、DI を使用することをお勧めします。また、フローをテストするために、ログを記録するクラスのバージョンを挿入できますが、これを行う場合は、挿入されたクラスがロギングを行うだけで、ロギングを持たない同じ関数を呼び出すため、クラスにラッパーを配置しています。

public class ReallyIntenseCalculation : ICalculation {

    public int calculate(int number) {
        return DoTheDirtyWork(number);
    }

    private int DoTheDirtyWork(int number) {
        // crazy math happens here
    }
}

public class CalculationLoggingDecorator : ICalculation {
    ICalculation calculation;
    ILogger log;
    public CalculationLogging() {
        this.calculation = new ReallyIntenseCalculation() ;
        this.log = SomeLogger(...);
        log.Debug("Initialized a CalculationLoggingDecorator using " + calculation.ToString());
    }

    public int calculate(int number) {
        log.Debug("Some debug logging.")
        var answer = calculation.calculate(number);
        log.Info(number + " resulted in " + answer);
    }
}

これはデコレータに似ていますが、ロギング バージョンを非ロギング バージョンに交換すると、余分なコードがすべて削除され、ロギング バージョンをテストすることで、それReallyIntenseCalculationが使用されていることと、メソッドが 1 回だけ定義されていることが保証されます。 .

これはより多くの作業であり、AOP が望ましいですが、DI が代わりになる場合があります。

更新:コメントに基づく。

このインターフェースを拡張する複数のクラスがある場合、クラスが急増する可能性がありますが、そのように設計してください。

AOP は最良のアプローチですが、一部の企業にとっては、この概念は DI よりも売りにくいものです。

実装ごとに 2 つのクラスになる可能性がありますが、ログ情報はこれらの他のクラスから引き続き削除され、各クラスが DI を介して挿入されるため、2 つの app.config ファイルを作成でき、1 つにはすべてのログ クラスが設定されます。もう 1 つは生産用で、生活を簡素化します。ただし、2 番目のクラスにはロギングとセットアップ情報が含まれているだけなので、余分な作業はそれほど多くないと思いますが、ロギングの細かい粒度が失われています。

于 2009-11-25T18:27:14.247 に答える
0

ロガーはいくつありますか?LoggerシングルトンまたはLoggerファクトリメソッドを使用して、計算機のコンストラクターの実装でロガーインスタンスをプライベートにインスタンス化するようにします(ログを記録するかどうかは、計算機のパブリックAPIの一部ではなく、計算機の実装の一部です)。

于 2009-11-25T17:47:26.823 に答える