教室预订管理系统的二次开发与架构升级
作者: hjy
课程: 软件开发与创新
项目来源: 基于室友原有项目的二次开发
开发环境: Visual Studio 2022, Windows 11
改进系统运行环境
操作系统: Windows 11
开发工具: VS Code / Visual Studio 2022
编译器: g++ 9.4.0 / MSVC v142
C++标准: C++11
数据库: SQLite
该系统主要用于学校教室资源的预订与管理,包括以下核心功能:
- 用户管理: 支持管理员和普通教师两种角色
- 教室管理: 支持实验室、多媒体教室、录课教室三种类型
- 预订管理: 教师可以申请预订教室,管理员负责审核
- 身份验证: 基于工号和密码的登录系统
- 数据持久化: 使用文本文件存储所有数据
源代码如下
点击查看代码
#pragma execution_character_set("utf-8")
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include <sstream>
#include <exception>
#include <cstdlib>
using namespace std;
class BookingException : public exception {
private:
string message;
public:
BookingException(const string& msg) : message(msg) {}
const char* what() const noexcept override { return message.c_str(); }
};
class TimeSlot {
private:
string date; // 格式: YYYY-MM-DD
int startHour; // 开始时间 (24小时制)
int duration; // 持续时间(小时)
public:
TimeSlot(const string& d = "", int start = 0, int dur = 0)
: date(d), startHour(start), duration(dur) {
}
// Getter方法
string getDate() const { return date; }
int getStartHour() const { return startHour; }
int getDuration() const { return duration; }
int getEndHour() const { return startHour + duration; }
// 检查时间冲突
bool isConflict(const TimeSlot& other) const {
if (date != other.date) return false;
int thisEnd = startHour + duration;
int otherEnd = other.startHour + other.duration;
return (startHour < otherEnd && thisEnd > other.startHour);
}
// 获取时间描述
string getTimeDescription() const {
stringstream ss;
ss << date << " "
<< setw(2) << setfill('0') << startHour << ":00-"
<< setw(2) << setfill('0') << (startHour + duration) << ":00";
return ss.str();
}
// 检查时间段是否有效
bool isValid() const {
return (startHour >= 8 && startHour <= 20 &&
duration > 0 && startHour + duration <= 22);
}
// 文件操作
string toFileString() const {
return date + "," + to_string(startHour) + "," + to_string(duration);
}
void fromFileString(const string& str) {
stringstream ss(str);
string item;
getline(ss, item, ','); date = item;
getline(ss, item, ','); startHour = stoi(item);
getline(ss, item, ','); duration = stoi(item);
}
};
// 基础教室类
class Classroom {
protected:
int roomId;
string roomName;
int capacity;
bool isOccupied;
int roomType; // 1-实验室, 2-多媒体, 3-录课教室
int attributeCode;
public:
Classroom(int id = 0, const string& name = "", int cap = 0,
bool occupied = false, int type = 0, int attr = 0)
: roomId(id), roomName(name), capacity(cap),
isOccupied(occupied), roomType(type), attributeCode(attr) {
}
virtual ~Classroom() = default;
// Getter方法
int getRoomId() const { return roomId; }
string getRoomName() const { return roomName; }
int getCapacity() const { return capacity; }
bool getIsOccupied() const { return isOccupied; }
int getRoomType() const { return roomType; }
int getAttributeCode() const { return attributeCode; }
// Setter方法
void setOccupied(bool occupied) { isOccupied = occupied; }
// 虚函数 - 获取教室类型描述
virtual string getTypeDescription() const = 0;
virtual string getAttributeDescription() const = 0;
// 运算符重载
friend ostream& operator<<(ostream& os, const Classroom& room);
friend istream& operator>>(istream& is, Classroom& room);
// 文件操作
virtual string toFileString() const {
stringstream ss;
ss << roomId << "," << roomName << "," << capacity << ","
<< isOccupied << "," << roomType << "," << attributeCode;
return ss.str();
}
virtual void fromFileString(const string& line) {
stringstream ss(line);
string item;
getline(ss, item, ','); roomId = stoi(item);
getline(ss, item, ','); roomName = item;
getline(ss, item, ','); capacity = stoi(item);
getline(ss, item, ','); isOccupied = (item == "1");
getline(ss, item, ','); roomType = stoi(item);
getline(ss, item, ','); attributeCode = stoi(item);
}
};
// 实验室类
class Laboratory : public Classroom {
public:
Laboratory(int id = 0, const string& name = "", int cap = 0,
bool occupied = false, int labType = 1)
: Classroom(id, name, cap, occupied, 1, labType) {
}
string getTypeDescription() const override { return "实验室"; }
string getAttributeDescription() const override {
switch (attributeCode) {
case 1: return "化学实验室";
case 2: return "物理实验室";
case 3: return "生物实验室";
case 4: return "计算机实验室";
case 5: return "水环境实验室";
default: return "未知类型实验室";
}
}
};
// 多媒体教室类
class MultimediaRoom : public Classroom {
public:
MultimediaRoom(int id = 0, const string& name = "", int cap = 0,
bool occupied = false, int aircon = 1)
: Classroom(id, name, cap, occupied, 2, aircon) {
}
string getTypeDescription() const override { return "多媒体教室"; }
string getAttributeDescription() const override {
return attributeCode == 1 ? "无空调" : "有空调";
}
};
// 录课教室类
class RecordingRoom : public Classroom {
public:
RecordingRoom(int id = 0, const string& name = "", int cap = 0,
bool occupied = false, int cameras = 0)
: Classroom(id, name, cap, occupied, 3, cameras) {
}
string getTypeDescription() const override { return "录课教室"; }
string getAttributeDescription() const override {
return "摄像头数量: " + to_string(attributeCode);
}
};
// 基础教师类
class Teacher {
protected:
string employeeId;
string name;
int permission; // 1-管理员, 2-普通教师
string phone;
string office;
string password; // 新增密码字段
public:
Teacher(const string& id = "", const string& n = "", int perm = 2,
const string& ph = "", const string& off = "", const string& pwd = "123456")
: employeeId(id), name(n), permission(perm), phone(ph), office(off), password(pwd) {
}
virtual ~Teacher() = default;
// Getter方法
string getEmployeeId() const { return employeeId; }
string getName() const { return name; }
int getPermission() const { return permission; }
string getPassword() const { return password; } // 新增
string getPhone() const { return phone; } // 新增
string getOffice() const { return office; } // 新增
// Setter方法
void setPassword(const string& pwd) { password = pwd; } // 新增
// 虚函数
virtual string getPermissionDescription() const = 0;
// 验证密码
bool verifyPassword(const string& pwd) const {
return password == pwd;
}
// 运算符重载
friend ostream& operator<<(ostream& os, const Teacher& teacher);
friend istream& operator>>(istream& is, Teacher& teacher);
// 文件操作
virtual string toFileString() const {
return employeeId + "," + name + "," + to_string(permission) + "," +
phone + "," + office + "," + password;
}
virtual void fromFileString(const string& line) {
stringstream ss(line);
string item;
getline(ss, item, ','); employeeId = item;
getline(ss, item, ','); name = item;
getline(ss, item, ','); permission = stoi(item);
getline(ss, item, ','); phone = item;
getline(ss, item, ','); office = item;
getline(ss, item, ','); password = item;
if (password.empty()) password = "123456"; // 默认密码
}
};
// 管理员类
class Administrator : public Teacher {
public:
Administrator(const string& id = "", const string& n = "",
const string& ph = "", const string& off = "", const string& pwd = "123456")
: Teacher(id, n, 1, ph, off, pwd) {
}
string getPermissionDescription() const override { return "系统管理员"; }
};
// 普通教师类
class RegularTeacher : public Teacher {
public:
RegularTeacher(const string& id = "", const string& n = "",
const string& ph = "", const string& off = "", const string& pwd = "123456")
: Teacher(id, n, 2, ph, off, pwd) {
}
string getPermissionDescription() const override { return "普通教师"; }
};
// 预订记录类
class BookingRecord {
private:
static int nextBookingId;
int bookingId;
string teacherId;
int roomId;
TimeSlot timeSlot;
string submitTime;
int status; // 0-待审核, 1-已通过, 2-已拒绝, 3-已取消, 4-已完成
public:
BookingRecord(const string& tId = "", int rId = 0,
const TimeSlot& ts = TimeSlot())
: bookingId(nextBookingId++), teacherId(tId), roomId(rId),
timeSlot(ts), status(0) {
// 获取当前时间
time_t now = time(0);
struct tm timeinfo;
#ifdef _WIN32
localtime_s(&timeinfo, &now);
#else
timeinfo = *localtime(&now);
#endif
char timeStr[100];
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &timeinfo);
submitTime = timeStr;
}
// Getter方法
int getBookingId() const { return bookingId; }
string getTeacherId() const { return teacherId; }
int getRoomId() const { return roomId; }
const TimeSlot& getTimeSlot() const { return timeSlot; }
int getStatus() const { return status; }
// Setter方法
void setStatus(int s) {
if (s < 0 || s > 4) {
throw BookingException("无效的状态值");
}
status = s;
}
string getStatusDescription() const {
switch (status) {
case 0: return "待审核";
case 1: return "已通过";
case 2: return "已拒绝";
case 3: return "已取消";
case 4: return "已完成";
default: return "未知状态";
}
}
// 检查预订是否已过期
bool isExpired() const {
// 获取当前时间
time_t now = time(0);
struct tm timeinfo;
#ifdef _WIN32
localtime_s(&timeinfo, &now);
#else
timeinfo = *localtime(&now);
#endif
// 构建当前日期字符串
char dateStr[11];
strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", &timeinfo);
string currentDate = dateStr;
// 比较日期
if (timeSlot.getDate() < currentDate) {
return true;
}
return false;
}
// 文件操作
string toFileString() const {
return to_string(bookingId) + "," + teacherId + "," + to_string(roomId) + ","
+ timeSlot.toFileString() + "," + submitTime + "," + to_string(status);
}
void fromFileString(const string& line) {
stringstream ss(line);
string item;
getline(ss, item, ','); bookingId = stoi(item);
getline(ss, item, ','); teacherId = item;
getline(ss, item, ','); roomId = stoi(item);
// 读取TimeSlot信息
string timeSlotStr;
for (int i = 0; i < 3; i++) {
getline(ss, item, ',');
timeSlotStr += item;
if (i < 2) timeSlotStr += ",";
}
timeSlot.fromFileString(timeSlotStr);
getline(ss, item, ','); submitTime = item;
getline(ss, item, ','); status = stoi(item);
// 更新下一个预订ID
if (bookingId >= nextBookingId) {
nextBookingId = bookingId + 1;
}
}
friend ostream& operator<<(ostream& os, const BookingRecord& record);
// 静态成员函数
static void setNextBookingId(int id) { nextBookingId = id; }
static int getNextBookingId() { return nextBookingId; }
};
// 静态成员初始化
int BookingRecord::nextBookingId = 1;
// 教室预订管理系统类
class BookingSystem {
private:
vector<Classroom*> classrooms;
vector<Teacher*> teachers;
vector<BookingRecord> bookings;
Teacher* currentUser;
// 文件路径
const string CLASSROOM_FILE = "classrooms.txt";
const string TEACHER_FILE = "teachers.txt";
const string BOOKING_FILE = "bookings.txt";
public:
BookingSystem() : currentUser(nullptr) {
initializeSystem();
}
~BookingSystem() {
saveToFiles();
// 清理动态分配的内存
for (auto& classroom : classrooms) delete classroom;
for (auto& teacher : teachers) delete teacher;
}
// 系统初始化
void initializeSystem() {
// 创建默认管理员账户(带默认密码)
teachers.push_back(new Administrator("10001", "Vincenzo老师", "13812345678", "A101", "admin123"));
teachers.push_back(new Administrator("10002", "Tina老师", "13823456789", "A102", "admin123"));
teachers.push_back(new Administrator("10003", "Lauv老师", "13834567890", "A103", "admin123"));
// 创建普通教师账户(带默认密码)
teachers.push_back(new RegularTeacher("20001", "Sandy老师", "13845678901", "B201", "teacher123"));
teachers.push_back(new RegularTeacher("20002", "Alexandra老师", "13856789012", "B202", "teacher123"));
teachers.push_back(new RegularTeacher("20003", "Vivienne老师", "13867890123", "B203", "teacher123"));
// 创建示例教室
classrooms.push_back(new Laboratory(101, "化学实验室1", 30, false, 1));
classrooms.push_back(new MultimediaRoom(201, "多媒体教室1", 50, false, 2));
classrooms.push_back(new RecordingRoom(301, "录课教室1", 40, false, 2));
loadFromFiles();
checkExpiredBookings();
}
// 显示欢迎信息
void showWelcomeInfo() {
std::cout << "========== 系统初始化完成 ==========" << endl;
std::cout << "首次登录提示: " << endl;
std::cout << " 管理员请使用工号登录后修改默认密码" << endl;
std::cout << " 教师可以注册新账号或联系管理员" << endl;
std::cout << " 建议定期备份系统数据" << endl;
std::cout << "===================================" << endl;
}
// 文件操作
void loadFromFiles();
void saveToFiles();
// 用户管理
bool login(const string& employeeId, const string& password); // 修改
void registerTeacher();
// 教室管理
void browseClassrooms();
void searchClassroom();
void addClassroom();
// 预订管理
void browseBookings();
void makeBooking();
void cancelBooking();
void approveBooking();
void checkExpiredBookings();
// 用户密码管理
void changePassword();
// 界面管理
void showMainMenu();
void showAdminMenu();
void showTeacherMenu();
void run();
};
// 实现运算符重载和其他成员函数
// Classroom类的运算符重载
ostream& operator<<(ostream& os, const Classroom& room) {
os << "教室号: " << room.roomId
<< ", 名称: " << room.roomName
<< ", 容量: " << room.capacity
<< ", 类型: " << room.getTypeDescription()
<< ", 属性: " << room.getAttributeDescription()
<< ", 状态: " << (room.isOccupied ? "占用" : "空闲");
return os;
}
istream& operator>>(istream& is, Classroom& room) {
std::cout << "请输入教室号: ";
is >> room.roomId;
std::cout << "请输入教室名称: ";
is >> room.roomName;
std::cout << "请输入容量: ";
is >> room.capacity;
// 根据教室类型显示不同的属性选项
if (room.roomType == 1) { // 实验室
std::cout << "请选择实验室类型:" << endl;
std::cout << "1 - 化学实验室" << endl;
std::cout << "2 - 物理实验室" << endl;
std::cout << "3 - 生物实验室" << endl;
std::cout << "4 - 计算机实验室" << endl;
std::cout << "5 - 水环境实验室" << endl;
std::cout << "请输入对应数字: ";
}
else if (room.roomType == 2) { // 多媒体教室
std::cout << "请选择空调配置:" << endl;
std::cout << "1 - 无空调" << endl;
std::cout << "2 - 有空调" << endl;
std::cout << "请输入对应数字: ";
}
else if (room.roomType == 3) { // 录课教室
std::cout << "请输入摄像头数量: ";
}
is >> room.attributeCode;
room.isOccupied = false;
return is;
}
// Teacher类的运算符重载
ostream& operator<<(ostream& os, const Teacher& teacher) {
os << "工号: " << teacher.employeeId
<< ", 姓名: " << teacher.name
<< ", 权限: " << teacher.getPermissionDescription();
return os;
}
istream& operator>>(istream& is, Teacher& teacher) {
std::cout << "请输入工号: ";
is >> teacher.employeeId;
std::cout << "请输入姓名: ";
is >> teacher.name;
std::cout << "请输入电话: ";
is >> teacher.phone;
std::cout << "请输入办公室: ";
is >> teacher.office;
std::cout << "请设置密码: ";
is >> teacher.password;
return is;
}
// BookingRecord类的运算符重载
ostream& operator<<(ostream& os, const BookingRecord& record) {
os << "预订号: " << record.bookingId
<< ", 教师ID: " << record.teacherId
<< ", 教室号: " << record.roomId
<< ", 预订时间: " << record.timeSlot.getTimeDescription()
<< ", 提交时间: " << record.submitTime
<< ", 状态: " << record.getStatusDescription();
if (record.isExpired() && record.getStatus() == 1) {
os << " (已过期)";
}
return os;
}
// BookingSystem类的成员函数实现
void BookingSystem::loadFromFiles() {
try {
// 加载教室信息
ifstream classroomFile(CLASSROOM_FILE);
if (classroomFile.is_open()) {
string line;
while (getline(classroomFile, line) && !line.empty()) {
stringstream ss(line);
string item;
vector<string> tokens;
while (getline(ss, item, ',')) {
tokens.push_back(item);
}
if (tokens.size() >= 6) {
int roomType = stoi(tokens[4]);
Classroom* room = nullptr;
switch (roomType) {
case 1: room = new Laboratory(); break;
case 2: room = new MultimediaRoom(); break;
case 3: room = new RecordingRoom(); break;
default: continue;
}
if (room) {
room->fromFileString(line);
classrooms.push_back(room);
}
}
}
classroomFile.close();
}
// 加载教师信息
ifstream teacherFile(TEACHER_FILE);
if (teacherFile.is_open()) {
string line;
while (getline(teacherFile, line) && !line.empty()) {
stringstream ss(line);
string item;
vector<string> tokens;
while (getline(ss, item, ',')) {
tokens.push_back(item);
}
if (tokens.size() >= 5) {
int permission = stoi(tokens[2]);
Teacher* teacher = nullptr;
if (permission == 1) {
teacher = new Administrator();
}
else {
teacher = new RegularTeacher();
}
if (teacher) {
teacher->fromFileString(line);
teachers.push_back(teacher);
}
}
}
teacherFile.close();
}
// 加载预订记录
ifstream bookingFile(BOOKING_FILE);
if (bookingFile.is_open()) {
string line;
while (getline(bookingFile, line) && !line.empty()) {
BookingRecord record;
record.fromFileString(line);
bookings.push_back(record);
}
bookingFile.close();
}
}
catch (const exception& e) {
std::cout << "加载文件时出错: " << e.what() << endl;
}
}
void BookingSystem::saveToFiles() {
try {
// 保存教室信息
ofstream classroomFile(CLASSROOM_FILE);
if (classroomFile.is_open()) {
for (const auto& classroom : classrooms) {
classroomFile << classroom->toFileString() << endl;
}
classroomFile.close();
}
// 保存教师信息
ofstream teacherFile(TEACHER_FILE);
if (teacherFile.is_open()) {
for (const auto& teacher : teachers) {
teacherFile << teacher->toFileString() << endl;
}
teacherFile.close();
}
// 保存预订记录
ofstream bookingFile(BOOKING_FILE);
if (bookingFile.is_open()) {
for (const auto& booking : bookings) {
bookingFile << booking.toFileString() << endl;
}
bookingFile.close();
}
}
catch (const exception& e) {
std::cout << "保存文件时出错: " << e.what() << endl;
}
}
bool BookingSystem::login(const string& employeeId, const string& password) {
for (auto& teacher : teachers) {
if (teacher->getEmployeeId() == employeeId) {
if (teacher->verifyPassword(password)) {
currentUser = teacher;
return true;
}
else {
std::cout << "密码错误!" << endl;
return false;
}
}
}
std::cout << "工号不存在!" << endl;
return false;
}
void BookingSystem::registerTeacher() {
try {
std::cout << "\n=== 教师注册 ===" << endl;
RegularTeacher* newTeacher = new RegularTeacher();
cin >> *newTeacher;
// 检查工号是否已存在
for (const auto& teacher : teachers) {
if (teacher->getEmployeeId() == newTeacher->getEmployeeId()) {
std::cout << "该工号已存在!" << endl;
delete newTeacher;
return;
}
}
teachers.push_back(newTeacher);
std::cout << "注册成功!" << endl;
}
catch (const exception& e) {
std::cout << "注册失败: " << e.what() << endl;
}
}
void BookingSystem::browseClassrooms() {
std::cout << "\n=== 教室列表 ===" << endl;
if (classrooms.empty()) {
std::cout << "暂无教室信息。" << endl;
return;
}
for (const auto& classroom : classrooms) {
std::cout << *classroom << endl;
}
}
void BookingSystem::searchClassroom() {
std::cout << "\n=== 搜索教室 ===" << endl;
std::cout << "请选择搜索方式:" << endl;
std::cout << "1. 按名称搜索" << endl;
std::cout << "2. 按容量搜索" << endl;
std::cout << "3. 按类型搜索" << endl;
std::cout << "请选择: ";
int choice;
cin >> choice;
bool found = false;
switch (choice) {
case 1: {
std::cout << "请输入教室名称: ";
string name;
cin >> name;
for (const auto& classroom : classrooms) {
if (classroom->getRoomName().find(name) != string::npos) {
std::cout << *classroom << endl;
found = true;
}
}
break;
}
case 2: {
std::cout << "请输入最小容量: ";
int minCapacity;
cin >> minCapacity;
for (const auto& classroom : classrooms) {
if (classroom->getCapacity() >= minCapacity) {
std::cout << *classroom << endl;
found = true;
}
}
break;
}
case 3: {
std::cout << "请选择教室类型:" << endl;
std::cout << "1. 实验室" << endl;
std::cout << "2. 多媒体教室" << endl;
std::cout << "3. 录课教室" << endl;
std::cout << "请选择: ";
int typeChoice;
cin >> typeChoice;
for (const auto& classroom : classrooms) {
if (classroom->getRoomType() == typeChoice) {
std::cout << *classroom << endl;
found = true;
}
}
break;
}
default:
std::cout << "无效选择!" << endl;
return;
}
if (!found) {
std::cout << "未找到匹配的教室。" << endl;
}
}
void BookingSystem::addClassroom() {
try {
std::cout << "\n=== 添加教室 ===" << endl;
std::cout << "请选择教室类型:" << endl;
std::cout << "1. 实验室" << endl;
std::cout << "2. 多媒体教室" << endl;
std::cout << "3. 录课教室" << endl;
std::cout << "请选择: ";
int choice;
cin >> choice;
Classroom* newRoom = nullptr;
switch (choice) {
case 1: newRoom = new Laboratory(); break;
case 2: newRoom = new MultimediaRoom(); break;
case 3: newRoom = new RecordingRoom(); break;
default:
std::cout << "无效选择!" << endl;
return;
}
cin >> *newRoom;
// 检查教室号是否已存在
for (const auto& classroom : classrooms) {
if (classroom->getRoomId() == newRoom->getRoomId()) {
std::cout << "该教室号已存在!" << endl;
delete newRoom;
return;
}
}
classrooms.push_back(newRoom);
std::cout << "教室添加成功!" << endl;
}
catch (const exception& e) {
std::cout << "添加教室失败: " << e.what() << endl;
}
}
void BookingSystem::browseBookings() {
std::cout << "\n=== 预订记录 ===" << endl;
if (bookings.empty()) {
std::cout << "暂无预订记录。" << endl;
return;
}
// 过滤选项
std::cout << "请选择查看方式:" << endl;
std::cout << "1. 查看所有预订" << endl;
std::cout << "2. 按日期查看" << endl;
std::cout << "3. 按状态查看" << endl;
std::cout << "请选择: ";
int choice;
cin >> choice;
vector<BookingRecord> filteredBookings;
switch (choice) {
case 1:
filteredBookings = bookings;
break;
case 2: {
std::cout << "请输入日期 (YYYY-MM-DD): ";
string date;
cin >> date;
for (const auto& booking : bookings) {
if (booking.getTimeSlot().getDate() == date) {
filteredBookings.push_back(booking);
}
}
break;
}
case 3: {
std::cout << "请选择状态:" << endl;
std::cout << "0. 待审核" << endl;
std::cout << "1. 已通过" << endl;
std::cout << "2. 已拒绝" << endl;
std::cout << "3. 已取消" << endl;
std::cout << "4. 已完成" << endl;
std::cout << "请选择: ";
int statusChoice;
cin >> statusChoice;
for (const auto& booking : bookings) {
if (booking.getStatus() == statusChoice) {
filteredBookings.push_back(booking);
}
}
break;
}
default:
std::cout << "无效选择!" << endl;
return;
}
// 如果是普通教师,只显示自己的预订记录
if (currentUser->getPermission() == 2) {
vector<BookingRecord> teacherBookings;
for (const auto& booking : filteredBookings) {
if (booking.getTeacherId() == currentUser->getEmployeeId()) {
teacherBookings.push_back(booking);
}
}
filteredBookings = teacherBookings;
}
if (filteredBookings.empty()) {
std::cout << "未找到符合条件的预订记录。" << endl;
return;
}
for (const auto& booking : filteredBookings) {
std::cout << booking << endl;
}
}
void BookingSystem::makeBooking() {
try {
std::cout << "\n=== 预订教室 ===" << endl;
// 显示可用教室
std::cout << "可用教室列表:" << endl;
for (const auto& classroom : classrooms) {
if (!classroom->getIsOccupied()) {
std::cout << *classroom << endl;
}
}
std::cout << "请输入要预订的教室号: ";
int roomId;
cin >> roomId;
// 检查教室是否存在
bool roomExists = false;
for (const auto& classroom : classrooms) {
if (classroom->getRoomId() == roomId) {
roomExists = true;
break;
}
}
if (!roomExists) {
std::cout << "教室不存在!" << endl;
return;
}
// 输入预订日期和时间
std::cout << "请输入预订日期 (YYYY-MM-DD): ";
string date;
cin >> date;
std::cout << "请输入开始时间 (8-20之间的整数小时): ";
int startHour;
cin >> startHour;
std::cout << "请输入持续时间 (小时): ";
int duration;
cin >> duration;
// 创建时间段
TimeSlot timeSlot(date, startHour, duration);
// 验证时间段是否有效
if (!timeSlot.isValid()) {
std::cout << "无效的时间段!可用时间为8:00-22:00。" << endl;
return;
}
// 检查时间冲突
for (const auto& booking : bookings) {
if (booking.getRoomId() == roomId &&
booking.getStatus() == 1 &&
booking.getTimeSlot().isConflict(timeSlot)) {
std::cout << "该时间段已被预订!" << endl;
return;
}
}
// 创建预订记录
BookingRecord newBooking(currentUser->getEmployeeId(), roomId, timeSlot);
bookings.push_back(newBooking);
std::cout << "预订申请提交成功,等待管理员审核。" << endl;
}
catch (const exception& e) {
std::cout << "预订失败: " << e.what() << endl;
}
}
void BookingSystem::cancelBooking() {
try {
std::cout << "\n=== 取消预订 ===" << endl;
std::cout << "您的预订记录:" << endl;
vector<BookingRecord*> userBookings;
for (auto& booking : bookings) {
if (booking.getTeacherId() == currentUser->getEmployeeId() &&
booking.getStatus() != 3 && booking.getStatus() != 4) {
std::cout << booking << endl;
userBookings.push_back(&booking);
}
}
if (userBookings.empty()) {
std::cout << "您没有可取消的预订记录。" << endl;
return;
}
std::cout << "请输入要取消的预订号: ";
int bookingId;
cin >> bookingId;
for (auto& booking : bookings) {
if (booking.getBookingId() == bookingId &&
booking.getTeacherId() == currentUser->getEmployeeId()) {
booking.setStatus(3); // 设置为已取消
std::cout << "预订取消成功!" << endl;
return;
}
}
std::cout << "未找到指定的预订记录或无权限取消。" << endl;
}
catch (const BookingException& e) {
std::cout << "取消预订失败: " << e.what() << endl;
}
}
void BookingSystem::approveBooking() {
try {
std::cout << "\n=== 审核预订 ===" << endl;
// 显示待审核的预订记录
std::cout << "待审核预订记录:" << endl;
vector<BookingRecord*> pendingBookings;
for (auto& booking : bookings) {
if (booking.getStatus() == 0) {
std::cout << booking << endl;
pendingBookings.push_back(&booking);
}
}
if (pendingBookings.empty()) {
std::cout << "没有待审核的预订记录。" << endl;
return;
}
std::cout << "请输入要审核的预订号: ";
int bookingId;
cin >> bookingId;
std::cout << "请选择审核结果:" << endl;
std::cout << "1. 通过" << endl;
std::cout << "2. 拒绝" << endl;
std::cout << "请选择: ";
int choice;
cin >> choice;
int newStatus = (choice == 1) ? 1 : 2;
for (auto& booking : bookings) {
if (booking.getBookingId() == bookingId && booking.getStatus() == 0) {
// 如果选择通过,先检查是否有时间冲突
if (newStatus == 1) {
for (const auto& existingBooking : bookings) {
if (existingBooking.getRoomId() == booking.getRoomId() &&
existingBooking.getStatus() == 1 &&
existingBooking.getTimeSlot().isConflict(booking.getTimeSlot())) {
std::cout << "无法通过: 该时间段已被其他预订占用!" << endl;
return;
}
}
}
booking.setStatus(newStatus);
// 如果通过,更新教室占用状态
if (newStatus == 1) {
for (auto& classroom : classrooms) {
if (classroom->getRoomId() == booking.getRoomId()) {
classroom->setOccupied(true);
break;
}
}
}
std::cout << "审核完成!" << endl;
return;
}
}
std::cout << "未找到指定的预订记录。" << endl;
}
catch (const BookingException& e) {
std::cout << "审核失败: " << e.what() << endl;
}
}
void BookingSystem::checkExpiredBookings() {
for (auto& booking : bookings) {
if (booking.getStatus() == 1 && booking.isExpired()) {
booking.setStatus(4); // 设置为已完成
// 更新教室状态
for (auto& classroom : classrooms) {
if (classroom->getRoomId() == booking.getRoomId()) {
classroom->setOccupied(false);
break;
}
}
}
}
}
void BookingSystem::changePassword() {
std::cout << "\n=== 修改密码 ===" << endl;
// 验证当前密码
std::cout << "请输入当前密码: ";
string currentPassword;
cin >> currentPassword;
if (!currentUser->verifyPassword(currentPassword)) {
std::cout << "当前密码错误!" << endl;
return;
}
// 输入新密码
std::cout << "请输入新密码: ";
string newPassword;
cin >> newPassword;
std::cout << "请再次输入新密码: ";
string confirmPassword;
cin >> confirmPassword;
// 验证两次输入是否一致
if (newPassword != confirmPassword) {
std::cout << "两次输入的密码不一致!" << endl;
return;
}
// 验证密码长度
if (newPassword.length() < 6) {
std::cout << "密码长度不能少于6位!" << endl;
return;
}
// 更新密码
currentUser->setPassword(newPassword);
std::cout << "密码修改成功!" << endl;
saveToFiles(); // 立即保存到文件
}
void BookingSystem::showMainMenu() {
std::cout << "\n========== 教室预订管理系统 ==========" << endl;
std::cout << "1. 登录" << endl;
std::cout << "2. 教师注册" << endl;
std::cout << "3. 退出" << endl;
std::cout << "请选择: ";
}
void BookingSystem::showAdminMenu() {
std::cout << "\n========== 管理员界面 ==========" << endl;
std::cout << "1. 浏览教室" << endl;
std::cout << "2. 添加教室" << endl;
std::cout << "3. 浏览预订记录" << endl;
std::cout << "4. 审核预订记录" << endl;
std::cout << "5. 修改密码" << endl;
std::cout << "6. 退出登录" << endl;
std::cout << "请选择: ";
}
void BookingSystem::showTeacherMenu() {
std::cout << "\n========== 教师界面 ==========" << endl;
std::cout << "1. 浏览教室" << endl;
std::cout << "2. 搜索教室" << endl;
std::cout << "3. 浏览预订记录" << endl;
std::cout << "4. 预订教室" << endl;
std::cout << "5. 取消预订" << endl;
std::cout << "6. 修改密码" << endl;
std::cout << "7. 退出登录" << endl;
std::cout << "请选择: ";
}
void BookingSystem::run() {
int choice;
start_flag:
while (true) {
// 每次循环检查过期预订
checkExpiredBookings();
showMainMenu();
cin >> choice;
if (cin.fail()) {
cin.clear();
cin.ignore(100, '\n');
std::cout << "\x1b[1;31m\x1b[4m请输入有效的数字!\x1b[0m" << std::endl;
goto start_flag;
}
switch (choice) {
case 1: {
std::cout << "请输入工号: ";
string employeeId;
cin >> employeeId;
std::cout << "请输入密码: ";
string password;
cin >> password;
if (login(employeeId, password)) {
std::cout << "登录成功!欢迎 " << currentUser->getName() << endl;
if (currentUser->getPermission() == 1) {
// 管理员菜单
int adminChoice;
while (true) {
showAdminMenu();
cin >> adminChoice;
switch (adminChoice) {
case 1:
browseClassrooms();
break;
case 2:
addClassroom();
break;
case 3:
browseBookings();
break;
case 4:
approveBooking();
break;
case 5:
changePassword();
break;
case 6:
currentUser = nullptr;
std::cout << "已退出登录。" << endl;
goto main_menu;
default:
std::cout << "无效选择,请重新输入。" << endl;
}
}
}
else {
// 普通教师菜单
int teacherChoice;
while (true) {
showTeacherMenu();
cin >> teacherChoice;
switch (teacherChoice) {
case 1:
browseClassrooms();
break;
case 2:
searchClassroom();
break;
case 3:
browseBookings();
break;
case 4:
makeBooking();
break;
case 5:
cancelBooking();
break;
case 6:
changePassword();
break;
case 7:
currentUser = nullptr;
std::cout << "已退出登录。" << endl;
goto main_menu;
default:
std::cout << "无效选择,请重新输入。" << endl;
}
}
}
}
else {
std::cout << "登录失败!" << endl;
}
break;
}
case 2:
registerTeacher();
break;
case 3:
std::cout << "感谢使用教室预订管理系统,再见!" << endl;
return;
default:
std::cout << "无效选择,请重新输入。" << endl;
}
main_menu:;
}
}
int main() {
system("chcp 65001");
system("cls");
try {
BookingSystem BookSystem;
BookSystem.showWelcomeInfo();
std::cout << "\n默认管理员账号: 10001, 10002, 10003" << endl;
std::cout << "默认管理员密码: admin123" << endl;
std::cout << "默认教师账号: 20001, 20002, 20003" << endl;
std::cout << "默认教师密码: teacher123" << endl;
std::cout << "===================================" << endl;
BookSystem.run();
}
catch (const exception& e) {
std::cout << "系统错误: " << e.what() << endl;
return 1;
}
return 0;
}
原项目采用**单文件架构**,所有代码集中在一个CPP文件中,于是我想到了,将代码拆分更利于修改升级维护查找问题。
要查找单独修改一个代码很麻烦,于是将代码分块

