2016-03-31 5 views
0

私のプロジェクトでは、カスタムプロパティを実装するクラスの階層を持っています。ここで私はコンソールアプリケーション用のバージョンに近いものです。OOPデザインパターンで基本クラスのプロパティ拡張メカニズムをよりよく実装する方法

class Property 
{ 
    string key; 
    object value; 

    public Property(string key, object value) 
    { 
     this.key = key; 
     this.value = value; 
    } 

    public override string ToString() 
    { 
     return "(key=" + key + ": value=" + value + ")"; 
    } 
} 

public struct PropertyConfig 
{ 
    public string key; 
    public object defaultValue; 
} 

abstract class BaseClass 
{ 
    Dictionary<string, Property> properties = new Dictionary<string, Property>(); 

    Dictionary<string, PropertyConfig> mergedConfigs = new Dictionary<string, PropertyConfig>(); 

    public BaseClass() 
    { 
     MergeWithInheritedConfigsAndCreateInstances(
      new PropertyConfig[] 
      { 
       new PropertyConfig() { key = "p1", defaultValue = "v1" }, 
       new PropertyConfig() { key = "p2", defaultValue = "v2" } 
      }, 
      true); 
    } 

    protected void MergeWithInheritedConfigsAndCreateInstances(PropertyConfig[] configs = null, bool IsBaseClass = false) 
    { 
     configs = configs ?? new PropertyConfig[] { }; 

     foreach (PropertyConfig config in configs) 
     { 
      mergedConfigs[config.key] = config; 
     } 

     if (!IsBaseClass) 
     { 
      CreatePropertyInstancesAfterMerge(); 
     } 
    } 

    private void CreatePropertyInstancesAfterMerge() 
    { 
     foreach (KeyValuePair<string, PropertyConfig> kvp in mergedConfigs) 
     { 
      PropertyConfig config = kvp.Value; 

      properties.Add(config.key, new Property(config.key, config.defaultValue)); 
     } 
    } 

    public override string ToString() 
    { 
     return GetType().Name + ".Properties: " + string.Join(",", properties.Select(kvp => kvp.Value.ToString()).ToArray()); 
    } 
} 

class DerivedClassA : BaseClass 
{ 
    public DerivedClassA(): base() 
    { 
     MergeWithInheritedConfigsAndCreateInstances(); 
    } 
} 

class DerivedClassB : BaseClass 
{ 
    public DerivedClassB() : base() 
    { 
     MergeWithInheritedConfigsAndCreateInstances(new PropertyConfig[] 
     { 
      new PropertyConfig() { key = "p2", defaultValue = true }, 
      new PropertyConfig() { key = "p3", defaultValue = "v3" } 
     }); 
    } 
} 

class DerivedClassC : BaseClass 
{ 
    public DerivedClassC() : base() 
    { 
     MergeWithInheritedConfigsAndCreateInstances(new PropertyConfig[] 
     { 
      new PropertyConfig() { key = "p2", defaultValue = false }, 
      new PropertyConfig() { key = "p4", defaultValue = "v4" } 
     }); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     DerivedClassA derivedA = new DerivedClassA(); 
     DerivedClassB derivedB = new DerivedClassB(); 
     DerivedClassC derivedC = new DerivedClassC(); 

     Console.WriteLine(derivedA.ToString()); 
     Console.WriteLine(derivedB.ToString()); 
     Console.WriteLine(derivedC.ToString()); 


     Console.ReadLine(); 
    } 
} 

基本抽象クラスは、派生クラスで継承されることを意図したプロパティオブジェクトの構成を定義します。

コンストラクタのコンフィグレーションでは、配列オブジェクトはMergeWithInheritedConfigsAndCreateInstancesメソッドコールに渡され、2番目のパラメータはtrueに設定され、プロパティオブジェクトのインスタンス化を延期する必要があることを示します。

マージされたプロパティ設定の現在の状態は、mergedConfigsDictionaryに格納されます。

派生クラスは、コンストラクタでMergeWithInheritedConfigsAndCreateInstancesメソッドを呼び出す基本クラス構成とマージ/オーバーライドするローカルプロパティ設定を渡し、2番目のパラメータをデフォルト値のfalseに設定して、今すぐマージ後にプロパティインスタンスを作成する必要があることを示します。

