学生信息管理系统 DAO 模式改造报告
1. DAO 接口方法
DAO(Data Access Object)接口定义了学生数据操作的统一规范,所有数据存取模式都需实现该接口,保证操作方式的一致性。
public interface StudentDAO {void addStudent(Student student);void removeStudent(Student student);List<Student> getStudents();List<Student> searchByName(String name);List<Student> searchByMajor(String major);List<Student> searchByGpa(double gpa);}
1.1 addStudent
-
作用:向数据存储中添加一个学生对象
-
说明:接收
Student
实体对象,将其存入对应的数据载体(List 或文件)中
1.2 removeStudent
-
作用:从数据存储中移除指定学生对象
-
说明:接收
Student
实体对象,从数据载体中删除该对象
1.3 getStudents
-
作用:获取所有学生数据
-
说明:返回存储中所有学生的列表,用于展示全部数据
1.4 searchByName
-
作用:按姓名搜索学生
-
说明:接收姓名字符串,返回所有姓名匹配的学生列表
1.5 searchByMajor
-
作用:按专业搜索学生
-
说明:接收专业字符串,返回所有专业匹配的学生列表
1.6 searchByGpa
-
作用:按 GPA 搜索学生
-
说明:接收 GPA 数值,返回所有 GPA 匹配的学生列表
2. List 模式(内存存储)
2.1 List 模式的核心逻辑
List 模式以内存中的ArrayList
作为数据载体,数据仅在程序运行时存在,程序退出后数据丢失。
public class StudentListDAO implements StudentDAO {private List\<Student> students; // 核心数据存储载体public StudentListDAO() {students = new ArrayList<>(); // 初始化内存列表}// 接口实现方法...}
2.2 List 模式的接口应用
通过实现StudentDAO
接口,完成内存中数据的操作:
public class StudentListDAO implements StudentDAO {// 成员变量及构造方法见2.1@Overridepublic void addStudent(Student student) { ... }@Overridepublic void removeStudent(Student student) { ... }@Overridepublic List\<Student> getStudents() { ... }@Overridepublic List\<Student> searchByName(String name) { ... }@Overridepublic List\<Student> searchByMajor(String major) { ... }@Overridepublic List\<Student> searchByGpa(double gpa) { ... }}
2.3 List 模式方法说明
- addStudent
@Overridepublic void addStudent(Student student) {students.add(student);}
-
作用:向内存列表中添加学生
-
逻辑:直接调用
ArrayList
的add()
方法存储学生对象
- removeStudent
@Overridepublic void removeStudent(Student student) {students.remove(student);}
-
作用:从内存列表中删除学生
-
逻辑:调用
ArrayList
的remove()
方法移除指定学生对象
- getStudents
@Overridepublic List\<Student> getStudents() {return students;}
-
作用:获取所有学生数据
-
逻辑:直接返回内存列表的引用
- searchByName
@Overridepublic List\<Student> searchByName(String name) {List\<Student> result = new ArrayList<>();for (Student student : students) {if (student.getName().equals(name)) {result.add(student);}}return result;}
-
作用:按姓名筛选学生
-
逻辑:遍历内存列表,将姓名匹配的学生存入结果列表并返回
- searchByMajor
@Overridepublic List\<Student> searchByMajor(String major) {List\<Student> result = new ArrayList<>();for (Student student : students) {if (student.getMajor().equals(major)) {result.add(student);}}return result;}
-
作用:按专业筛选学生
-
逻辑:遍历内存列表,将专业匹配的学生存入结果列表并返回
- searchByGpa
@Overridepublic List\<Student> searchByGpa(double gpa) {List\<Student> result = new ArrayList<>();for (Student student : students) {if (student.getGpa() == gpa) {result.add(student);}}return result;}
-
作用:按 GPA 筛选学生
-
逻辑:遍历内存列表,将 GPA 匹配的学生存入结果列表并返回
3. 文本文件模式(持久化存储)
3.1 文本文件模式的核心逻辑
文本文件模式以students.txt
文件作为数据载体,通过文件 IO 实现数据的持久化存储(程序退出后数据不丢失)。核心逻辑是 "加载 - 操作 - 保存":初始化时从文件加载数据到内存列表,操作后将内存列表同步到文件。
public class StudentFileDAO implements StudentDAO {private static final String FILE\_PATH = "students.txt"; // 文件路径private List\<Student> students; // 内存缓存列表public StudentFileDAO() {students = loadFromFile(); // 初始化时从文件加载数据}// 从文件加载数据到内存private List\<Student> loadFromFile() { ... }// 将内存数据保存到文件private void saveToFile() { ... }// 接口实现方法...}
3.2 文本文件模式的接口应用
实现StudentDAO
接口,通过文件 IO 完成数据的持久化操作:
public class StudentFileDAO implements StudentDAO {// 成员变量、构造方法及工具方法见3.1@Overridepublic void addStudent(Student student) { ... }@Overridepublic void removeStudent(Student student) { ... }@Overridepublic List\<Student> getStudents() { ... }@Overridepublic List\<Student> searchByName(String name) { ... }@Overridepublic List\<Student> searchByMajor(String major) { ... }@Overridepublic List\<Student> searchByGpa(double gpa) { ... }}
3.3 文本文件模式方法说明
- loadFromFile(工具方法)
private List\<Student> loadFromFile() {List\<Student> list = new ArrayList<>();File file = new File(FILE\_PATH);if (!file.exists()) {return list; // 文件不存在则返回空列表}try (BufferedReader br = new BufferedReader(new FileReader(file))) {String line;while ((line = br.readLine()) != null) {// 解析文件内容为Student对象String\[] parts = line.split(",");if (parts.length == 6) {String name = parts\[0];int age = Integer.parseInt(parts\[1]);String gender = parts\[2];String id = parts\[3];String major = parts\[4];double gpa = Double.parseDouble(parts\[5]);list.add(new Student(name, age, gender, id, major, gpa));}}} catch (IOException e) {e.printStackTrace();}return list;}
-
作用:从文件读取数据并转换为学生列表
-
逻辑:使用
BufferedReader
读取文件,按行解析字符串为Student
对象
- saveToFile(工具方法)
private void saveToFile() {try (BufferedWriter bw = new BufferedWriter(new FileWriter(FILE\_PATH))) {for (Student student : students) {// 将Student对象转换为字符串并写入文件String line = String.join(",",student.getName(),String.valueOf(student.getAge()),student.getGender(),student.getId(),student.getMajor(),String.valueOf(student.getGpa()));bw.write(line);bw.newLine();}} catch (IOException e) {e.printStackTrace();}}
-
作用:将内存中的学生列表写入文件
-
逻辑:遍历学生列表,将对象属性拼接为字符串(逗号分隔),通过
BufferedWriter
写入文件
- addStudent
@Overridepublic void addStudent(Student student) {students.add(student);saveToFile(); // 添加后同步到文件}
-
作用:添加学生并持久化到文件
-
逻辑:先添加到内存列表,再调用
saveToFile()
同步到文件
- removeStudent
@Overridepublic void removeStudent(Student student) {students.remove(student);saveToFile(); // 删除后同步到文件}
-
作用:删除学生并更新文件
-
逻辑:先从内存列表删除,再调用
saveToFile()
同步到文件
- getStudents
@Overridepublic List\<Student> getStudents() {return students;}
-
作用:获取所有学生数据
-
逻辑:返回内存缓存的学生列表(已从文件加载)
- searchByName、searchByMajor、searchByGpa
-
实现逻辑与 List 模式完全一致(基于内存列表遍历筛选)
-
区别:数据来源是从文件加载的内存列表,而非直接初始化的空列表
3.4 文本文件模式的特殊用法
-
try-with-resources 语法
自动关闭文件流,避免资源泄露:
try (BufferedReader br = new BufferedReader(new FileReader(file))) {// 读取操作} catch (IOException e) {e.printStackTrace();}
-
字符串分割与解析
使用
split(",")
分割文件中的字符串,并通过Integer.parseInt()
、Double.parseDouble()
转换数据类型:
String\[] parts = line.split(",");int age = Integer.parseInt(parts\[1]);double gpa = Double.parseDouble(parts\[5]);
-
文件不存在处理
初始化时检查文件是否存在,不存在则返回空列表,避免空指针异常:
File file = new File(FILE\_PATH);if (!file.exists()) {return list;}
4. 主程序修改部分
4.1 主程序的核心修改
-
引入 DAO 接口依赖
主程序不再直接操作 List,而是通过
StudentDAO
接口调用方法:
StudentDAO studentDAO; // 声明接口类型,不依赖具体实现
-
支持模式选择与切换
允许用户选择数据存储模式,并在运行中切换:
// 初始化选择模式System.out.println("请选择数据存储模式:");System.out.println("1. 内存模式(List)");System.out.println("2. 文件模式");int modeChoice = scanner.nextInt();studentDAO = modeChoice == 1 ? new StudentListDAO() : new StudentFileDAO();// 运行中切换模式(菜单选项7)case 7:System.out.println("请选择数据存储模式:");modeChoice = scanner.nextInt();studentDAO = modeChoice == 1 ? new StudentListDAO() : new StudentFileDAO();System.out.println("模式切换成功");break;
-
统一操作接口
所有数据操作通过
studentDAO
接口完成,与具体存储模式解耦:
// 添加学生studentDAO.addStudent(student);// 搜索学生List\<Student> searchResults = studentDAO.searchByName(searchName);// 显示所有学生List\<Student> studentList = studentDAO.getStudents();
4.2 修改的好处与作用
-
实现数据存储模式的自由切换
用户可根据需求选择内存模式(临时数据,速度快)或文件模式(持久化数据,可保存),无需修改核心逻辑。
-
降低代码耦合度
主程序仅依赖
StudentDAO
接口,不关心具体实现,符合 "依赖倒置原则"。 -
提高扩展性
若后续需添加数据库存储模式,只需新增
StudentDBDAO
实现接口,主程序无需修改。 -
统一操作方式
两种模式的操作接口完全一致,用户无需学习新的操作逻辑。
5. 拓展:DAO 模式详解
5.1 DAO 模式的含义与作用
DAO 模式是一种数据访问层设计模式,用于隔离业务逻辑与数据访问逻辑。其核心思想是:
-
定义
DAO接口
:规范数据操作方法 -
实现
DAO实现类
:针对不同数据存储方式(如内存、文件、数据库)提供具体实现 -
通过
接口调用
:业务逻辑层仅依赖接口,不依赖具体存储方式
作用:
-
分离数据访问与业务逻辑,降低耦合度
-
统一数据操作接口,简化业务层代码
-
便于切换数据存储方式,提高系统扩展性
5.2 本系统中 DAO 模式的优势
-
多存储模式支持:通过实现不同 DAO,轻松支持 List(内存)和文本文件(持久化)两种模式。
-
操作一致性:无论使用哪种存储模式,添加、删除、查询的方法名和参数完全一致。
-
可维护性提升:数据访问逻辑集中在 DAO 实现类中,修改存储方式时无需改动主程序。
-
可扩展性增强:如需添加数据库存储,只需新增
StudentDBDAO
实现接口,主程序代码不变。
5.3 适合使用 DAO 模式的系统
-
需要多种数据存储方式的系统:如同时支持内存缓存、文件存储、数据库存储的系统。
-
数据访问逻辑复杂的系统:通过 DAO 封装数据操作,简化业务层代码。
-
需要长期维护和扩展的系统:DAO 模式的低耦合特性便于后期功能迭代。
-
分层架构的系统:在 MVC 等分层架构中,DAO 作为数据访问层,可清晰划分各层职责。