逆向软件设计—网上购书结账系统

一、作业要求
找一个已有的项目(同学、高年级同学、网络下载),阅读分析,找出软件尚存的缺陷, 改进其软件做二次开发,并将这个过程整理成一份博客。
二、原项目介绍
本次课程设计我逆向开发的软件是一个使用c++编写的网上购书结账系统,原作者是22软工2班的熊知宇学长,学号2252721。
运行环境:Windows 11 ,Visual Studio 2022

该网上购书结账系统已经包含了必要的注册、登录、购书、查看信息等功能,操作简单,运行效率高,界面设计简洁明了,代码量较少,逻辑清晰,容易定位问题,适合快速原型开发,不需要复杂的设计和架构。
(一)源代码如下:

点击查看代码
#include<iostream>
#include<cmath>
#include<string>
#include<conio.h>
#include<fstream>
#include<vector>

using namespace std;

//基类buyer
class buyer {
protected:
    string name;
    string address;
    int id;
    double pay;
    string usersname;
    string password;
public:
    buyer();//默认某个值
    buyer(string n, string a, int i, double p, string u, string pa);//构造函数
    string GetName();
    string GetAddress();
    string GetUsersname();
    string GetPassword();
    int GetId();
    double GetPay();
    virtual void display() = 0;//显示对象信息
    virtual void setpay(double p = 0) = 0;//计算消费
};
buyer::buyer() {
    name = "";
    address = "";
    id = 0;
    pay = 0;
}
buyer::buyer(string n, string a, int i, double p, string u, string pa) {
    name = n;
    address = a;
    id = i;
    pay = p;
    usersname = u;
    password = pa;
}
string buyer::GetAddress() {
    return address;
}
string buyer::GetName() {
    return name;
}
string buyer::GetUsersname() { return usersname; }
string buyer::GetPassword() { return password; }
int buyer::GetId() {
    return id;
}
double buyer::GetPay() {
    return pay;
}

//普通人类folk
class folk :public buyer {
public:
    folk(string n, string a, int i, double p, string u, string pa) :buyer(n, a, i, p, u, pa) {}
    void display();
    void setpay(double p);
};
void folk::display() {
    cout << "购书人姓名:" << name << endl;
    cout << "购书人编号:" << id << endl;
    cout << "购书人类型:普通用户" << endl;
    cout << "购书人地址:" << address << endl;
    cout << "消费金额:" << pay << endl;
}
void folk::setpay(double p) {
    pay += p;
}

//会员类vip
class vip :public buyer {
private:
    short vip_grade;
public:
    vip(string n, string a, int i, double p, short g, string u, string pa);
    void display();
    void setpay(double p);
    short GetGrade();
};
vip::vip(string n, string a, int i, double p, short g, string u, string pa) :buyer(n, a, i, p, u, pa) {
    vip_grade = g;
}
void vip::display() {
    cout << "购书人姓名:" << name << endl;
    cout << "购书人编号:" << id << endl;
    cout << "购书人为" << vip_grade << "级会员" << endl;
    cout << "购书人地址:" << address << endl;
    cout << "消费金额:" << pay << endl;
}
void vip::setpay(double p) {
    if (vip_grade == 1) {
        pay += p * 0.95;
    }
    else if (vip_grade == 2) {
        pay += p * 0.9;
    }
    else if (vip_grade == 3) {
        pay += p * 0.85;
    }
    else if (vip_grade == 4) {
        pay += p * 0.8;
    }
    else if (vip_grade == 5) {
        pay += p * 0.7;
    }
    else {
        cout << "会员级别有误!" << endl;
    }
}
short vip::GetGrade() { return vip_grade; }

//贵宾类svip
class svip :public buyer {
private:
    double discount;
public:
    svip(string n, string a, int i, double p, double d, string u, string pa);
    void display();
    void setpay(double p);
    double GetDiscount();
};
svip::svip(string n, string a, int i, double p, double d, string u, string pa) :buyer(n, a, i, p, u, pa) {
    discount = d;
}
void svip::display() {
    cout << "购书人姓名:" << name << endl;
    cout << "购书人编号:" << id << endl;
    cout << "购书人为贵宾,折扣率为:" << discount << endl;
    cout << "购书人地址:" << address << endl;
    cout << "消费金额:" << pay << endl;
}
void svip::setpay(double p) {
    pay += p * discount;
}
double svip::GetDiscount() { return discount; }

