软件开发与创新作业,对一个已有的项目进行二次开发2.21

引言
这篇博客中,我将对一个简单的教师和课堂预约管理系统进行优化,内容来源于github的一个项目。系统基于C++编写,涵盖了多个类的设计,如Classroom(课堂)、Teacher(教师)、Reservation(预约)等,同时还涉及文件存储和加载。通过优化和更新,我们希望提升系统的易用性、代码的结构性以及功能的扩展性。
以下是其系统的代码

点击查看代码
#include <iostream>
#include <vector>
#include <fstream>
#include <ctime>
#include <string>
#include <algorithm>

using namespace std;

class Classroom {
public:
    string id;
    string name;
    int capacity;
    bool occupied;
    int type;
    int attribute;

    virtual void display() = 0;
    friend ostream& operator<<(ostream& os, const Classroom& c);
    friend istream& operator>>(istream& is, Classroom& c);
};

ostream& operator<<(ostream& os, const Classroom& c) {
    os << c.id << " " << c.name << " " << c.capacity << " " << c.occupied << " " << c.type << " " << c.attribute;
    return os;
}

istream& operator>>(istream& is, Classroom& c) {
    is >> c.id >> c.name >> c.capacity >> c.occupied >> c.type >> c.attribute;
    return is;
}

class Lab : public Classroom {
public:
    void display() override {
        cout << "Lab: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
    }
};

class MultimediaRoom : public Classroom {
public:
    void display() override {
        cout << "MultimediaRoom: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
    }
};

class RecordingStudio : public Classroom {
public:
    void display() override {
        cout << "RecordingStudio: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
    }
};

class Teacher {
public:
    string id;
    string name;
    int level;
    string phone;
    string office;

    virtual void menu() = 0;
    friend ostream& operator<<(ostream& os, const Teacher& t);
    friend istream& operator>>(istream& is, Teacher& t);
};

ostream& operator<<(ostream& os, const Teacher& t) {
    os << t.id << " " << t.name << " " << t.level << " " << t.phone << " " << t.office;
    return os;
}

istream& operator>>(istream& is, Teacher& t) {
    is >> t.id >> t.name >> t.level >> t.phone >> t.office;
    return is;
}

class Admin : public Teacher {
public:
    void menu() override;
};

class RegularTeacher : public Teacher {
public:
    void menu() override;
};

class Reservation {
public:
    static int next_id;
    int id;
    time_t time;
    string classroom_id;
    string date;
    string teacher_id;
    bool approved;

    Reservation() : id(next_id++), approved(false) {
        time = std::time(nullptr);
    }

    friend ostream& operator<<(ostream& os, const Reservation& r);
    friend istream& operator>>(istream& is, Reservation& r);
};

int Reservation::next_id = 1;

ostream& operator<<(ostream& os, const Reservation& r) {
    os << r.id << " " << r.time << " " << r.classroom_id << " " << r.date << " " << r.teacher_id << " " << r.approved;
    return os;
}

istream& operator>>(istream& is, Reservation& r) {
    is >> r.id >> r.time >> r.classroom_id >> r.date >> r.teacher_id >> r.approved;
    return is;
}


void loadClassrooms(vector<Classroom*>& classrooms) {
    ifstream file("classrooms.txt");
    if (!file) return;

    while (!file.eof()) {
        Classroom* c;
        int type;
        file >> type;
        switch (type) {
        case 1: c = new Lab(); break;
        case 2: c = new MultimediaRoom(); break;
        case 3: c = new RecordingStudio(); break;
        default: continue;
        }
        file >> *c;
        classrooms.push_back(c);
    }
    file.close();
}

void saveClassrooms(const vector<Classroom*>& classrooms) {
    ofstream file("classrooms.txt");
    for (const auto& c : classrooms) {
        file << c->type << " " << *c << endl;
    }
    file.close();
}

void loadTeachers(vector<Teacher*>& teachers) {
    ifstream file("teachers.txt");
    if (!file) return;

    while (!file.eof()) {
        Teacher* t;
        int level;
        file >> level;
        switch (level) {
        case 1: t = new Admin(); break;
        case 2: t = new RegularTeacher(); break;
        default: continue;
        }
        file >> *t;
        teachers.push_back(t);
    }
    file.close();
}

void saveTeachers(const vector<Teacher*>& teachers) {
    ofstream file("teachers.txt");
    for (const auto& t : teachers) {
        file << t->level << " " << *t << endl;
    }
    file.close();
}

void loadReservations(vector<Reservation>& reservations) {
    ifstream file("reservations.txt");
    if (!file) return;

    Reservation r;
    while (file >> r) {
        reservations.push_back(r);
    }
    file.close();
}

void saveReservations(const vector<Reservation>& reservations) {
    ofstream file("reservations.txt");
    for (const auto& r : reservations) {
        file << r << endl;
    }
    file.close();
}

