于鸿硕项目案例作业03

学生信息管理系统 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



   @Override

   public void addStudent(Student student) { ... }

    

    @Override

    public void removeStudent(Student student) { ... }

    

    @Override

    public List\<Student> getStudents() { ... }

    

    @Override

    public List\<Student> searchByName(String name) { ... }

    

    @Override

    public List\<Student> searchByMajor(String major) { ... }

    

    @Override

    public List\<Student> searchByGpa(double gpa) { ... }

}

2.3 List 模式方法说明

  1. addStudent
@Override

public void addStudent(Student student) {

    students.add(student);

}
  • 作用:向内存列表中添加学生

  • 逻辑:直接调用ArrayListadd()方法存储学生对象

  1. removeStudent
@Override

public void removeStudent(Student student) {

    students.remove(student);

}
  • 作用:从内存列表中删除学生

  • 逻辑:调用ArrayListremove()方法移除指定学生对象

  1. getStudents
@Override

public List\<Student> getStudents() {

    return students;

}
  • 作用:获取所有学生数据

  • 逻辑:直接返回内存列表的引用

  1. searchByName
@Override

public List\<Student> searchByName(String name) {

    List\<Student> result = new ArrayList<>();

    for (Student student : students) {

        if (student.getName().equals(name)) {

            result.add(student);

        }

    }

    return result;

}
  • 作用:按姓名筛选学生

  • 逻辑:遍历内存列表,将姓名匹配的学生存入结果列表并返回

  1. searchByMajor
@Override

public List\<Student> searchByMajor(String major) {

    List\<Student> result = new ArrayList<>();

    for (Student student : students) {

        if (student.getMajor().equals(major)) {

            result.add(student);

        }

    }

    return result;

}
  • 作用:按专业筛选学生

  • 逻辑:遍历内存列表,将专业匹配的学生存入结果列表并返回

  1. searchByGpa
@Override

public 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

    

    @Override

    public void addStudent(Student student) { ... }

    

    @Override

    public void removeStudent(Student student) { ... }

    

    @Override

    public List\<Student> getStudents() { ... }

    

    @Override

    public List\<Student> searchByName(String name) { ... }

    

    @Override

    public List\<Student> searchByMajor(String major) { ... }

    

    @Override

    public List\<Student> searchByGpa(double gpa) { ... }

}

3.3 文本文件模式方法说明

  1. 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对象

  1. 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写入文件

  1. addStudent
@Override

public void addStudent(Student student) {

    students.add(student);

    saveToFile();  // 添加后同步到文件

}
  • 作用:添加学生并持久化到文件

  • 逻辑:先添加到内存列表,再调用saveToFile()同步到文件

  1. removeStudent
@Override

public void removeStudent(Student student) {

    students.remove(student);

    saveToFile();  // 删除后同步到文件

}
  • 作用:删除学生并更新文件

  • 逻辑:先从内存列表删除,再调用saveToFile()同步到文件

  1. getStudents
@Override

public List\<Student> getStudents() {

    return students;

}
  • 作用:获取所有学生数据

  • 逻辑:返回内存缓存的学生列表(已从文件加载)

  1. searchByName、searchByMajor、searchByGpa
  • 实现逻辑与 List 模式完全一致(基于内存列表遍历筛选)

  • 区别:数据来源是从文件加载的内存列表,而非直接初始化的空列表

3.4 文本文件模式的特殊用法

  1. try-with-resources 语法

    自动关闭文件流,避免资源泄露:

try (BufferedReader br = new BufferedReader(new FileReader(file))) {

    // 读取操作

} catch (IOException e) {

    e.printStackTrace();

}
  1. 字符串分割与解析

    使用split(",")分割文件中的字符串,并通过Integer.parseInt()Double.parseDouble()转换数据类型:

String\[] parts = line.split(",");

int age = Integer.parseInt(parts\[1]);

double gpa = Double.parseDouble(parts\[5]);
  1. 文件不存在处理

    初始化时检查文件是否存在,不存在则返回空列表,避免空指针异常:

File file = new File(FILE\_PATH);

if (!file.exists()) {

    return list;

}

4. 主程序修改部分

4.1 主程序的核心修改

  1. 引入 DAO 接口依赖

    主程序不再直接操作 List,而是通过StudentDAO接口调用方法:

StudentDAO studentDAO;  // 声明接口类型,不依赖具体实现
  1. 支持模式选择与切换

    允许用户选择数据存储模式,并在运行中切换:

// 初始化选择模式

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;
  1. 统一操作接口

    所有数据操作通过studentDAO接口完成,与具体存储模式解耦:

// 添加学生

studentDAO.addStudent(student);

// 搜索学生

List\<Student> searchResults = studentDAO.searchByName(searchName);

// 显示所有学生

List\<Student> studentList = studentDAO.getStudents();

4.2 修改的好处与作用

  1. 实现数据存储模式的自由切换

    用户可根据需求选择内存模式(临时数据,速度快)或文件模式(持久化数据,可保存),无需修改核心逻辑。

  2. 降低代码耦合度

    主程序仅依赖StudentDAO接口,不关心具体实现,符合 "依赖倒置原则"。

  3. 提高扩展性

    若后续需添加数据库存储模式,只需新增StudentDBDAO实现接口,主程序无需修改。

  4. 统一操作方式

    两种模式的操作接口完全一致,用户无需学习新的操作逻辑。

5. 拓展:DAO 模式详解

5.1 DAO 模式的含义与作用

DAO 模式是一种数据访问层设计模式,用于隔离业务逻辑与数据访问逻辑。其核心思想是:

  • 定义DAO接口:规范数据操作方法

  • 实现DAO实现类:针对不同数据存储方式(如内存、文件、数据库)提供具体实现

  • 通过接口调用:业务逻辑层仅依赖接口,不依赖具体存储方式

作用:

  • 分离数据访问与业务逻辑,降低耦合度

  • 统一数据操作接口,简化业务层代码

  • 便于切换数据存储方式,提高系统扩展性

5.2 本系统中 DAO 模式的优势

  1. 多存储模式支持:通过实现不同 DAO,轻松支持 List(内存)和文本文件(持久化)两种模式。

  2. 操作一致性:无论使用哪种存储模式,添加、删除、查询的方法名和参数完全一致。

  3. 可维护性提升:数据访问逻辑集中在 DAO 实现类中,修改存储方式时无需改动主程序。

  4. 可扩展性增强:如需添加数据库存储,只需新增StudentDBDAO实现接口,主程序代码不变。

5.3 适合使用 DAO 模式的系统

  1. 需要多种数据存储方式的系统:如同时支持内存缓存、文件存储、数据库存储的系统。

  2. 数据访问逻辑复杂的系统:通过 DAO 封装数据操作,简化业务层代码。

  3. 需要长期维护和扩展的系统:DAO 模式的低耦合特性便于后期功能迭代。

  4. 分层架构的系统:在 MVC 等分层架构中,DAO 作为数据访问层,可清晰划分各层职责。

posted @ 2025-10-16 11:34  KinthYu  阅读(14)  评论(1)    收藏  举报