啊,OP 我觉得我终于懂你在说什么了。
首先要强调的是 Visitor 是一个行为设计模式,这意味着 Visitor 表达的是一个动作。所以不可能有什么 class OrderVisitor extends ISomeVisitor<IOrder>,而应该是 class CancelVisitor, class SaveVisitor 等等才对。
面向对象把一个类的多个方法放在一起,而 Visitor 模式恰好反过来了。那 visitor 方法里该怎么做呢?如果数据类是传统的属性封装,那就只能转发给类内部的函数。如果暴露了实现细节,那就可以直接编写实现。Visitor 本身自然不应该包含任何状态(这点你是对的)。
那么 visit-accept 应该是泛型,或者说该有返回值吗?实际上 Visitor 里的 visit 函数(或者可以把它重命名为和 Visitor 一样的名字)就相当于一个普通的方法,所以它的写法等同于为所有的 DataType 实现,那参数和返回值都是可以任意设计的。
visitor 模式都可以用一个很简单的转化把方法都塞回原本的数据类里。即:data.accept(evalVisitor) 和 data.eval() 是等价的写法。
但是如果现在只有一个大而全的万能 visitor 呢?实际上让它的职责更清晰的办法是通过不同操作拆分,而非通过操作的数据类型拆分。这时候,组合 visitor 相当于组合方法。这也是函数式编程的一大特色。
实际上设计模式只是当时的权宜之计,Java 21 中引入了 Switch 模式匹配。配合 sealed class 后 visitor 的意义就不大了。
关于 expression problem 可以看这一篇,我觉得非常有水平:
https://zhuanlan.zhihu.com/p/53810286@
netabare