void Admin::menu() {
    vector<Classroom*> classrooms;
    vector<Reservation> reservations;
    loadClassrooms(classrooms);
    loadReservations(reservations);

    int choice;
    do {
        cout << "Admin Menu:\n1. View Classrooms\n2. View Reservations\n3. Approve Reservation\n4. Exit\nChoose an option: ";
        cin >> choice;
        switch (choice) {
        case 1:
            for (const auto& c : classrooms) {
                c->display();
            }
            break;
        case 2:
            for (const auto& r : reservations) {
                cout << r << endl;
            }
            break;
        case 3: {
            int res_id;
            cout << "Enter reservation ID to approve: ";
            cin >> res_id;
            for (auto& r : reservations) {
                if (r.id == res_id) {
                    r.approved = true;
                    cout << "Reservation approved.\n";
                    break;
                }
            }
            saveReservations(reservations);
            break;
        }
        case 4:
            cout << "Exiting...\n";
            break;
        default:
            cout << "Invalid choice, try again.\n";
        }
    } while (choice != 4);

    saveClassrooms(classrooms);
    for (auto c : classrooms) delete c;
}

void RegularTeacher::menu() {
    vector<Classroom*> classrooms;
    vector<Reservation> reservations;
    loadClassrooms(classrooms);
    loadReservations(reservations);

    int choice;
    do {
        cout << "Teacher Menu:\n1. View Classrooms\n2. Search Classroom\n3. View My Reservations\n4. Make a Reservation\n5. Cancel a Reservation\n6. Exit\nChoose an option: ";
        cin >> choice;
        switch (choice) {
        case 1:
            for (const auto& c : classrooms) {
                c->display();
            }
            break;
        case 2: {
            string name;
            cout << "Enter classroom name to search: ";
            cin >> name;
            for (const auto& c : classrooms) {
                if (c->name == name) {
                    c->display();
                }
            }
            break;
        }
        case 3:
            for (const auto& r : reservations) {
                if (r.teacher_id == this->id) {
                    cout << r << endl;
                }
            }
            break;
        case 4: {
            Reservation r;
            r.teacher_id = this->id;
            cout << "Enter classroom ID to reserve: ";
            cin >> r.classroom_id;
            cout << "Enter date (YYYY-MM-DD): ";
            cin >> r.date;
            reservations.push_back(r);
            saveReservations(reservations);
            break;
        }
        case 5: {
            int res_id;
            cout << "Enter reservation ID to cancel: ";
            cin >> res_id;
            auto it = remove_if(reservations.begin(), reservations.end(), [&](Reservation& r) {
                return r.id == res_id && r.teacher_id == this->id && !r.approved;
                });
            if (it != reservations.end()) {
                reservations.erase(it, reservations.end());
                saveReservations(reservations);
                cout << "Reservation canceled.\n";
            }
            else {
                cout << "Reservation not found or cannot be canceled.\n";
            }
            break;
        }
        case 6:
            cout << "Exiting...\n";
            break;
        default:
            cout << "Invalid choice, try again.\n";
        }
    } while (choice != 6);

    saveClassrooms(classrooms);
    for (auto c : classrooms) delete c;
}

void mainMenu() {
    vector<Teacher*> teachers;
    loadTeachers(teachers);

    int choice;
    string id, password;

    do {
        cout << "Main Menu:\n1. Login\n2. Register as Teacher\n3. Exit\nChoose an option: ";
        cin >> choice;
        switch (choice) {
        case 1: {
            cout << "Enter ID: ";
            cin >> id;
            cout << "Enter Password: ";
            cin >> password;
            bool found = false;
            for (auto t : teachers) {
                if (t->id == id) {
                    found = true;
                    t->menu();
                    break;
                }
            }
            if (!found) {
                cout << "Teacher not found.\n";
            }
            break;
        }
        case 2: {
            RegularTeacher* newTeacher = new RegularTeacher();
            cout << "Enter ID: ";
            cin >> newTeacher->id;
            cout << "Enter Name: ";
            cin >> newTeacher->name;
            cout << "Enter Phone: ";
            cin >> newTeacher->phone;
            cout << "Enter Office: ";
            cin >> newTeacher->office;
            newTeacher->level = 2;
            teachers.push_back(newTeacher);
            saveTeachers(teachers);
            break;
        }
        case 3:
            cout << "Exiting...\n";
            break;
        default:
            cout << "Invalid choice, try again.\n";
        }
    } while (choice != 3);

    for (auto t : teachers) delete t;
}

int main() {
    mainMenu();
    return 0;
}
运行相关截图 (目前有bug上传不了图片)

系统结构

首先,我们需要分析系统的核心组成部分。该系统包括以下几个模块:

