[Design Pattern Series 23] The Ultimate BOSS of Design Patterns: Visitor Pattern

Design pattern series overview

Design Patterns Air ticket
Three factory models Boarding entrance
Strategy mode Boarding entrance
Delegation mode Boarding entrance
Template method pattern Boarding entrance
Observer mode Boarding entrance
Singleton mode Boarding entrance
Prototype mode Boarding entrance
Agency model Boarding entrance
Decorator mode Boarding entrance
Adapter mode Boarding entrance
Builder mode Boarding entrance
Chain of Responsibility Model Boarding entrance
Flyweight model Boarding entrance
Combination mode Boarding entrance
Facade pattern Boarding entrance
Bridge mode Boarding entrance
Intermediary model Boarding entrance
Iterator mode Boarding entrance
State mode Boarding entrance
Interpreter mode Boarding entrance
Memo mode Boarding entrance
Command mode Boarding entrance
Visitor mode Boarding entrance
Summary of 7 principles and design patterns of software design Boarding entrance

Preface

The design pattern series here is the last design pattern of 23 design patterns. The visitor pattern can also be said to be the most difficult design pattern of all design patterns. Of course, we rarely use it. The author of the design pattern evaluates the visitor pattern like this: In most cases, you don't need to use the visitor pattern, but once you need to use it, you really need to use it.

What is the visitor pattern

The visitor pattern (Vistor Pattern) is a design pattern that separates data structure and data operation. It refers to encapsulating some operations that act on various elements in a certain data structure. It can define new operations that act on these elements without changing the data structure. The visitor mode is a behavioral mode.

The basic idea of ​​the visitor pattern is to provide an accept() method in it to accept the visitor's object for certain fixed types of object structures (elements) in the system. Different visitors have different access content to the same element, so that the same element set can produce different element results. The accept() method can accept different visitor objects, and then internally forwards itself to the visit() method of the visitor object.

The core idea of ​​the visitor pattern is to decouple the data structure and data operation, so that the operation of the element has excellent scalability. We can implement different operations on the same element by extending different data operation types (visitors).

After reading this large number of theoretical concepts, do you feel a little dizzy? This does sound a bit abstract, don't worry, continue to look down:

The moment of pretending is here again: Talk is cheap, Show you the code , let’s take an example to see how the visitor pattern is written.

Sample visitor pattern

We take as an example that when ordering in a restaurant, the customer needs to view the order through the menu. In this example, the customer is the visitor, and the dishes are the information that the visitor needs to access.

1. First establish a dish (recipe) interface, and only define a method that accepts visitors to visit:

package com.zwx.design.pattern.visitor;

public interface IRecipe {
    
    
    void accept(ICustomer customer);
}

Next we only list two kinds of videos, one kind of braised pork and one kind of seasonal vegetables. So two classes are needed:

package com.zwx.design.pattern.visitor;

public class Meat implements IRecipe {
    
    
    @Override
    public void accept(ICustomer customer) {
    
    
        customer.visit(this);
    }

    public String getPrice(){
    
    
        return "88元/份";
    }
}
package com.zwx.design.pattern.visitor;

public class Cabbage implements IRecipe {
    
    
    @Override
    public void accept(ICustomer customer) {
    
    
        customer.visit(this);
    }

    public String getPrice(){
    
    
        return "44元/份";
    }
}

In addition to implementing the accept method in these two classes, they also provide a method to check the price.

3. At this time we need to create an abstract visitor:

package com.zwx.design.pattern.visitor;

public interface ICustomer {
    
    
    void visit(Meat meat);
    void visit(Cabbage cabbage);
}

Two methods with the same method name are defined, but the parameters are different, and the parameters correspond to the elements. In theory, there are several dishes above. We need to define several methods, that is, the number of methods and the number of elements to be accessed must be equal.

4. Next, create a specific visitor role for customer A to implement abstract visitors:

package com.zwx.design.pattern.visitor;

public class CustomerA implements ICustomer{
    
    
    @Override
    public void visit(Meat meat) {
    
    
        System.out.println("肉类:" + meat.getPrice());
    }

