Java-----基于面向对象开发学生管理系统

1、大致功能

开发一个简单的系统,该系统可以对学生进行增删改查(CRUD);

2、需求分析

  • 添加学生:键盘录入学生信息(学号,姓名,年龄,出生日期),使用数组存储学生信息,要求学号不能重复。
  • 删除学生:键盘录入要删除的学生学号,将学生从数组中移除
  • 修改学生:键盘录入要修改学生的学号和修改后的信息,将数组中学生的信息修改
  • 遍历学生: 将所有的学生信息输出到控制台

3、基本类的创建

在开发中,我们要学会对很多类进行分类思想,不能把所有的类一股脑塞到一个包里面,下面是我对这个小demo类的分类分包的详情。


image.png

搭建以后目录结构如下所示:


image.png

4、菜单搭建

主要分为主菜单搭建和学生管理系统菜单搭建
先来看主菜单搭建,主菜搭建在程序入口InfoManagerEntry里面进行搭建
主菜单搭建:

public class InfoManagerEntry {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        //主菜单搭建
        while(true){
            System.out.println("----------欢迎来到学生老师管理系统----------");
            System.out.println("请输入您的选择:1、学生管理  2、老师管理  3、退出");
            String choice = sc.next();
            switch(choice){
                case "1":
                    //开启学生管理系统
                    StudentController studentcontroller=new StudentController();
                    studentcontroller.start();
                    break;
                case "2":
                    System.out.println("老师管理");
                    break;
                case "3":
                    System.out.println("感谢您的使用");
                    //退出当前正在运行的JVM虚拟机,关闭程序
                    System.exit(0);
                    break;
                default:
                    System.out.println("您的输入有误,清重新输入");
                    break;
            }
        }

    }
}

上面代码中我们输入1进入学生管理系统,执行StudentController 的Start()方法,StudentController 代码实现如下:

public class StudentController {
    //该方法用于开启学生管理系统,展示学生管理系统菜单
    public void start() {
        Scanner sc=new Scanner(System.in);
        studentLoop:while(true){
            System.out.println("----------欢迎来到学生管理系统----------");
            System.out.println("请输入您的选择:1、添加学生  2、删除学生  3、修改学生  4、查找学生  5、退出");
            String choice = sc.next();
            switch(choice){
                case "1":
                    System.out.println("添加");
                    break;
                case "2":
                    System.out.println("删除");
                    break;
                case "3":
                    System.out.println("修改");
                    break;
                case "4":
                    System.out.println("查找");
                    break;
                case "5":
                   /* 这里是退出这个循环而不是退出JVM虚拟机,所以不能用System.exit(),
                    这里的做法是给循环取个名字叫studentLoop,然后输入5后break这个循环就可以了*/
                    System.out.println("感谢您使用学生管理系统,再见!");
                    break studentLoop;
                default:
                    System.out.println("您的输入有误,清重新输入");
                    break;
            }
        }

    }
}

到这里基本的菜单搭建就完成了,接下来我们把菜单里面的功能一个个实现出来。

5、添加功能的实现

添加功能分析(主要着重分包分类思想分析,每个类的分工合作)


image.png

这里需要明确不同包下的每个类的作用,我在第三步中已经给出了每个类具体负责的事务。大家自己领悟就好。
代码实现,如上图所示,在上图三个类中都有一个addStudent()方法,每个方法需要实现不同的功能,我们先来看StudentController里面的addStudent方法,图中说明该方法主要实现以下功能:

  • 方法中接受用户输入的信息
  • 将学生信息封装为学生对象传递给StudentService
  • 接收方法的boolean类型返回值,根据结果在控制台打印添加成功\添加失败
    那我们就根据这三点要求来创建addStudent方法。
 public void addStudent() {
        //1、接收用户输入的信息
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入学生id:");
        String id = sc.next();
        System.out.println("请输入学生姓名:");
        String name = sc.next();
        System.out.println("请输入学生年龄:");
        String age = sc.next();
        System.out.println("请输入学生生日:");
        String birthday = sc.next();
        //2、将学生信息封装为学生对象传递给StudentService
        Student stu = new Student(id, name, age, birthday);
        //3、将学生对象传递给StudentService中的addStudent方法
        StudentService studentservice = new StudentService();
        boolean result = studentservice.addStudent(stu);
        //4、接收方法的boolean类型返回值,根据结果在控制台打印添加成功\添加失败
        if (result) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }

    }

