Writing in the front

  • Take notes on learning design patterns
  • Improve flexibility in the use of design patterns

Learning to address

https://www.bilibili.com/vide…

https://www.bilibili.com/vide…

Refer to the article

http://c.biancheng.net/view/1…

Project source https://gitee.com/zhuang-kang/DesignPattern

19. Visitor pattern

19.1 Visitor pattern definitions and characteristics

The definition of the Visitor pattern: The operations on each element in a data structure are separated and encapsulated into independent classes, so that new operations on these elements can be added without changing the data structure, providing multiple access methods for each element in the data structure. It separates the manipulation of data from the data structure and is one of the most complex behavioral patterns.

The Visitor pattern is an object behavior pattern with the following main advantages.

  1. Good scalability. The ability to add new functionality to elements in an object structure without modifying the elements in the object structure.
  2. Good reusability. You can use visitors to define functionality that is common throughout the object structure, thus increasing the degree of system reuse.
  3. Good flexibility. The Visitor pattern decouples the data structure from the operations that act on the structure, allowing the set of operations to evolve relatively freely without affecting the data structure of the system.
  4. Comply with the Single Responsibility Principle. The Visitor pattern encapsulates related behaviors into a single visitor, so that each visitor has a single function.

The main disadvantages of the Visitor pattern are as follows.

  1. Adding new element classes is difficult. In the Visitor pattern, each new element class is added with a corresponding concrete operation in each specific Visitor class, which violates the Open Closed Principle.
  2. Break encapsulation. Specific elements in the visitor pattern expose details to the visitor, which breaks the encapsulation of the object.
  3. It violates the principle of dependency inversion. Visitor patterns rely on concrete classes rather than abstract classes.

19.2 Structure and implementation of the Visitor pattern

19.2.1 Structure of the Visitor pattern

  1. Abstract Visitor role: Defines an interface to access a concrete element, and for each concrete element class there is an access operation visit() in which the parameter type identifies the concrete element being visited.
  2. Concrete-Visitor role: Implements the various access operations declared in the abstract visitor role to determine what visitors should do when they access an element.
  3. The Element role: Declare an interface that contains the accept operation, with the accepted visitor object as a parameter to the accept() method.
  4. Concrete element (ConcreteElement) role: Implement the accept() operation provided by the abstract element role, which typically has a method body of visit.visit (this), and may also contain related operations of its own business logic.
  5. Object Structure Role: A container containing element roles that provide methods for visitor objects to traverse all elements in the container, usually implemented by aggregate classes such as List, Set, Map, etc.

19.2.2 Code implementation

Now there are many people who keep pets, we take this as an example. Of course, pets are divided into dogs, cats and so on. If you want to feed the pet, the owner can feed it and others can also feed it.

  • Role of the visitor: the person who feeds the pet
  • Specific visitor roles: host, others
  • Abstract element role: animal abstract class
  • Specific elemental characters: pet dog, pet cat
  • Structure object role: host

Person

package com.zhuang.visitor; /** * @ClassName Person * @Description * @Date 2021/3/27 16:48 * @Created by Dell */ public interface Person { Void feed(Dog Dog); Void feed(Cat Cat); }

Owner

package com.zhuang.visitor; /** * @ClassName Owner * @Description * @Date 2021/3/27 16:49 * @Created by Dell */ public class Owner Implements Person {@Override public void feed(Dog Dog) {System.out.println("..."); ); } @Override public void feed(Cat Cat) {System.out.println();} @Override public void feed(Cat Cat) {System.out.println(); ); }}

Someone

package com.zhuang.visitor; /** * @className Someone * @description * @date 2021/3/27 16:49 * @Created by Dell */ public class Someone * @Created by Dell */ public class Someone * @Created by Dell */ public class Someone * @Created by Dell */ public class Someone * @Created by Dell */ Implements Person {@Override public void feed(Dog Dog) {System.out.println("..."); / / Override public void feed(Dog Dog) {System.out. ); } @Override public void feed(Cat Cat) {System.out.println();} @Override public void feed(Cat Cat) {System.out.println(); ); }}

Animal

package com.zhuang.visitor; /** * @ClassName * @Description * @Date 2021/3/27 16:50 * @Created by Dell */ public interface Animal { void accept(Person person); }

Dog

package com.zhuang.visitor;

/**
 * @Classname Dog
 * @Description 具体节点 实现Animal接口
 * @Date 2021/3/27 16:48
 * @Created by dell
 */

public class Dog implements Animal {
    @Override
    public void accept(Person person) {
        person.feed(this);
        System.out.println("真香~,汪汪汪!!!");
    }
}

Cat

package com.zhuang.visitor; /** * @ClassName Cat * @Description * @Date 2021/3/27 16:49 * @Created by Dell */ public class Cat implements  Animal { @Override public void accept(Person person) { person.feed(this); Println (" This is so sweet ~, meow meow!!" ); }}

