[Design Patterns] Chapter 26 Visitor Pattern

1. Overview of visitor mode

Let's introduce the visitor pattern through an example.
After the doctor issues a prescription (drug list), the price-computing staff calculates the total price based on the name and quantity of the drug after getting the prescription, and the pharmacy staff calculates the total price based on the name and quantity of the drug.
Here, the prescription list sees a set of drug information, which contains one or more different types of drug information. Different types of staff will provide different processing methods when operating the same drug information set, and may also New types of staff will be added to handle prescription orders.

Something like this common, you can use the visitor pattern.
Definition:
Visitor pattern : Represents an operation that acts on each element in an object structure. The Visitor pattern allows users to define new operations on elements without changing their classes.

2. Visitor pattern structure and implementation

2.1 The structure of the visitor pattern

The structure of the visitor pattern is relatively complex, including the following five roles:

  1. Visitor (abstract visitor) : declares a visit operation for each concrete element class in the object structure;
  2. ConcreteVisitor (concrete visitor) : implements each operation declared by the abstract visitor;
    3. **Element (abstract element)**: declares an accept() method to accept the visitor's visit operation;
  3. ConcreteElement (concrete element) : The accept() method is implemented, and the visitor's access method is called in the accept() method to complete the operation on an element;
  4. ObjectStructure (object structure) : It is a collection of elements, which is used to store element objects, and provides methods for traversing its internal elements.

2.2 Implementation of visitor pattern

Let's use a case to further study the visitor pattern.

//abstract visitor

/**
 * 奖励类
 * 抽象访问者类
 */
public abstract class Award {

    public abstract void visit(Student candidate);
    public abstract void visit(Teacher candidate);
}

// Specific visitor

/**
 * 科研奖
 * 具体访问者
 */
public class ScientificAward extends Award {

    @Override
    public void visit(Student candidate) {
        if (candidate.getThesisNumber() > 2) {
            System.out.println("学生候选人:" + candidate.getName() + ",论文数"
                    + candidate.getThesisNumber() + ",符合评审科研奖的要求");
        }
    }

    @Override
    public void visit(Teacher candidate) {
        if (candidate.getThesisNumber() > 10) {
            System.out.println("教师候选人:" + candidate.getName() + ",论文数"
                    + candidate.getThesisNumber() + ",符合评审科研奖的要求");
        }
    }
}

/**
 * 成绩优秀奖
 * 具体访问者
 */
public class AchievementAward extends Award {

    @Override
    public void visit(Student candidate) {
        if (candidate.getScore() >= 90) {
            System.out.println("学生候选人:" + candidate.getName() + ",平均成绩"
                    + candidate.getScore() + ",符合评审成绩优秀奖的要求");
        }
    }

    @Override
    public void visit(Teacher candidate) {
        if (candidate.getScore() >= 90) {
            System.out.println("教师候选人:" + candidate.getName() + ",教学反馈分"
                    + candidate.getScore() + ",符合评审成绩优秀奖的要求");
        }
    }
}

//abstract element

/**
 * 候选人
 * 抽象元素类
 */
public interface Candidate {

    void accept(Award handle);//接受一个抽象访问者访问

}

// specific elements

/**
 * 学生
 * 具体元素类
 */
public class Student implements Candidate{

    //姓名
    private String name;
    //成绩分数
    private Double score;
    //论文数量
    private Integer thesisNumber;

    public Student(String name, Double score, Integer thesisNumber) {
        this.name = name;
        this.score = score;
        this.thesisNumber = thesisNumber;
    }

    @Override
    public void accept(Award handle) {
        handle.visit(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    public Integer getThesisNumber() {
        return thesisNumber;
    }

    public void setThesisNumber(Integer thesisNumber) {
        this.thesisNumber = thesisNumber;
    }
}

/**
 * 教师
 * 具体元素类
 */
public class Teacher implements Candidate{

    //姓名
    private String name;
    //成绩分数
    private Double score;
    //论文数量
    private Integer thesisNumber;

    public Teacher(String name, Double score, Integer thesisNumber) {
        this.name = name;
        this.score = score;
        this.thesisNumber = thesisNumber;
    }

    @Override
    public void accept(Award handle) {
        handle.visit(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    public Integer getThesisNumber() {
        return thesisNumber;
    }

    public void setThesisNumber(Integer thesisNumber) {
        this.thesisNumber = thesisNumber;
    }
}

//object structure

/**
 * 候选人列表类
 * 充当对象结构
 *
 */
public class CandidateList {

    private List<Candidate> list = new ArrayList<>();

    public void addCandidate(Candidate candidate) {
        list.add(candidate);
    }

    //遍历访问候选人集合中的每一个对象
    public void accept(Award handler) {
        for (Candidate c : list) {
            c.accept(handler);
        }
    }

}

//client

public class Client {

    public static void main(String[] args) {

        /**
         * 案例需求描述:
         * 某公司为某高校开发一套奖励审批系统,该系统可以实现教师奖励和学生奖励的审批,
         * 如果教师发表论文数操作10篇或者学生论文数超过两篇可以平科研奖;
         * 如果教师教学反馈分大于等于90分或者学生平均成绩大于等于90分可以评选成绩优秀奖。
         * 请用访问者模式实现该系统,以判断候选人集合中的教师或学生是否符合某种获奖要求。
         *
         */

        //定义候选人集合
        CandidateList candidateList = new CandidateList();
        Candidate s1,s2,s3,t1,t2,t3;

        s1 = new Student("刘备",70.0,1);
        s2 = new Student("张飞",78.0,3);
        s3 = new Student("关羽",91.5,0);

        t1 = new Teacher("诸葛亮",95.0,0);
        t2 = new Teacher("庞统",75.0,11);
        t3 = new Teacher("周瑜",88.5,6);

        candidateList.addCandidate(s1);
        candidateList.addCandidate(s2);
        candidateList.addCandidate(s3);
        candidateList.addCandidate(t1);
        candidateList.addCandidate(t2);
        candidateList.addCandidate(t3);

        //以科研奖来访问
        Award scientificAward = new ScientificAward();
        candidateList.accept(scientificAward);

        System.out.println("-----------------------");

        //以成绩优秀奖来访问
        Award achievementAward = new AchievementAward();
        candidateList.accept(achievementAward);
    }
}

3. The advantages and disadvantages of the visitor model and the applicable environment

3.1 Advantages of the visitor pattern

  1. It is convenient to add new access operations in the visitor mode;
  2. Concentrate the access behavior of related elements into a visitor object instead of scattered in individual element classes, and the responsibilities of the classes are clearer;
  3. Enables users to define operations that operate on existing element class hierarchies without modifying that hierarchy.

3.2 Disadvantages of the visitor pattern

  1. It is difficult to add new element classes in the visitor mode, which violates the requirements of the principle of opening and closing;
  2. Destroys the encapsulation of the object.

3.3 Applicable environment of visitor mode

  1. An object structure contains multiple types of objects, and it is hoped to perform some operations on these objects that depend on their specific types;
  2. You need to perform many different and unrelated operations on objects in an object structure, and you need to avoid letting these operations "pollute" the classes of these objects, and you don't want to modify these classes when adding new operations;
  3. The class corresponding to the object in the object structure rarely changes, but often needs to define new operations on this object structure.

[References]:
This article is based on the study notes of Liu Wei's "Java Design Patterns". It is for learning purposes only. Do not use it for other purposes. Please respect intellectual property rights.

[Code warehouse for this article]: https://gitee.com/xiongbomy/java-design-pattern.git

Guess you like

Origin blog.csdn.net/weixin_44143114/article/details/126533160