Java设计模式大作业——访问者模式

Java设计模式大作业——访问者模式

系统以web网页设计为主,采用的技术架构为服务端SpringBoot+Mybatis-plus+Satoken,客户端(Web)Vue3+Element-plus+Echarts.

系统对于不同不同访问者身份存于mysql数据库,登陆后系统自动识别访问者身份并显示对应内容

源代码Gitee仓库地址:edu-manage-system: 大三课程设计大作业,基于vue3+echarts+springboot+mybatis-plus+satoken的简易web教务管理系统 (gitee.com) https://gitee.com/rranr/edu-manage-system

一.应用场景与案例描述

访问者模式是一种行为设计模式,其主要目的是封装一组可能会经常变化的操作,使这些操作可以在不改变被操作对象的类的前提下应用于这些对象。它通过在被访问的元素类中添加一个接受访问者的方法,使得访问者可以访问被访问者的元素。

在校园中,对于一个学院的师生,辅导员更为关心同学们的成绩以及基本个人信息,学业主观努力度、系主任则关注教师的满意度,学生的学分修读情况,学校则关注该学院的师资力量与学生整体学习情况,企业关注学生的修读课程水平以及教资力量。这些整体都是对于一个学院的师生进行不同角度查阅信息,因此在不同的场景下可以构造不同访问者。

二.案例分析与解决问题

案例分析

角色定义:

学生:包含成绩、课程修读情况、基本个人信息等。

教师:包含个人信息、职称学生满意度等。

学院:包含师资力量、学生整体学习情况等。

企业:关注学生的修读课程水平和教资力量。

辅导员:关注学生的基本个人信息,以及任课教师基本信息

系主任:关注学生整体课程要求完成的、教师教学满意度

问题描述:

不同角色对相同的学院信息有不同的关注点。

不同角色需要执行不同的操作,比如计算学生成绩、查看教师满意度等。

为什么使用访问者模式:

解耦合适: 访问者模式将数据结构和操作分离,每个角色都可以定义自己的访问者。这样,当需要新增一种角色或者新增一种操作时,不需要修改已有的代码。

易扩展性: 可以方便地新增访问者,而不影响已有的数据结构和其他访问者。

单一职责原则: 每个访问者负责执行一种操作,保证了每个类的职责单一。

使用访问者模式的优势:

灵活性: 不同的访问者可以根据自己的需要定义自己的操作,而无需修改被访问的对象(学院、学生、教师等)。

可扩展性: 当需要新增一种角色或者新增一种操作时,只需要添加对应的访问者,而不需要修改已有代码。

维护性: 操作和数据结构分离,使得系统更易维护和理解。

使用访问者模式可以有效地解决不同角色对于相同对象的不同关注点,提高了系统的灵活性和可维护性。

三.各个角色描述与UML图示

基本类Person包括每个人的基本信息,编号、姓名、性别、年龄、所属部门、联系方式。

对于学生类Student还包括个人平均成绩、所有修读课程成绩。

对于教师类Teacher还包括教学满意度、职称。

元素类在基本方法外需要添加一个accept()方法

对于访问者Vistor而言,辅导员Counsellor关注学生基本个人信息,还有平均成绩以及排名、任课教师的基本个人信息包括联系方式、姓名、所属部门;系主任Principal关注整个学院的教资力量以及学生课程整体修读情况,包括不同职称教师人数、教评满意度、学生专业修读学分完成度。访问者分别实现对不同角色的访问方法visit(),将整个学院的师生用Department中的ArrayList<Person>装载,接受不同访问者实现不同操作后数据返回给客户端。

整体UML图如下

四.程序完整源代码

源代码较多,仅给出关键访问者模式设计代码

Gitee仓库地址:edu-manage-system: 大三课程设计大作业,基于vue3+echarts+springboot+mybatis-plus+satoken的简易web教务管理系统 (gitee.com) https://gitee.com/rranr/edu-manage-system

抽象元素类Person,记录个人基本信息,编号、姓名、性别、年龄、所属部门、联系方式。

Person.java

/**
 * @author zouran
 * createDate:2023/12/23  17:27
 */
@Component
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "person", discriminatorType = DiscriminatorType.STRING)
@Data
@Accessors(chain = true)
public abstract class Person implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer id;

    private String name;

    private String sex;

    private Integer age;

    private String department;

    private String phone;

    /**
     * @return 人物身份
     */
    public abstract String getIdentify();

    public abstract Map<String, Object> accept(Visitor visitor);
}

学生类,继承Person类,实现accept方法,新增成员List<Grade> gradeList记录个人所有的修读课程成绩。

Student.java

