Skip to content

学生信息管理系统

学生信息管理系统需求说明

需求分析

业务功能梳理

学生信息管理系统需求

  1. StudentManagement实现增删改查功能
  2. 控制端输入
  3. 控制端打印相关输出

实现思路

uml diagram

代码实现

流程图

uml diagram

基本实现

相关知识
  1. 封装
  2. 面向对象编程
  3. 错误与异常
实现代码
import entity.Student;
import enums.SexEnum;
import exceptions.StudentIdAlreadyExitException;
import exceptions.StudentIdNotExitException;
import exceptions.StudentSexInputException;

import java.util.*;

public class StudentManagement {
    private static Map<Integer, Student> students;

    public void initData() {
        students = new HashMap<>();
    }

    public void addStudent(Integer id, String name, String sex) {
        SexEnum se = null;
        // 判断学生id
        if (students.containsKey(id)) {
            throw new StudentIdAlreadyExitException();
        }
        //判断性别
        if (sex.equals(SexEnum.man.getChineseName())) {
            se = SexEnum.man;
        } else if (sex.equals(SexEnum.female.getChineseName())) {
            se = SexEnum.female;
        } else {
            throw new StudentSexInputException();
        }
        students.put(id, new Student(id, name, se));
        System.out.println("学生添加成功!");
    }


    public void deleteStudent(Integer id) {
        // 判断学生是否存在
        if (students.containsKey(id)) {
            students.remove(id);
        } else {
            throw new StudentIdNotExitException();
        }
        System.out.println("学生删除成功!");
    }


    public Student getStudent(Integer id) {
        if (!students.containsKey(id)) {
            throw new StudentIdNotExitException();
        }
        return students.get(id);
    }


    public List<Student> getStudentAll() {
        // 返回所有学生
        return new ArrayList<>(students.values());
    }

    public void show(Integer studentId) {
        // 展示学生信息
        System.out.println(this.getStudent(studentId));
    }

    public void showAll() {
        // 打印所有学生
        List<Student> studentAll = this.getStudentAll();
        for(int i = 0; i<this.getStudentAll().size(); i++){
            System.out.print(i+1+"."+studentAll.get(i));
        }

    }

    public void run() {
        //初始化数据
        this.initData();
        final Integer SHOW_FLAG = 1;
        final Integer ADD_FLAG = 2;
        final Integer DEL_FLAG = 3;
        final Integer EXIT_FLAG = 4;
        System.out.println("-------欢迎来到学员信息管理系统-------");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            try {
                System.out.println("\n\n1.根据学号查看学员信息\n2.添加学员\n3.根据学号删除学员后,查看所有学员信息\n4.退出系统\n请输入你的选择");
                Integer fun = scanner.nextInt();
                if (fun.equals(SHOW_FLAG)) {
                    System.out.println("请输入学生id");
                    int studentId = scanner.nextInt();
                    this.show(studentId);
                } else if (fun.equals(ADD_FLAG)) {
                    System.out.println("请输入学生id");
                    int studentId = scanner.nextInt();
                    // 处理回车
                    scanner.nextLine();
                    System.out.println("请输入学生姓名");
                    String studentName = scanner.nextLine();
                    System.out.println("请输入学生性别");
                    String studentSex = scanner.nextLine();
                    this.addStudent(studentId, studentName, studentSex);
                } else if (fun.equals(DEL_FLAG)) {
                    System.out.println("请输入学生id");
                    int studentId = scanner.nextInt();
                    this.deleteStudent(studentId);
                    this.showAll();
                } else if (fun.equals(EXIT_FLAG)) {
                    System.exit(0);
                } else {
                    System.out.println("无该操作选项,请重新选择");
                }
            }catch (RuntimeException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        new StudentManagement().run();
    }
}
单元测试
package student;

import entity.Student;
import enums.SexEnum;
import exceptions.StudentIdNotExitException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;


import java.util.List;

public class StudentManagementTest {
    StudentManagement studentManagement;
    @Before
    public void setUp() {
        studentManagement = new StudentManagement();
        studentManagement.initData();
    }

    @Test
    public void testAddStudent() {
        Integer id = 1;
        String name = "Tom";
        String sex = "男";

        studentManagement.addStudent(id, name, sex);
        Student student = studentManagement.getStudent(id);

        Assert.assertEquals(id, student.getId());
        Assert.assertEquals(name, student.getName());
        Assert.assertEquals(SexEnum.man, student.getSex());
    }

