机房预约系统需求:学校存在几个机房,但是由于大家使用的时间基本都是一样的,所以需要设计一个预约系统来解决这一问题。
身份简介
在这个系统中会有三类人用到这个机房。
- 学生:申请使用机房。
- 教师:审核学生的预约申请。
- 管理员:给学生、教师创建账号。
机房简介
机房总共有3
间:
1
号机房:最大容量20
人。2
号机房:最多容量50
人。3
号机房:最多容量100
人。
申请简介
- 每周由管理员清空一次申请订单。所以管理员需要给它提供一个清空的能力。
- 学生可以预约未来一周内的机房使用,预约日期为周一至周五,预约时需要选择预约时段(上午、下午)。
- 老师来审核预约,依据实际情况审核预约通过或者不通过。
系统具体需求
主界面展示
- 首先进入系统登录界面,可选登录身份有:
- 学生
- 老师
- 管理员
- 退出
各子菜单展示
- 每一个身份都需要进行验证之后,才能进入子菜单:
- 学生需要输入:学号、姓名、登录密码。
- 老师需要输入:职工号、姓名、登录密码。
- 管理员需要输入:管理员姓名、登录密码。
学生
- 学生的具体功能:
- 申请预约。
- 查看自己的预约状态。
- 查看全部预约信息以及预约状态。
- 取消自身的预约,预约成功或审核中的预约均可取消。
- 注销登录。
老师
- 教师具体功能:
- 查看全部预约信息以及预约状态。
- 对学生的预约进行审核。
- 注销登录。
管理员
- 管理员具体功能:
- 添加学生或教师的账号,需要检测学生编号或教师职工号是否重复。
- 可以选择查看学生或教师的全部信息。
- 查看所有机房的信息。
- 清空所有机房的信息。
- 清空所有预约记录。
- 退出登录。
代码逻辑
主逻辑
身分类的共性
在这个预约系统中总共有三种身份:学生、老师和管理员。他们都有一些共性,比如像,他们都有用户名和密码。因此可以将其抽象出来作为一个身份的基类identity
。除了具有用户名和密码这两个特性之外,每个类都还有一个子菜单界面,并且每个类下面的子菜单是不一样的。
// Base Class of Identity
class Identity{
public:
virtual void openMenu() = 0;
string m_name; // user name
string m_pwd; // user passward
}
所以提供了一个openMenu()
的纯虚函数,子类必须要去重写这个纯虚函数。如果对c++
中虚函数的概念还不清楚的话,可以参考我的另外一篇文章:C/C++笔试面试基础与进阶(十二)虚函数详解。
管理员模块
学生和老师的账号信息都是有管理员来添加或者删除的。所以我们首先实现管理员模块。
提供一个全局函数来实现子菜单的内容。
void managerMenu(Identity* &manager){
while(true){
// Call the administrator submenu
manager->openMenu();
// Casting base class pointer to derived class pointer
Manager* man = (Manager*)manager;
int select = 0;
if(cin >> select){
if(select == 1){
cout << "add account" << endl;
man->addPerson();
}else if(select == 2){
cout << "view account" << endl;
man->showPerson();
}else if(select == 3){
cout << "view computer room information" << endl;
man->showComputer();
}else if(select == 4){
cout << "clear reservation record" << endl;
man->cleanFile();
}else{
// Logout
// Destroys the specified heap object
delete manager; //
cout << "Logout successfully!" << endl;
return;
}
}else{
std::cout << "managerMenu Invalid input!" << std::endl;
cin.clear();
}
}
}
除此之外还需要提供一个去重的操作,当添加新账号时,如果是重复的学生编号,或者是重复的教师职工编号,提示有误!要去除重复的账号,首先要先将学生和教师的账号信息获取到程序中,方可检测。在manager.h
中,添加两个容器,用于存放学生和教师的信息。添加一个新的成员函数void initVector()
初始化容器。
管理员还需要查看机房的相关信息,在案例需求中,机房一共有三个,其中1
号机房容量20
台机器,2
号50
台机器,3
号100
台机器。我们可以将信息录入到computerRomm.txt
中:
显示预约,显示预约记录时,需要从文件中获取到所有记录,用来显示,创建预约的类来管理记录以及更新在头文件以及源文件下分别创建orderFile.h
和orderFile.cpp
文件。
管理员类
管理员类主要功能是对学生和老师账户进行管理,查看机房信息以及清空预约记录。管理员类中主要功能有:1. 显示管理员操作的菜单界面;2. 添加账号;3. 查看账号;4. 查看机房信息;5. 清空预约记录。
在头文件以及源文件下创建manager.h
和manager.cpp
文件。
manager.h
class Manager :public Identity{
public:
// Default constructor
Manager();
// Parameterized constructor, parameter: manager ID, name and password
Manager(string name, string pwd);
// Menu interface
virtual void openMenu();
// add Person Information
void addPerson();
// show Person Information
void showPerson();
// show computer information
void showComputer();
// clear the order information
void cleanFile();
}
到目前为止我们实现了身份的基类,身份基类的派生类声明和派生类的实现。
学生模块
学生模块的主要外层功能逻辑,思路与管理员模块类似:
void studentMenu(Identity* &student){
while(true){
student->openMenu();
Student* stu = (Student*)student;
int select = 0;
if(cin >> select){
if(select == 1){
// Apply for a reservation
stu->applyOrder();
}else if(select == 2){
// View your own reservation
stu->showMyOrder();
}else if(select == 3){
// View all reservation
stu->showAllOrder();
}else if(select == 4){
// Cancel reservation
stu->cancelOrder();
}else{
delete student;
cout << "quit successful " << endl;
}
}else{
cout << "Invalid input!" << endl;
cin.clear();
}
}
}
学生类
有了抽象基类之后,我们就可以来实现派生类:学生类。学生类主要功能是可以通过类中成员函数,实现预约实验室操作。学生类中主要功能有:1. 显示学生操作的菜单界面;2. 申请预约;3. 查看自身预约;4. 查看所有预约;5. 取消预约。
所以在写这个类的时候,首先第一步,我们需要创建出来这个类。我们需要声明student.h
和student.cpp
。分别在头文件夹和源文件夹下创建。
student.h
class Student:public Identity{
public:
// Default constructor
Student();
// Parameterized constructor, parameter: student ID, name and password
Student(int id, string name, string pwd);
// Menu interface
virtual void openMenu();
// Apply for a reservation
void applyOrder();
// View your own reservation
void showMyOrder();
// View all reservation
void showAllOrder();
// Cancel reservation
void cancelOrder();
// Student ID
int m_Id;
}
- 在有参构造函数中,需要读取机房的一些信息;
- 在
openMenu
函数中提供用于学生选择的菜单界面;在applyOrder
中需要实现学生的申请预约操作,需要接收学生的申请日期、申请时间段、以及申请的机房信息; - 然后将申请的信息写入文件中;
- 在
showMyOrder
函数中,需要对预约信息存储的文件进行读取,然后循环判断学号等于自己学号的时候,输出显示预约信息; - 在
showAllOrder
函数中,需要对预约文件夹下存储的信息进行读取并循环输出。
老师模块
在老师模块中,我们需要对老师的主要功能实现逻辑上的连接:
void teacherMenu(Identity* &teacher) {
while (true) {
// Call the teacher submenu
teacher->openMenu();
// Casting base class pointer to derived class pointer
Teacher* tea = (Teacher*)teacher;
int select = 0;
cin >> select;
if (select == 1) {
// View all reservation
tea->showALLOrder();
}
else if (select == 2) {
// Review reservation
tea->validOrder();
}
else {
// Logout
delete teacher;
cout << "Logout successful!" << endl;
return;
}
}
}
老师类
在教师类中,有:1. 老师操作的菜单界面;2. 查看所有预约的功能;3. 审核预约。在头文件以及源文件下我们需要去创建teacher.h
和teacher.cpp
这两个文件。
teacher.h
class Teacher:Identity{
public:
// Default constructor
Teacher();
// Parameterized constructor, parameter: student ID, name and password
Teacher(int empID, string name, string pwd);
// Menu interface
virtual void openMenu();
// View all reservation
void showALLOrder();
// check the order
void validOrder();
int m_EmpId; // teacher ID
}
- 在
Teacher
的有参构造函数中实现教工信息的ID
,name
以及pwd
等参数的初始化; - 在
openMenu
中输出给教师的选择菜单界面,主要是两个,输出所有预约和审核预约; - 在
showALLOrder
函数中,对存取预约信息的文件进行读取然后输出显示; - 在
validOrder
中需要对预约记录一个一个处理。
登录模块
在进入系统之后,我们有三种身份可以选择。不管用户选择哪个身份,他都需要进行文件的操作。我们可以将所有的文件名定义到一个全局的文件中。
登录函数需要根据用户的选择,进入不同的身份登录。在main.cpp
文件中添加全局函数void LoginIn(string fileName, int type)
。参数fileName
表示操作的文件名,type
表示登录的身份(1
代表学生;2
代表老师;3
代表管理员)。
void LoginIn(string fileName, int type){
// base class pointer pointing to derived object
Identity* person = NULL;
// read file
ifstream ifs;
ifs.open(fileName.c_str(), ios::in);
// determine if the file exists
if(!ifs.is_open()){
cout << "file is not exist" << endl;
ifs.close();
return;
}
// Ready For Input Information
int id = 0;
string name;
string pwd;
if(type == 1){ // student login
cout << "Please Input Your Student ID" << endl;
// if(){
// }else{
// }
cin >> id;
}else if(type == 2){ // teacher login
cout << "Please Input Your Teacher ID" << endl;
cin >> id;
}
cout << "Please Input Your User Name" << endl;
cin >> name;
cout << "Please Input Your PassWard" << endl;
cin >> pwd;
if(type == 1){ // student login
// ID, name and passward from file
int fID;
string fName;
string fPwd;
while(ifs >> fID && ifs >> fName && ifs >> fPwd){
if(fID == id && fName == name && fPwd == pwd){
cout << "Student login verification success!" << endl;
person = new Student(id, name, pwd);
// enter student submenu page
studentMenu(person);
return;
}
}
}else if(type == 2){ // teacher login
// ID, name and passward from file
int fID;
string fName;
string fPwd;
while(ifs >> fID && ifs >> fName && ifs >> fPwd){
if(fID == id && fName == name && fPwd == pwd){
cout << "Teacher login verification success!" << endl;
person = new Teacher(id, name, pwd);
// enter Teacher submenu page
teacherMenu(person);
return;
}
}
}else if(type == 3){ // administer login
// name and passward from file
string fName;
string fPwd;
while(ifs >> fName && ifs >> fPwd){
if(fName == name && fPwd == pwd){
cout << "admin login verification success!" << endl;
person = new Manager(name, pwd);
// enter Admin submenu page
managerMenu(person);
return;
}
}
}
cout << "Failed to verify login" << endl;
return;
}