2010-12-06 8 views
4

私は、ローカリゼーション、拡張、グループ化という点でできるだけ最適なものにする必要があるアプリケーションの設定構造を設計したいという問題がありました。エンティティタイプごとの設定をグループ化する必要があります(コントローラごとのグループ化設定と考えることができます)。設定はユーザーに表示されるので、それぞれの設定にはかなりのタイトルと説明が必要で、どちらもローカライズする必要があります。新しい設定は開発者によってのみ導入され、再コンパイルが必要になります。設定構造を設計する

私が思い描いたのは、静的なプロパティとして設定を公開するクラスであり、静的な方法でアプリケーション全体に簡単にアクセスできるようになっています。設定は、クラスの構築時に初めてロードされ(設定が要求されたときに実行されます)、データベースを使用して設定を保存し、リフレクションを使用して実行時に対応するプロパティに割り当てます。それは、この

public class FirmSettings 
{ 
    private static IFirmSettingsRepository _repository { get; set; } 

    public static bool ShowInvoicePaymentDetails { get; set; } 

    public static bool ShowInvoiceDiscountValue { get; set; } 

    public static bool ShowDocumentComment { get; set; } 

    public static bool ShowDocumentTaxStatement { get; set; } 

    public static bool ShowDocumentAuthor { get; set; } 

    #region Constructors 

    /// <summary> 
    ///  Initializes a new instance of the <see cref = "FirmSettings" /> class. 
    /// </summary> 
    static FirmSettings() 
    { 
     Load(); 
    } 

    #endregion 

    #region Load Settings 

    public static void Load() 
    { 
     _repository = MvcApplication.Container.Get<IFirmSettingsRepository>(); 
     Type settingsType = typeof (FirmSettings); 

     //------------------------------------------------------------ 
     // Enumerate through individual settings nodes 
     //------------------------------------------------------------ 
     StringDictionary dic = _repository.LoadSettings(); 

     if (dic == null) 
     { 
      Save(); // prepares the settings with blank settings 
      dic = _repository.LoadSettings(); // reload 
     } 

     foreach (string key in dic.Keys) 
     { 
      //------------------------------------------------------------ 
      // Extract the setting's name/value pair 
      //------------------------------------------------------------ 
      string name = key; 
      string value = dic[key]; 

      //------------------------------------------------------------ 
      // Enumerate through public properties of this instance 
      //------------------------------------------------------------ 
      foreach (PropertyInfo propertyInformation in settingsType.GetProperties(BindingFlags.Public | 
                        BindingFlags.Static)) 
      { 
       //------------------------------------------------------------ 
       // Determine if configured setting matches current setting based on name 
       //------------------------------------------------------------ 
       if (propertyInformation.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) 
       { 
        //------------------------------------------------------------ 
        // Attempt to apply configured setting 
        //------------------------------------------------------------ 
        try 
        { 
         if (propertyInformation.CanWrite) 
         { 
          propertyInformation.SetValue(typeof (FirmSettings), 
                 Convert.ChangeType(value, propertyInformation.PropertyType, 
                      CultureInfo.CurrentCulture), null); 
         } 
        } 
        catch 
        { 
         // TODO: Log exception to a common logging framework? 
        } 
        break; 
       } 
      } 
     } 

     // perform resave if there are any new settings 
     Save(); 
    } 

    #endregion 

    #region Save settings 

    /// <summary> 
    ///  Saves the settings to disk. 
    /// </summary> 
    public static void Save() 
    { 
     StringDictionary dic = new StringDictionary(); 
     Type settingsType = typeof (FirmSettings); 

     //------------------------------------------------------------ 
     // Enumerate through settings properties 
     //------------------------------------------------------------ 
     foreach (PropertyInfo propertyInformation in settingsType.GetProperties(BindingFlags.Public | 
                       BindingFlags.Static)) 
     { 
      //------------------------------------------------------------ 
      // Extract property value and its string representation 
      //------------------------------------------------------------ 
      object propertyValue = propertyInformation.GetValue(typeof (FirmSettings), null); 

      string valueAsString; 
      //------------------------------------------------------------ 
      // Format null/default property values as empty strings 
      //------------------------------------------------------------ 
      if (propertyValue == null || propertyValue.Equals(Int32.MinValue) || propertyValue.Equals(Single.MinValue)) 
      { 
       valueAsString = String.Empty; 
      } 
      else 
      { 
       valueAsString = propertyValue.ToString(); 
      } 
      //------------------------------------------------------------ 
      // Write property name/value pair 
      //------------------------------------------------------------ 
      dic.Add(propertyInformation.Name, valueAsString); 
     } 

     _repository.SaveSettings(dic); 
    } 

