前言

这学期在学校上了一学期面向对象程序设计数据库原理及应用的课程(虽然但是其实是自己学的上课根本不可能听),做了一学期的实验后,也是最终迎来了Java和数据库的大作业。

这两门课的大作业其实差不多,Java的是用Java设计一个系统,拓展是可以用到数据库;数据库的是创建一个数据库,拓展是用一种语言结合数据库实现一个系统。所以我就当成一项做了。

其实大多数课程我是不那么认真的。Java是因为我感觉和C#很像,所以学起来其实很轻松,数据库的话以后会用到我就也认真学了,虽然学校教的是微软的SQL Server我学的是MySQL。

这个作业我做的十分认真(其实大多数情况都是找现成的或者直接丢给AI来写),甚至前前后后改了三版。我就当练习面向对象的思想和原则以及设计模式来做的了,所以有哪里我觉得抽象的不好或者哪里耦合比较高我都会去绞尽脑汁改很多遍。

GitHub项目地址


项目实现

ps:从没想过有一天我会结合我的实验报告来写文章…

功能结构图

代码结构图

系统的第一版确定了基本代码结构。我选择了单例模式作为主要的设计模式,因为前不久才刚刚学到,正好巩固一下,加深一下对它的理解,而且也比较符合系统需求。

图中 Managers 文件夹中的类都是单例,我让它们每个类负责自己的事情:

  • SqlManager 中封装了使用JDBC通过Java代码链接数据库并执行SQL语句的方法,如从数据库中获取车辆、获取用户、获取租借记录、写入数据、删除表等。

  • DataManager 中封装了车辆表、用户表、租借表的List列表,并提供公共方法通过 SqlManager 从数据库中获取各表,使以下三种 Manager 在初始化时可以获取各自的数据表。同时SqlManager还提供私有方法将各表存到数据库中。

  • VehicleManager 是车辆类的管理类,其中封装了添加、修改、删除等对车辆列表的操作。

  • RentManager 是租借管理类,负责提供营业额及对租借记录的管理。

  • UsersManager 是用户管理类,负责账户账号的登录、添加、删除,系统的进入等。

在第一版中, DataManager 是不存在的。用户对于数据的管理是直接通过车辆、租借、用户的Manager调用SqlManager中的方法来直接对数据库进行增删查改的。在第一版完成之后,我发现系统对数据库的操作过于频繁:查询一次车辆就要查询一次数据库,获取某个信息要查询一次数据库,添加、删除、修改等都要查询数据库。
这样不仅降低了程序的效率,还造成了代码的冗余,于是我想到使用集合框架,在程序开始时查询一次数据库,将所有如车辆、用户、租借的信息存储到集合框架中,在程序运行过程中只需要从集合框架中查询、添加、修改信息,最后在程序结束时或是需要的地方再将这些数据统一存回数据库,对数据库的操作只需要两次,同时使增删查改等操作更加简单,大大提升了程序的效率。于是便有了 DataManager

后来,我发现这种方法固然方便快捷,但这降低了程序的容错率,调取与存储数据只在程序的开始与结束进行,一旦程序异常退出,数据就会出现异常,而且程序存在很多的隐患,很多的非法输入可能会导致程序报错。

为了解决以上问题,我先是从程序的隐患下手,我发现大多数容易出错的地方都在输入上。例如需要 Int 时输入字符就会报错等。所以我加工出了 IO 类代替普通的 Scanner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package IO;

import java.util.Scanner;

/**
 * 输入输出
 */
public abstract class IO {
    private Scanner input = new Scanner(System.in);

    /**输出 */
    public void _Speak(String str) {
        System.out.println(str);
    }

    /**输入Int */
    public int _ReadInt() {
        try {
            return input.nextInt();
        } catch (Exception e) {
            _Speak("输入错误!请重新输入:");
            input.nextLine();
            return _ReadInt();
        }        
    }

    /**输入String */
    public String _ReadStr() {
        try {
            return input.next();
        } catch (Exception e) {
            _Speak("输入错误!请重新输入:");
            input.nextLine();
            return _ReadStr();
        }
    }

    /**输入Float */
    public float _ReadFloat() {
        try {
            return input.nextFloat();
        } catch (Exception e) {
            _Speak("输入错误!请重新输入:");
            input.nextLine();
            return _ReadFloat();
        }
    }
}

IO 类中对 Input 操作进行包装,使用异常处理,如果监测到异常就通过递归调用重新执行输入方法,这样既减少了事故触发的可能,也避免了在系统中到处添加异常处理的麻烦

接下来,我开始着手于数据的存储与调用。既然两次太少,那多调几次就行了呗!我用多线程不就好了嘛!

于是我将 DataManager 继承 Runnable 类,将数据的存储写在 run() 方法中调用,这样就实现了新开辟一个线程去异步存储数据,避免了数据过大存储时会卡顿,然后在关键的地方适当多次启动线程存储数据就好啦。

对于Vehicle车辆和User用户的封装这里就不过多解释了,感兴趣的可以直接去项目仓库下载源码。这里放下程序入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Managers.*;

/**
 * 程序入口
 */
public class App {
    public static void main(String[] args) throws Exception {
        // 初始化数据库
        SqlManager.Init();
        // 初始化数据管理器
        DataManager.Init();
        // 初始化车辆管理器
        VehicleManager.Init();
        // 初始化租借管理器
        RentManager.Init();
        // 初始化用户管理器
        UsersManager.Init();

        // 登录
        UsersManager.Instance.Login();
    }
}

url类关系图
(类关系图很乱其实也看不清,V2源码文件夹里有这张图片)

到第二版系统就已经非常完善了,第三版是为了适应数据库的大作业,在前两版的开发中我对数据库的造诣不是很深,都是乱开的表乱存的。在第三版中,我优化了数据库之间的关系,也使用了更高级的存储与查询方式,使系统更加完美。


尾声

通过这次车辆租赁系统的开发实践,我深刻体会到了理论知识与实际应用相结合的重要性。从最初简单的功能实现,到不断优化架构设计,再到最终完善数据库关系,整个过程让我收获颇丰。

在技术层面,我巩固了以下知识点:

  1. 单例模式在实际项目中的合理应用
  2. 集合框架作为内存缓存提升系统性能
  3. 多线程异步处理耗时操作
  4. 输入输出的安全封装
  5. 数据库设计与优化技巧

更重要的是,这次项目让我对软件开发的工程化思维有了更深的理解。从发现问题(如频繁数据库操作导致性能问题),到分析问题(找出性能瓶颈),再到解决问题(引入DataManager作为缓存层),这个过程培养了我的系统思考能力和工程实践能力。

这个项目不仅是一次课程作业,更是我编程成长路上的重要里程碑。希望未来能继续在实践中学习,在学习中进步。

—end—