public interface TreeVisitor<T> {
T visitLeaf();
T visitNode(Node node);
}
こういうVisitorなら以下の様なファクトリがあると便利かなと思ったけど
public interface TreeVisitor<T> {
T visitLeaf();
T visitNode(Node node);
static <TT> TreeVisitor<TT> of(Supplier<? extends T> forLeaf, Function<? super Node, ? extends T> forNode) {
return new TreeVisitor<TT>() {
public TT visitLeaf() {
return forLeaf.get();
}
public TT visitNode(Node node) {
return forNode.apply(node);
}
}
}
}
Composite パターンのような構造を走査する場合、this でVisitor自身を参照できなくなるのであんまり便利にならないですね。
Enum に対する Visitor とかなら便利かも位
Visitor を受け取れるようにしてみる
public interface TreeVisitor<T> {
T visitLeaf();
T visitNode(Node node);
static <TT> TreeVisitor<TT> of(Function<? super TreeVisitor<? extends TT>, ? extends T> forLeaf, BiFunction<? super Node, ? super TreeVisitor<? extends TT>, ? extends TT> forNode) {
return new TreeVisitor<TT>() {
public TT visitLeaf() {
return forLeaf.apply(this);
}
public TT visitNode(Node node) {
return forNode.apply(node, this);
}
}
}
}
とするとこの辺の例も以下の様にかける
Doc doc = tree.accept(TreeVisitor.of<Doc>(
self -> Doc.text("Leaf"),
(node, self) -> {
Doc lhsDoc = node.lhs.accept(self);
Doc rhsDoc = node.rhs.accept(self);
Doc inner = lhsDoc.concat(Doc.line()).concat(rhsDoc);
Doc ret = Doc.bracket("(Node " + node.value, inner, ")");
return ret;
});
System.out.println(doc.layout());
すっきり。
でも数が増えると意味わからないので名前付きメソッド呼び出し欲しい。
// 妄想。コンパイル通らない
Doc doc = tree.accept(TreeVisitor.of<Doc>(
forLeaf = self -> Doc.text("Leaf"),
forNode = (node, self) -> {
Doc lhsDoc = node.lhs.accept(self);
Doc rhsDoc = node.rhs.accept(self);
Doc inner = lhsDoc.concat(Doc.line()).concat(rhsDoc);
Doc ret = Doc.bracket("(Node " + node.value, inner, ")");
return ret;
});
System.out.println(doc.layout());