/**
 * @author zouran
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Component
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@DiscriminatorValue("student")
@ToString(callSuper = true)
public class Student extends Person {


    private Double gradeAverage;
    @TableField(exist = false)
    private List<Grade> gradeList = new ArrayList<>();

    /**
     * @return 人物身份
     */
    @Override
    public String getIdentify() {
        return "student";
    }

    public List<Map<String, Object>> getAllGrades() {
        List<Map<String, Object>> maps = new ArrayList<>();
        for (Grade grade : this.gradeList) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", this.getName());
            map.put("courseId", grade.getCourseId());
            map.put("term", grade.getSchoolYear() + "-" + (grade.getSchoolYear() + 1) + (grade.getTerm() == 1 ? "-秋" : "-春"));
            map.put("courseName", grade.getCourse().getCourseName());
            map.put("teacherName", grade.getCourse().getTeacher().getName());
            map.put("score", grade.getScore());
            map.put("gradePoint", grade.getGradePoint());
            map.put("credit", grade.getCourse().getCredit());
            maps.add(map);
        }
        return maps;
    }

    @Override
    public Map<String, Object> accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

教师类,继承Person类,实现accept方法,新增成员记录职称、学生满意度。

Teacher.java

/**
 * @author zouran
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Component
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@DiscriminatorValue("teacher")
@ToString(callSuper = true)
public class Teacher extends Person {

    private Double satisfaction;
    private String title;

    /**
     * @return 人物身份
     */
    @Override
    public String getIdentify() {
        return "teacher";
    }

    @Override
    public Map<String, Object> accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

访问者接口,针对不同元素类定义多个visit方法,接受参数不同。

Visitor.java

/**
 * @author zouran
 * createDate:2023/12/26  12:30
 */
public interface Visitor {
    Map<String, Object> visit(Student student);

    Map<String, Object> visit(Teacher teacher);
}

辅导员类,实现父类的visit方法,对于访问学生,返回学生学号、姓名、性别、年龄、部门、所有课程成绩,还有平均成绩、任课教师的基本个人信息包括联系方式、姓名、所属部门。

Counsellor.java

/**
 * @author zouran
 * createDate:2023/12/26  12:29
 */
public class Counsellor implements Visitor {
    @Override
    public Map<String, Object> visit(Student student) {
        List<Map<String, Object>> maps = student.getAllGrades();
        double sumCredit = 0.0;
        double sumGradePoint = 0.0;
        for (Map<String, Object> map : maps) {
            sumGradePoint += (double) map.get("credit") * (double) map.get("gradePoint");
            sumCredit += (double) map.get("credit");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("identify", student.getIdentify());
        map.put("id", student.getId());
        map.put("name", student.getName());
        map.put("sex", student.getSex());
        map.put("age", student.getAge());
        map.put("department", student.getDepartment());
//        map.put("gradeAverage",student.getGradeAverage());
        map.put("allGrades", student.getAllGrades());
        map.put("phone", student.getPhone());
        map.put("gradeAverage", String.format("%.2f", sumGradePoint / sumCredit));
        return map;
    }

    @Override
    public Map<String, Object> visit(Teacher teacher) {
        Map<String, Object> map = new HashMap<>();
        map.put("identify", teacher.getIdentify());
        map.put("name", teacher.getName());
        map.put("department", teacher.getDepartment());
        map.put("phone", teacher.getPhone());
        return map;
    }
}

系主任类,实现父类的visit方法,对于访问学生,返回学生学号、姓名、部门、总的课程修读学分和。教师编号、姓名、部门、教评满意度、职称、联系方式

Principal.java

/**
 * @author zouran
 * createDate:2023/12/26  12:30
 */
public class Principal implements Visitor {
    @Override
    public Map<String, Object> visit(Student student) {
        List<Map<String, Object>> maps = student.getAllGrades();
        double sumCredit = 0.0;
        for (Map<String, Object> map : maps) {
            if ((double) map.get("score") >= 60)
                sumCredit += (double) map.get("credit");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("identify", student.getIdentify());
        map.put("id", student.getId());
        map.put("name", student.getName());
        map.put("department", student.getDepartment());
        map.put("sumCredit", sumCredit);
        return map;
    }

    @Override
    public Map<String, Object> visit(Teacher teacher) {
        Map<String, Object> map = new HashMap<>();
        map.put("identify", teacher.getIdentify());
        map.put("id", teacher.getId());
        map.put("name", teacher.getName());
        map.put("department", teacher.getDepartment());
        map.put("satisfaction", teacher.getSatisfaction());
        map.put("title", teacher.getTitle());
        map.put("phone", teacher.getPhone());
        return map;
    }
}

对象结构类,装载所有Person实例,相当于容纳了一个学院所有师生信息,information()返回师生信息

Department.java

/**
 * @author zouran
 * createDate:2023/12/26  0:34
 */
@Data
public class Department implements Serializable {
    private final List<Person> personList = new ArrayList<>();

    public Department() {
    }

    public Department(List<Teacher> teachers, List<Student> students) {
        personList.addAll(teachers);
        personList.addAll(students);
    }