然后在用户输入1时调用就可以了,

  case "1":
                    addStudent();
                    break;

在上面这个方法中需要接收StudentService 中的addStudent方法返回的结果,再来看看StudentService 中的addStudent方法,上面图中已经给出这个方法需要实现的功能,直接照着写就好了。

//1.将接受到的学生对象,传递给StudentDao
//2.接受方法的boolean返回值将结果返还给StudentC ontroller
 public boolean addStudent(Student stu) {
        StudentDao studentdao = new StudentDao();
        return studentdao.addStudent(stu);
    }

这个方法又用到了StudentDao 里面的addStudent方法,也是一样的,根据需求在studentdao内部实现该方法就可以了。代码如下:

public boolean addStudent(Student stu) {
        //1.创建Student学生数组长度为5
        Student[] students = new Student[5];
        // 2.将接受到的学生对象添加到数组中
        int index = -1;
        for (int i = 0; i < students.length; i++) {
            Student student = students[i];
            if (student == null) {
                index = i;
                break;
            }
        }
        //3.返回是否添加成功的boolean类型值
        if (index == -1) {
            return false;
        } else {
            students[index] = stu;
            return true;
        }
    }

但是上面的代码还有缺陷,比如我们输入一个已经存在的学生,他也会直接添加进去,所以我们需要添加判断学生是否存在的逻辑代码,这部分逻辑代码同样使用分包分类的思想,先来看一个分析图:


image.png

判断id是否存在属于业务逻辑代码,应该在StudentService中实现,接收学生id属于和用户打交道,在StudentController中实现,实现判断时需要拿到现在数组中的所有学生对象,这个属于访问存贮数据,应该在StudentDao中实现,这里我直接把每个类的完整代码贴出来了。
StudentController:

public class StudentController {
    //该方法用于开启学生管理系统,展示学生管理系统菜单
    public void start() {
        Scanner sc = new Scanner(System.in);
        studentLoop:
        while (true) {
            System.out.println("----------欢迎来到学生管理系统----------");
            System.out.println("请输入您的选择:1、添加学生  2、删除学生  3、修改学生  4、查找学生  5、退出");
            String choice = sc.next();
            switch (choice) {
                case "1":
                    addStudent();
                    break;
                case "2":
                    System.out.println("删除");
                    break;
                case "3":
                    System.out.println("修改");
                    break;
                case "4":
                    System.out.println("查找");
                    break;
                case "5":
                   /* 这里是退出这个循环而不是退出JVM虚拟机,所以不能用System.exit(),
                    这里的做法是给循环取个名字叫studentLoop,然后输入5后break这个循环就可以了*/
                    System.out.println("感谢您使用学生管理系统,再见!");
                    break studentLoop;
                default:
                    System.out.println("您的输入有误,清重新输入");
                    break;
            }
        }

    }


    public void addStudent() {
        //1、接收用户输入的信息
        StudentService studentservice = new StudentService();
        Scanner sc = new Scanner(System.in);
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean flag = studentservice.isExits(id);
            if (flag) {
                System.out.println("学号已被占用,请重新输入");
            } else {
                break;
            }
        }
        System.out.println("请输入学生姓名:");
        String name = sc.next();
        System.out.println("请输入学生年龄:");
        String age = sc.next();
        System.out.println("请输入学生生日:");
        String birthday = sc.next();
        //2、将学生信息封装为学生对象传递给StudentService
        Student stu = new Student(id, name, age, birthday);
        //3、将学生对象传递给StudentService中的addStudent方法

