C#中的数据继承

时间:2009-05-20 07:58:16

标签: c# design-patterns

是否有已知的模式来继承分层对象结构中的数据?我有一个分层的'Item'结构,需要从'Parent'继承它的'Type'(默认拥有相同的数据)。子项的类型可以自己修改,当父项的类型发生更改时,其类型未更改的所有子项都应该获得新类型的父项。

请注意,我不能伪装它

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);
}

有更好的方法吗? 感谢。

4 个答案:

答案 0 :(得分:3)

这是一个常见问题,通常与维护各种分层设置/配置有关。所以,我猜一个解决方案可以被认为是“一种模式”。

无论如何,从内部架构的角度来看,您有两个主要选择:

  • 规范化结构
  • 非规范化结构

“Normazlied”是用递归实现的。一个特定的数据总是存储在一个地方,所有其他地方都有对它的引用(例如,对父项)。该结构很容易更新,但从中读取可能是一个问题。

“非规范化”意味着每个节点都将存储其级别的整套设置,每当您更新节点时,需要一些时间沿着层次结构并核心所有子节点。但阅读操作是即时的。

所以“非规范化”版本似乎被更广泛地使用,因为设置的常见情况是你很少更新它们,而经常阅读它们,因此你需要更好的读取性能。例如,Windows ACL security model使用“非规范化”方法快速进行安全检查。你可以阅读他们resolve conflicts between the "inherited" and explicit permissions (ACEs) by checking them in a specific order的方式。对于您的特定系统而言,这可能是一种过度杀伤,您可以简单地设置一个特定值被覆盖的标志,或者相反,重置为“默认”......

进一步的细节取决于您的系统需求,您可能会想要一个“混合”架构,其中一些字段将“标准化”而另一些字段则不会。但你似乎走在正确的道路上。

答案 1 :(得分:1)

我不是百分之百确定你要做的是什么......但你可以使用泛型将父对象的类型传递给子对象......但是有一个setter并不是真的有意义......父对象的类型将在实例化时设置,那你为什么要在那里设置一个setter来改变它。

假设你有类似的东西......

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

那么,当你拥有任何类型的Parent对象时,你可以将它传递给你的子属性......

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&amp; ParentC分别。

Buit我有一种有趣的感觉,你没有完全解释你正在尝试做什么。 你能发布更多的代码示例,显示父类和&amp;儿童/物品类

答案 2 :(得分:1)

显而易见的优化是在读取类型时缓存从父级获得的值。这意味着你最多只能遍历每个路径一次(而天真的解决方案意味着你将为包含它的每个路径反复遍历每个子路径,这意味着最多为O(h ^ 2)而不是O(h)) 。如果你有更多的读取而不是写作,那将会很有效。

考虑一下:

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是分支级别(因为我们只更新一层!)。我认为这通常会比UpdateUnchangedChildren解决方案更好(我假设递归更新节点一直到叶子),除非你做的读取比写入更多。

答案 3 :(得分:0)

“......结构太深,不能使用递归而不担心性能。”

你真的测过这个吗?您处理了多少项,结构有多深,以及项目没有自己的“类型”值有多常见?您的应用程序的性能目标是什么?递归解决方案与这些目标相比如何?

人们常常认为递归很慢,因此在没有尝试的情况下将其排除在外。在没有首先测量的情况下,出于性能原因拒绝最简单的设计绝对不是一个好主意。否则你会发现一个更复杂的解决方案,当更简单的解决方案工作得很好。

当然,你的第二个解决方案也是使用递归,只是在层次结构中而不是向上。如果孩子插入是在不同的时间发生并且可以吸收可能的性能损失,那么这可能更容易接受。