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中的分类分包思想,什么包下的类需要做什么事,每个包下面的类分工合作完成整个工程,这才是我想要传达给大家的,这在开发中对降低代码耦合度有很好的作用,我们在开发中也应该时刻把这种原则放在第一位,否则写出来的代码会变得杂乱无章,甚至自己维护都非常费力,更别提代码迭代了。
就这样吧,有问题请评论去留言,会第一时间改正。。
网友评论