        boolean result = studentservice.addStudent(stu);
        //4、接收方法的boolean类型返回值,根据结果在控制台打印添加成功\添加失败
        if (result) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }

    }
}

StudentService:

public class StudentService {
    StudentDao studentdao = new StudentDao();
    public boolean addStudent(Student stu) {
        return studentdao.addStudent(stu);
    }

    public boolean isExits(String id) {
        Student[] stus = studentdao.findAllAtudents();
        boolean exits = false;
        for (int i = 0; i < stus.length; i++) {
            Student student = stus[i];
            if (student != null && student.getId().equals(id)) {
                exits = true;
                break;
            }
        }
        return exits;
    }
}

StudentDao:

public class StudentDao {
    //1.创建Student学生数组长度为5
    Student[] students = new Student[5];
    public boolean addStudent(Student stu) {
        // 2.将接受到的学生对象添加到数组中
        int index = -1;
        for (int i = 0; i < students.length; i++) {
            Student student = students[i];
            if (student == null) {
                index = i;
                break;
            }
        }
        //3.返回是否添加成功的boolean类型值
        if (index == -1) {
            return false;
        } else {
            students[index] = stu;
            return true;
        }
    }

    public Student[] findAllAtudents() {
        return students;
    }
}

然后我在测试的时候发现我先添加一个学生,然后在添加同样的学生还是能添加进去,这是为什么呢,其实原因就是因为第二次添加的时候它会重新创建一个对象,和第一次添加的对象不是同一个导致他不能判断是否重复,怎么解决呢?这里就要用到Static关键字了,下面是static关键字的一些知识点。


image.png

在内存中有一块静态存储位置专门负责存储status修饰的内容,随着类的加载它会一直存在。
使用Static需要注意的几点:

  • 静态方法内部只能访问静态成员(成员变量、成员方法)
    原因分析:静态的内容随着类的加载而加载,非静态内容必须在创建对象之后才能使用,所以当静态内容存在时可能非静态内容还没有,所以静态方法内部只能访问静态成员。
  • 非静态成员方法可以使用静态成员变量,也可以使用非静态成员变量。
  • 静态方法中没有this关键字。
    原因分析:this代表当前对象的引用,但是静态存在时可能还没有创建对象,所以没有this关键字。
    到这里问题就很清楚了,因为我们从StudentDao拿到的学生数组和第一次添加的不是同一个,所以只需要把StudentDao中的学生数组改为Static变量就可以了
public class StudentDao {
    //1.创建Student学生数组长度为5
    public static Student[] students = new Student[5];
    public boolean addStudent(Student stu) {
        // 2.将接受到的学生对象添加到数组中
        int index = -1;
        for (int i = 0; i < students.length; i++) {
            Student student = students[i];
            if (student == null) {
                index = i;
                break;
            }
        }
        //3.返回是否添加成功的boolean类型值
        if (index == -1) {
            return false;
        } else {
            students[index] = stu;
            return true;
        }
    }

    public Student[] findAllAtudents() {
        return students;
    }
}

学号重复问题测试效果如下:


image.png

到这里整个添加方法就实现了,这样层层嵌套就是为了说明一个分包分类思想,哪些功能需要由哪个类来实现,放在哪个包下,在实际开发中也是需要这样来降低程序的耦合度,这样便于维护代码,要是全部揉成一坨后期维护会非常非常困难,这一点博主也是深有体会。

6、查看学生代码实现

同样的先来分析每个类需要完成的工作:


image.png

这个很简单了,参照开头给出的分类分包思想图进行分析就可以了。
代码实现(根据上图步骤创建每个类中的方法)
StudentController中的findAllStudent方法:

   private void findAllAtudents() {
        Student[] stus=studentservice.findAllStudents();
        if (stus==null){
            System.out.println("系统内暂无学生信息,请添加重试");
            return;
        }else{
            for (int i = 0; i < stus.length; i++) {
                Student stu3=stus[i];
                if (stu3!=null) {
                    System.out.println("学号:" + stus[i].getId() + "姓名:" + stus[i].getName() + "年龄:" + stus[i].getAge() + "生日:" + stus[i].getBirthday());
                }
            }
        }
    }

