10

私はSimple Injectorを使用していますが、おそらく私が必要としているのは概念的な答えです。

アプリケーション設定とのインターフェースがあるとします。

public interface IApplicationSettings
{
    bool EnableLogging { get; }
    bool CopyLocal { get; }
    string ServerName { get; }
}

次に、通常、IApplicationSettings を実装するクラスを持ち、指定されたソースから各フィールドを取得します。たとえば、次のようになります。

public class AppConfigSettings : IApplicationSettings
{
    private bool? enableLogging;
    public bool EnableLogging
    {
        get
        {
            if (enableLogging == null)
            {
                enableLogging = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableLogging"];
            }
            return enableLogging;
        }
    }
    ...
}

でも!EnableLoggingapp.config、CopyLocalデータベース、およびServerName現在のコンピューター名を取得する別の実装から取得したいとします。組み合わせごとに 1 つずつ、9 つの実装を作成することなく、アプリの構成をミックスマッチできるようにしたいと考えています。

インターフェイスはインジェクター (コンテナー) によって解決されるため、パラメーターを渡すことができないと想定しています。

私は最初にこれを考えました:

public interface IApplicationSettings<TEnableLogging,TCopyLocal,TServerName>
where TEnableLogging : IGetValue<bool>
where TCopyLocal : IGetValue<bool>
where TServerName : IGetValue<string>
{
    TEnableLogging EnableLog{get;}
    TCopyLocal CopyLocal{get;}
    TServerName ServerName{get;}
}

public class ApplicationSettings<TEnableLogging,TCopyLocal,TServerName>
{
    private bool? enableLogging;
    public bool EnableLogging
    {
        get
        {
            if (enableLogging == null)
            {
                enableLogging = Container.GetInstance<TEnableLogging>().Value
            }
            return enableLogging;
        }
    }
}

TEnableLoggingただし、これには主な問題が 1 つあります。 ( である)のインスタンスを作成する方法を知るにはどうすればよいIGetValue<bool>ですか? IGetValue<bool>ああ、具象クラスによって実装される Value プロパティを持つインターフェースであると仮定します。ただし、具体的なクラスには、いくつかの詳細 (app.config のキーの名前など) が必要な場合とそうでない場合があります (単に常に true を返したい場合があります)。

私は依存性注入に比較的慣れていないので、間違った方法で考えているかもしれません。これを達成する方法について誰かアイデアがありますか?

(別の DI ライブラリを使用して答えることができますが、気にしません。その概念をつかむ必要があると思います。)

4

1 に答える 1

17

あなたは間違いなくここで間違った方向に向かっています。

数年前、あなたの によく似たインターフェースを含むアプリケーションを構築しましたIApplicationSettings。という名前を付けたと思いますIApplicationConfigurationが、すべてのアプリケーションの構成値も含まれていました。

最初はアプリケーションをテスト可能にするのに役立ちましたが、しばらくすると設計が邪魔になり始めました。多くの実装がそのインターフェイスに依存していましたが、実装とテスト バージョンに伴い、多くの変更が加えられました。

あなたと同じように、遅延読み込みを実装しましたが、これにはひどい欠点がありました。構成値の 1 つが欠落している場合、その値が初めて呼び出されたときにのみ欠落していることがわかりました。これにより、検証が困難な構成になりました。

問題の核心が何であるかを見つけるために、リファクタリングを数回繰り返しました。大きなインターフェースは問題です。私のクラスはインターフェイス分離の原則IApplicationConfigurationに違反していたため、保守性が低下していました。

結局、このインターフェースはまったく役に立たないことがわかりました。ISPに違反するだけでなく、これらの構成値は実装の詳細を記述しているため、アプリケーション全体を抽象化するのではなく、必要な構成値と必要な値のみを各実装に直接提供する方がはるかに優れています.

これを行う場合、最も簡単な方法は、それらの値をパラメーター オブジェクトにラップし (値が 1 つだけであっても)、それらの構成値をコンストラクターに挿入することです。ここにecampleがあります:

var enableLogging =
    Convert.ToBoolean(ConfigurationManager.AppSettings["EnableLogging"]);

container.RegisterSingleton(new LoggerSettings(loggingEnabled: enableLogging));

この場合、LoggerSettingsは に固有の構成オブジェクトLoggerであり、コンストラクターの引数としてそれを必要とします。

これを行う場合、enableLogging値は構成ファイルから 1 回だけ読み取られ、アプリケーションの起動時に読み取られます。これにより高速になり、値が欠落している場合にアプリケーションの起動時に失敗します。

于 2013-03-11T18:41:52.063 に答える