You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4中泛型类可编码树的解码实现技术问询

Implementing a Tree-Structured Generic Object System (Trunk/Branch/Apple)

Hey there! Let's build a type-safe tree structure that enforces your exact rules for trunk, branch, and apple nodes. The key here is using generic classes with strict type constraints to lock down which nodes can be parents/children of each other, so invalid structures get caught at compile time (or early runtime, if needed).

Core Design Approach

We'll start with a base abstract tree node class that handles common parent/child logic, then create specialized classes for each node type. Each subclass will enforce its specific rules:

  • Trunk: Root node, no parent allowed, can only have Branches as children
  • Branch: Middle node, parent must be Trunk or another Branch, can only have Apples as children
  • Apple: Leaf node, no children allowed, parent must be a Branch

Code Example (C#)

First, the base abstract node class to handle shared functionality:

public abstract class TreeNode<TParent, TChild>
    where TParent : TreeNode<TParent, TChild>?
    where TChild : TreeNode<TParent, TChild>?
{
    private TParent? _parent;
    private readonly List<TChild> _children = new();

    // Parent property - subclasses can override to add constraints
    public virtual TParent? Parent
    {
        get => _parent;
        set
        {
            if (_parent != null)
                throw new InvalidOperationException("Can't reassign a node's parent once set");
            _parent = value;
            _parent?.AddChild((TChild)this);
        }
    }

    // Read-only access to children
    public IReadOnlyList<TChild> Children => _children.AsReadOnly();

    // Protected method to add children - subclasses control public access
    protected virtual void AddChild(TChild child)
    {
        if (child == null) throw new ArgumentNullException(nameof(child));
        if (child.Parent != null) throw new InvalidOperationException("Child already has a parent");
        _children.Add(child);
        child.Parent = (TParent)this;
    }
}

Now let's implement each specific node type:

Trunk (Root Node)

public class Trunk : TreeNode<object, Branch>
{
    // Trunk can never have a parent - override to block setting
    public override object? Parent
    {
        get => null;
        set => throw new InvalidOperationException("Trunks can't have parent nodes - they're the root!");
    }

    // Public method to add branches (only allowed child type)
    public void AddBranch(Branch branch) => base.AddChild(branch);
}

Branch (Middle Node)

public class Branch : TreeNode<TreeNode<object, Branch>, Apple>
{
    // Ensure parent is either Trunk or another Branch
    public override TreeNode<object, Branch>? Parent
    {
        get => base.Parent;
        set
        {
            if (value != null && !(value is Trunk || value is Branch))
                throw new ArgumentException("Branches can only have Trunks or other Branches as parents");
            base.Parent = value;
        }
    }

    // Public method to add apples (only allowed child type)
    public void AddApple(Apple apple) => base.AddChild(apple);
}

Apple (Leaf Node)

public class Apple : TreeNode<Branch, object>
{
    // Apples can't have children - override to block adding
    protected override void AddChild(object child)
    {
        throw new InvalidOperationException("Apples are leaf nodes - they can't have children!");
    }

    // Ensure parent is always a Branch
    public override Branch? Parent
    {
        get => base.Parent;
        set
        {
            if (value != null && !(value is Branch))
                throw new ArgumentException("Apples can only have Branches as parents");
            base.Parent = value;
        }
    }
}

How to Use & Verify the Rules

Let's test out the structure to make sure all constraints work:

// Create the root trunk
var mainTrunk = new Trunk();

// Add a branch to the trunk - this works
var firstBranch = new Branch();
mainTrunk.AddBranch(firstBranch);

// Add an apple to the branch - this works
var redApple = new Apple();
firstBranch.AddApple(redApple);

// Add another branch to the trunk - totally fine
var secondBranch = new Branch();
mainTrunk.AddBranch(secondBranch);

// Try to add a branch to another branch - ERROR!
// firstBranch.AddBranch(secondBranch); // Won't compile, since Branch only has AddApple()

// Try to set a parent on the trunk - throws exception
// mainTrunk.Parent = firstBranch; // Throws InvalidOperationException

// Try to add a child to an apple - throws exception
// redApple.AddChild(new Apple()); // Throws InvalidOperationException

Why This Works

  • Compile-Time Safety: Most invalid operations (like adding a Branch to a Branch) won't even compile, since the Branch class only exposes AddApple().
  • Runtime Checks: For edge cases (like trying to manually set a parent), we throw clear exceptions to enforce the rules.
  • Flexibility: The base node class keeps common logic DRY, while each subclass enforces its specific constraints.

内容的提问来源于stack exchange,提问作者SebKas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:37:05