2

私は木を持っています。

class TreeNode {
    public TreeNode(string name, string description) {
        Name = name;
        Description = description;
    }
    string Name { get; set; }
    string Description { get; set; }
    public List<TreeNode> Children = new List<TreeNode>();
}

単体テストの目的で大きなものを作成したいと思います。私は本当に物をDRYに保ちたいです。

説明のために、私のツリーには次の構造があるとします

親、説明
  子 1、desc1
    孫 1、desc1
  子 2、desc2

エレガントで保守しやすい方法でツリーを作成するにはどうすればよいでしょうか?

このコードは非常に繰り返しが多く、エラーが発生しやすいと思います。

var parent = new TreeNode("Parent", "desc");
var child1 = new TreeNode("Child 1", "desc1");
var child2 = new TreeNode("Child 2", "desc2");
var grandchild1 = new TreeNode("Grandchild 1", "desc1");

parent.Children.Add(child1);
parent.Children.Add(child2);

child1.Children.Add(grandchild1);

編集

私は最終的にDSLアプローチを行いました:

デモテストはここにあります

実装はこちらです。

ビルダーと単純な DSL を使用します。

4

5 に答える 5

3

いくつかの接続の混乱を避けるために、状態を指定して「TreeBuilder」を作成できます。

TreeBuilder builder = new TreeBuilder();

builder.AddNode("Parent", "desc"); // Adds a node, and sets the cursor to it
builder.AddLeaf("Child 1", "desc1"); // Adds a node and leaves the cursor at the Parent
builder.AddNode("Child 2", "desc2");
builder.AddLeaf("Grandchild 1", "desc1");
builder.Up(); // Moves the cursor to the parent
builder.AddNode("Child 3", "desc3");

root = builder.GetRoot()

もう 1 つの方法は、いくつかの単純な形式で単純な構成ファイル/文字列を発明することです。

于 2009-02-18T23:32:58.147 に答える
2

ここでは、ネストされた構造が適切なオプションになる可能性があります。子のリストも公開しないことをお勧めします。

class Program
{
    static void Main(string[] args)
    {
        var parent = 
            new TreeNode( "Parent", "desc", new TreeNode[] { 
                new TreeNode( "Child 1", "desc1", new TreeNode[] { 
                    new TreeNode( "Grandchild 1", "desc1" ) } ),
                new TreeNode( "Child 2", "desc2" ) } );
    }
}

class TreeNode
{
    public TreeNode(string name, string description, IEnumerable<TreeNode> children)
        : this(name, description)
    {
        _children.AddRange(children);
    }

    public TreeNode(string name, string description)
    {
        Name = name;
        Description = description;
    }

    public string Name { get; set; }
    public string Description { get; set; }

    public IEnumerable<TreeNode> Children
    {
        get
        {
            return _children.AsReadOnly();
        }

        set
        {
            _children.Clear();
            _children.AddRange(value);
        }
    }

    private List<TreeNode> _children = new List<TreeNode>();
}
于 2009-02-18T23:43:43.020 に答える
2
  • 理想的には、言語をカスタム型のリテラルに拡張する方法が必要です。C# にはこれがないため、別の方法を見つける必要があります。

  • 通常は流暢なインターフェイスを備えた内部 DSLを作成できます。

  • 機能構築XElementの例に従ってください。

  • カスタム パーサーを使用して外部 DSLを作成します。言語を注意深く設計すれば、パーサーは簡単になります。

  • XMLを使用します。基本的に、これは外部 DSL を作成し、パーサーを無料で入手する方法です。

外部 DSL オプションは便利です。なぜなら、それらを読むと、そこには data しかないことがわかり、コード構成の意味を理解する必要がないからです。また、データはファイルであり、ファイルはデータです。これにより、ファイルを変更してデータを簡単に交換でき、ファイルの変更履歴を簡単に準備できます。最後に、外部 DSL は、プログラマー以外がデータを提供する場合に適しています。

ここでのトレードオフは、時間と価値です。どのくらいのデータを保持するか、どのくらいの頻度で変更するか、誰が変更するかは、あなたが答えなければならない質問です。

于 2009-02-19T00:16:58.227 に答える
1

実装を TreeClass と TreeNodeClass に分割します

Tree クラスにはメンバー変数があります

TreeNodeClass root

メソッド付き

TreeNodeClass addAtRoot(data) 

作成したばかりのノードを返す

TreeNodeClass には、追加したばかりのノードを返す AddChild() メソッドも必要です。

次に、次のようなことができます

addAtRoot(rootData).AddChild(childData).AddChild(grandchildData);

また

このようなものを使用して、ツリーをランダムに生成します

AddRecursively(TreeNodeClass root)
{
    numChildren = SomeRandomNumber;
    While(numChildren > 0)
    {
       CTreeNodeClass newnode = root.AddChild(SomeRandomData);
       AddRecursively(newnode);
    }
}

主なアイデアは、ツリーに追加したばかりのノードを返したいということです。

また、場合によっては非常に便利なため、子供に親を知らせたい場合もあります。

于 2009-02-19T00:39:46.923 に答える
1

ツリーにデータを入力する単純なパーサーを使用して、ツリー コンテンツの単純な XML 表現を作成できます。以下は、上で指定した構造を示します。

<Node description="desc">
    Parent
    <Node description="desc1">
        Child 1
        <Node description="desc1">
            Grandchild 1
        </Node>
    </Node>
    <Node description="desc2">
        Child 2
    </Node>
</Node>
于 2009-02-18T23:36:04.067 に答える