class book {
public:
    string num, bname;
    short price;

    book(string num, string bname, short price) {
        this->num = num;
        this->bname = bname;
        this->price = price;
    }

};

class ListNode;
void welcome();
void insert_info(ListNode* head);
void search_info(ListNode* head);
void print_info(ListNode* head);
void buy_book(ListNode* head);
void booklist();
void loadin(ListNode* head);
void addpay(ListNode* head, short p);
void save_info2(vector<book>& books);
void load_info2();
void newbook();
void save_info1(ListNode* head);
void load_info(ListNode* head);
void CheckUsersname(ListNode* head);
void Checkpassword(ListNode* head);

// 定义链表节点的类
class ListNode {
public:
    buyer* data; // 指向buyer类对象的指针
    ListNode* next; // 指向下一个节点的指针
    ListNode() {
        data = nullptr;
        next = nullptr;
    }
};

class BookNode {
public:
    book* data;
    BookNode* next;
    BookNode() {
        data = nullptr;
        next = nullptr;
    }
};

string na, users, pass;
int flag;


int main() {
    // 创建链表的头节点
    ListNode* head = new ListNode();
    BookNode* hhead = new BookNode();
    load_info(head);

    while (true) {
        welcome();
        cout << "请选择功能>> ";
        short _n;
        cin >> _n;
        switch (_n) {
        case 1:
            insert_info(head);
            break;
        case 2:
            search_info(head);
            break;
        case 3:
            print_info(head);
            break;
        case 4:
            buy_book(head);
            break;

        case 5:
            cout << "欢迎下次光临!" << endl;
            exit(0);
        default:
            cout << "输入有误,请重新输入!" << endl;
            break;
        }
    }

    // 释放动态分配的内存
    ListNode* p = head;
    while (p != nullptr) {
        ListNode* tmp = p;
        p = p->next;
        delete tmp->data;
        delete tmp;
    }

    return 0;
}

void welcome() {
    cout << "**\t\t" << "网上购书结账系统" << "\t**" << endl;
    cout << "**\t\t" << "1.注册信息" << "\t\t**" << endl;
    cout << "**\t\t" << "2.查询个人" << "\t\t**" << endl;
    cout << "**\t\t" << "3.信息列表" << "\t\t**" << endl;
    cout << "**\t\t" << "4.购买图书" << "\t\t**" << endl;
    cout << "**\t\t" << "5.退出系统" << "\t\t**" << endl;
}

void booklist() {
    cout << "图书信息:" << endl;
    cout << "1.书号:7-301-07854-1\t\t书名:《秒速五厘米》\t\t定价:20元" << endl;
    cout << "2.书号:7-300-01562-4\t\t书名:《你的名字》\t\t定价:35元" << endl;
    cout << "3.书号:7-372-01532-5\t\t书名:《言叶之庭》\t\t定价:15元" << endl;
    cout << "4.书号:7-356-02512-3\t\t书名:《天气之子》\t\t定价:25元" << endl;
    cout << "5.书号:7-345-09655-7\t\t书名:《铃芽之旅》\t\t定价:25元" << endl;
}