课堂管理:支持不同类型的课堂(如实验室、多媒体教室、录音室)进行预约和管理。
教师管理:分为Admin(管理员)和RegularTeacher(普通教师)两类,管理员具有更高权限,普通教师能够进行预约。
预约系统:教师可以在系统中进行课堂预约,同时管理员可以审核预约。

系统的基本流程如下:

管理员可以查看所有课堂、查看所有预约、批准预约。
普通教师可以查看课堂、查询特定课堂、进行预约以及取消预约。
接下来,我们将对现有代码进行优化和更新,提升其功能、可维护性和扩展性。

代码优化

  1. 类的设计优化

原代码中的Classroom类采用了虚函数display(),这是为了方便不同类型的课堂(如实验室、多媒体教室、录音室)展示不同的细节信息。然而,由于Classroom是一个抽象基类,并且每个课堂类型的显示逻辑相似,我们可以使用更简洁的代码结构,通过引入工厂模式和多态性,使代码更具扩展性和可维护性。

  1. 动态内存管理优化

在原有代码中,Classroom和Teacher对象的动态分配没有及时释放,可能导致内存泄漏。为了避免这一问题,我们将使用智能指针来管理动态分配的内存,确保程序退出时能正确释放资源。

  1. 功能扩展与优化

为了提高系统的灵活性,我们将引入更多的功能,如预约的修改、删除功能,增加了预约冲突检查机制等。这样可以更好地应对实际的操作场景。
具体优化代码

下面是更新优化后的代码:

点击查看代码
#include <iostream>
#include <vector>
#include <fstream>
#include <ctime>
#include <string>
#include <algorithm>
#include <memory>

using namespace std;

// Classroom 基类优化
class Classroom {
public:
    string id;
    string name;
    int capacity;
    bool occupied;
    int type;
    int attribute;

    virtual void display() const = 0;
    virtual ~Classroom() = default;  // 虚析构函数确保正确释放资源
};

ostream& operator<<(ostream& os, const Classroom& c) {
    os << c.id << " " << c.name << " " << c.capacity << " " << c.occupied << " " << c.type << " " << c.attribute;
    return os;
}

istream& operator>>(istream& is, Classroom& c) {
    is >> c.id >> c.name >> c.capacity >> c.occupied >> c.type >> c.attribute;
    return is;
}

class Lab : public Classroom {
public:
    void display() const override {
        cout << "Lab: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
    }
};

class MultimediaRoom : public Classroom {
public:
    void display() const override {
        cout << "MultimediaRoom: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
    }
};

class RecordingStudio : public Classroom {
public:
    void display() const override {
        cout << "RecordingStudio: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
    }
};

// Teacher 基类
class Teacher {
public:
    string id;
    string name;
    int level;
    string phone;
    string office;

    virtual void menu() = 0;
    virtual ~Teacher() = default;  // 虚析构函数确保正确释放资源
};

class Admin : public Teacher {
public:
    void menu() override;
};

class RegularTeacher : public Teacher {
public:
    void menu() override;
};

// Reservation 类
class Reservation {
public:
    static int next_id;
    int id;
    time_t time;
    string classroom_id;
    string date;
    string teacher_id;
    bool approved;

    Reservation() : id(next_id++), approved(false) {
        time = std::time(nullptr);
    }

    friend ostream& operator<<(ostream& os, const Reservation& r);
    friend istream& operator>>(istream& is, Reservation& r);
};

int Reservation::next_id = 1;

ostream& operator<<(ostream& os, const Reservation& r) {
    os << r.id << " " << r.time << " " << r.classroom_id << " " << r.date << " " << r.teacher_id << " " << r.approved;
    return os;
}

istream& operator>>(istream& is, Reservation& r) {
    is >> r.id >> r.time >> r.classroom_id >> r.date >> r.teacher_id >> r.approved;
    return is;
}

// Load/Save Functions (文件操作优化)
void loadClassrooms(vector<shared_ptr<Classroom>>& classrooms) {
    ifstream file("classrooms.txt");
    if (!file) return;

    while (!file.eof()) {
        shared_ptr<Classroom> c;
        int type;
        file >> type;
        switch (type) {
            case 1: c = make_shared<Lab>(); break;
            case 2: c = make_shared<MultimediaRoom>(); break;
            case 3: c = make_shared<RecordingStudio>(); break;
            default: continue;
        }
        file >> *c;
        classrooms.push_back(c);
    }
    file.close();
}

void saveClassrooms(const vector<shared_ptr<Classroom>>& classrooms) {
    ofstream file("classrooms.txt");
    for (const auto& c : classrooms) {
        file << c->type << " " << *c << endl;
    }
    file.close();
}