Home

package com.zhuang.visitor; import java.util.ArrayList; import java.util.List; /** * @ClassName Home * @Description * @Date 2021/3/27 16:50 * @Created by Dell */ public class Home { private List<Animal> nodeList = new ArrayList<Animal>(); Public void add(Animal Animal) {nodelist.add (Animal); } public void aciton(Person person) { for (Animal node : nodeList) { node.accept(person); }}}

Client

package com.zhuang.visitor; /** * @ClassName Client * @Description Visitor model * @Date 2021/3/27 16:50 * @Created by Dell */ public class Client { public static void main(String[] args) { Home home = new Home(); home.add(new Dog()); home.add(new Cat()); Owner owner = new Owner(); home.aciton(owner); System.out.println("==========================="); Someone someone = new Someone(); home.aciton(someone); }}

19.3 extensions

The Visitor pattern uses a double-dispatch technique.

1. Assignment:

The type of a variable when it is declared is called the static type of the variable. Some people also call static types explicit types. The actual type of the object that the variable refers to is also called the actual type of the variable. For example, Map Map = new HashMap(), the static type of the Map variable is Map, and the actual type is HashMap. The selection of methods based on the type of object is called dispatching, and there are two types of dispatches, static and dynamic.

Static Dispatch occurs at compile time and occurs based on Static type information. Static dispatch is nothing new to us, and method overloading is static dispatch.

Dynamic Dispatch occurs at run time and dynamically displaces a method. Java supports dynamic dispatch through overrides of methods.

2. Dynamic dispatch:

Dynamic dispatch is supported through overriding of methods.

public class Animal { public void execute() { System.out.println("Animal"); }} public class Dog extends Animal {@Override public void execute() {System.out.println();} public class Dog extends Animal {@Override public void execute() {System.out.println(); ); }} public class Cat extends Animal {@Override public void execute() {System.out.println();} public void execute() {System.out.println(); ); } } public class Client { public static void main(String[] args) { Animal a = new Dog(); a.execute(); Animal a1 = new Cat(); a1.execute(); }}

The results of the above code should be directly can be said, this is not polymorphic! Runs execute methods in subclasses.

The Java compiler does not always know what code will be executed at compile time because the compiler only knows the static type of the object, not the actual type of the object; Methods are called according to the actual type of the object, not the static type.

Static dispatch:

Static dispatch is supported through method overloading.

public class Animal { } public class Dog extends Animal { } public class Cat extends Animal { } public class Execute { public void execute(Animal a) { System.out.println("Animal"); } public void execute(Dog d) {System.out.println();} public void execute(Dog d); ); } public void execute(Cat c) {System.out.println();} public void execute(Cat c); ); } } public class Client { public static void main(String[] args) { Animal a = new Animal(); Animal a1 = new Dog(); Animal a2 = new Cat(); Execute exe = new Execute(); exe.execute(a); exe.execute(a1); exe.execute(a2); }}

Running results:

This may come as a surprise to some, but why?

Overloaded method dispatching is done based on static type, which is done at compile time.

4. Double assignment:

The so-called double dispatch technique is to select a method not only according to the message receiver (receiver) runtime difference, but also according to the parameter runtime difference.

public class Animal { public void accept(Execute exe) { exe.execute(this); } } public class Dog extends Animal { public void accept(Execute exe) { exe.execute(this); } } public class Cat extends Animal { public void accept(Execute exe) { exe.execute(this); } } public class Execute { public void execute(Animal a) { System.out.println("animal"); } public void execute(Dog d) {System.out.println();} public void execute(Dog d); ); } public void execute(Cat c) {System.out.println();} public void execute(Cat c); ); } } public class Client { public static void main(String[] args) { Animal a = new Animal(); Animal d = new Dog(); Animal c = new Cat(); Execute exe = new Execute(); a.accept(exe); d.accept(exe); c.accept(exe); }}

In the code above, the client will Execute objects as arguments passed to the Animal the method called types of variables, here to complete the first dispatch, here is the way to rewrite, so is the dynamic dispatch, also is to perform the actual type of the method, at the same time also this passed as a parameter in, here is completed the second assignment, There are multiple overloaded methods in the Execute class, and the pass is this, which is an object of concrete actual type.

At this point, we’ve seen how double dispatch works, but what effect does it have? We can implement the dynamic binding method, we can modify the above program.

The running results are as follows:

The essence of the dynamic binding implemented by double dispatch is that the delegate of the overloaded method is preceded by the part of the inheritance system that is overridden. Since overriding is dynamic, overloading is dynamic.

Write in the last

  • If my article is useful to you, please click 👍, thank you!
  • Let me know in the comments section if you have any questions! 💪