void insert_info(ListNode* head) {
    string name, address;
    int id;
    double pay;
    short vip_grade;
    double discount;
    int type;

    cout << "请输入购书人姓名:";
    cin >> name;

    cout << "请输入购书人地址:";
    cin >> address;

    cout << "请输入购书人编号:";
    cin >> id;

    cout << "请创建您的用户名:";
    CheckUsersname(head);

    cout << "请创建您的密码:";
    Checkpassword(head);

    pay = 0;

    cout << "请选择购书人类型(1代表普通用户,2代表会员,3代表贵宾):";
    cin >> type;

    if (type == 1) {
        buyer* b = new folk(name, address, id, pay, users, pass);
        ListNode* node = new ListNode();
        node->data = b;

        // 将节点插入到链表中
        node->next = head->next;
        head->next = node;
        cout << "注册成功!" << endl;
    }
    else if (type == 2) {
        cout << "请输入会员级别(1~5):";
        cin >> vip_grade;

        buyer* b = new vip(name, address, id, pay, vip_grade, users, pass);
        ListNode* node = new ListNode();
        node->data = b;

        // 将节点插入到链表中
        node->next = head->next;
        head->next = node;
        cout << "注册成功!" << endl;
    }
    else if (type == 3) {
        cout << "请输入折扣率(0~1):";
        cin >> discount;

        buyer* b = new svip(name, address, id, pay, discount, users, pass);
        ListNode* node = new ListNode();
        node->data = b;

        // 将节点插入到链表中
        node->next = head->next;
        head->next = node;
        cout << "注册成功!" << endl;
    }
    else {
        cout << "购书人类型输入有误,请重新输入!" << endl;
    }
    save_info1(head);
    system("pause");
    system("cls");
}

void search_info(ListNode* head) {
    cout << "请输入要查询的购书人的用户名:";
    string uname;
    cin >> uname;

    ListNode* p = head->next;
    while (p != nullptr) {
        if (p->data->GetUsersname() == uname) {
            p->data->display();
            system("pause");
            system("cls");
            return;

        }
        else {
            p = p->next;
        }
    }

    cout << "没有找到该购书人信息!" << endl;
    system("pause");
    system("cls");
}

void print_info(ListNode* head) {
    // 遍历链表,输出所有buyer类对象的信息
    ListNode* p = head->next;
    while (p != nullptr) {
        p->data->display();
        cout << "---------------------" << endl;
        p = p->next;
    }
    system("pause");
    system("cls");
}

void buy_book(ListNode* head) {
    loadin(head);
    if (flag == 1) {
        booklist();
        cout << "请选择你想要购买的图书序号:" << endl;
        short ch;
        cin >> ch;
        switch (ch) {
        case 1:
            addpay(head, 20);
            break;
        case 2:
            addpay(head, 35);
            break;
        case 3:
            addpay(head, 15);
        case 4:
            addpay(head, 25);
        case 5:
            addpay(head, 25);
        }
        save_info1(head);
        system("pause");
        system("cls");
    }
    else
        system("pause");
    system("cls");
}

void addpay(ListNode* head, short p) {
    ListNode* pmove = head->next;
    while (pmove != nullptr) {
        if (pmove->data->GetUsersname() == na) {
            pmove->data->setpay(p);
            cout << "您需要支付的费用是:" << pmove->data->GetPay() << "元" << endl;
            cout << "按任意键自动扣款" << endl;
            _getch();
            cout << "自动扣款成功!" << endl;
            break;
        }
        else {
            pmove = pmove->next;
            if (pmove->next == nullptr) {
                cout << "ERROR" << endl;
            }
        }

    }
}

void loadin(ListNode* head) {
    cout << "请先输入用户名:" << endl;
    string uname, pasw;
    cin >> uname;
    ListNode* pmove = head->next;
    while (pmove != nullptr) {
        if (pmove->data->GetUsersname() == uname) {
            cout << "请输入密码" << endl;
            cin >> pasw;
            if (pmove->data->GetPassword() != pasw) {
                cout << "密码错误!" << endl;
                flag = 0;
                break;
            }
            na = pmove->data->GetUsersname();
            flag = 1;
            break;
        }
        else {
            pmove = pmove->next;
            if (pmove->next == nullptr) {
                cout << "未查询到信息!" << endl;
                flag = 0;
                return;
            }
        }

    }

}