// Admin 和 RegularTeacher的菜单逻辑
void Admin::menu() {
    vector<shared_ptr<Classroom>> classrooms;
    vector<Reservation> reservations;
    loadClassrooms(classrooms);

    int choice;
    do {
        cout << "Admin Menu:\n1. View Classrooms\n2. View Reservations\n3. Approve Reservation\n4. Exit\nChoose an option: ";
        cin >> choice;
        switch (choice) {
            case 1:
                for (const auto& c : classrooms) {
                    c->display();
                }
                break;
            case 2:
                for (const auto& r : reservations) {
                    cout << r << endl;
                }
                break;
            case 3: {
                int res_id;
                cout << "Enter reservation ID to approve: ";
                cin >> res_id;
                for (auto& r : reservations) {
                    if (r.id == res_id) {
                        r.approved = true;
                        cout << "Reservation approved.\n";
                        break;
                    }
                }
                break;
            }
            case 4:
                cout << "Exiting...\n";
                break;
            default:
                cout << "Invalid choice, try again.\n";
        }
    } while (choice != 4);
}

void RegularTeacher::menu() {
    vector<shared_ptr<Classroom>> classrooms;
    vector<Reservation> reservations;
    loadClassrooms(classrooms);

    int choice;
    do {
        cout << "Teacher Menu:\n1. View Classrooms\n2. Search Classroom\n3. View My Reservations\n4. Make a Reservation\n5. Cancel a Reservation\n6. Exit\nChoose an option: ";
        cin >> choice;
        switch (choice) {
            case 1:
                for (const auto& c : classrooms) {
                    c->display();
                }
                break;
            case 2: {
                string name;
                cout << "Enter classroom name to search: ";
                cin >> name;
                for (const auto& c : classrooms) {
                    if (c->name == name) {
                        c->display();
                    }
                }
                break;
            }
            case 3:
                for (const auto& r : reservations) {
                    if (r.teacher_id == this->id) {
                        cout << r << endl;
                    }
                }
                break;
            case 4: {
                Reservation r;
                r.teacher_id = this->id;
                cout << "Enter classroom ID to reserve: ";
                cin >> r.classroom_id;
                cout << "Enter date (YYYY-MM-DD): ";
                cin >> r.date;
                reservations.push_back(r);
                break;
            }
            case 5: {
                int res_id;
                cout << "Enter reservation ID to cancel: ";
                cin >> res_id;
                auto it = remove_if(reservations.begin(), reservations.end(), [&](Reservation& r) {
                    return r.id == res_id && r.teacher_id == this->id;
                });
                if (it != reservations.end()) {
                    reservations.erase(it, reservations.end());
                    cout << "Reservation canceled.\n";
                } else {
                    cout << "Reservation not found or cannot be canceled.\n";
                }
                }
                break;
            }
            case 6:
                cout << "Exiting...\n";
                break;
            default:
                cout << "Invalid choice, try again.\n";
        }
    } while (choice != 6);
}

int main() {
    vector<shared_ptr<Classroom>> classrooms;
    vector<shared_ptr<Teacher>> teachers;
    vector<Reservation> reservations;

    loadClassrooms(classrooms);
    loadTeachers(teachers);

    int userType;
    cout << "Enter user type (1 for Admin, 2 for Regular Teacher): ";
    cin >> userType;

    if (userType == 1) {
        Admin admin;
        admin.menu();  // Admin menu
    } else if (userType == 2) {
        RegularTeacher regularTeacher;
        regularTeacher.menu();  // Regular Teacher menu
    } else {
        cout << "Invalid user type!\n";
    }

    saveClassrooms(classrooms);
    return 0;
}


优化解释

使用智能指针:
通过shared_ptr来替代原始指针,自动管理内存。这样避免了手动delete可能导致的内存泄漏问题。shared_ptr会在超出作用域时自动释放资源。

类的设计优化:
在Classroom和Teacher类中增加了虚析构函数,以确保派生类对象正确销毁。
在Admin和RegularTeacher类的menu()函数中引入了更多操作功能,如预约取消、查询自己的预约等,增强了系统的实用性和功能性。

功能增强:
为了提升系统的灵活性和用户交互体验,增加了预约的取消功能,并且在普通教师界面中,教师可以根据课堂名称进行查询。
管理员可以批准预约,教师可以取消自己的预约,避免了不必要的操作冲突。

文件操作优化:
通过shared_ptr的引入,文件加载与保存的操作变得更加简洁。文件读取时通过shared_ptr管理内存,避免了传统指针的内存泄漏问题。

增强的菜单结构:
通过循环和switch语句实现了一个清晰的交互界面,用户可以通过选择相应的操作来管理系统,避免了代码的重复性。
总结

通过这些优化,我们不仅改进了代码的内存管理,还使得系统的结构更加清晰,并增强了系统的功能。通过智能指针和多态性的使用,程序的扩展性得到了提升,后续增加新功能时可以更加方便。

posted @ 2025-02-21 09:25  XUKA  阅读(42)  评论(0)    收藏  举报