2

最近、DI、SL アンチパターン、AOP など、アプリケーションの設計パターンに関する多くの記事を読んでいました。この理由 - 私は設計の妥協点を見つけたいと思っています: 疎結合で、クリーンで、使いやすいです。DI は、コンストラクターまたはプロパティの汚染につながるクロスカッティングとオプションの依存関係という 1 つの問題を除いて、ほぼ解決策のようです。だから私はこれに対する私自身の解決策を持ってきて、あなたがそれについてどう思うか知りたい.

マーク シーマン (DI 本の著者であり、有名な「SL はアンチ パターン」という声明の著者) は、その本の中で、アンビエント コンテキストと呼ばれるパターンについて言及しています。あまり好きではないと彼は言いますが、このパターンは依然として興味深いものです。スコープがあり、デフォルト値を提供するため、null をチェックする必要がないことを除けば、古き良きシングルトンのようなものです。それには 1 つの欠陥があります - それはありませんし、そのスコープと自分自身を処分する方法について知ることができません。

では、ここで Service Locator を適用してみませんか? Ambient Context オブジェクトのスコーピングと破棄の両方の問題を解決できます。アンチパターンだと言う前に: コントラクトを隠すときです。しかし、私たちの場合、OPTIONAL コントラクトを非表示にしているので、IMO はそれほど悪くありません。

ここに私が何を意味するかを示すいくつかのコードがあります:

public interface ILogger
{
    void Log(String text);
}

public interface ISomeRepository
{
    // skipped
}


public class NullLogger : ILogger
{
    #region ILogger Members

    public void Log(string text)
    {
        // do nothing
    }

    #endregion
}

public class LoggerContext
{
    public static ILogger Current
    {
        get
        {
            if(ServiceLocator.Current == null)
            {
                return new NullLogger();
            }
            var instance = ServiceLocator.Current.GetInstance<ILogger>();
            if (instance == null)
            {
                instance = new NullLogger();
            }
            return instance;
        }
    }
}

public class SomeService(ISomeRepository repository)
{
    public void DoSomething()
    {
        LoggerContext.Current.Log("Log something");
    }
}

編集:具体的な質問をしないことは、スタックオーバーフローの設計と矛盾することを認識しています。したがって、この設計が悪い理由を最もよく説明している投稿を回答としてマークし、より良い解決策(または追加?)を提供します。しかし、AOP を提案しないでください。それは良いことですが、コード内で本当に何かをしたい場合には解決策ではありません。

編集 2: ServiceLocator.Current is null のチェックを追加しました。SL が構成されていない場合に既定の設定で動作するようにすることが、私のコードで意図していることです。

4

2 に答える 2

3

あなたが提案するようなアンビエントコンテキストの問題は、テストがはるかに難しくなることです。いくつかの理由から:

  1. 単体テストの実行中は、常に有効なインスタンスが「ServiceLocator.Current」に登録されている必要があります。しかし、それだけでなく、有効な で登録する必要がありますILogger
  2. テストで偽のロガー (単純な NullLogger 以外) を使用する必要がある場合、これにフックする方法がないため、コンテナーを構成する必要がありますが、コンテナーはシングルトンであるため、他のすべてのテストは使用しますその同じロガー。
  3. 単体テストが並列で実行されている場合 (MSTest が既定で実行しているように) に機能するソリューションを作成することは、簡単ではありません (時間の無駄です)。

これらの問題はすべてILogger、アンビエント コンテキストを使用する代わりに、それを必要とするサービスにインスタンスを注入するだけで解決できます。

また、システム内の多くのクラスがその抽象化に依存している場合は、ログを取りすぎていないかをILogger真剣に自問する必要があります。

また、依存関係がオプションであることはほとんどないことに注意してください。

于 2012-05-21T10:38:00.267 に答える
3

手作りのデコレーターまたは何らかのインターセプト ( Castle DynamicProxyUnity のインターセプション拡張機能など) を使用して、分野横断的な懸念を追加できます。

ILoggerそのため、コア ビジネス クラスに注入する必要はまったくありません。

于 2012-05-21T10:48:38.093 に答える