Xiaokan Design Patterns (Twenty-Two)-Visitor Pattern

1 Overview

Visitor Pattern means that when the internal structure of the class remains unchanged, different visitors will show different processing methods when accessing this object. Its main function is to separate data structures from data operations, and to separate different algorithms from the objects they act on. This article will detail how the visitor pattern works and how to use it.

2.Principle and use

2.1 Principle

The visitor UML class diagram is as follows:
Insert image description here
The class diagram mainly contains five core elements: abstract visitor interface (Visitor), concrete visitor class (ConcreteVisitorA, ConcreteVisitorB) , abstract element interface (Element), concrete element class (ConcreteElementA, ConcreteElementB), object structure class (ObjectStructure). The specific explanation is as follows:

Abstract Visitor Interface (Visitor): Interface or abstract class, which defines the access behavior for each Element. Logically, the number of internal methods and the number of elements are Consistent. Under normal circumstances, the types of elements inside the Visitor are relatively stable. If the interface needs to be changed frequently, it means there is a problem with the mode selection, which may be more suitable for the strategy mode or other modes;
Specific visitor class (ConcreteVisitorA, ConcreteVisitorB): Implement the abstract interface Visitor, and internally implement the processing logic for visitors to access different elements;
Abstract Element Interface (Element) : Interface or abstract class, which defines an accept() method for calling the visitor itself to implement specific logic;
Concrete element class (ConcreteElementA, ConcreteElementB) a>: Implement abstract element (Element), most of the accept() method directly calls Visitor, which can add specific processing logic;
Object Structure Class (ObjectStructure): Responsible for associating visitors and element objects, storing element objects, and providing methods to access elements. Generally, there is an accept() method to interpret the visitor object.

2.2 Case

There is now a supermarket called Fatty. Customers can apply for different types of membership cards (platinum membership, gold membership, silver membership and ordinary membership). At the end of the year, different types of members buy New Year’s goods (pork, milk, etc. ) will have different discounts (50% off for platinum members, 30% off for gold members, 10% off for silver members, and no discount for ordinary members).
According to the visitor pattern, draw the UML class diagram as follows:
Insert image description here
The code is as follows:

public interface Goods {
    
    

    double accept(Member member);

    void display();

}

public class Milk implements Goods{
    
    

    private String name="天真蓝水牛奶";

    private double price;

    private int number;

    public double getPrice() {
    
    
        return price;
    }

    public void setPrice(double price) {
    
    
        this.price = price;
    }

    public int getNumber() {
    
    
        return number;
    }

    public void setNumber(int number) {
    
    
        this.number = number;
    }

    public Milk(double price, int number) {
    
    
        this.price = price;
        this.number = number;
    }

    @Override
    public double accept(Member member) {
    
    
        return member.visit(this);
    }

    @Override
    public void display() {
    
    
        System.out.println(name + ",价格:" + price + ",数量:" + number);
    }
}
public class Pork implements Goods {
    
    

    private String name = "进口黑猪肉";

    private double price;

    private int number;

    public double getPrice() {
    
    
        return price;
    }

    public void setPrice(double price) {
    
    
        this.price = price;
    }

    public int getNumber() {
    
    
        return number;
    }

    public void setNumber(int number) {
    
    
        this.number = number;
    }

    public Pork(double price, int number) {
    
    
        this.price = price;
        this.number = number;
    }

    @Override
    public double accept(Member member) {
    
    
        return member.visit(this);
    }

    @Override
    public void display() {
    
    
        System.out.println(name + ",价格:" + price + ",数量:" + number);
    }
}

public class ObjectStructure {
    
    

    private static List<Goods> goods = new ArrayList<>();

    //计算总价
    public double accept(Member member) {
    
    
        double sum = goods.stream().mapToDouble(goods1 -> goods1.accept(member)).sum();
        return sum;
    }

    public void add(Goods good) {
    
    
        goods.add(good);
    }

    public void remove(Goods good) {
    
    
        goods.remove(good);
    }

}

