设计模式(行为型模式)访问者模式

目录

    • 一、简介
    • 二、策略模式
      • 2.1、抽象节点接口
      • 2.2、具体节点
      • 2.3、抽象访问者接口
      • 2.4、具体访问者实现
      • 2.5、使用
    • 三、优点与缺点

一、简介

  访问者模式(Visitor Pattern)是一种行为设计模式,它允许在不改变被访问对象的类的情况下定义新的操作。

  该模式的核心思想是将数据结构和对数据的操作分离开来,使得可以在不修改数据结构的前提下定义新的操作。它允许定义在数据结构上进行的操作,并且可以在数据结构上方便地增加新的操作,而无需修改原有的代码。访问者模式包括以下主要角色:

  • 访问者(Visitor): 定义了对数据结构中各元素的访问操作接口或抽象类。每个具体的访问者类都实现了对应的访问操作。
  • 具体访问者(Concrete Visitor): 实现了Visitor定义的接口或抽象类,提供了针对数据结构中各元素的具体访问操作。
  • 元素(Element): 定义了一个接受访问者访问的接口或抽象类。通常会提供一个accept方法,接收访问者的访问。
  • 具体元素(Concrete Element): 实现了Element定义的接口或抽象类,具体元素中实现了accept方法,用于接受访问者的访问。
  • 对象结构(Object Structure): 包含一个或多个元素,可以是集合、列表、树等数据结构,提供一个接受访问者访问的方法。

  访问者模式适用于当一个数据结构(如集合、树等)中包含的元素类别固定,但需要对这些元素执行不同的操作时。通过访问者模式,可以将对数据结构的操作集中到访问者类中,使得数据结构和操作之间解耦,提高了系统的灵活性和扩展性。

二、策略模式

  假设有一个简单的算术表达式语法树,包含加法和乘法操作符,以及数字作为操作数。我们将创建一个访问者来执行不同类型节点的操作。

2.1、抽象节点接口

// 抽象节点接口
public interface Node {
    void accept(Visitor visitor);
}

2.2、具体节点

数字节点

// 具体节点:数字节点
public class NumberNode implements Node {
    private int value;

    public NumberNode(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

加法节点

// 具体节点:加法节点
public class AdditionNode implements Node {
    private Node left;
    private Node right;

    public AdditionNode(Node left, Node right) {
        this.left = left;
        this.right = right;
    }

    public Node getLeft() {
        return left;
    }

    public Node getRight() {
        return right;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

乘法节点

// 具体节点:乘法节点
public class MultiplicationNode implements Node {
    private Node left;
    private Node right;

    public MultiplicationNode(Node left, Node right) {
        this.left = left;
        this.right = right;
    }

    public Node getLeft() {
        return left;
    }

    public Node getRight() {
        return right;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

其他节点省略…

2.3、抽象访问者接口

// 抽象访问者接口
public interface Visitor {
    void visit(NumberNode node);
    void visit(AdditionNode node);
    void visit(MultiplicationNode node);
}

2.4、具体访问者实现

// 具体访问者实现
public class ExpressionEvaluator implements Visitor {
    private int result;

    @Override
    public void visit(NumberNode node) {
        result = node.getValue(); // 数字节点直接返回其值
    }

    @Override
    public void visit(AdditionNode node) {
        node.getLeft().accept(this); // 计算左子树
        int leftValue = result;

        node.getRight().accept(this); // 计算右子树
        int rightValue = result;

        result = leftValue + rightValue; // 执行加法操作
    }

    @Override
    public void visit(MultiplicationNode node) {
        node.getLeft().accept(this); // 计算左子树
        int leftValue = result;

        node.getRight().accept(this); // 计算右子树
        int rightValue = result;

        result = leftValue * rightValue; // 执行乘法操作
    }

    public int getResult() {
        return result;
    }
}

2.5、使用

  构建一个简单的表达式树:2 * (3 + 4)

// 测试
public class VisitorCompilerExample {
    public static void main(String[] args) {
        // 构建一个简单的表达式树:2 * (3 + 4)
        Node expression = new MultiplicationNode(
            new NumberNode(2),
            new AdditionNode(
                new NumberNode(3),
                new NumberNode(4)
            )
        );
        // 创建访问者并执行计算
        ExpressionEvaluator evaluator = new ExpressionEvaluator();
        expression.accept(evaluator);

        // 输出结果
        System.out.println("Result: " + evaluator.getResult());
    }
}

运行结果:

Result: 14

  在这个示例中,我们建立了一个简单的算术表达式语法树,包括数字、加法和乘法节点。Visitor 是访问者接口,定义了访问不同类型节点的方法。ExpressionEvaluator 是一个具体的访问者实现,根据节点类型执行不同的操作(计算)。

三、优点与缺点

  访问者模式具有以下优点和缺点:

优点

  • 增加新的操作: 可以在不修改被访问对象的类的情况下,定义新的操作,通过添加新的具体访问者类,扩展现有的功能。
  • 增加新的元素类: 通过添加新的具体元素类,可以容易地扩展访问者模式,而不会影响现有的代码。
  • 数据结构与操作分离: 将数据结构与操作分离开来,使得数据结构的稳定性和操作的灵活性得到了提升,增加了代码的可维护性和可扩展性。

缺点

  • 违反开闭原则: 添加新的元素类需要修改访问者接口或抽象类,以及所有具体访问者类,可能会违反开闭原则。
  • 增加了类的数量: 随着具体元素类和具体访问者类的增加,类的数量可能会急剧增加,导致系统变得更加复杂。
  • 破坏封装性: 访问者模式会使得具体元素暴露访问者接口,可能会破坏封装性,增加对象之间的耦合度。

  总的来说,访问者模式可以在不修改现有代码的情况下,增加新的操作,使得代码更具扩展性和灵活性。但是,随着具体元素类和具体访问者类的增加,可能会导致系统复杂度上升,并且需要权衡代码的扩展性和维护性。使用访问者模式时,需要谨慎考虑并根据具体情况选择是否使用。

你可能感兴趣的:(设计模式,设计模式,访问者模式)