    public List<Map<String, Object>> information(Visitor visitor) {
        List<Map<String, Object>> maps = new ArrayList<>();
        for (Person person : personList) {
            maps.add(person.accept(visitor));
        }
        return maps;
    }
}

客户端类,调用数据

VisitorController.java

/**
 * 访问者接口
 *
 * @author zouran
 * createDate:2023/12/27  23:49
 */
@RestController
@RequestMapping("/visitor")
public class VisitorController {
    private final IStudentService iStudentService;
    private final ITeacherService iTeacherService;

    private final ResultMap<Object> resultMap;

    public VisitorController(IStudentService iStudentService, ITeacherService iTeacherService, ResultMap<Object> resultMap) {
        this.iStudentService = iStudentService;
        this.iTeacherService = iTeacherService;
        this.resultMap = resultMap;
    }

    private Map<String, Object> classify(List<Map<String, Object>> list) {
        Map<String, Object> maps = new HashMap<>();
        List<Map<String, Object>> students = new ArrayList<>();
        List<Map<String, Object>> teachers = new ArrayList<>();
        for (Map<String, Object> stringObjectMap : list) {
            if (stringObjectMap.get("identify") == "student") {
                stringObjectMap.remove("identify");
                students.add(stringObjectMap);
            }
            if (stringObjectMap.get("identify") == "teacher") {
                stringObjectMap.remove("identify");
                teachers.add(stringObjectMap);
            }
        }
        maps.put("student", students);
        maps.put("teacher", teachers);
        return maps;
    }

    /**
     * 辅导员视角
     *
     * @return 辅导员视角
     */
    @RequestMapping("/counsellor")
    public ResultMap<Object> counsellorQueryAll() {
        System.out.println(StpUtil.getPermissionList());
        return resultMap.success(classify(
                new Department(iTeacherService.list(null), iStudentService.queryAll()).information(new Counsellor())));
    }

    /**
     * 校长视角
     *
     * @return 校长视角
     */
    @RequestMapping("/principal")
    public ResultMap<Object> principalQueryAll() {
        return resultMap.success(classify(
                new Department(iTeacherService.list(null), iStudentService.queryAll()).information(new Principal())));
    }

}

五.程序运行结果

1.登录页面

2.辅导员登录后页面显示

2.1查看学生基本信息,学生学号、姓名、性别、年龄、部门、平均成绩。系统会可视化个人信息情况,如各专业人数以及占比,男女比例

2.2对表格数据筛选,仅查看软件工程专业学生信息

2.3查看同学课程成绩,系统利用echarts可视化各科目挂科人数以及优秀人数

2.4仅查看挂科课程成绩情况,包括学生名字、课程名、教师名等信息

2.5查看教师姓名、联系方式、所属部门

2.6除此之外,表格数据可以进行排序,如将软件工程学生个人平均成绩从高到低

3.系主任视角

3.1查看学生信息,可以看到学号、姓名、总的已修读学分、所属专业。同时可视化了各专业未达到毕业要求学分人数和占比分布

3.2筛选修读学分不达标同学信息

3.3筛选软件工程修读学分不达标同学信息

3.4查看教资力量统计,会统计不同职称的教师人数,用直方图和饼状图可视化加载,同时可以看到教师的满意度情况

3.5筛选职称为讲师且满意度为非常满意的教师

3.6筛选软件教师信息

  • 18
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Java设计模式 (含有相关源码) Abstract Factory:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 Adapter:将一个类的接口转换成客户希望的另一个接口,使得原来由于接口不兼容而不能一起工作的那些类可以一起工作。 Bridge:将抽象部分与它的实现部分分离,使之可以独立变化。 Chain of Responsibility:为解除请求的发送者和接收者之间的耦合,而使多个对象有机会处理这个请求。将这些请求连成一个链,并沿着这条链传递该请求,直到有个对象处理它。 Command:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可以取消的操作。 Composite:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。 Decorator:动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更加灵活。 Facade:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,使得这个子系统更加容易使用。 Factory Method:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method让一个类的实例化延迟到子类。 Flyweight:运用共享技术有效的支持大量细粒度的对象。 Interpreter:给定一个语言,定义它的文法的一种表示,并定义一个解释器用于解释特定文法。 Iterator:提供一种方法顺序访问一个聚合对象中的各种元素,而无需暴露该对象的内部表示。 Mediator:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式相互引用,从而使得耦合松散,可以独立改变相互之间的交互。 Memento:不破坏封装的前提下,捕获对象的内部状态,并在该对象之外保存这个状态。 Observer:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生变化时依赖于它的所有的对象都得到通知和刷新。 Prototype:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。 Proxy:为其他对象提供一个代理以控制对这个对象的访问。 Singleton:保证一个类仅有一个实例,并提供一个访问它的全局点。 State:允许一个对象再内部状态改变的时候改变它的行为。对象看起来似乎修改了所属的类。 Strategy:定义一系列的算法,把他们封装起来,并可以相互替换,使算法独立于客户。 Template Method:定义一个操作中的算法骨架,而将这些算法的具体实现的代码延迟到子类中完成。 Visitor:标识一个作用于某对象结构中的各元素的操作,在不改变各元素的类的前提下定义作用于这个元素的新操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我还没秃头~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值