每个级别具有不同类型的通用非二叉树

时间:2019-06-27 15:53:43

标签: c# data-structures tree polymorphism

我正在尝试创建一个通用的对象层次结构树,该树允许通过名称和ID以及遍历来查找对象。基类如下:

public abstract class RuntimeObject
{
  public Guid Id {get;}
  public string Name {get;}
  public Type ObjectType {get;}

  protected RuntimeObject( string name )
  {
    Id = Guid.NewGuid();
    Name = name;
  }
}

该类旨在由属于层次结构一部分的类继承。

接下来,我想在此基础上进行扩展,以增加对在父子之间进行导航的支持,同时保持通用性,并且不需要顶级父级定义Parent字段,也不需要叶对象来定义子字段。这样做变得非常混乱,而且我的设计方法很糟糕:

// Top-level parent class
public abstract class RuntimeObject<TChild> : RuntimeObject
  where TChild : RuntimeObject<RuntimeObject<TChild>>
{
  public int ChildCount {get;}
  public TChild FirstChild {get;}
}

// Middle-level class
public abstract class RuntimeObject<TParent,TChild> : RuntimeObject
  where TParent : RuntimeObject<RuntimeObject<TParent,TChild>>
  where TChild : RuntimeObject<RuntimeObjecT<TParent,TChild>>
{
  public TParent Parent {get;}
  public RuntimeObject<TParent,TChild> NextSibling {get;}

  public int ChildCount {get;}
  public TChild FirstChild {get;}
}

// Leaf class
public abstract class RuntimeObject<TParent> : RuntimeObject
  where TParent : RuntimeObject<RuntimeObject<TParent>>
{
  public TParent Parent {get;}
  public RuntimeObject<TParent> NextSibling {get;}
}

不仅让人讨厌阅读,而且完全无效。

目标:让A是顶级父级,C是叶子,而B是A的子代并具有类型的子代C.理想情况下,实现层次结构看起来应该类似于:

public class A : RuntimeObject<B>
{ ... }

public class B : RuntimeObject<A,C>
{ ... }

public class C : RuntimeObject<B>
{ ... }

此实现不起作用,但是这个主意仍然存在:我想创建一个用于实现对象的可遍历层次结构的通用系统,并希望避免要求使用具体的类来定义ParentChild字段(如果不需要)。

是否有一种设计模式可以做到这一点?有人对它的结构有任何建议吗?

1 个答案:

答案 0 :(得分:1)

如果使用一个类来表示具有或不具有子代的节点,则可以通过查看节点是否具有子代来判断该节点是否为叶节点。阅读属性。如果子级为null(或为空,具体取决于您如何编写),则为叶子。很简单。

如果定义一个单独的类来表示叶节点,则一个节点现在可以通过两种方式成为叶节点。它可以是“叶节点”类型,也可以是没有子节点的分支节点。这有点尴尬,除非节点是不可变的或不能使用空子代构造且子代不能设置为空,这意味着您必须始终执行两项检查。它是叶节点吗?首先检查其类型。如果不是叶节点类型,请检查其是否具有子节点。遍历时必须执行相同的操作。首先,请确保其为 not 叶子类型,并且查看其是否有子代。

如果树节点是不可变的,这会使构造树变得混乱。您不能不首先知道节点是否有子节点而构造节点,如果节点确实有子节点,则必须提供它们。这些孩子也是如此。 (可能有一个场景,但是您的节点不是一成不变的,所以我猜它不是您想要的。即使在这种场景下,定义一个单独的类仍然会使遍历树的工作更多。)

这还意味着定义新的类型,这些新类型什么也不做,只表示处于不同状态的现有类型。换句话说,没有子节点的节点已经由“普通”分支节点类表示。检查节点并查看是否有子节点很容易。使用“叶节点”类型,您必须同时检查类型和属性,并且两项检查实际上都将告诉您相同的事实,这说明了为什么类型会多余。实际上,这只是表示同一件事的另一种方式。

定义单独的类型意味着新的类型仅存在以描述处于特定状态的现有类型。在大多数情况下,我们希望通过调用对象的方法或检查其属性来与对象进行交互,而不是通过查看其类型来进行交互。但这就是您要做的。您必须始终检查每个节点的类型。如果它的功能与检查属性的目的完全相同,我们就不必这样做。