本文纲要
- 案例驱动教学概述
- 分类思想
2.1 代码臃肿与可维护性问题
2.2 分工协作:专人干专事
2.3 信息管理系统的类职责划分
2.4 类之间的交互流程 - 分包思想与包的使用
3.1 包的本质与创建
3.2 package、import 与全类名访问
3.3 包使用的注意事项 - static 关键字
4.1 static 的特点
4.2 static 的内存图解
4.3 static 的注意事项
4.4 解决学号重复问题 - 信息管理系统实战
5.1 项目结构
5.2 环境搭建
5.3 菜单搭建
5.4 添加功能实现
5.5 查询功能实现
5.6 删除功能实现
5.7 修改功能实现
5.8 代码优化
5.9 老师管理系统实现 - 总结
案例驱动学习概述
采用案例驱动的学习方式:先用已掌握的知识点实现一个案例,然后找出案例中存在的重复代码多、业务逻辑耦合紧、可维护性差等问题,再通过新的知识点进行解决。这样能让大家对知识点的应用场景有更深刻的认知。
基础班的学生管理系统将所有增删改查功能写在一个类中,导致阅读困难、维护不便。实际开发中,我们需要将代码进行分类管理,并引入分类思想和分包思想来提升代码的复用性、可读性和维护性。
分类思想
1 ) 代码臃肿与可维护性问题
如果将多个业务功能集中在一个类文件中,代码量会急剧膨胀,阅读和修改都非常痛苦。例如,学生管理系统的添加和修改方法中,键盘录入学生信息并封装为对象的代码完全重复,导致代码臃肿。
2 ) 分工协作:专人干专事
分类思想的核心是分工协作,专人干专事。就像物流公司,刚开始只有一名员工负责客服、发货、仓库管理,业务量增大后,需要招聘新员工,分别负责客服、发货、库管,这样职责清晰,管理方便。
编写代码也一样,我们应该将不同职责的代码划分到不同的类中,每个类只负责自己的事情
3 ) 信息管理系统的类职责划分
在信息管理系统中,结合分类思想,我们设计出以下类:
| 类名 | 角色比喻 | 职责 |
|---|---|---|
| Student | 数据实体 | 封装学生信息(id, name, age, birthday) |
| StudentDao | 库管 | 负责访问存储数据的数组或集合,进行增删改查操作 |
| StudentService | 业务员 | 负责业务逻辑处理,如判断学号是否存在 |
| StudentController | 客服 | 与用户交互,接收用户需求,采集数据,打印结果 |
注意:DAO 是 Data Access Object(数据访问对象)的缩写,不要读作“到”。
4 )类之间的交互流程
用户的操作会依次经过 Controller → Service → Dao,最后将结果返回给用户。
例如添加学生:
这种分层设计,使得每个类职责清晰,便于维护和扩展。
分包思想与包的使用
1 ) 包的本质与创建
如果项目中有很多类文件,全部放在一起不便于管理。包(package) 就是用来对类文件进行分门别类管理的,它在硬盘上就是一个文件夹。
创建包的规范:
- 使用多级包,用 . 分隔,如 com.wb.edu.info.manager
- 命名惯例:公司域名倒写,去掉 www,例如 www.wb.com → com.wb
包名全部小写
在 IDEA 中,右键 src → New → Package,输入 com.wb.edu.info.manager 即可创建多级包。
2 ) package、import 与全类名访问
package 关键字:声明当前类所属的包,必须放在文件的第一条可执行代码之前(注释不算可执行代码)。每个类文件只能有一个 package 声明。
import 关键字:当需要在不同包下访问类时,可以使用 import 导包,然后直接使用类名。
全类名访问:包名 + 类名,如 com.wb.test2.Student stu = new com.wb.test2.Student();。这种方式主要用于解决多个包下存在同名类时的冲突。
示例代码:
// 不同包下的访问方式
package com.wb.test;
// 方式一:import导包
import com.wb.test2.Student;
public class TestPackage {
public static void main(String[] args) {
Student stu = new Student(); // 使用test2包下的Student
// 方式二:全类名访问,区分同名类
com.wb.test3.Student stu2 = new com.wb.test3.Student();
}
}
3 ) 包使用的注意事项
package 语句必须是程序的第一条可执行代码(注释可放在前面)
一个 Java 文件中最多只能有一个 package 语句
如果没有写 package,默认表示无包名,但一般不建议这样做
三个关键字的位置顺序:package → import → class
static 关键字
1 ) static 的特点
static 是“静态”的意思,可以修饰成员变量和成员方法。被它修饰的内容具有以下特点:
- 被所有对象共享:一个对象修改了静态变量的值,其他对象也会看到变化。
- 随着类的加载而加载,优先于对象存在:类加载时静态变量就在内存中初始化了,不用等到创建对象。
- 多了一种调用方式:可以通过 类名.静态成员 直接调用,如 Student.school = “网炐学院”;。
2 ) static 的内存图解
静态变量 school 存储在堆内存的静态存储区,只有一份。
所有对象通过指针共享这份数据。
3 ) static 的注意事项
静态方法中只能访问静态成员(变量和方法),不能访问非静态成员,因为静态存在时对象可能还没创建。
非静态方法中既可以访问静态成员,也可以访问非静态成员。
静态方法中没有 this 关键字,因为 this 代表当前对象,而静态方法不依赖于对象。
public class Student {
String name;
int age;
static String school;
public void show() {
// 非静态方法可以访问静态和非静态成员
System.out.println(name + " " + age + " " + school);
}
public static void method() {
// 静态方法不能访问非静态成员,也不能使用this
// this.name = "张三"; // 编译错误
// name = "张三"; // 编译错误
school = "程序员"; // 正确
}
}
4 ) 解决学号重复问题
在添加学生功能中,如果每次调用 addStudent 方法都 new 一个 StudentController,会导致 StudentDao 中的数组对象被多次创建,数据不共享,学号重复判断失效。
解决方案:将 StudentDao 中的数组声明为 static,使其成为所有对象共享的同一份数据。
public class StudentDao {
private static Student[] stus = new Student[5]; // 静态共享数组
// ...
}
这样无论创建多少个 Controller 对象,操作的都是同一个数组,学号重复判断就能正常工作了。
信息管理系统实战
1 ) 项目结构
wb-edu-info-manager
└─ src
└─ com.wb.edu.info.manager
├─ domain
│ ├─ Person.java
│ ├─ Student.java
│ └─ Teacher.java
├─ dao
│ ├─ StudentDao.java
│ └─ TeacherDao.java
├─ service
│ ├─ StudentService.java
│ └─ TeacherService.java
├─ controller
│ ├─ StudentController.java
│ └─ TeacherController.java
└─ entry
└─ InfoManagerEntry.java
2 ) 环境搭建
创建模块 wb-edu-info-manager
在 src 下按照上述包结构创建包
创建实体类 Student 和 Teacher,都继承自 Person
创建 Dao、Service、Controller 类,并在 entry 包中创建入口类 InfoManagerEntry
3 ) 菜单搭建
主菜单循环显示,用户选择进入学生管理或老师管理,退出时使用 System.exit(0) 结束 JVM
学生管理菜单也类似,退出时使用带标签的 break 返回主菜单。
// 主菜单
while (true) {
System.out.println("--------欢迎来到信息管理系统--------");
System.out.println("请输入您的选择: 1.学生管理 2.老师管理 3.退出");
String choice = sc.next();
switch (choice) {
case "1":
new StudentController().start(); break;
case "2":
new TeacherController().start(); break;
case "3":
System.out.println("感谢您的使用");
System.exit(0); break;
default:
System.out.println("您的输入有误, 请重新输入");
}
}
4 ) 添加功能实现
基本添加流程:
StudentController.addStudent()接收用户输入的学号、姓名、年龄、生日,封装为Student对象,传递给StudentService.addStudent(stu)StudentService.addStudent(stu)将对象传给StudentDao.addStudent(stu),并返回添加结果StudentDao.addStudent(stu)遍历数组找到第一个null位置,存入对象,返回true;若数组已满返回false
加入学号重复判断:
在 Controller 中,先接收学号,调用 StudentService.isExists(id) 判断是否存在
如果存在,循环提示重新输入;如果不存在,跳出循环,继续录入其他信息
StudentService.isExists(id) 调用 StudentDao.findAllStudent() 获取数组,遍历比对 id
关键代码:
// Controller 中
public void addStudent() {
String id;
while (true) {
System.out.println("请输入学生id:");
id = sc.next();
if (studentService.isExists(id)) {
System.out.println("学号已被占用, 请重新输入");
} else {
break;
}
}
Student stu = inputStudentInfo(id); // 封装对象
boolean result = studentService.addStudent(stu);
System.out.println(result ? "添加成功" : "添加失败");
}
// Dao 中
public boolean addStudent(Student stu) {
int index = -1;
for (int i = 0; i < stus.length; i++) {
if (stus[i] == null) {
index = i;
break;
}
}
if (index == -1) return false;
stus[index] = stu;
return true;
}
5 ) 查询功能实现
Controller 调用 studentService.findAllStudent() 得到数组
如果数组为 null(无数据),提示“查无信息”;否则遍历数组,跳过 null 元素,打印学生信息
Service 中 findAllStudent() 调用 Dao 获取数组,判断数组中是否有非 null 元素,有则返回数组,否则返回 null
6 ) 删除功能实现
Controller 中先调用 inputStudentId() 方法获取一个存在的学号(循环判断)
调用 studentService.deleteStudentById(id) 执行删除,并提示“删除成功”
Dao 中根据 id 找到索引,将该位置置为 null
// 获取索引的通用方法
public int getIndex(String id) {
int index = -1;
for (int i = 0; i < stus.length; i++) {
Student stu = stus[i];
if (stu != null && stu.getId().equals(id)) {
index = i;
break;
}
}
return index;
}
7 ) 修改功能实现
Controller 获取存在的学号,再录入新信息并封装为 Student 对象。
调用 studentService.updateStudent(updateId, newStu),提示“修改成功”。
Dao 中通过 getIndex 找到索引,用新对象替换旧对象
8 ) 代码优化
抽取重复代码,提高复用性:
inputStudentId():封装“录入学号并判断是否存在”的逻辑,返回一个存在的学号(用于删除、修改)或一个不存在的学号(用于添加,添加逻辑单独处理)
inputStudentInfo(String id):封装录入学生信息并封装成对象的逻辑,返回 Student 对象
// 抽取的方法
public String inputStudentId() {
String id;
while (true) {
System.out.println("请输入学生id:");
id = sc.next();
if (!studentService.isExists(id)) {
System.out.println("您输入的id不存在, 请重新输入:");
} else {
break;
}
}
return id;
}
public Student inputStudentInfo(String id) {
System.out.println("请输入学生姓名:");
String name = sc.next();
System.out.println("请输入学生年龄:");
String age = sc.next();
System.out.println("请输入学生生日:");
String birthday = sc.next();
Student stu = new Student();
stu.setId(id);
stu.setName(name);
stu.setAge(age);
stu.setBirthday(birthday);
return stu;
}
9 ) 老师管理系统实现
老师管理系统的实现与学生管理系统完全对称,只需将 Student 相关类替换为 Teacher 即可
包括:
- 实体类
Teacher TeacherDao、TeacherService、TeacherController- 菜单、增删改查及代码优化方法均与学生管理相同
总结
通过本次实战,我们掌握了以下核心技能:
- 分类思想:将代码按职责划分到不同类中,实现高内聚低耦合
- 分包思想:使用包管理类文件,规范项目结构
- static 关键字:解决数据共享问题,理解其内存模型和注意事项
- 分层架构:
Controller(交互)→Service(业务)→Dao(数据访问),职责清晰,便于维护。 - 代码优化:抽取重复代码,提高复用性
这些思想和方法是 Java 项目开发的基础,在后续学习中多加练习,形成良好的编码习惯
本文结合案例驱动,从问题出发,逐步引入面向对象高级特性,并完成了一个完整的信息管理系统
代码示例已精简至核心逻辑
1512

被折叠的 条评论
为什么被折叠?



