@
zhuisui @
mahaoqu 感谢讲解!
所以这里我想我可能陷入了一个很大的误区,就是把 visitor 机械地等同于 pattern matching ,然后把 pattern matching 在 subtyping 下面的作用(也就是 dynamic dispatch )给搬运到了 visitor pattern 下,但是这个 dynamic dispatch 只是 visitor 的其中一个「稍微显著但不是主要的作用」,而 visitor pattern 的主要作用,就像 @
mahaoqu 说的,「面向对象把一个类的多个方法放在一起,而 Visitor 模式恰好反过来了」,或者 @
zhuisui 所说的「多个 visitor 分别代表可以输出不同形式的业务逻辑,visitor 之间是互相独立的」这样的作用。
我的理解是你说的「避免了业务侧用 switch case 做模式匹配,仅需 iterate elements 的 accept 方法即可完成调用」用我前面的表达其实就是「 dynamic dispatch 」对吧。比如用户解析 Tree 的时候,它不关心 Tree 具体长啥样或者具体怎么解析,它只希望能够正确的拿到 XML/JSON 或者 Table 。那么 visitor pattern 就充当了这个解析的作用吧。
这么说来倒是很多东西都说得清了。
至于副作用的问题,主要是我对这样的代码有很大的意见:
```java
class ... {
/* L.18 */ResultType result;
public void visitSomeArm(...) {
/* L.259 */ ResultType oldResult = result;
/* L.343 */ ... = visitAnotherArm(...);
/* L.569 */ result = ...;
}
public void VisitAnotherArm(...) {
/* L.1982 */ result = ...
}
}
```
当然这个其实并不是 effectful visitor 的问题而更像是某种 structural 的 code smell 了,如果一个 visitor 的实现能够把副作用清晰的表达出来,让我能够人肉去建模出 Effect 大概长啥样,我对这样的代码并没有太大的意见。
顺祝新年快乐!