访问者模式(Visitor Pattern)

访问者模式

说明

访问者模式(Visitor Pattern)属于行为型模式,表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

该模式是将数据结构与数据操作分离的设计模式,是将作用于某种数据结构中的各元素的操作封装起来。该模式的实施前提是数据结构相对稳定,不会频繁变动,但是作用于结构上的操作又经常变动。

结构

访问者模式的主要角色如下:

抽象访问者(Visitor):即作用于元素操作的抽象,定义了访问具体元素的接口;

具体访问者(Concrete Visitor):根据需求实现对具体元素的操作;

抽象元素(Element):被访问的元素抽象,定义了接收访问者的接口;

具体元素(Concrete Element):被访问的具体元素,实现接收方法;

结构对象(Object Struture):维护了具体元素的集合,并提供方法接收访问者对集合中的元素进行访问。

代码案例

业务背景是:某个培训机构只有语文、英语、数学老师,每个科目的老师都有对应的行为,并且行为会随着需求而改变。

反例

java 复制代码
/**
 * @program: visitor
 * @description: 老师抽象类
 * @author: wxw
 * @create: 2024-03-14 16:12
 **/
public abstract class Teacher {

    // 姓名
    protected String name;

    public Teacher(String name) {
        this.name = name;
    }

    // 备课
    public abstract void prepareLessons();

    // 上课
    public abstract void giveClass();

    // 布置作业
    public abstract void assignHomework();

    // 批改作业
    public abstract void homeworkCorrecting();
}
java 复制代码
/**
 * @program: visitor
 * @description: 语文老师
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class ChineseTeacher extends Teacher{

    public ChineseTeacher(String name) {
        super(name);
    }

    @Override
    public void prepareLessons() {
        System.out.println(String.format("语文老师【%s】开始备课.", this.name));
    }

    @Override
    public void giveClass() {
        System.out.println(String.format("语文老师【%s】开始授课.", this.name));
    }

    @Override
    public void assignHomework() {
        System.out.println(String.format("语文老师【%s】开始布置作业.", this.name));
    }

    @Override
    public void homeworkCorrecting() {
        System.out.println(String.format("语文老师【%s】开始批改作业.", this.name));
    }

}
java 复制代码
/**
 * @program: visitor
 * @description: 英语老师
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class EnglishTeacher extends Teacher{

    public EnglishTeacher(String name) {
        super(name);
    }

    @Override
    public void prepareLessons() {
        System.out.println(String.format("英语老师【%s】开始备课.", this.name));
    }

    @Override
    public void giveClass() {
        System.out.println(String.format("英语老师【%s】开始授课.", this.name));
    }

    @Override
    public void assignHomework() {
        System.out.println(String.format("英语老师【%s】开始布置作业.", this.name));
    }

    @Override
    public void homeworkCorrecting() {
        System.out.println(String.format("英语老师【%s】开始批改作业.", this.name));
    }

}
java 复制代码
/**
 * @program: visitor
 * @description: 数学老师
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class MathTeacher extends Teacher{

    public MathTeacher(String name) {
        super(name);
    }

    @Override
    public void prepareLessons() {
        System.out.println(String.format("数学老师【%s】开始备课.", this.name));
    }

    @Override
    public void giveClass() {
        System.out.println(String.format("数学老师【%s】开始授课.", this.name));
    }

    @Override
    public void assignHomework() {
        System.out.println(String.format("数学老师【%s】开始布置作业.", this.name));
    }

    @Override
    public void homeworkCorrecting() {
        System.out.println(String.format("数学老师【%s】开始批改作业.", this.name));
    }

}
java 复制代码
public class Test {
    public static void main(String[] args) {
        List<Teacher> teachers = new ArrayList<>();
        Teacher zhangsan = new ChineseTeacher("张三");
        Teacher lisi = new MathTeacher("李四");
        Teacher wangwu = new EnglishTeacher("王五");
        teachers.add(zhangsan);
        teachers.add(lisi);
        teachers.add(wangwu);

        for (Teacher t: teachers) {
            System.out.println("============================");
            t.prepareLessons();
            t.giveClass();
            t.assignHomework();
            t.homeworkCorrecting();
            System.out.println("============================");
        }
    }
}

假设培训机构为了提高教学质量,要求所有老师都必须跟同学进行单独沟通,了解每个同学的情况。

这时就需要在Teacher抽象类中添加沟通的方法,所有的子类都得实现该方法,违背了开闭原则。

重构后

抽象元素(Element)

java 复制代码
/**
 * @program: visitor
 * @description: 老师抽象类
 *              抽象元素(Element)
 * @author: wxw
 * @create: 2024-03-14 16:12
 **/
public abstract class Teacher {

    // 姓名
    protected String name;

    public Teacher(String name) {
        this.name = name;
    }

    // 接收方法
    public abstract void accept(IActionVisitor actionVisitor);
}

抽象访问者(Visitor)

java 复制代码
/**
 * @program: visitor
 * @description: 老师行为访问者接口
 *              抽象访问者(Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:33
 **/
public interface IActionVisitor {

