Skip to content

Visitor (Посетитель)

Шаблон проектирования "Посетитель" (Visitor) позволяет добавлять новые операции к объектам, не изменяя их классы. Этот паттерн особенно полезен, когда у вас есть структура объектов с различными классами, и вы хотите выполнить операции над этими объектами, не изменяя их внутреннюю реализацию.

Основные компоненты паттерна "Посетитель":

  1. Посетитель (Visitor): интерфейс, который определяет методы для каждого типа элемента, который может быть посещен.
  2. Конкретный посетитель (Concrete Visitor): класс, который реализует интерфейс посетителя и определяет конкретные операции для каждого типа элемента.
  3. Элемент (Element): интерфейс, который определяет метод accept, который принимает посетителя.
  4. Конкретные элементы (Concrete Elements): классы, реализующие интерфейс элемента и определяющие, как посетитель будет взаимодействовать с ними.
  5. Структура объектов (Object Structure): класс, который содержит коллекцию элементов и позволяет посетителю проходить по ним.

Пример на Java

Рассмотрим пример, в котором у нас есть структура объектов, представляющая различные фигуры (круги и прямоугольники), и мы хотим вычислить их площади.

// Интерфейс посетителя
interface ShapeVisitor {
    void visit(Circle circle);
    void visit(Rectangle rectangle);
}

// Интерфейс элемента
interface Shape {
    void accept(ShapeVisitor visitor);
}

// Конкретный элемент: Круг
class Circle implements Shape {
    private double radius;

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

    public double getRadius() {
        return radius;
    }

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

// Конкретный элемент: Прямоугольник
class Rectangle implements Shape {
    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(ShapeVisitor visitor) {
        visitor.visit(this);
    }
}

// Конкретный посетитель: Вычисление площади
class AreaCalculator implements ShapeVisitor {
    private double totalArea = 0;

    @Override
    public void visit(Circle circle) {
        double area = Math.PI * circle.getRadius() * circle.getRadius();
        totalArea += area;
        System.out.println("Площадь круга: " + area);
    }

    @Override
    public void visit(Rectangle rectangle) {
        double area = rectangle.getWidth() * rectangle.getHeight();
        totalArea += area;
        System.out.println("Площадь прямоугольника: " + area);
    }

    public double getTotalArea() {
        return totalArea;
    }
}

// Пример использования
public class VisitorPatternExample {
    public static void main(String[] args) {
        Shape[] shapes = new Shape[]{
            new Circle(5),
            new Rectangle(4, 6)
        };

        AreaCalculator areaCalculator = new AreaCalculator();

        for (Shape shape : shapes) {
            shape.accept(areaCalculator);
        }

        System.out.println("Общая площадь: " + areaCalculator.getTotalArea());
    }
}

Объяснение кода:

  1. Интерфейс ShapeVisitor определяет методы visit для каждого типа фигуры (круга и прямоугольника).
  2. Интерфейс Shape определяет метод accept, который принимает посетителя.
  3. Классы Circle и Rectangle реализуют интерфейс Shape и определяют, как посетитель будет взаимодействовать с ними.
  4. Класс AreaCalculator реализует интерфейс ShapeVisitor и определяет, как вычислять площадь для каждой фигуры.
  5. В методе main мы создаем массив фигур и используем AreaCalculator для вычисления их площадей.

Таким образом, паттерн "Посетитель" позволяет добавлять новые операции (например, вычисление площади) к объектам (фигурами) без изменения их классов. Это делает код более гибким и расширяемым, особенно когда количество операций может увеличиваться.