2009-05-20 6 views
3

階層オブジェクト構造にデータを継承する既知のパターンはありますか?私は '親'(デフォルトと同じデータを持つ)から 'タイプ'を継承する必要がある階層的な 'Item'構造を持っています。サブアイテムのタイプはそれ自身で変更することができ、親アイテムのタイプが変更された場合、そのタイプが変更されていないすべてのサブアイテムは新しいタイプの親を取得する必要があります。C#でのデータ継承

なお、私は偽のできない、それ

public string Type 
{ 
    get 
    { 
     if (type == null) 
      return Parent != null ? Parent.Type : null; 

     return type; 
    } 
} 

「のような私は、データベース内の値を入力する必要があり、その構造は、再帰を使用し、パフォーマンスを心配しないように深すぎる原因。

私は今それを考えることができる唯一の方法は、

public string Type 
{ 
    set 
    { 
     type = value; 
     UpdateUnchangedChildren(value); 
    } 
} 

public int AddChild(Item item) 
{ 
    item.Type = Type; 
    return Items.Add(item); 
} 

ある良い方法はありますか?おかげさまで

答えて

3

これは一般的な問題です。通常、さまざまな階層設定や構成のメンテナンスに関連しています。だから、それに対する解決策は "パターン"と考えることができると思います。

  • 正規化された構造

は "Normazliedは" 再帰で実装一つです

  • 非正規化された構造:

    とにかく、内部アーキテクチャの観点から、あなたは、2つの主要なオプションがあります。特定のデータは常に1つの場所に格納され、他のすべての場所はそのデータを参照します(たとえば、親に)。構造は簡単に更新できますが、そこからの読み込みは問題になる可能性があります。

    "非正規化"とは、すべてのノードがそのレベルの設定全体を保存することを意味し、ノードを更新するたびに、階層を下ってすべての子ノードをコアする時間がかかります。しかし、読み取り操作は即座です。

    また、「非正規化」バージョンは、一般的な設定ではあまり頻繁に更新するのではなく、読み取りパフォーマンスが向上するため、より広く使用されているようです。たとえば、Windows ACL security modelは、セキュリティチェックを高速化するために「非正規化」アプローチを使用します。どのように彼らresolve conflicts between the "inherited" and explicit permissions (ACEs) by checking them in a specific orderを読むことができます。それはあなたの特定のシステムの過剰なものかもしれませんが、単に特定の値が上書きされたか、逆に "デフォルト"にリセットされるフラグを持つことができます...

    詳細は、いくつかのフィールドが「正規化」され、他のフィールドは正規化されない「ハイブリッド」アーキテクチャを持つことがあります。しかし、あなたは正しい方法でいるようです。

  • 1

    私はそれが何をしようとしているかを100%確信していませんが、親オブジェクトのタイプを子オブジェクトに渡すためにジェネリックスを使用できます...しかし、セッターはありません本当に意味をなさない... Parentオブジェクトの型は、インスタンス化されるときに設定されるので、なぜそれを変更するためのセッターがあるでしょうか?あなたはどんなタイプのParentオブジェクトを持っているときにこのような何かを持っていると仮定すると

    ...

    public class Child<T> 
    { 
        public string Type 
        { 
         get { return typeof(T).ToString(); } 
        } 
    } 
    

    それでは、あなたは...あなたの子プロパティに

    public class ParentA 
    { 
        public Child<ParentA> ChildObj { get; set; } 
    } 
    
    public class ParentB 
    { 
        public Child<ParentB> ChildObj { get; set; } 
    } 
    
    public class ParentC 
    { 
        public Child<ParentC> ChildObj { get; set; } 
    } 
    
    ていることに渡すことができます

    これらのChildObj.Typeプロパティのいずれかを呼び出すと、ParentA、ParentB & ParentCがそれぞれ返されます。

    Buit私はあなたがしようとしていることを完全には説明していないという面白い気持ちがあります。 親クラスを示すいくつかのコード例を投稿できますか&子/アイテムクラス

    +0

    私はもっと説明しようとします。 – reticent

    0

    "構造が複雑すぎて再帰を使用できず、パフォーマンスが心配しません。

    これは実際に測定しましたか?あなたが扱っているアイテムの数、構造の深さ、そしてアイテムが独自の "タイプ"値を持たないのはどれほど共通していますか?アプリケーションのパフォーマンス目標は何ですか?また、再帰的なソリューションとそれらの目標との比較はどのようになっていますか?

    人々は再帰が遅いと考えることが多いので、それを試みることなく考慮する必要はありません。最初に測定することなく、パフォーマンス上の理由から最も単純な設計を拒否することは、決して良い考えではありません。そうでなければ、より単純なものがうまくいっていれば、より複雑な解決法を発明します。

    もちろん、2番目のソリューションでは再帰を使用していますが、上に行くのではなく下に移動するだけです。子の挿入が別の時間に起こっている可能性があり、パフォーマンスのヒットを吸収する可能性がある場合は、おそらくそれが受け入れられるでしょう。

    +0

    再帰についての良い点はありますが、私はそれをテストしました。遅延ロードと再帰は良いペアにはならないと思います。あなたが言ったように、値を変更するよりも値を読み込む方が頻繁です。 – reticent

    1

    明らかな最適化は、型の読み込み時に親から取得した値をキャッシュすることです。これは、各パスをたかだか1回だけトラバースすることを意味します(純粋な解法では、O(h)の代わりにO(h^2)までのパスを含むパスごとに、 。これは、書き込みよりも読み込み量が多い場合に効果的です。

    class Node 
    { 
        string _cachedParentType = null; 
        string _type; 
        string Type 
        { 
         get { return _type ?? _cachedParentType ?? (_cachedParentType = Parent.Type); } 
         set 
         { 
          _type = value; 
          foreach (var child in Children) { child._cachedParentType = null; } 
         } 
        } 
    } 
    

    これは十分に読み取り、いくつかの書き込みで、読み取りが最良の場合にはO(1)になるか、最悪の場合、「キャッシュミス」は、あなたの費用がかかりますO(H)意味:

    はこの考えてみましょうhは木の高さである。更新はO(k)で、kは分岐レベルです(1つのレイヤーを更新するだけなので!)。私はこれがUpdateUnchangedChildrenソリューション(通常は更新ノードを再帰的にリーフに推測する)よりも優れていると思います。

    +0

    リーフまでノードを再帰的に更新する必要はありませんか?このようにして、孫ノードが親の型(祖父の型である)をキャッシュし、祖父の型が変更された場合、孫ノードは無効な値を返します。 – reticent