    // 访问语文老师
    void visitorChineseTeacher(ChineseTeacher chineseTeacher);
    // 访问英语老师
    void visitorEnglishTeacher(EnglishTeacher englishTeacher);
    // 访问数学老师
    void visitorMathTeacher(MathTeacher mathTeacher);

}

具体元素(Concrete Element)

java 复制代码
/**
 * @program: visitor
 * @description: 语文老师
 *              具体元素(Concrete Element)
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class ChineseTeacher extends Teacher {

    public ChineseTeacher(String name) {
        super(name);
    }

    @Override
    public void accept(IActionVisitor actionVisitor) {
        actionVisitor.visitorChineseTeacher(this);
    }

}

/**
 * @program: visitor
 * @description: 英语老师
 *              具体元素(Concrete Element)
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class EnglishTeacher extends Teacher {

    public EnglishTeacher(String name) {
        super(name);
    }

    @Override
    public void accept(IActionVisitor actionVisitor) {
        actionVisitor.visitorEnglishTeacher(this);
    }

}

/**
 * @program: visitor
 * @description: 数学老师
 *              具体元素(Concrete Element)
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class MathTeacher extends Teacher {

    public MathTeacher(String name) {
        super(name);
    }

    @Override
    public void accept(IActionVisitor actionVisitor) {
        actionVisitor.visitorMathTeacher(this);
    }
}

具体访问者(Concrete Visitor)

java 复制代码
/**
 * @program: visitor
 * @description: 备课访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class PrepareLessonsVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始备课.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始备课.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始备课.", mathTeacher.name));
    }
}

/**
 * @program: visitor
 * @description: 上课访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class GiveClassVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始上课.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始上课.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始上课.", mathTeacher.name));
    }
}

/**
 * @program: visitor
 * @description: 布置作业访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class AssignHomeworkVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始布置作业.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始布置作业.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始布置作业.", mathTeacher.name));
    }
}

/**
 * @program: visitor
 * @description: 批改作业访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class HomeworkCorrectingVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始批改作业.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始批改作业.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始批改作业.", mathTeacher.name));
    }
}

结构对象(Object Struture)

java 复制代码
/**
 * @program: visitor
 * @description: 培训机构对象结构
 *              结构对象(Object Struture)
 * @author: wxw
 * @create: 2024-03-14 16:43
 **/
public class TrainingAgency {

    private List<Teacher> teacherList = new ArrayList<>();

    public void addTeacher(Teacher teacher){
        teacherList.add(teacher);
    }

    public void removeTeacher(Teacher teacher){
        teacherList.remove(teacher);
    }

    public void startWork(IActionVisitor visitor){
        System.out.println("================================");
        for (Teacher t: teacherList) {
            t.accept(visitor);
        }
        System.out.println("================================");
    }
}

客户端

java 复制代码
public class Test {

    public static void main(String[] args) {
        TrainingAgency trainingAgency = new TrainingAgency();
        trainingAgency.addTeacher(new ChineseTeacher("张三"));
        trainingAgency.addTeacher(new EnglishTeacher("李四"));
        trainingAgency.addTeacher(new MathTeacher("王五"));

        // 备课访问者
        IActionVisitor prepareLessonsVisitor = new PrepareLessonsVisitor();
        trainingAgency.startWork(prepareLessonsVisitor);

        // 上课访问者
        IActionVisitor giveClassVisitor = new GiveClassVisitor();
        trainingAgency.startWork(giveClassVisitor);

        // 布置作业访问者
        IActionVisitor assignHomeworkVisitor = new AssignHomeworkVisitor();
        trainingAgency.startWork(assignHomeworkVisitor);

        // 批改作业访问者
        IActionVisitor homeworkCorrectingVisitor = new HomeworkCorrectingVisitor();
        trainingAgency.startWork(homeworkCorrectingVisitor);
    }
}

增加沟通访问者,无需修改Teacher相关的类

java 复制代码
/**
 * @program: visitor
 * @description: 与学生沟通访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class CommunicationVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始与学生沟通.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始与学生沟通.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始与学生沟通.", mathTeacher.name));
    }
}
相关推荐
java_heartLake4 天前
设计模式之访问者模式
java·设计模式·访问者模式
林小果14 天前
访问者模式
java·开发语言·设计模式·访问者模式
学步_技术4 天前
Python编码系列—Python访问者模式:为对象结构添加新功能的艺术
开发语言·python·访问者模式
BIGSHU09235 天前
GPT带我学-设计模式18-访问者模式
gpt·设计模式·访问者模式
10km11 天前
javdoc:(JDK9)VISITOR模式遍历语法树(DocCommentTree)获取代码注释中的tag(@return,@param)对象
java·访问者模式·javadoc·jdk9·doccommenttree·doctreevisitor
鲤籽鲲13 天前
C#设计模式之访问者模式
设计模式·c#·访问者模式
LB_bei23 天前
设计模式-行为型模式-访问者模式
设计模式·访问者模式
WineMonk24 天前
设计模式 23 访问者模式
设计模式·访问者模式
不是仙人的闲人1 个月前
C++ 设计模式——访问者模式
c++·设计模式·访问者模式
胜天半子_王二_王半仙1 个月前
访问者模式详解
c++·访问者模式