void save_info1(ListNode* head) {
    string filename = R"(C:\Users\熊知宇\Desktop\程序期末大作业\buyer.txt)";
    ofstream fout(filename, ios::trunc);

    if (!fout.is_open()) {
        cout << "打开文件失败!" << endl;
        return;
    }

    // 遍历链表,将buyer类对象的信息写入文件
    ListNode* p = head->next;
    while (p != nullptr) {
        fout << p->data->GetName() << " ";
        fout << p->data->GetAddress() << " ";
        fout << p->data->GetId() << " ";
        fout << p->data->GetPay() << " ";
        if (dynamic_cast<vip*>(p->data)) {
            fout << "2" << " ";
            fout << dynamic_cast<vip*>(p->data)->GetGrade() << " ";
            fout << p->data->GetUsersname() << " ";
            fout << p->data->GetPassword() << endl;
        }
        else if (dynamic_cast<svip*>(p->data)) {
            fout << "3" << " ";
            fout << dynamic_cast<svip*>(p->data)->GetDiscount() << " ";
            fout << p->data->GetUsersname() << " ";
            fout << p->data->GetPassword() << endl;
        }
        else {
            fout << "0" << " ";
            fout << "1" << " ";
            fout << p->data->GetUsersname() << " ";
            fout << p->data->GetPassword() << endl;
        }
        p = p->next;
    }

    fout.close();
    cout << "信息存储成功!" << endl;
}

void load_info(ListNode* head) {
    string filename = R"(C:\Users\熊知宇\Desktop\程序期末大作业\buyer.txt)";
    ifstream fin;
    fin.open(filename, ios::in);
    if (!fin.is_open()) {
        cout << "打开文件失败!" << endl;
        return;
    }

    string name, address, usersname, password;
    int id;
    double pay;
    short vip_grade;
    double discount;
    int type;

    while (fin >> name >> address >> id >> pay >> type) {

        if (type == 2) {
            fin >> vip_grade;
            fin >> usersname >> password;
            buyer* b = new vip(name, address, id, pay, vip_grade, usersname, password);
            ListNode* node = new ListNode();
            node->data = b;

            // 将节点插入到链表中
            node->next = head->next;
            head->next = node;
        }
        else if (type == 3) {
            fin >> discount;
            fin >> usersname >> password;
            buyer* b = new svip(name, address, id, pay, discount, usersname, password);
            ListNode* node = new ListNode();
            node->data = b;

            // 将节点插入到链表中
            node->next = head->next;
            head->next = node;
        }
        else {
            fin >> usersname >> password;
            buyer* b = new folk(name, address, id, pay, usersname, password);
            ListNode* node = new ListNode();
            node->data = b;

            // 将节点插入到链表中
            node->next = head->next;
            head->next = node;
        }
    }
    fin.close();
    cout << "信息读取成功!" << endl;
}

void CheckUsersname(ListNode* head) {
    ListNode* pmove = head->next;
    string CinUsersname;
    cin >> CinUsersname;
    while (pmove != nullptr) {
        if (pmove->data->GetUsersname() == CinUsersname) {
            cout << "用户名已存在!\n请重新输入!" << endl;
            return;
        }
        pmove = pmove->next;
    }
    users = CinUsersname;
}

void Checkpassword(ListNode* head) {
    ListNode* pmove = head->next;
    string CinPassword;
    cin >> CinPassword;
    while (pmove != nullptr) {
        if (pmove->data->GetUsersname() == CinPassword) {
            cout << "密码已存在!\n请重新输入!" << endl;
            return;
        }
        pmove = pmove->next;
    }
    pass = CinPassword;
}

void save_info2(vector<book>& books) {
    string filename = R"(C:\Users\熊知宇\Desktop\程序期末大作业\book.txt)";
    ofstream fout(filename, ios::app);
    if (!fout.is_open()) {
        cout << "打开文件失败!" << endl;
        return;
    }

    for (const auto& b : books) {
        fout << b.num << " ";
        fout << b.bname << " ";
        fout << b.price << endl;
    }

    fout.close();
    cout << "信息存储成功!" << endl;
}



(二)改进前运行截图:
客户注册信息:

查询个人信息:

信息列表查询:

购买图书操作:

信息列表查询:

但仍有一些可以优化的地方。以下是一些优化建议:

(三)功能模块图
改进前的功能模块图:

改进后的功能模块图:

(四)代码修改

  1. 主菜单分离管理员和用户登录

原代码:

