22. 访问者模式(Visitor)

问题:想在不修改对象结构的前提下,为其增加新操作。

核心:把操作从对象结构中分离出来,放到访问者中。

class NumberNode {
  constructor(value) { this.value = value; }
  accept(visitor) { return visitor.visitNumber(this); }
}

class StringNode {
  constructor(value) { this.value = value; }
  accept(visitor) { return visitor.visitString(this); }
}

class TypeVisitor {
  visitNumber(node) { return `数字: ${node.value}`; }
  visitString(node) { return `字符串: "${node.value}"`; }
}

class LengthVisitor {
  visitNumber(node) { return String(node.value).length; }
  visitString(node) { return node.value.length; }
}

const nodes = [new NumberNode(42), new StringNode('hello')];

nodes.forEach(n => console.log(n.accept(new TypeVisitor())));
// 数字: 42
// 字符串: "hello"

nodes.forEach(n => console.log(n.accept(new LengthVisitor())));
// 2
// 5
package visitor

import (
  "fmt"
  "strconv"
)

type Visitor interface {
  VisitNumber(n *NumberNode) string
  VisitString(s *StringNode) string
}

type Node interface {
  Accept(v Visitor) string
}

type NumberNode struct{ Value int }

func (n *NumberNode) Accept(v Visitor) string { return v.VisitNumber(n) }

type StringNode struct{ Value string }

func (s *StringNode) Accept(v Visitor) string { return v.VisitString(s) }

type TypeVisitor struct{}

func (t TypeVisitor) VisitNumber(n *NumberNode) string {
  return fmt.Sprintf("数字: %d", n.Value)
}

func (t TypeVisitor) VisitString(s *StringNode) string {
  return fmt.Sprintf("字符串: \"%s\"", s.Value)
}

type LengthVisitor struct{}

func (l LengthVisitor) VisitNumber(n *NumberNode) string {
  return strconv.Itoa(len(strconv.Itoa(n.Value)))
}

func (l LengthVisitor) VisitString(s *StringNode) string {
  return strconv.Itoa(len(s.Value))
}