- 数据持久化升级: 从文本文件迁移到SQLite数据库
- 架构重构: 实现分层架构设计(数据层、业务逻辑层、表示层)
- 代码模块化: 将单文件代码拆分为多模块结构
- 异常处理增强: 完善错误处理机制
- 性能优化: 改进数据查询效率
- 可维护性提升: 增强代码的可读性和可扩展性

`#pragma execution_character_set("utf-8")
改进后


原代码片段 (文件I/O部分):
void BookingSystem::saveToFiles() {
// 保存教室信息
ofstream classroomFile(CLASSROOM_FILE);
if (classroomFile.is_open()) {
for (const auto& classroom : classrooms) {
classroomFile << classroom->toFileString() << endl;
}
classroomFile.close();
}
// 保存教师信息
ofstream teacherFile(TEACHER_FILE);
// ... 类似操作
// 保存预订记录
ofstream bookingFile(BOOKING_FILE);
// ... 类似操作
}
教室类继承示例:
// 基类定义
class Classroom {
protected:
int roomId;
string roomName;
int capacity;
bool isOccupied;
int roomType;
int attributeCode;
public:
virtual string getTypeDescription() const = 0; // 纯虚函数
virtual string getAttributeDescription() const = 0;
// ...
};
// 派生类实现
class Laboratory : public Classroom {
public:
string getTypeDescription() const override { return "实验室"; }
string getAttributeDescription() const override {
switch (attributeCode) {
case 1: return "化学实验室";
case 2: return "物理实验室";
// ...
}
}
};
bool TimeSlot::isConflict(const TimeSlot& other) const {
if (date != other.date) return false;
int thisEnd = startHour + duration;
int otherEnd = other.startHour + other.duration;
return (startHour < otherEnd && thisEnd > other.startHour);
}
原系统核心代码片段:
// 原系统: 文件读写
void BookingSystem::saveToFiles() {
ofstream bookingFile(BOOKING_FILE);
if (bookingFile.is_open()) {
for (const auto& booking : bookings) {
bookingFile << booking.toFileString() << endl;
}
bookingFile.close();
}
}
// 原系统: 时间冲突检测(遍历)
for (const auto& booking : bookings) {
if (booking.getRoomId() == roomId &&
booking.getStatus() == 1 &&
booking.getTimeSlot().isConflict(timeSlot)) {
cout << "该时间段已被预订!" << endl;
return;
}
}
改进系统核心代码片段:
// 改进系统: 数据库操作
int Database::insertBooking(const BookingRecord& booking) {
const char* sql = R"(
INSERT INTO bookings (teacher_id, room_id, booking_date,
start_hour, duration, status)
VALUES (?, ?, ?, ?, ?, ?);
)";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
// 预编译语句防止SQL注入
sqlite3_bind_text(stmt, 1, booking.getTeacherId().c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, booking.getRoomId());
// ...
return sqlite3_last_insert_rowid(db);
}
// 改进系统: 时间冲突检测(SQL查询+索引)
bool Database::checkTimeConflict(int roomId, const TimeSlot& timeSlot) {
const char* sql = R"(
SELECT COUNT(*) FROM bookings
WHERE room_id = ? AND booking_date = ? AND status = 1
AND NOT (start_hour + duration <= ? OR start_hour >= ?);
)";
// 利用索引 idx_booking_room 和 idx_booking_date
// 时间复杂度从 O(n) 降低到 O(log n)
}
原实现存在的问题
数据存储层面的问题
文本文件的局限性
重构实现:
// 创建数据库表结构
CREATE TABLE bookings (
booking_id INTEGER PRIMARY KEY AUTOINCREMENT,
teacher_id TEXT NOT NULL,
room_id INTEGER NOT NULL,
booking_date TEXT NOT NULL,
start_hour INTEGER NOT NULL,
duration INTEGER NOT NULL,
status INTEGER DEFAULT 0,
FOREIGN KEY (teacher_id) REFERENCES teachers(employee_id),
FOREIGN KEY (room_id) REFERENCES classrooms(room_id)
);
// 创建索引优化查询
CREATE INDEX idx_booking_date ON bookings(booking_date);
CREATE INDEX idx_booking_room ON bookings(room_id);
CREATE INDEX idx_booking_status ON bookings(status);
架构层面的问题
BookingSystem 类承担了过多功能:
class BookingSystem {
private:
vector classrooms; // 数据存储
vector teachers;
vector bookings;
Teacher* currentUser; // 会话管理
public:
void loadFromFiles(); // 文件I/O
void saveToFiles();
bool login(...); // 身份验证
void browseClassrooms(); // UI交互
void makeBooking(); // 业务逻辑
void showMainMenu(); // 界面显示
void run(); // 主循环控制
};
重构实现:
// 数据访问层 - 只负责数据库操作
class Database {
public:
bool insertBooking(const BookingRecord& booking);
BookingRecord getBookingById(int id);
bool updateBookingStatus(int id, BookingStatus status);
bool checkTimeConflict(int roomId, const TimeSlot& timeSlot);
};
// 业务逻辑层 - 负责业务规则
class BookingManager {
private:
Database* database;
public:
bool approveBooking(int bookingId) {
// 业务规则: 审核时检查冲突,更新教室状态
database->beginTransaction();
try {
if (database->checkTimeConflict(...)) {
throw BookingException("时间冲突");
}
database->updateBookingStatus(id, APPROVED);
database->updateClassroomOccupied(roomId, true);
database->commitTransaction();
} catch (...) {
database->rollbackTransaction();
}
}
};
// 表示层 - 负责UI交互
class BookingSystemUI {
public:
void adminMenu(); // 管理员菜单
void teacherMenu(); // 教师菜单
void makeBooking(); // 预订界面
};
一个类同时负责了:
- 数据存储 (Data Layer)
- 业务逻辑 (Business Logic Layer)
- 用户界面 (Presentation Layer)
- 文件I/O (Persistence Layer)
改进:引入实体类(Entities)作为数据在各层之间传递的载体,同时使用单例模式或依赖注入来管理这些模块。
struct Classroom { int id; string name; bool isAvailable; }; struct Teacher { int id; string name; string password; }; struct BookingRecord { int id; int teacherId; int roomId; string timeSlot; };
`class Database {
public:
// 专门负责持久化
void loadData(vector
void saveData(const vector
// 原子操作
bool updateBookingStatus(int id, int status);
bool checkTimeConflict(int roomId, const string& slot);
}; class BookingManager {
private:
Database& db; // 引用注入,方便单元测试
Teacher* currentUser = nullptr;
public:
BookingManager(Database& database) : db(database) {}
bool login(int id, const string& pwd) {
// 逻辑:验证身份并设置 currentUser
return true;
}
bool requestBooking(int roomId, const string& slot) {
if (!currentUser) return false;
if (db.checkTimeConflict(roomId, slot)) return false;
// 执行预订...
return true;
}
};`
代码质量问题
错误处理不完善
void BookingSystem::loadFromFiles() {
try {
ifstream classroomFile(CLASSROOM_FILE);
if (classroomFile.is_open()) {
// 读取数据...
}
}
catch (const exception& e) {
cout << "加载文件时出错: " << e.what() << endl;
// 仅打印错误,没有恢复机制
}
}
问题:
- 文件打开失败时没有创建默认文件
- 数据格式错误时可能导致程序崩溃
- 缺乏日志记录机制
本次二次开发采用以下改进策略:
| 原系统 | 改进后系统 |
|---|---|
| 文本文件存储 | SQLite数据库 |
| 单文件架构 | 多模块分层架构 |
| 全量内存加载 | 按需查询 |
| 简单异常处理 | 完善的错误处理 |
技术选型
数据库选择: SQLite
架构选择: 三层架构
数据库设计
1. 教室表 (classrooms)
CREATE TABLE classrooms (
room_id INTEGER PRIMARY KEY,
room_name TEXT NOT NULL,
capacity INTEGER NOT NULL CHECK(capacity > 0),
is_occupied INTEGER DEFAULT 0 CHECK(is_occupied IN (0,1)),
room_type INTEGER NOT NULL CHECK(room_type IN (1,2,3)),
attribute_code INTEGER NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
-- 索引优化
CREATE INDEX idx_room_type ON classrooms(room_type);
CREATE INDEX idx_capacity ON classrooms(capacity);
2. 教师表 (teachers)
CREATE TABLE teachers (
employee_id TEXT PRIMARY KEY,
name TEXT NOT NULL,
permission INTEGER NOT NULL CHECK(permission IN (1,2)),
phone TEXT,
office TEXT,
password TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
-- 索引优化
CREATE INDEX idx_permission ON teachers(permission);
3. 预订记录表 (bookings)
CREATE TABLE bookings (
booking_id INTEGER PRIMARY KEY AUTOINCREMENT,
teacher_id TEXT NOT NULL,
room_id INTEGER NOT NULL,
booking_date TEXT NOT NULL,
start_hour INTEGER NOT NULL CHECK(start_hour >= 8 AND start_hour <= 20),
duration INTEGER NOT NULL CHECK(duration > 0),
submit_time TEXT DEFAULT CURRENT_TIMESTAMP,
status INTEGER DEFAULT 0 CHECK(status IN (0,1,2,3,4)),
FOREIGN KEY (teacher_id) REFERENCES teachers(employee_id),
FOREIGN KEY (room_id) REFERENCES classrooms(room_id)
);
-- 索引优化
CREATE INDEX idx_booking_teacher ON bookings(teacher_id);
CREATE INDEX idx_booking_room ON bookings(room_id);
CREATE INDEX idx_booking_date ON bookings(booking_date);
CREATE INDEX idx_booking_status ON bookings(status);
状态码说明:
- 0: 待审核
- 1: 已通过
- 2: 已拒绝
- 3: 已取消
- 4: 已完成
改进后的项目/
├── include/ # 头文件目录
│ ├── database.h # 数据库操作层
│ ├── models.h # 数据模型定义
│ ├── business.h # 业务逻辑层
│ └── ui.h # 用户界面层
├── src/ # 源文件目录
│ ├── database.cpp
│ ├── models.cpp
│ ├── business.cpp
│ ├── ui.cpp
│ └── main.cpp # 主程序入口
├── classroom_booking.db # SQLite数据库文件
└── README.md # 项目说明
类设计
**数据访问层 **:
class Database {
private:
sqlite3* db;
string dbPath;
public:
// 基础操作
bool connect();
void disconnect();
bool execute(const string& sql);
// 教室CRUD
bool insertClassroom(const Classroom& room);
bool updateClassroom(const Classroom& room);
bool deleteClassroom(int roomId);
vector getAllClassrooms();
Classroom* getClassroomById(int id);
// 教师CRUD
bool insertTeacher(const Teacher& teacher);
Teacher* getTeacherById(const string& id);
// 预订CRUD
bool insertBooking(const BookingRecord& booking);
bool updateBookingStatus(int bookingId, int status);
vector getBookingsByTeacher(const string& teacherId);
vector getBookingsByDate(const string& date);
// 查询优化
bool checkTimeConflict(int roomId, const TimeSlot& timeSlot);
};
业务逻辑层 (BLL):
class BookingManager {
private:
Database* database;
Teacher* currentUser;
public:
// 身份验证
bool login(const string& employeeId, const string& password);
void logout();
// 业务规则
bool canMakeBooking(const BookingRecord& booking);
bool validateTimeSlot(const TimeSlot& timeSlot);
bool checkRoomAvailability(int roomId, const TimeSlot& timeSlot);
// 高级功能
vector searchClassrooms(const SearchCriteria& criteria);
bool approveBooking(int bookingId);
bool rejectBooking(int bookingId);
void checkAndUpdateExpiredBookings();
};
数据库初始化
bool Database::connect() {
int rc = sqlite3_open(dbPath.c_str(), &db);
if (rc != SQLITE_OK) {
cerr << "无法打开数据库: " << sqlite3_errmsg(db) << endl;
return false;
}
// 创建表结构
const char* createClassroomsTable = R"(
CREATE TABLE IF NOT EXISTS classrooms (
room_id INTEGER PRIMARY KEY,
room_name TEXT NOT NULL,
capacity INTEGER NOT NULL CHECK(capacity > 0),
is_occupied INTEGER DEFAULT 0 CHECK(is_occupied IN (0,1)),
room_type INTEGER NOT NULL CHECK(room_type IN (1,2,3)),
attribute_code INTEGER NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
)";
if (!execute(createClassroomsTable)) {
return false;
}
// 创建索引
execute("CREATE INDEX IF NOT EXISTS idx_room_type ON classrooms(room_type);");
execute("CREATE INDEX IF NOT EXISTS idx_capacity ON classrooms(capacity);");
// ... 创建其他表和索引
return true;
}
插入操作(使用预编译语句防止SQL注入)
bool Database::insertClassroom(const Classroom& room) {
const char* sql = R"(
INSERT INTO classrooms (room_id, room_name, capacity,
is_occupied, room_type, attribute_code)
VALUES (?, ?, ?, ?, ?, ?);
)";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
cerr << "SQL准备失败: " << sqlite3_errmsg(db) << endl;
return false;
}
// 绑定参数
sqlite3_bind_int(stmt, 1, room.getRoomId());
sqlite3_bind_text(stmt, 2, room.getRoomName().c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 3, room.getCapacity());
sqlite3_bind_int(stmt, 4, room.getIsOccupied() ? 1 : 0);
sqlite3_bind_int(stmt, 5, room.getRoomType());
sqlite3_bind_int(stmt, 6, room.getAttributeCode());
// 执行
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) {
cerr << "插入失败: " << sqlite3_errmsg(db) << endl;
return false;
}
return true;
}
查询操作(时间冲突检测)
bool Database::checkTimeConflict(int roomId, const TimeSlot& timeSlot) {
const char* sql = R"(
SELECT COUNT(*) FROM bookings
WHERE room_id = ?
AND booking_date = ?
AND status = 1
AND NOT (start_hour + duration <= ? OR start_hour >= ?);
)";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
sqlite3_bind_int(stmt, 1, roomId);
sqlite3_bind_text(stmt, 2, timeSlot.getDate().c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 3, timeSlot.getStartHour());
sqlite3_bind_int(stmt, 4, timeSlot.getEndHour());
bool hasConflict = false;
if (sqlite3_step(stmt) == SQLITE_ROW) {
int count = sqlite3_column_int(stmt, 0);
hasConflict = (count > 0);
}
sqlite3_finalize(stmt);
return hasConflict;
}
事务处理实现
bool BookingManager::approveBooking(int bookingId) {
// 开启事务
database->execute("BEGIN TRANSACTION;");
try {
// 1. 获取预订信息
BookingRecord booking = database->getBookingById(bookingId);
if (booking.getStatus() != 0) {
throw BookingException("该预订已被处理");
}
// 2. 检查时间冲突
if (database->checkTimeConflict(booking.getRoomId(),
booking.getTimeSlot())) {
throw BookingException("该时间段已被占用");
}
// 3. 更新预订状态
if (!database->updateBookingStatus(bookingId, 1)) {
throw BookingException("更新预订状态失败");
}
// 4. 更新教室占用状态
if (!database->updateClassroomOccupied(booking.getRoomId(), true)) {
throw BookingException("更新教室状态失败");
}
// 提交事务
database->execute("COMMIT;");
return true;
} catch (const BookingException& e) {
// 回滚事务
database->execute("ROLLBACK;");
cerr << "审核失败: " << e.what() << endl;
return false;
}
}
高级搜索功能
vector BookingManager::searchClassrooms(
const SearchCriteria& criteria) {
string sql = "SELECT * FROM classrooms WHERE 1=1";
vector conditions;
// 动态构建查询条件
if (criteria.hasRoomType()) {
conditions.push_back(" AND room_type = " +
to_string(criteria.getRoomType()));
}
if (criteria.hasMinCapacity()) {
conditions.push_back(" AND capacity >= " +
to_string(criteria.getMinCapacity()));
}
if (!criteria.getRoomName().empty()) {
conditions.push_back(" AND room_name LIKE '%" +
criteria.getRoomName() + "%'");
}
// 组合查询
for (const auto& condition : conditions) {
sql += condition;
}
// 排序
sql += " ORDER BY " + criteria.getSortField() + " " +
criteria.getSortOrder();
return database->executeQuery(sql);
}
测试场景: 查询特定日期的所有预订
原系统实现:
// 遍历vector,时间复杂度 O(n)
for (const auto& booking : bookings) {
if (booking.getTimeSlot().getDate() == date) {
filteredBookings.push_back(booking);
}
}
改进后系统:
// 使用索引查询,时间复杂度 O(log n)
SELECT * FROM bookings
WHERE booking_date = '2026-03-15'
-- 利用 idx_booking_date 索引
原系统:
// 职责混乱
class BookingSystem {
void browseBookings() {
// UI代码
cout << "=== 预订记录 ===" << endl;
// 数据操作
vector filteredBookings;
for (const auto& booking : bookings) {
if (booking.getTimeSlot().getDate() == date) {
filteredBookings.push_back(booking);
}
}
// 业务逻辑
if (currentUser->getPermission() == 2) {
// 过滤逻辑...
}
// UI输出
for (const auto& booking : filteredBookings) {
cout << booking << endl;
}
}
};
改进后:
// 职责清晰,分层明确
// 数据访问层
class Database {
vector getBookingsByDate(const string& date) {
// 纯粹的数据库查询
}
};
// 业务逻辑层
class BookingManager {
vector filterBookingsForUser(
const vector& bookings,
const Teacher* user) {
// 纯粹的业务规则
}
};
// 表示层
class BookingUI {
void displayBookings(const vector& bookings) {
// 纯粹的UI渲染
}
};


总结:主要成果与技术收获
成果:成功将原本 “万能类” BookingSystem 拆分为表示层(UI)、业务逻辑层(Service)、数据持久层(Database)和领域对象(Entity)。程序跑起来和以前一样稳,但代码读起来爽多了。
技术收获:
好的代码应该像乐高积木,每一块都能拆下来单独换。
理解了职责单一原则 :现在每一个类只管一件事,改 Bug 也不用满世界搜变量了。
一开始的想法:想一口气把所有问题都改掉,结果改着改着就乱了,不知道哪个功能还能用,哪个已经坏了。
先把数据库基本功能写好,测试能用
再加事务,测试能用
再优化性能,测试能用
每改一步就用Git提交一次,出问题还能回退。
数据库真的比txt文件靠谱 - 虽然用起来麻烦点,但用起来安全性实用性更好
代码分文件分层很重要 - 看着清楚,改起来方便
测试 - 自己觉得没问题,测一下才发现一堆bug

浙公网安备 33010602011771号