点击查看代码
void welcome() {
cout << "**\t\t" << "网上购书结账系统" << "\t**" << endl;
cout << "**\t\t" << "1.注册信息" << "\t\t**" << endl;
    cout << "**\t\t" << "2.查询个人" << "\t\t**" << endl;
    cout << "**\t\t" << "3.信息列表" << "\t\t**" << endl;
    cout << "**\t\t" << "4.购买图书" << "\t\t**" << endl;
    cout << "**\t\t" << "5.退出系统" << "\t\t**" << endl;
}
修改后新代码:
点击查看代码
void Welcome() {
    cout << "**\t\t" << "网上购书结账系统" << "\t**" << endl;
    cout << "**\t\t" << "1. 管理员登录" << "\t\t**" << endl;
    cout << "**\t\t" << "2. 用户登录" << "\t\t**" << endl;
    cout << "**\t\t" << "3. 退出系统" << "\t\t**" << endl;
}

修改后的好处:

功能分离:将管理员和用户的功能分开,避免功能混杂。
逻辑清晰:用户和管理员的操作路径更加明确,提升了系统的易用性。
2. 增加管理员登录功能
原代码:无管理员登录功能。
新代码:

点击查看代码
void AdminLogin() {
    string username, password;
    cout << "请输入管理员用户名:";
    cin >> username;
    cout << "请输入管理员密码:";
    cin >> password;

    if (username == "admin" && password == "admin123") {
        cout << "管理员登录成功!" << endl;
        unique_ptr<ListNode> head = make_unique<ListNode>();
        vector<Book> books;
        LoadInfo(head.get());
        LoadBooks(books);
        AdminMenu(head.get(), books);
    } else {
        cout << "管理员用户名或密码错误!" << endl;
    }
}
修改后的好处:

权限控制:只有管理员可以管理书籍和用户信息,增强了系统的安全性。
功能扩展:管理员可以录入、查看、删除书籍信息,以及查询用户信息。
3. 增加用户登录功能
原代码:用户登录功能与购书功能混杂在一起。
新代码:

点击查看代码
void UserLogin() {
    unique_ptr<ListNode> head = make_unique<ListNode>();
    vector<Book> books;
    LoadInfo(head.get());
    LoadBooks(books);

    string username, password;
    cout << "请输入用户名:";
    cin >> username;
    cout << "请输入密码:";
    cin >> password;

    ListNode* current = head->next.get();
    while (current != nullptr) {
        if (current->data->GetUsername() == username && current->data->GetPassword() == password) {
            cout << "用户登录成功!" << endl;
            UserMenu(head.get(), books);
            return;
        }
        current = current->next.get();
    }
    cout << "用户名或密码错误!" << endl;
}

修改后的好处:

功能分离:用户登录后只能进行书籍查询和购买,逻辑更加清晰。
用户体验提升:用户登录后可以直接进入用户菜单,操作更加便捷。
4. 增加管理员菜单
原代码:无管理员菜单。
新代码:

点击查看代码
void AdminMenu(ListNode* head, vector<Book>& books) {
    while (true) {
        cout << "**\t\t" << "管理员菜单" << "\t\t**" << endl;
        cout << "**\t\t" << "1. 录入图书" << "\t\t**" << endl;
        cout << "**\t\t" << "2. 查看图书" << "\t\t**" << endl;
        cout << "**\t\t" << "3. 删除图书" << "\t\t**" << endl;
        cout << "**\t\t" << "4. 查询用户信息" << "\t\t**" << endl;
        cout << "**\t\t" << "5. 更改用户信息" << "\t\t**" << endl;
        cout << "**\t\t" << "6. 返回主菜单" << "\t\t**" << endl;
        cout << "请选择功能>> ";
        short choice;
        cin >> choice;

        switch (choice) {
            case 1: {
                string num, name;
                short price;
                cout << "请输入书号:";
                cin >> num;
                cout << "请输入书名:";
                cin >> name;
                cout << "请输入定价:";
                cin >> price;
                books.emplace_back(num, name, price);
                SaveBooks(books);
                cout << "图书录入成功!" << endl;
                break;
            }
            case 2: {
                cout << "图书列表:" << endl;
                for (const auto& book : books) {
                    book.Display();
                }
                break;
            }
            case 3: {
                string num;
                cout << "请输入要删除的书号:";
                cin >> num;
                auto it = books.begin();
                while (it != books.end()) {
                    if (it->num == num) {
                        it = books.erase(it);
                        cout << "图书删除成功!" << endl;
                        SaveBooks(books);
                        break;
                    } else {
                        ++it;
                    }
                }
                if (it == books.end()) {
                    cout << "未找到该图书!" << endl;
                }
                break;
            }
            case 4: {
                string username;
                cout << "请输入要查询的用户名:";
                cin >> username;
                SearchInfo(head);
                break;
            }
            case 5: {
                string username;
                cout << "请输入要更改的用户名:";
                cin >> username;
                // 更改用户信息逻辑(未实现)
                cout << "功能未实现!" << endl;
                break;
            }
            case 6: return;
            default: cout << "输入有误,请重新输入!" << endl; break;
        }
        system("pause");
        system("cls");
    }
}

