设计模式-访问者模式

2023-05-05 14:06:11 浏览数 (1)

一、什么是访问者模式?

访问者模式是一种行为型设计模式,它允许你在不修改现有代码的情况下添加新的行为,通过将算法与对象结构分离,来实现对数据结构中的元素进行新的操作。访问者模式的核心思想是,将数据结构与算法分离开来,使得数据结构可以保持不变,而算法可以根据需要自由地变化。

访问者模式适用于数据结构相对稳定,但其中操作或算法需要频繁修改的情况,例如编译器的代码生成、文档解析器等。

二、访问者模式的角色

在访问者模式中,主要有以下角色:

  1. 抽象访问者(Visitor):定义一个访问者可以访问哪些元素,并为每种元素都提供一个访问方法,从而对元素进行不同的操作。
  2. 具体访问者(ConcreteVisitor):实现抽象访问者中定义的访问方法,完成对元素的具体操作。
  3. 抽象元素(Element):定义一个接受访问者访问的接口,从而使得访问者可以访问元素。
  4. 具体元素(ConcreteElement):实现抽象元素中定义的接口,即实现接受访问者的访问方法。
  5. 对象结构(Object Structure):由多个不同类型的元素组成的复杂对象,提供让访问者访问各个元素的接口。
  6. 客户端(Client):通过访问者来访问对象结构中的元素,完成不同的操作。

三、访问者模式的实现

下面给出一个简单的访问者模式的 Java 示例。假设有一个图形类 Shape,它有三种类型:圆形、矩形和三角形。现在需要对这三种图形进行不同的操作,例如计算面积、计算周长等,同时又不希望在 Shape 类中添加过多的方法。这时候,可以使用访问者模式。

定义抽象访问者 Visitor

代码语言:javascript复制
public interface Visitor {
    void visit(Circle circle);
    void visit(Rectangle rectangle);
    void visit(Triangle triangle);
}

定义具体访问者 AreaVisitor 和 PerimeterVisitor

代码语言:javascript复制
// Circle、Rectangle、Triangle 分别为具体元素
public class PerimeterVisitor implements Visitor {
    @Override
    public void visit(Circle circle) {
        System.out.println("计算圆形周长:"   2 * Math.PI * circle.getRadius());
    }

    @Override
    public void visit(Rectangle rectangle) {
        System.out.println("计算矩形周长:"   2 * (rectangle.getWidth()   rectangle.getHeight()));
    }

    @Override
    public void visit(Triangle triangle) {
        double a = triangle.getA();
        double b = triangle.getB();
        double c = triangle.getC();
        System.out.println("计算三角形周长:"   (a   b   c));
    }
}

// Element 接口,定义 accept 方法,接受 Visitor 访问
public interface Element {
    void accept(Visitor visitor);
}

// Circle、Rectangle、Triangle 分别为具体元素,实现 accept 方法
public class Circle implements Element {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

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

public class Rectangle implements Element {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public double getWidth() {
        return width;
    }

    public double getHeight() {
        return height;
    }

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

public class Triangle implements Element {
    private double a;
    private double b;
    private double c;

    public Triangle(double a, double b, double c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    public double getA() {
        return a;
    }

    public double getB() {
        return b;
    }

    public double getC() {
        return c;
    }

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

// ObjectStructure 对象结构,存储多个 Element
public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void removeElement(Element element) {
        elements.remove(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Circle circle = new Circle(5);
        Rectangle rectangle = new Rectangle(3, 4);
        Triangle triangle = new Triangle(3, 4, 5);

        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(circle);
        objectStructure.addElement(rectangle);
        objectStructure.addElement(triangle);

        AreaVisitor areaVisitor = new AreaVisitor();
        objectStructure.accept(areaVisitor);

        PerimeterVisitor perimeterVisitor = new PerimeterVisitor();
        objectStructure.accept(perimeterVisitor);
    }
}

在示例代码中,Visitor 接口定义了访问三种元素的 visit 方法,具体访问者 AreaVisitor 和 PerimeterVisitor 实现了 visit 方法。Element 接口定义了 accept 方法,具体元素 Circle、Rectangle、Triangle 实现了 accept 方法,接受 Visitor 访问。ObjectStructure 对象结构存储多个 Element,提供添加、删除、接受 Visitor 访问等方法。客户端 Client 构造具体元素和 ObjectStructure 对象结构,并使用具体访问者 AreaVisitor 和 PerimeterVisitor 访问元素。

访问者模式的优缺点如下:

优点:

  1. 可以在不修改元素类的情况下添加新的操作,符合开闭原则;
  2. 将相关行为集中在访问者中,分离了行为和元素,提高了系统的可扩展性和灵活性;
  3. 访问者模式可以对元素进行一些复杂的操作,尤其是在集合类元素的处理上,可以避免迭代器造成的性能问题。

缺点:

  1. 增加新的元素类需要修改访问者接口,违反了开闭原则;
  2. 具体元素对访问者公布细节,破坏了封装性;
  3. 访问者模式中元素的增加和删除比较困难。

0 人点赞