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

为每个访问节点设置不同返回类型的Visitor模式实现问询

为Visitor模式实现不同Visitable节点的专属返回类型

我正尝试实现Visitor设计模式,已了解其基础概念与经典实现方式,现需对该模式进行调整以满足特定需求:为每个被访问的Visitable(节点)设置专属的返回类型。

目前我看到的经典Visitor返回特定类型的实现多通过泛型完成,但这无法满足我的需求——让不同Visitable节点对应不同的返回类型。

在提问前我已查阅了以下Stack Overflow问题:

  • Visitor Design Pattern - return type
  • java - Return a value from Visitor
  • Implementing Visitor Pattern while allowing different return types of functions——该问题提供了在Visitor内部存储状态的方案,但我不希望API调用者需要在调用visit后手动获取状态。

以下代码示例展示了我的困境:

public interface IVisitor<TReturn>
{
    TReturn Visit(VisitableClassReturnString visitableClass);

    TReturn Visit(VisitibleClassReturnInt visitibleClass);
}

public class Visitor : IVisitor<string>
{

    public string Visit(VisitableClassReturnString visitableClass)
    {
        // 返回类型正确
        // 访问逻辑(仅为返回类型示例)
        return string.Empty;
    }

    public string Visit(VisitibleClassReturnInt visitibleClass)
    {
        // 返回类型错误
        // 访问逻辑(仅为返回类型示例)
        return 0;
    }
}

如代码所示,我有两个不同的Visitable类(节点),在当前业务场景中访问它们需要返回不同类型的值。需注意的是,这种不同返回类型仅针对该具体Visitor实现,其他IVisitor实现的节点通常会使用相同返回类型。

单泛型无法实现该需求,请问有什么可行的实现思路?


可行实现思路

1. 多泛型参数定制Visitor接口

针对每个Visitable节点的返回类型,在Visitor接口中声明对应的泛型参数,让每个Visit方法的返回类型独立:

public interface IVisitor<TStringResult, TIntResult>
{
    TStringResult Visit(VisitableClassReturnString visitableClass);
    TIntResult Visit(VisitibleClassReturnInt visitibleClass);
}

public class SpecificVisitor : IVisitor<string, int>
{
    public string Visit(VisitableClassReturnString visitableClass)
    {
        return "处理字符串节点的结果";
    }

    public int Visit(VisitibleClassReturnInt visitibleClass)
    {
        return 123;
    }
}

优势:编译期类型安全,能直接检查返回类型是否匹配;局限:若Visitable节点数量较多,泛型参数会变得冗长,适合节点数量固定的场景。

2. 标记接口+模式匹配(C# 7.0+)

定义一个空的标记接口作为所有返回结果的基类,Visitor方法统一返回该接口类型,调用方通过模式匹配获取具体结果:

// 标记接口,统一所有返回类型
public interface IVisitorResult { }

// 针对不同节点的结果封装类
public class StringResult : IVisitorResult
{
    public string Value { get; }
    public StringResult(string value) => Value = value;
}

public class IntResult : IVisitorResult
{
    public int Value { get; }
    public IntResult(int value) => Value = value;
}

// 调整后的Visitor接口
public interface IVisitor
{
    IVisitorResult Visit(VisitableClassReturnString visitableClass);
    IVisitorResult Visit(VisitibleClassReturnInt visitibleClass);
}

public class SpecificVisitor : IVisitor
{
    public IVisitorResult Visit(VisitableClassReturnString visitableClass)
    {
        return new StringResult("字符串节点处理结果");
    }

    public IVisitorResult Visit(VisitibleClassReturnInt visitibleClass)
    {
        return new IntResult(456);
    }
}

// 调用示例
var visitor = new SpecificVisitor();
var stringNode = new VisitableClassReturnString();
if (visitor.Visit(stringNode) is StringResult strRes)
{
    Console.WriteLine(strRes.Value);
}
var intNode = new VisitibleClassReturnInt();
if (visitor.Visit(intNode) is IntResult intRes)
{
    Console.WriteLine(intRes.Value);
}

优势:避免泛型参数爆炸,同时通过模式匹配保证类型安全,调用方无需手动管理状态;局限:需要为每个返回类型定义封装类,适合节点数量较多的场景。

3. 为特殊Visitor定制独立接口

如果仅少数Visitor需要不同返回类型,可以单独为其定义接口,不影响基础泛型Visitor的使用:

// 基础泛型Visitor,供大多数场景使用
public interface IBasicVisitor<TReturn>
{
    TReturn Visit(VisitableClassReturnString visitableClass);
    TReturn Visit(VisitibleClassReturnInt visitibleClass);
}

// 针对特定需求的定制Visitor接口
public interface ISpecificVisitor
{
    string Visit(VisitableClassReturnString visitableClass);
    int Visit(VisitibleClassReturnInt visitibleClass);
}

public class SpecificVisitor : ISpecificVisitor
{
    public string Visit(VisitableClassReturnString visitableClass)
    {
        return "字符串结果";
    }

    public int Visit(VisitibleClassReturnInt visitibleClass)
    {
        return 789;
    }
}

优势:完全定制化,不干扰其他场景的Visitor实现;局限:若特殊场景增多,会增加接口数量,适合仅个别Visitor需要特殊返回类型的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:44:56