39

このシナリオを考えてみましょう。ログに書き込む必要があるビジネス ロジックがいくつかあります。

interface ILogger
{
    void Log(string stuff);
}

interface IDependency
{
    string GetInfo();
}

class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)
    {
        _dependency = dependency;
    }

    public string DoSomething(string input)
    {
        // Process input
        var info = _dependency.GetInfo();
        var intermediateResult = PerformInterestingStuff(input, info);

        if (intermediateResult== "SomethingWeNeedToLog")
        {
            // How do I get to the ILogger-interface?
        }

        var result = PerformSomethingElse(intermediateResult);

        return result;
    }
}

ILogger インターフェイスはどのように取得しますか? 主な可能性は 2 つあります。

  1. コンストラクターで依存性注入を使用して渡します。
  2. シングルトン Service Locator を介して取得します。

あなたはどちらの方法を好みますか、またその理由は何ですか? それとももっと良いパターンがありますか?

更新: すべてのメソッド呼び出しをログに記録する必要はないことに注意してください。メソッド内で発生する可能性がある、または発生しない可能性があるいくつかの (まれな) イベントのみをログに記録したいと考えています。

4

9 に答える 9

18

私は個人的に両方の混合を行います。

ここに私の慣例があります:

  • 静的コンテキストから- サービスの場所
  • インスタンス コンテキストから- 依存性注入

これにより、テスト容易性の適切なバランスが得られると思います。Service Location を使用するクラスに対してテストをセットアップするのは、DI を使用するよりも少し難しいと思います。これが、Service Location がルールではなく例外になる理由です。ただし、私はその使用法に一貫性があるため、どのタイプのテストを作成する必要があるかを思い出すのは難しくありません。

DI がコンストラクターを乱雑にする傾向があるという懸念を提起する人もいます。これは問題ではないと思いますが、このように感じる場合は、DI を使用する代わりにコンストラクターのパラメーターを使用しない方法がいくつかあります。Ninject の DI メソッドのリストは次のとおりです: http://ninject.codeplex.com/wikipage?title=Injection%20Patterns

Inversion of Control コンテナーのほとんどは、Ninject と同じ機能を備えていることがわかります。最も簡潔なサンプルがあるため、Ninject を表示することにしました。

うまくいけば、これは役に立ちます。

編集:明確にするために、私は Unity とCommon Service Locatorを使用しています。DI 用の Unity コンテナーのシングルトン インスタンスがあり、IServiceLocator の実装は、そのシングルトン Unity コンテナーの単なるラッパーです。このようにして、型マッピングを 2 回行う必要はありません。

また、トレース以外に AOP が特に役立つとは思いません。単純にわかりやすくするために、手動ログ記録の方が好きです。ほとんどの AOP ロギング フレームワークが両方の機能を備えていることは知っていますが、ほとんどの場合、前者 (AOP のパンとバター) は必要ありません。もちろん、これは単なる個人的な好みです。

于 2010-04-21T13:34:08.763 に答える
9

ロガーは明らかにビジネス ロジックが依存するサービスであるため、IDependency. コンストラクターにロガーを挿入します。

注:ログを挿入する方法として AOP が言及されていますが、この場合の解決策であることに同意しません。AOP は実行トレースには最適ですが、ビジネス ロジックの一部としてログを記録するためのソリューションにはなりません。

于 2010-04-21T13:50:49.943 に答える
5

私の小さな経験則:

  • クラス ライブラリにある場合は、コンストラクターの挿入またはプロパティの挿入のいずれかを null オブジェクト パターンと共に使用します。

  • メイン アプリケーションにある場合は、サービス ロケーター (またはシングルトン) を使用します。

これは、log4net を使用する場合に非常によく当てはまります。クラス ライブラリが存在しない可能性があるものにアクセスすることは望ましくありませんが、アプリケーション プログラムでは、ロガーが存在することがわかっており、log4net などのライブラリは service-location パターンに大きく基づいています。

私はロギングを、実際には DI を必要としない十分に静的なものと考える傾向があります。アプリケーションのロギングの実装を変更することはまずありません。特に、世の中に出回っているすべてのロギング フレームワークは信じられないほど柔軟で、簡単に拡張できるためです。クラス ライブラリでは、既に異なるロガーを使用している複数のアプリケーションでライブラリを使用する必要がある場合に、より重要になります。

もちろんYMMVです。DI は優れていますが、すべてを DI する必要があるわけではありません。

于 2010-04-21T13:51:13.277 に答える
5

おそらくこれは少し話題から外れますが、クラスの最初に入力するだけでよいのに、なぜロガーを注入する必要があるのでしょうか。

Logger logger = LogManager.GetLogger("MyClassName");

ロガーは、開発中およびその後のメンテナンス中に変更されません。最新のロガーは高度にカスタマイズ可能であるため、引数

テキストロガーをデータベースに置き換えたい場合はどうすればよいですか?

見逃されています。

依存性注入の使用を否定しているわけではありません。あなたの心に興味があるだけです。

于 2016-10-07T14:11:31.483 に答える
4

すべてのロギング/トレースをPostSharp(AOPフレームワーク)属性に切り替えました。メソッドのロギングを作成するために必要なのは、メソッドに属性を追加することだけです。

利点:

  • AOPの使いやすさ
  • 関心の分離_
  • コンパイル時に発生->パフォーマンスへの影響を最小限に抑える

これをチェックしてください。

于 2010-04-21T11:53:59.127 に答える
2

シングルトンサービスを希望します。

依存性注入はコンストラクターを混乱させます。

AOPを使用できるのであれば、それが最適です。

于 2010-04-21T11:53:00.737 に答える
2

LoggableBusinessObjectたとえば、コンストラクターでロガーを取る別の型を派生させることができます。これは、ロガーを使用するオブジェクトに対してのみロガーを渡すことを意味します。

public class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)   
    {   
        _dependency = dependency;   
    }   

    public virtual string DoSomething(string input)   
    {   
        // Process input   
        var info = _dependency.GetInfo();   
        var result = PerformInterestingStuff(input, info);   
        return result;   
    }   
}

public class LoggableBusinessObject : MyBusinessObject
{
    private ILogger _logger;

    public LoggableBusinessObject(ILogger logger, IDependency dependency)
        : base(dependency)
    {
        _logger = logger;
    }

    public override string DoSomething(string input)
    {
        string result = base.DoSomething(input);
        if (result == "SomethingWeNeedToLog")
        {
             _logger.Log(result);
        }
    }
}
于 2010-04-21T12:22:44.843 に答える
0

DIはここでうまく機能します。注目すべきもう1つのことはAOPです。

于 2010-04-21T11:52:34.933 に答える
0

これらのアプローチのどちらもお勧めしません。アスペクト指向プログラミングを使用することをお勧めします。ロギングはAOPの「HelloWorld」です。

于 2010-04-21T11:52:59.777 に答える