    @Test(expected = StudentIdNotExitException.class)
    public void testDeleteStudent() {
        Integer id = 1;
        String name = "Tom";
        String sex = "男";

        studentManagement.addStudent(id, name, sex);
        studentManagement.deleteStudent(id);
        Student student = studentManagement.getStudent(id);
        Assert.assertNull(student);
    }

    @Test
    public void testGetStudent() {
        Integer id = 1;
        String name = "Tom";
        String sex = "男";

        studentManagement.addStudent(id, name, sex);
        Student student = studentManagement.getStudent(id);
        Assert.assertEquals(id, student.getId());
        Assert.assertEquals(name, student.getName());
        Assert.assertEquals(SexEnum.man, student.getSex());
    }

    @Test
    public void testGetStudentAll() {
        Integer id1 = 1;
        String name1 = "Tom";
        String sex1 = "男";
        Integer id2 = 2;
        String name2 = "Jane";
        String sex2 = "女";

        studentManagement.addStudent(id1, name1, sex1);
        studentManagement.addStudent(id2, name2, sex2);
        List<Student> students = studentManagement.getStudentAll();
        Assert.assertEquals(2, students.size());
    }

}

代码重构与优化

相关知识点
  1. 接口
  2. 多态
面向接口编程

但是上面的核心实现都是放在同一个类里,这大大的提高了维护难度,而且导致代码可测性下降。

进行改造可以先根据函数功能以及单一职责进行拆分,分别拆为学员管理以及展示客户端,通过接口定义行为完成编程

面向接口编程优点:

  1. 实现多态性:接口定义了一组公共的方法,而不关心具体的实现细节。通过使用接口,可以在不改变代码结构的情况下,轻松地切换不同的实现类。这样可以实现代码的高度可扩展性和可维护性,同时也方便进行单元测试和模块化开发。
  2. 减少耦合性:面向接口编程能够降低组件和模块之间的耦合度。
  3. 提高代码的可读性和可维护性:接口定义了一组易于理解和调用的方法。
  4. 支持并行开发:在多人协作开发时,代码的接口也提供了开发者之间的约定,统一了代码的规范和实现方式。不同开发人员可以独立开发实现类,而不需要等待其他模块的开发完成。

完整代码示例

类关系图

uml diagram

单元测试

最后我们可以对核心功能进行单元测试

public class StudentManagerTest {
    StudentManager studentManager;
    @Before
    public void setUp() {
        studentManager = new StudentManagerMemoryImpl();
        studentManager.initData();
    }

    @Test
    public void testAddStudent() {
        Integer id = 1;
        String name = "Tom";
        String sex = "男";

        studentManager.addStudent(id, name, sex);
        Student student = studentManager.getStudent(id);

        Assert.assertEquals(id, student.getId());
        Assert.assertEquals(name, student.getName());
        Assert.assertEquals(SexEnum.man, student.getSex());
    }

    @Test(expected = StudentIdNotExitException.class)
    public void testDeleteStudent() {
        Integer id = 1;
        String name = "Tom";
        String sex = "男";

        studentManager.addStudent(id, name, sex);
        studentManager.deleteStudent(id);
        Student student = studentManager.getStudent(id);
        Assert.assertNull(student);
    }

    @Test
    public void testGetStudent() {
        Integer id = 1;
        String name = "Tom";
        String sex = "男";

        studentManager.addStudent(id, name, sex);
        Student student = studentManager.getStudent(id);
        Assert.assertEquals(id, student.getId());
        Assert.assertEquals(name, student.getName());
        Assert.assertEquals(SexEnum.man, student.getSex());
    }

    @Test
    public void testGetStudentAll() {
        Integer id1 = 1;
        String name1 = "Tom";
        String sex1 = "男";
        Integer id2 = 2;
        String name2 = "Jane";
        String sex2 = "女";

        studentManager.addStudent(id1, name1, sex1);
        studentManager.addStudent(id2, name2, sex2);
        List<Student> students = studentManager.getStudentAll();
        Assert.assertEquals(2, students.size());
    }

}

总结

  1. 熟悉封装、多态面向对象知识点
  2. 通过面向接口编程降低了耦合度,提高代码的可重用性等
  3. 更好的支持单元测试:接口编程可以更方便地进行单元测试。通过定义接口,可以很容易地创建模拟对象或者使用桩对象来进行测试,从而验证代码的正确性。

总的来说,接口编程提供了一种灵活、可扩展和可维护的编程方式,可以提高代码质量和开发效率,适用于大型项目和团队协作。