• 设计模式之访问者模式


    访问者模式

    概述

    表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。

    在访问者模式中国,数据结构与处理被分离开来。我们白那些一个表示“访问者”的类来访问数据结构中的元素,并把对个元素的处理交给访问者类。当需要增加新的处理时,我们只需要编写新的访问者,然后让数据结构可以接收访问者的访问即可。

    示例程序

    在示例程序中我们模拟校园中有老师、学生两个被访问的对象,而校长、家长就是两个访问者。对于校长来说他只关心老师所在班级的升学率,对于家长来说他只关心学生的排名。

    关于这个案例的核心逻辑实现,有以下几点:

    1. 建立用户抽象类喝抽象访问方法,再由不同的用户实现:老师和学生
    2. 建立访问者接口,用于不同人员的访问操作:校长和家长
    3. 最终对数据的看板建设,用于实现不同视角的访问结果输出

    在这里插入图片描述

    代码实现

    User抽象类

    User定义了核心访问方法,这个方法是为了让后续的用户具体实现者都能提供出一个访问方法,共外部使用。

    public abstract class User {
        public String name;      // 姓名
        public String identity;  // 身份;重点班、普通班 | 特级教师、普通教师、实习教师
        public String clazz;     // 班级
    
        public User(String name, String identity, String clazz) {
            this.name = name;
            this.identity = identity;
            this.clazz = clazz;
        }
    
        // 核心访问方法
        public abstract void accept(Visitor visitor);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    User实现类

    Student代表学生类,Teacher代表老师类,他们继承了User类,但又单独提供了各自的特性方法

    public class Student extends User {
        public Student(String name, String identity, String clazz) {
            super(name, identity, clazz);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    
        //排名信息
        public int ranking(){
            return (int) (Math.random() * 100);
        }
    }
    
    public class Teacher extends User {
        public Teacher(String name, String identity, String clazz) {
            super(name, identity, clazz);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    
        // 升本率
        public double entranceRatio() {
            return BigDecimal.valueOf(Math.random() * 100).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    Visitor接口

    Visitor接口重载visit方法,不同的入参用户类型让具体的访问者类,在实现时可以关注每一种用户类型的具体访问数据对象

    public interface Visitor {
        //访问学生方法
        void visit(Student student);
    
        //访问教师方法
        void visit(Teacher teacher);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Visitor实现类

    两个具体的访问者实现类,他们都有自己的视角需求。家长需要看到学生的排名,而校长需要看到老师的升学率

    @Slf4j
    public class Parent implements Visitor {
        @Override
        public void visit(Student student) {
            log.info("学生信息 姓名:{} 班级:{} 排名:{}", student.name, student.clazz, student.ranking());
        }
    
        @Override
        public void visit(Teacher teacher) {
            log.info("老师信息 姓名:{} 班级:{}", teacher.name, teacher.clazz);
        }
    }
    
    @Slf4j
    public class Principal implements Visitor {
        @Override
        public void visit(Student student) {
            log.info("学生信息  姓名:{} 班级:{}",student.name,student.clazz);
        }
    
        @Override
        public void visit(Teacher teacher) {
            log.info("老师信息 姓名:{} 班级:{} 升学率:{}", teacher.name, teacher.clazz,teacher.entranceRatio());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    数据看板

    在这个类中初始化一些被访问者的基本数据,并提供一个展示类,通过不同的访问者,差异化的打印信息

    public class DataView {
        List<User> userList = new ArrayList<>();
    
        public DataView(){
            userList.add(new Student("谢飞机", "重点班", "一年一班"));
            userList.add(new Student("windy", "重点班", "一年一班"));
            userList.add(new Student("大毛", "普通班", "二年三班"));
            userList.add(new Student("Shing", "普通班", "三年四班"));
            userList.add(new Teacher("BK", "特级教师", "一年一班"));
            userList.add(new Teacher("娜娜Goddess", "特级教师", "一年一班"));
            userList.add(new Teacher("dangdang", "普通教师", "二年三班"));
            userList.add(new Teacher("泽东", "实习教师", "三年四班"));
        }
    
        //展示
        public void show(Visitor visitor){
            for (User user : userList){
                user.accept(visitor);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    测试

    通过测试结果,我们可以看到家长和校长访问同一个对象所看到的结果是不一样的,到这里大家应该都明白了访问者模式的核心思想

    @Slf4j
    @SpringBootTest
    class Practice2500ApplicationTests {
    
        @Test
        void contextLoads() {
            DataView dataView = new DataView();
    
            log.info("\r\n家长视角访问:");
            dataView.show(new Parent());     // 家长
    
            log.info("\r\n校长视角访问:");
            dataView.show(new Principal());  // 校长
        }
    
    }
    
    //结果
    家长视角访问:
    学生信息 姓名:谢飞机 班级:一年一班 排名:43
    学生信息 姓名:windy 班级:一年一班 排名:22
    学生信息 姓名:大毛 班级:二年三班 排名:78
    学生信息 姓名:Shing 班级:三年四班 排名:16
    老师信息 姓名:BK 班级:一年一班
    老师信息 姓名:娜娜Goddess 班级:一年一班
    老师信息 姓名:dangdang 班级:二年三班
    老师信息 姓名:泽东 班级:三年四班
    
    校长视角访问:
    学生信息  姓名:谢飞机 班级:一年一班
    学生信息  姓名:windy 班级:一年一班
    学生信息  姓名:大毛 班级:二年三班
    学生信息  姓名:Shing 班级:三年四班
    老师信息 姓名:BK 班级:一年一班 升学率:56.53
    老师信息 姓名:娜娜Goddess 班级:一年一班 升学率:50.28
    老师信息 姓名:dangdang 班级:二年三班 升学率:14.89
    老师信息 姓名:泽东 班级:三年四班 升学率:18.82
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    总结

    访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。

    访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。

    访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。

  • 相关阅读:
    外贸分享:多哥市场开发攻略
    Python中的3D绘图命令~这还不放到论文或PPT里?
    nginx使用lua通过request_body按条件开放访问权限
    产品市场研究的方法有哪些
    ClearML入门:简化机器学习解决方案的开发和管理
    数据结构【力扣-初级算法】
    mysql sql语句遍历树结构
    【Linux】exec函数族及进程控制相关
    什么是CMDB?为什么企业需要CMDB?
    uni-app 之 tabBar 底部切换按钮
  • 原文地址:https://blog.csdn.net/Yellow_Star___/article/details/125536259