Home >Java >javaTutorial >How to use Java visitor pattern to handle object structures in a beautiful way
Java Visitor Pattern (Visitor Pattern) is a behavioral design pattern that allows the algorithm to be separated from the objects it operates on. This pattern defines a visitor object that can access different Type of object and perform some operations, it also allows you to add new operations without modifying the existing code.
In the visitor pattern, there are two important roles: visitor and Element. An element is a component of an object structure. A visitor is an object that represents an operation to be performed. Visitors can access elements through the element's accept method.
Java visitor patterns usually involve the following 5 types Role:
Abstract Visitor: Defines the access method that can access each element.
Concrete Visitor ): Implements the access method defined by the abstract visitor, including specific operations for different elements.
Abstract Element (Element): Defines a method that accepts the visitor object to enable access The visitor can access himself.
Concrete Element: Implements the visitor method defined by the abstract element so that the visitor can access himself.
Object Structure: A collection containing elements that can provide an iterator to traverse the elements and can accept access from visitors.
There are different types of animals in the zoo, including dogs, cats and birds. The visitor mode can be used to count the number of different types of animals, as well as the attribute information of different types of animals.
Abstract Elements
public interface Animal { void accept(Visitor visitor); }
Concrete element
@Data public class Bird implements Animal{ private String name; private String habitat; public Bird(String name, String habitat) { this.name = name; this.habitat = habitat; } @Override public void accept(Visitor visitor) { visitor.visitor(this); } } @Data public class Cat implements Animal{ private String sound; private int age; public Cat(String sound, int age) { this.sound = sound; this.age = age; } @Override public void accept(Visitor visitor) { visitor.visitor(this); } } @Data public class Dog implements Animal{ private String color; private int size; public Dog(String color, int size) { this.color = color; this.size = size; } @Override public void accept(Visitor visitor) { visitor.visitor(this); } }
Abstract visitor
public interface Visitor { void visitor(Dog dog); void visitor(Cat cat); void visitor(Bird bird); }
Specific visitor
public class AnimalCountVisitor implements Visitor{ private int dogCount; private int birdCount; private int catCount; @Override public void visitor(Dog dog) { dogCount++; } @Override public void visitor(Cat cat) { catCount++; } @Override public void visitor(Bird bird) { birdCount++; } public void printCount(){ System.out.println("狗的个数:"+dogCount); System.out.println("猫的个数:"+catCount); System.out.println("鸟的个数:"+birdCount); } } public class AnimalFeatureVisitor implements Visitor { private List<String> features; public AnimalFeatureVisitor() { features = new ArrayList<>(); } @Override public void visitor(Dog dog) { features.add("Dog:color=" + dog.getColor() + ",size=" + dog.getSize()); } @Override public void visitor(Cat cat) { features.add("Car:sound=" + cat.getSound() + ",age=" + cat.getAge()); } @Override public void visitor(Bird bird) { features.add("Bird:name=" + bird.getName() + ",habitat=" + bird.getHabitat()); } public void printFeatures(){ features.forEach(System.out::println); } }
Test
public class Demo { public static void main(String[] args) { List<Animal> animals = new ArrayList<>(); animals.add(new Dog("褐色", 50)); animals.add(new Dog("白色", 45)); animals.add(new Cat("喵喵叫", 2)); animals.add(new Cat("呜呜声", 3)); animals.add(new Bird("鹦鹉", "森林")); animals.add(new Bird("麻雀", "田野")); AnimalCountVisitor animalCountVisitor = new AnimalCountVisitor(); AnimalFeatureVisitor animalFeatureVisitor = new AnimalFeatureVisitor(); animals.forEach(animal -> { animal.accept(animalCountVisitor); animal.accept(animalFeatureVisitor); }); animalCountVisitor.printCount(); animalFeatureVisitor.printFeatures(); } }
In this example, we have defined three animal classes, including Dog, Cat and Bird. They all implement the Animal interface and have an accept method, which passes in the Visitor type parameter.
Next, the Visitor interface is defined, which contains the visitor method, which accesses according to the different types of animals passed in.
In the specific implementation of Visitor, two visitors, AnimalCountVisitor and AnimalFeatureVisitor, are defined , the former is used to count the number of different types of animals, and the latter is used to print the attributes of different types of animals.
Separate algorithms and objects: The visitor pattern makes it possible to separate algorithms and objects, because the algorithm is defined in the visitor, and the object exposes its own data to the visitor when it is accessed.
Good scalability: This mode can easily add new operations without affecting the existing object structure, because the visitor mode separates the object structure from the operation.
Conform to the open-closed principle: The visitor pattern conforms to the open-closed principle because you can add new visitors and new element types without changing existing code.
Simplify Code logic: The visitor pattern separates objects and operations, simplifying the code logic.
It is difficult to add new element types : When a new element type needs to be added, the existing visitor interface must be modified, which may lead to modifications to the existing code.
Destruction of encapsulation: The visitor pattern requires the object to be The internal data is exposed to visitors, which may destroy the encapsulation of the object.
When a complex object structure needs to be When performing operations without exposing its internal implementation, you can use the visitor pattern.
When you need to add some new operations to each object in the object structure without affecting its class hierarchy When the object's class hierarchy changes, but its operation remains relatively stable, the visitor pattern can be used.
When you need to dynamically determine the operation to be performed at runtime, you can use the visitor pattern.
The above is the detailed content of How to use Java visitor pattern to handle object structures in a beautiful way. For more information, please follow other related articles on the PHP Chinese website!