web-dev-qa-db-ja.com

Dependency Injectionを使用して構成コードをロジックコードから除外する方法

Settings(ApplicationSettingsBase)とDependency Injectionを使用して、すべての構成ファイルコードをロジックコードから除外するにはどうすればよいですか?

構成とは、お客様固有の構成ファイルを意味します。

本当に必要なときに毎回構成クラスを注入する必要がありますか、それとも別のパターンがありますか?

サンプルコードを入手していただければ幸いです。

サンプル:

静的構成:

public static class StaticConfiguration
{
    public static bool ShouldApplySpecialLogic { get; set; }
    public static string SupportedFileMask { get; set; }
}

public class ConsumerOfStaticConfiguration
{
    public void Process()
    {
        if (StaticConfiguration.ShouldApplySpecialLogic)
        {
            var strings = StaticConfiguration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}

非静的構成:

public interface IConfiguration
{
    bool ShouldApplySpecialLogic { get; set; }
    string SupportedFileMask { get; set; }
}

public class Configuration : IConfiguration
{
    public bool ShouldApplySpecialLogic { get; set; }
    public string SupportedFileMask { get; set; }
}

public class Consumer
{
    private readonly IConfiguration _configuration;

    public Consumer(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Process()
    {
        if (_configuration.ShouldApplySpecialLogic)
        {
            var strings = _configuration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}

非静的構成の静的コンテキスト:

public static class Context
{
    public static IConfiguration Configuration { get; set; }
}

public class ConsumerOfStaticContext
{
    public void Process()
    {
        if (Context.Configuration.ShouldApplySpecialLogic)
        {
            var strings = Context.Configuration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}
36
Rookian

認識すべき重要な部分は、構成は、アプリケーションの動作を駆動するいくつかの値のソースのうちの1つにすぎないということです。

2番目のオプション(非静的構成)は、完全にコンシューマーを構成値のソースから切り離すを可能にするため、最適です。ただし、構成設定は通常Value Objectsとしてモデル化するのが最も良いため、インターフェースは必要ありません。

それでも設定ファイルから値を読みたい場合は、アプリケーションの Composition Root から行うことができます。 StructureMapでは、次のようになります。

var config = (MyConfigurationSection)ConfigurationManager.GetSection("myConfig");

container.Configure(r => r
    .For<Consumer>()
    .Ctor<MyConfigurationSection>()
    .Is(config));
26
Mark Seemann

構成クラスは理解を減らし、コンシューマの結合を増やします。これは、クラスに必要な1つまたは2つに関連しない設定が多数ある可能性があるためです。ただし、依存関係を満たすために、IConfigurationの実装は、すべてのアクセサーに値を提供する必要があります。無関係なもの。

また、クラスとインフラストラクチャの知識を結び付けます。「これらの値は一緒に構成されます」などの詳細がアプリケーション構成からクラスに流出し、無関係なシステムへの変更によって影響を受ける表面領域が増加します。

構成値を共有する最も複雑で最も柔軟な方法は、値自体のコンストラクター注入を使用して、インフラストラクチャの懸念を外部化することです。ただし、別の回答のコメントでは、コンストラクターパラメーターがたくさんあるのが怖いことを示していますが、これは妥当な懸念事項です。

認識すべき重要な点は、プリミティブと複雑な依存関係に違いがないということです。整数に依存するかインターフェイスに依存するかに関係なく、それらは両方ともあなたが知っていることですわからないので教えてください。この観点から、IConfigurationIDependenciesと同じくらい意味があります。大きなコンストラクターは、パラメーターがプリミティブであるか複雑であるかに関係なく、クラスの責任が大きすぎることを示しています。

intstringおよびboolを他の依存関係と同様に扱うことを検討してください。これにより、クラスがより明確になり、焦点が絞られ、変更に対する耐性が高まり、単体テストが容易になります。

29
Bryan Watts

1つの方法は、投稿するように構成インターフェースを挿入することです。他にいくつかの方法があります。

セッターの公開

class Consumer
{
    public bool ShouldApplySpecialLogic { get; set; }

    ...
}

構成ルートでは、構成ファイルを読み取るか、ハードコードすることができます。 Autofacの例:

builder.RegisterType<Consumer>().AsSelf()
    .OnActivated(e => e.Instance.ShouldApplySpecialLogic = true);

これはおそらく、適切なデフォルトがある場合にのみお勧めします

コンストラクター注入

public class Server
{
    public Server(int portToListenOn) { ... }
}

構成ルート:

builder.Register(c => new Server(12345)).AsSelf();
2
default.kramer

私のアプリケーションでは、IoCを使用して上記で行ったことを行います。つまり、IoCコンテナー(StructureMapも)を使用してIApplicationSettingsをクラスに挿入します。

たとえば、ASP.NET MVC3プロジェクトでは、次のようになります。

Public Class MyController
    Inherits Controller

    ...
    Private ReadOnly mApplicationSettings As IApplicationSettings

    Public Sub New(..., applicationSettings As IApplicationSettings)
        ...
        Me.mApplicationSettings = applicationSettings
    End Sub

    Public Function SomeAction(custId As Guid) As ActionResult
         ...

         ' Look up setting for custId
         ' If not found fall back on default like
         viewModel.SomeProperty = Me.mApplicationSettings.SomeDefaultValue

         Return View("...", viewModel)
    End Function
End Class

私のIApplicationSettingsの実装は、アプリの.configファイルからほとんどのものを引き出し、ハードコーディングされた値もいくつかあります。

私の例は、ロジックフロー制御ではありませんでしたが(例のように)、実際の場合と同じように機能しました。

これを行うもう1つの方法は、サービスロケータタイプのパターンを実行することです。このパターンでは、依存性注入コンテナに構成クラスのインスタンスを即座に取得するように要求します。 Service-Location 一般にアンチパターンと見なされます ですが、まだ使用されている可能性があります。

0
ckittel