結果は次のとおりです。

DerivedClassA.Properties: (key=p1: value=v1),(key=p2: value=v2) 
DerivedClassB.Properties: (key=p1: value=v1),(key=p2: value=True),(key=p3: value=v3) 
DerivedClassC.Properties: (key=p1: value=v1),(key=p2: value=False),(key=p4: value=v4) 

そして、それは私が必要なものですが、私は好きではない、このソリューションのいくつかの欠点があります。

1)各コンストラクタでMergeWithInheritedConfigsAndCreateInstancesを呼び出す必要があります。 2番目のパラメータは、抽象クラスコンストラクタで提供する必要があります。

すべてのマージ/インスタンス化メカニズムが実装され、基本クラスで呼び出されたソリューションが必要です。また、派生クラス固有のプロパティ設定をメソッドパラメータとしてではなく、メンバーフィールド/プロパティとして(静的なのかもしれません)定義することができます。

2)マージ処理は、クラスがインスタンス化されるたびに実行されます。

私はそれを1回だけ行うことを好むでしょう。 (静的コンストラクタに配置しますか?)

UPD:意図した考え方をよりよく示す書き換えられたサンプルコードです。

+0

FYI:これはXAML/WPFは、依存関係プロパティでボンネットの下にどのように動作するか..です –

+0

私のコードでは、wpf構造に依存することはできません。同様の要件があるように見えますが、wpf依存関係プロパティシステムの内部実装は、そのドメイン固有のものであり、実装の詳細をそのままここで再利用することはできません。 –

+0

具体的なクラスを再利用することではなく、その背後にあるアイデア.../ –

答えて

2

私はあなたが複雑すぎると思っています。でも、複雑な設定のために、これで十分です:

class BaseClass 
{ 
    private readonly Dictionary<string, string> properties = new Dictionary<string, string>(); 
    protected string this[string key] 
    { 
     get { string value; return properties.TryGetValue(key, out value) ? value : null; } 
     set { if (value == null) properties.Remove(key); else properties[key] = value; } 
    } 

    public BaseClass() 
    { 
     this["p1"] = "v1"; 
     this["p2"] = "v2"; 
    } 

    public override string ToString() 
    { 
     return GetType().Name + ".Properties: " + string.Join(",", properties.Select(kvp => $"{kvp.Key}:{kvp.Value}")); 
    } 
} 

class DerivedClass : BaseClass 
{ 
    public DerivedClass() : base() 
    { 
     this["p2"] = "update"; 
     this["p3"] = "v3"; 
    } 
} 

をしかし率直に言って、これはより単純で明白です:

class BaseClass 
{ 
    public string P1 {get;set;} 
    public string P2 { get; set; } 
    public BaseClass() 
    { 
     P1 = "v1"; 
     P2 = "v2"; 
    } 
    public override string ToString() 
    { 
     return GetType().Name + ".Properties: " + string.Join(",", GetType().GetProperties(
      BindingFlags.Public | BindingFlags.Instance).Select(p => $"{p.Name}:{p.GetValue(this)}")); 
    } 
} 

class DerivedClass : BaseClass 
{ 
    public string P3 { get; set; } 
    public DerivedClass() : base() 
    { 
     P2 = "update"; 
     P3 = "v3"; 
    } 
} 
+0

ありがとう!もちろん、私はコードを単純化しました。タスクは、依存関係プロパティシステムの一種を実装することです。各プロパティクラスにはロジックがあります。基本クラスは、さまざまなタイプのプロパティ値に対してpub/sub、getters/setterを実装します。クロスリファレンス。プロパティはその場で追加/削除できます。 この質問では、基本クラスで定義されたプロパティの初期化を提供し、派生クラスで定義されたプロパティのセットを継承/オーバーライド/マージできるプロパティシステムの一部のソリューションを見つける必要があります。 あまりにも単純すぎると尋ねると、私はそれを再調整します。 –

+0

更新された質問とその例 –

関連する問題