    #endregion 
} 

のように見えます

各設定は(読み込みのために私たちはケースを無視する)プロパティ名の小文字バージョンとしてDBに格納されます。ローカライゼーション文字列は、たとえばFirmSettings_ShowDocumentTaxStatement_TitleFirmSettings_ShowDocumentTaxStatement_Descのように格納されます。

このアプローチではグループ化は解決されません。 UIでは、何らかの種類の設定が必要になるため、請求書の設定がグループに表示されます。私は特定の設定のプレフィックスを導入し、プレフィックスに基づいてそれをレンダリングすることができます(もう1つのコンベンション)。

この方法が好きですか?そうでない場合、どうやってそれをしますか?このアプローチにはたくさんの慣習がありますが、それは私を悩ますことです、ほんの少しです。

答えて

1

あなたが私をここに失った...

私はあなたには、いくつかの種類のコンテナを使用して参照して、なぜあなただ​​けその設定クラスのシングルトンインスタンスにあなたがそれへの参照を必要とするたびに注入しないのですか?静的なクラス+メソッドは単体テストには悪い(これはあなたが必要とする)。

また、私はあなたの記憶/検索を設定するためにリフレクション/文字列のマッチングを使用する理由を知りません。複雑なグループ分けの設定が本当に重要な場合は、適切なDALを考え出すために時間を費やす必要があります。

"Key"(例:FirmSettings_ShowDocumentTaxStatement_Title)には名前空間が含まれていないので、2つのクラスが同じ名前と同じメソッドを持つ場合は、捕らえにくいバグに終わります。それは単純なシナリオです。私の指摘は、あなたのクラス+識別名の目的のためのメソッド名は、良い考えではない文字列です。

最後に、「実行時に他の静的(または通常)のプロパティに他の値を割り当てる方法が他にはありません。他の方法はありません。反射の使用よりも。クラス/メソッド/プロパティの属性を使用して、ファクトリクラスに必要な設定クラスのシングルトンを(自分の場合は)取り出すことができます。適切なDB列/行関連情報を属性に含めることができます。

P.S.反射は性能面では問題ありません。静的クラスを使用せず、代わりにシングルトンを使用し、設定クラスの初期化時にバックグラウンドタスクを実行してください。シングルトンが開始されると、シングルトンを再度初期化する必要はありません。しかし、あなたが何をするにしても、クラス/メソッド名と一致する文字列を失うことを強くお勧めします。

P.P.S. AoP /ポリシーインジェクション(またはMicrosoft Unity DIコンテナでの介入でした)を見てください。私はそれらが多分あなたの助けを信じていますか?

P.P.P.S.最後に3つのポストスクリプトには悪い英語があります...

+0

K TBH、書き込み質問に答えるかどうかわからない... –

+0

シングルトンについてのご意見ありがとうございました。私は実際にシングルトンクラスや静的クラスを使ってconccurency問題に関する新しい質問を開きましたhttp://stackoverflow.com/questions/4382537/singleton-class-or-a-class-with-static-methods-in-asp-net-mvc-応用 – mare

0

IMHO解決策が複雑すぎます。もっと簡単なことを考えてみてください。まず、リフレクション(パフォーマンス上の理由)を使用しないでください。次に、アプリケーション/ユーザー設定のDBではなく、構成ファイル(xml)を使用します。

this反射とパフォーマンスに関する包括的な記事を参照してください。

+1

ここではパフォーマンスの問題を引き起こす反射の使用を見ることができません –

+0

@Kev一般的な反射は遅く、避けるべきです。私のoptinionに設定を保存することは、リフレクションを必要とするものではありません。それは多くの異なる方法で行うことができます。 –

+0

DBを使用するようになったので、ここで変更はありません。私たちはイージーメンテナンスのためにDB内のすべてを欲しがっています。 – mare

関連する問題