修改后的好处:

功能完善:管理员可以录入、查看、删除书籍信息,以及查询用户信息。
灵活性增强:管理员可以动态管理书籍信息,无需修改代码。
5. 增加用户菜单
原代码:用户功能与管理员功能混杂。
新代码:

点击查看代码
void UserMenu(ListNode* head, const vector<Book>& books) {
    while (true) {
        cout << "**\t\t" << "用户菜单" << "\t\t**" << endl;
        cout << "**\t\t" << "1. 查询图书" << "\t\t**" << endl;
        cout << "**\t\t" << "2. 购买图书" << "\t\t**" << endl;
        cout << "**\t\t" << "3. 返回主菜单" << "\t\t**" << endl;
        cout << "请选择功能>> ";
        short choice;
        cin >> choice;

        switch (choice) {
            case 1: {
                cout << "图书列表:" << endl;
                for (const auto& book : books) {
                    book.Display();
                }
                break;
            }
            case 2: BuyBook(head, books); break;
            case 3: return;
            default: cout << "输入有误,请重新输入!" << endl; break;
        }
        system("pause");
        system("cls");
    }
}

修改后的好处:

功能分离:用户只能查询和购买书籍,逻辑更加清晰。
用户体验提升:用户操作更加简单直观。
6. 书籍信息动态管理
原代码:书籍信息是固定的。
新代码:

点击查看代码
void ManageBooks(vector<Book>& books) {
    // 书籍录入、查看、删除等功能
}

修改后的好处:

灵活性增强:管理员可以动态管理书籍信息,无需修改代码。
数据持久化:书籍信息存储在文件中,程序重启后不会丢失。
(五)改进后运行截图
主菜单:

管理员登录:

管理员菜单:

录入图书:

查看图书:

删除图书:

返回主菜单:

用户菜单:

用户查询书籍:

用户购买书籍:

返回主菜单:

(六)总结:
通过以上修改,系统实现了以下优化:
1.功能分离:管理员和用户的功能完全分离,逻辑更加清晰。
2.权限控制:管理员可以管理书籍和用户信息,用户只能查询和购买书籍。
3.灵活性增强:管理员可以动态管理书籍信息,用户可以选择更多书籍。
4.用户体验提升:用户和管理员的操作路径更加明确,提升了系统的易用性。
5.数据持久化:用户信息和书籍信息可以长期保存,程序重启后不会丢失。
总之,通过本次对网上购书结账系统的代码修改和优化,我深刻认识到逆向软件设计和开发作为学习软件开发创新的重要手段,具有深远的意义。虽然在日常开发中,纯粹修改他人代码的情况并不多见,但通过逆向分析和优化,我显著提升了阅读和理解他人代码的能力,这对于未来可能面临的团队合作至关重要。
此外,逆向软件设计和开发也在不断锻炼着我的思维。通过分析他人代码中的不足,我能够反思自身在开发中可能存在的类似问题,从而避免重复错误,提升代码质量。这种从他人代码中学习、发现问题并改进的过程,不仅帮助我更好地理解软件设计的核心思想,也为实现软件开发的创新奠定了坚实基础。通过本次实践,我更加明确了模块化设计、数据持久化、输入验证和用户体验优化的重要性,这些经验将为我未来的开发工作提供宝贵的指导。

posted @ 2025-02-27 22:19  园友3607115  阅读(55)  评论(0)    收藏  举报