访问者(Visitor)

意图

表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下,定义作用于这些元素的新操作。

结构

访问者结构图

适用性

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作;
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类;
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。

优缺点

  • 访问者模式使得易于增加新的操作,仅需增加一个新的访问者即可在一个对象结构上定义一个新的操作;
  • 相关的行为被集中在访问者中,无关的行为被分散到各自的访问者子类中;
  • 每增加一个新的Element类,就需要在Visitor及其子类中添加新的操作;
  • 通过类层次进行访问,可以访问具有不同父类的对象,可以对Visitor增加任意类型的对象;
  • 当访问者访问对象结构中每一个元素时,它能够积累状态;
  • 访问者通常需要访问每一个元素的内部状态,因此很可能会破坏元素的封装性。


示例

一个编译器将源代码转换为抽象语法树之后,需要对该抽象语法树中的各个节点(变量节点,赋值节点等)进行类型检查(TypeCheck)、格式打印(PrettyPrint)及扩展的各种操作。

实现(C#)

using System;

public abstract class Node
{
    public abstract void Accept(NodeVisitor visitor);
}

public class VariableRefNode : Node
{
    public override void Accept(NodeVisitor visitor)
    {
        visitor.VisitVariableRefNode(this);
    }
}

public class AssignmentNode : Node
{
    public override void Accept(NodeVisitor visitor)
    {
        visitor.VisitAssignmentNode(this);
    }
}

public abstract class NodeVisitor
{
    public abstract void VisitVariableRefNode(VariableRefNode node);
    public abstract void VisitAssignmentNode(AssignmentNode node);
}

// 1. 类型检查
public class TypeCheckingVisitor : NodeVisitor
{
    public override void VisitVariableRefNode(VariableRefNode node)
    {
        Console.WriteLine("类型检查「变量表达式」..");
    }

    public override void VisitAssignmentNode(AssignmentNode node)
    {
        Console.WriteLine("类型检查「赋值表达式」..");
    }
}

// 2. 格式打印
public class PrettyPrintingVisitor : NodeVisitor
{
    public override void VisitVariableRefNode(VariableRefNode node)
    {
        Console.WriteLine("格式打印「变量表达式」..");
    }

    public override void VisitAssignmentNode(AssignmentNode node)
    {
        Console.WriteLine("格式打印「赋值表达式」..");
    }
}

public class App
{
    public static void Main(string[] args)
    {
        // 模拟一个对象结构
        Node[] objectStructure = { new VariableRefNode(), new AssignmentNode() };

        // 1. 类型检查
        objectStructure.Accept(new TypeCheckingVisitor());

        // 2. 格式打印
        objectStructure.Accept(new PrettyPrintingVisitor());
    }
}

public static class NodeExtensions
{
    public static void Accept(this Node[] nodes, NodeVisitor visitor)
    {
        foreach(Node node in nodes)
        {
            node.Accept(visitor);
        }
    }
}

// 控制台输出:
//  类型检查「变量表达式」..
//  类型检查「赋值表达式」..
//  格式打印「变量表达式」..
//  格式打印「赋值表达式」..
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容