public interface Member {
    
    

    //铂金会员折扣价
    double visit(Pork pork);

    //黄金会员折扣价
    double visit(Milk milk);


}

public class Platinum implements Member {
    
    

    @Override
    public double visit(Pork pork) {
    
    
        return 0.6 * pork.getPrice() * pork.getNumber();
    }

    @Override
    public double visit(Milk milk) {
    
    
        return 0.6 * milk.getPrice() * milk.getNumber();
    }
}

public class Gold implements Member {
    
    
    @Override
    public double visit(Pork pork) {
    
    
        return 0.7 * pork.getPrice() * pork.getNumber();
    }

    @Override
    public double visit(Milk milk) {
    
    
        return 0.7 * milk.getPrice() * milk.getNumber();
    }
}

public class Silver implements Member{
    
    
    @Override
    public double visit(Pork pork) {
    
    
        return 0.9 * pork.getPrice() * pork.getNumber();
    }

    @Override
    public double visit(Milk milk) {
    
    
        return 0.9 * milk.getPrice() * milk.getNumber();
    }
}

public class Normal implements Member {
    
    

    @Override
    public double visit(Pork pork) {
    
    
        return pork.getPrice() * pork.getNumber();
    }

    @Override
    public double visit(Milk milk) {
    
    
        return milk.getPrice() * milk.getNumber();
    }

}

public class Client {
    
    

    public static void main(String[] args) {
    
    
        //铂金会员
        Platinum platinum = new Platinum();
        //黄金会员
        Gold gold = new Gold();
        //白银
        Silver silver = new Silver();
        //普通
        Normal normal = new Normal();

        ObjectStructure objectStructure = new ObjectStructure();
        //买10箱牛奶
        Goods milk = new Milk(129.0, 10);
        //买10斤猪肉
        Goods pork = new Pork(108.0, 10);

        objectStructure.add(milk);
        objectStructure.add(pork);

        double accept = objectStructure.accept(platinum);
        System.out.println("铂金会员,买10箱牛奶和10斤进口猪肉,总价为:" + accept);

        double accept1 = objectStructure.accept(gold);
        System.out.println("黄金会员,买10箱牛奶和10斤进口猪肉,总价为:" + accept1);

        double accept2 = objectStructure.accept(silver);
        System.out.println("白银会员,买10箱牛奶和10斤进口猪肉,总价为:" + accept2);

        double accept3 = objectStructure.accept(normal);
        System.out.println("普通会员,买10箱牛奶和10斤进口猪肉,总价为:" + accept3);

    }
}


The running results are as follows:

Insert image description here

2.3 Advantages and Disadvantages

2.3.1 Advantages

1. Comply with the single responsibility principle, allowing the program to have excellent scalability and flexibility;
2. The visitor mode is suitable for systems with relatively stable data structures and can be used to Functions like filters and interceptors.

2.3.2 Disadvantages

1. Violating Demeter's Law, the visitor pays attention to the internal details of other classes;
2. Violating the principle of dependency inversion, the visitor accesses specific elements instead of Abstract elements.

3. Summary

1. Visitor mode is a more complex mode among design patterns. It is mainly suitable for scenarios where the class corresponding to the object changes less and requires more operations on the object;
2. To a certain extent, the visitor pattern has certain similarities with the strategy pattern and the state pattern. The strategy pattern is an abstract algorithm class, which allows subclasses to implement specific algorithms and replace the algorithm according to conditions; the state pattern is to replace the state Encapsulated into objects, combining state and behavior; visitors encapsulate the operations corresponding to different visitors into classes, and each class has strategies.

4. References

1. "Zen of Design Patterns" - written by Qin Xiaobo
2. "Dahua Design Patterns" - written by Cheng Jie
3. https: //www.bilibili.com/video/BV1G4411c7N4-Silicon Valley Design Pattern
4. https://www.runoob.com/design-pattern/observer-pattern.html

Guess you like

Origin blog.csdn.net/qq_33479841/article/details/128368642