    @Override
    public void visit(Cabbage cabbage) {
    
    
        System.out.println("时蔬:" + cabbage.getPrice());
    }
}

Now that there are visitors and dishes, there is one less menu, because customers need to view the dish information through the menu, and then order, so we also need a menu category to manage all dishes.

5. Create a new menu class:

package com.zwx.design.pattern.visitor;

import java.util.ArrayList;
import java.util.List;

public class RestaurantMenu {
    
    
    private List<IRecipe> recipeList = new ArrayList<>();

    public RestaurantMenu(IRecipe recipe) {
    
    
        recipeList.add(recipe);
    }

    public void addRecipe(IRecipe recipe){
    
    
        recipeList.add(recipe);
    }

    public void display(ICustomer customer){
    
    
        for (IRecipe recipe : recipeList){
    
    
            recipe.accept(customer);
        }
    }
}

In the menu class, all dishes are maintained through a list, and then all the dish information is displayed through the display method.

6. Next we create a test class to test:

package com.zwx.design.pattern.visitor;

public class TestVistor {
    
    
    public static void main(String[] args) {
    
    
        IRecipe recipe = new Meat();
        RestaurantMenu menu = new RestaurantMenu(recipe);
        menu.addRecipe(new Cabbage());
        menu.display(new CustomerA());
    }
}

Output the following information:

肉类:88/
时蔬:44/

This is a visitor pattern. The above is because visitors must change frequently, but we only need to add more customer classes, which is very convenient.

If it is the first time for you to come into contact with the visitor pattern, you may feel that the example is still a bit abstract, then I suggest that you write a few times against the example yourself, and you will gradually find the feeling.

Visitor role

From the above example, we can conclude that the visitor pattern mainly has 5 roles:

  • Abstract visitor (Vistor): Either interface or abstract class (such as ICustomer in the example). This role is mainly to define the visit method for specific elements. The parameters are specific elements. In theory, the number of methods is equal to the number of elements. Therefore, if the element is unstable and often changes, then the visitor must always modify it, and it is not suitable to use the visitor mode, so the visitor mode is suitable for scenarios where the element structure is relatively stable.
  • Concrete Visitor (ConcreteVistor): to achieve access to specific elements (such as CustomerA in the example).
  • Abstract element (Element): Interface or abstract class. Defines a method accept (such as IRecipe in the example) that accepts visitor access.
  • Concrete Element (ConcreteElement): Provides a specific implementation for accepting visitor access, usually by visitor.visit() (such as Cabbage and Meat in the example).
  • Structure object (ObjectStruture): used to maintain elements and provide a method to accept visitors to access all elements (such as RestaurantMenu in the example).

Application scenarios for visitor mode

The visitor mode is suitable for the following scenarios:

  • 1. The data structure should be stable, but the operations that act on the data structure often change (for example, if the recipe changes frequently in the above example, the visitor object must be modified every time it changes).
  • 2. It is necessary to operate on different data types (elements) without using branches to determine specific types of scenes.

Advantages and disadvantages of visitor mode

advantage:

  • 1. The data structure and data operation are decoupled, so that the operation set can be changed independently.
  • 2. The visitor role is very easy to expand.
  • 3. Each role performs its own duties and conforms to the principle of single responsibility.
    Disadvantage
  • 1. It is difficult to increase the element type. If the element type changes, the visitor source code needs to be modified, which violates the opening and closing principle and is not conducive to maintenance.
  • 2. Violating the dependency inversion principle, such as the visitor interface in our example, the defined method relies on concrete elements rather than abstract elements.

to sum up

This article mainly introduces the last design pattern among the 23 design patterns of GoF, which is also the most difficult design pattern. It can be called the ultimate BOSS of design patterns. An example is used to demonstrate the way of writing the visitor pattern, and finally the summary The role of the visitor model and its advantages and disadvantages.

Please pay attention to me and learn and progress with the lone wolf .

Guess you like

Origin blog.csdn.net/zwx900102/article/details/109412658