StudentService中的findAllStudent方法:

  public Student[] findAllStudents() {
        Student[] stus = studentdao.findAllAtudents();
        boolean flag = false;
        for (int i = 0; i < stus.length; i++) {
            Student stus1 = stus[i];
            if (stus1 != null) {
                flag = true;
            }
        }
        if (flag) {
            return stus;
        } else {
            return null;
        }
    }

StudentDao中的findAllStudents方法:

public Student[] findAllAtudents() {
        return students;
    }

测试结果:


image.png

7、删除学生代码实现

和前面一样,先来一张思路分析图:


image.png

StudentController中的deleteStudentById方法:

  public void deleteStudentById(){
        System.out.println("请输入需要删除的学生id");
        Scanner sc=new Scanner(System.in);
        String id=sc.next();
        boolean exits = studentservice.isExits(id);
        if (exits){
            boolean b = studentservice.deleteStudentById(id);
            if (b){
                System.out.println("删除成功");
            }else{
                System.out.println("删除失败");
            }
        }else{
            System.out.println("没有该名学生,不需要删除");
        }
    }

StudentService中的deleteStudentById方法:

 public boolean deleteStudentById(String id) {
        boolean isDelete=studentdao.deleteStudentById(id);
        return isDelete;
    }

StudentDao中的deleteStudentById方法:

public boolean deleteStudentById(String id) {
        boolean b = false;
        for (int i = 0; i < students.length; i++) {
            Student student = students[i];
            if (student.getId().equals(id)) {
                students[i] = null;
                b = true;
                break;
            }
        }
        return b;
    }

测试效果:


image.png

8、修改学生代码实现

这里我就不一一去分析了,大家可以参照前面的三个对它每个类里面的修改方法做功能分析,我在这里就直接上代码了。
StudentController中的updateStudentById方法:

public void updateStudentById() {
        Scanner sc1 = new Scanner(System.in);
        String id;

        System.out.println("请输入需要修改的学生id:");
        id = sc1.next();
        boolean flag = studentservice.isExits(id);
        if (!flag) {
            System.out.println("未找到该名学生!");
            return;
        }
        System.out.println("请输入学生姓名:");
        String name = sc1.next();
        System.out.println("请输入学生年龄:");
        String age = sc1.next();
        System.out.println("请输入学生生日:");
        String birthday = sc1.next();
        //2、将学生信息封装为学生对象传递给StudentService
        Student stu = new Student(id, name, age, birthday);
        //3、将学生对象传递给StudentService中的addStudent方法

        boolean result = studentservice.updateStudentById(stu,id);
        //4、接收方法的boolean类型返回值,根据结果在控制台打印添加成功\添加失败
        if (result) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }
    }

StudentService中的updateStudentById方法:

public boolean updateStudentById(Student stu, String id) {
        return studentdao.updateStudentById(stu,id);
    }

StudentDao中的updateStudentById方法:

public boolean updateStudentById(Student stu, String id) {
        boolean b1 = false;
        for (int i = 0; i < students.length; i++) {
            Student student = students[i];
            if (student.getId().equals(id)) {
                students[i] = stu;
                b1 = true;
                break;
            }
        }
        return b1;
    }

最后上一个测试截图:


image.png

总结:其实开发这样一个简单的学生管理系统非常简单,甚至可能觉得我把这个过程弄得非常复杂,很多人会觉得没必要这样,我想说的是,这么简单的系统很多人都能做,我只是想通过这个简单的demo来温习一下Java中的分类分包思想,什么包下的类需要做什么事,每个包下面的类分工合作完成整个工程,这才是我想要传达给大家的,这在开发中对降低代码耦合度有很好的作用,我们在开发中也应该时刻把这种原则放在第一位,否则写出来的代码会变得杂乱无章,甚至自己维护都非常费力,更别提代码迭代了。
就这样吧,有问题请评论去留言,会第一时间改正。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容