软件逆向设计二次开发:书店购书管理系统重构与改进
软件逆向设计二次开发:书店购书管理系统重构与改进
一、项目来源
本次作业选择的项目来源于同学大一C++程序设计期末报告: BuyBook.cpp,该程序实现了一个简易的书店购书管理系统,主要包含以下功能:
- 会员管理
- 图书管理
- 购书交易处理
- 交易记录查看
- 数据文件读写(永久)
原始代码采用面向对象方式设计,定义了 Buyer、Book、Purchase、LibraryManager 等类,初步具备一定的软件工程结构,适合作为本次“阅读分析—找缺陷—重构优化—测试验证”的二次开发对象。
二、运行环境 + 运行结果
1. 运行环境
-
操作系统:
![image]()
-
软件版本:
Microsoft Visual Studio Community 2022 (64 位) - Current
版本 17.11.5
2. 原程序运行情况
原程序能够完成基本菜单显示、图书购买、会员管理和交易记录保存,但在复读源码和实际运行中发现以下不足:
- 大量使用
system("cls")和system("pause"),导致该C++项目仅限于 Windows 环境; - 输入读取大多使用
cin >>,测试中发现当输入带空格的书名、出版社、地址等文本时无法处理; - 交易金额逻辑存在缺陷,累计消费与“本次实付金额”混在一起;
- 添加图书、添加会员时缺少重复校验与数值合法性校验;
- 搜索功能只支持完全匹配,实用性不高。
3. 运行结果截图

4. 源码
点击查看源码
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <vector>
#include <cstdlib>
#include <sstream>
using namespace std;
// 购书者基类
class Buyer {
protected:
string name; // 姓名
int buyerID; // 购书人编号
string address; // 地址
double totalPay; // 总购书费用
public:
Buyer();
Buyer(string n, int b, string a, double p);
string getBuyerName() const; // 取姓名
string getAddress() const; // 取地址
double getTotalPay() const; // 取总费用
int getID() const; // 取购书人编号
virtual string getType() const = 0; // 获取买家类型
virtual string getDetail() const = 0; // 获取详细信息
virtual void display() const = 0; // 显示对象
virtual void calculatePay(double price) = 0; // 计算购书费用
virtual ~Buyer() {}; // 虚析构函数
};
// 会员类
class Member : public Buyer {
private:
int memberGrade; // 会员级别
public:
Member(string n, int b, int l, string a, double p) : Buyer(n, b, a, p) {
memberGrade = l;
} // 构造函数
string getType() const override { return "M"; }
string getDetail() const override { return to_string(memberGrade); }
void display() const override; // 显示函数
void calculatePay(double price) override; // 计算购书费用
};
// 贵宾类
class HonouredGuest : public Buyer {
private:
double discountRate; // 折扣率
public:
HonouredGuest(string n, int b, double r, string a, double p) : Buyer(n, b, a, p) {
discountRate = r;
} // 构造函数
string getType() const override { return "H"; }
string getDetail() const override { return to_string(discountRate); }
void display() const override; // 显示对象
void calculatePay(double price) override; // 计算购书费用
};
// 普通人类
class Layfolk : public Buyer {
public:
Layfolk(string n, int b, string a, double p) : Buyer(n, b, a, p) {}
// 构造函数
string getType() const override { return "L"; }
string getDetail() const override { return ""; }
void display() const override; // 显示对象
void calculatePay(double price) override; // 计算购书费用
};
// 临时顾客类
class TemporaryBuyer : public Buyer {
public:
TemporaryBuyer(string n, string a, double p) : Buyer(n, 0, a, p) {}
string getType() const override { return "T"; }
string getDetail() const override { return ""; }
void display() const override;
void calculatePay(double price) override;
};
// 图书类
class Book {
protected:
string bookID; // 书号
string bookName; // 书名
string author; // 作者
string publishing; // 出版社
double price; // 定价
int stock; // 库存
public:
// 构造函数
Book();
Book(string b_id, string b_n, string au, string pu, double pr, int st);
void display() const; // 显示图书信息
string getBookID() const; // 取书号
string getBookName() const; // 取书名
string getAuthor() const; // 取作者
string getPublishing() const; // 取出版社
double getPrice() const; // 取定价
int getStock() const; // 取库存
void setStock(int st); // 设置库存
};
// 购买记录类
class Purchase {
private:
string buyerName; // 购书人姓名
int buyerID; // 购书人编号
string date; // 购买日期
string address; // 地址
double totalAmount; // 应付金额
double actualAmount; // 实付金额
vector<string> bookIDs; // 购买的图书ID列表
public:
Purchase(string bn, int bid, string d, string addr, double total, double actual);
void addBookID(string bookID);
void display(const vector<Book>& books) const;
string getDate() const;
string getBuyerName() const;
int getBuyerID() const;
string getAddress() const;
double getTotalAmount() const;
double getActualAmount() const;
const vector<string>& getBookIDs() const;
};
// 购书者基类实现
Buyer::Buyer() {
name = "";
buyerID = 0;
address = "";
totalPay = 0;
}
Buyer::Buyer(string n, int b, string a, double p) {
name = n;
buyerID = b;
address = a;
totalPay = p;
}
string Buyer::getBuyerName() const {
return name;
}
string Buyer::getAddress() const {
return address;
}
double Buyer::getTotalPay() const {
return totalPay;
}
int Buyer::getID() const {
return buyerID;
}
// 会员类实现
void Member::display() const {
cout << left << setw(10) << name << setw(10) << buyerID
<< setw(15) << "会员(级别:" << memberGrade << ")"
<< setw(15) << address << setw(10) << totalPay << endl;
}
void Member::calculatePay(double price) {
double discount = 1.0;
switch (memberGrade) {
case 1: discount = 0.95; break;
case 2: discount = 0.90; break;
case 3: discount = 0.85; break;
case 4: discount = 0.80; break;
case 5: discount = 0.70; break;
default: cout << "会员级别错误!" << endl; return;
}
totalPay += price * discount;
}
// 贵宾类实现
void HonouredGuest::display() const {
cout << left << setw(10) << name << setw(10) << buyerID
<< setw(9) << "贵宾(折扣:" << discountRate * 100 << "%) "
<< setw(15) << address << setw(10) << totalPay << endl;
}
void HonouredGuest::calculatePay(double price) {
totalPay += price * (1 - discountRate);
}
// 普通人类实现
void Layfolk::display() const {
cout << left << setw(10) << name << setw(10) << buyerID
<< setw(15) << "普通人"
<< setw(15) << address << setw(10) << totalPay << endl;
}
void Layfolk::calculatePay(double price) {
totalPay += price;
}
// 临时顾客实现
void TemporaryBuyer::display() const {
cout << left << setw(10) << name << setw(10) << buyerID
<< setw(15) << "临时顾客"
<< setw(15) << address << setw(10) << totalPay << endl;
}
void TemporaryBuyer::calculatePay(double price) {
totalPay += price;
}
// 图书类实现
Book::Book() {
bookID = "";
bookName = "";
author = "";
publishing = "";
price = 0;
stock = 0;
}
Book::Book(string b_id, string b_n, string au, string pu, double pr, int st) {
bookID = b_id;
bookName = b_n;
author = au;
publishing = pu;
price = pr;
stock = st;
}
void Book::display() const {
cout << left << setw(15) << bookID << setw(20) << bookName
<< setw(15) << author << setw(15) << publishing
<< setw(10) << price << setw(10) << stock << endl;
}
string Book::getBookID() const {
return bookID;
}
string Book::getBookName() const {
return bookName;
}
string Book::getAuthor() const {
return author;
}
string Book::getPublishing() const {
return publishing;
}
double Book::getPrice() const {
return price;
}
int Book::getStock() const {
return stock;
}
void Book::setStock(int st) {
stock = st;
}
// 购买记录类实现
Purchase::Purchase(string bn, int bid, string d, string addr, double total, double actual) {
buyerName = bn;
buyerID = bid;
date = d;
address = addr;
totalAmount = total;
actualAmount = actual;
}
void Purchase::addBookID(string bookID) {
bookIDs.push_back(bookID);
}
void Purchase::display(const vector<Book>& books) const {
cout << "\n===================================================================================" << endl;
cout << "购书人: " << buyerName << " (ID: " << buyerID << ")" << endl;
cout << "日期: " << date << ", 地址: " << address << endl;
cout << "应付金额: " << totalAmount << ", 实付金额: " << actualAmount << endl;
cout << "\n购买的图书:" << endl;
cout << left << setw(25) << "书号" << setw(20) << "书名"
<< setw(15) << "作者" << setw(15) << "出版社"
<< setw(10) << "定价" << endl;
for (const auto& bookID : bookIDs) {
bool found = false;
for (const auto& book : books) {
if (book.getBookID() == bookID) {
cout << left << setw(25) << book.getBookID()
<< setw(20) << book.getBookName()
<< setw(15) << book.getAuthor()
<< setw(15) << book.getPublishing()
<< setw(10) << book.getPrice() << endl;
found = true;
break;
}
}
if (!found) {
cout << left << setw(25) << bookID << setw(20) << "[未知图书]"
<< setw(15) << "" << setw(15) << ""
<< setw(10) << 0.0 << endl;
}
}
cout << "===================================================================================" << endl;
}
string Purchase::getDate() const {
return date;
}
string Purchase::getBuyerName() const {
return buyerName;
}
int Purchase::getBuyerID() const {
return buyerID;
}
string Purchase::getAddress() const {
return address;
}
double Purchase::getTotalAmount() const {
return totalAmount;
}
double Purchase::getActualAmount() const {
return actualAmount;
}
const vector<string>& Purchase::getBookIDs() const {
return bookIDs;
}
// 字符串分割函数
vector<string> split(const string& s, char delimiter) {
vector<string> tokens;
string token;
istringstream tokenStream(s);
while (getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
// 图书馆管理类
class LibraryManager {
private:
vector<Buyer*> buyers;
vector<Book> books;
vector<Purchase> purchases;
vector<TemporaryBuyer> tempBuyers;
string getCurrentDate();
void createEmptyFilesIfNotExist();
public:
LibraryManager();
~LibraryManager();
void loadData();
void saveData();
void mainMenu();
void buyerManagementMenu();
void bookManagementMenu();
void transactionMenu();
void displayAllBuyers();
void displayAllBooks();
void addBuyer();
void addBook();
void makeTransaction();
void searchBuyerByName();
void searchBookByName();
void displayAllPurchases();
};
LibraryManager::LibraryManager() {
createEmptyFilesIfNotExist();
loadData();
}
LibraryManager::~LibraryManager() {
for (auto buyer : buyers) {
delete buyer;
}
}
void LibraryManager::createEmptyFilesIfNotExist() {
// 检查并创建空的数据文件
ifstream checkFile("LibraryHouse.txt");
if (!checkFile.good()) {
ofstream("LibraryHouse.txt") << "书号,书名,作者,出版社,价格,库存\n";
}
checkFile.close();
checkFile.open("LibraryDeal.txt");
if (!checkFile.good()) {
ofstream("LibraryDeal.txt") << "购书人姓名,购书人编号,日期,地址,应付金额,实付金额,购买的书号列表\n";
}
checkFile.close();
checkFile.open("LibraryMember.txt");
if (!checkFile.good()) {
ofstream("LibraryMember.txt") << "类型,姓名,编号,会员级别/折扣率,地址,总消费金额\n";
}
checkFile.close();
checkFile.open("LibraryTem.txt");
if (!checkFile.good()) {
ofstream("LibraryTem.txt") << "姓名,地址,总消费金额\n";
}
checkFile.close();
}
string LibraryManager::getCurrentDate() {
time_t now = time(0);
tm localTime;
#ifdef _MSC_VER // Microsoft Visual C++
errno_t err = localtime_s(&localTime, &now);
if (err != 0) {
return "错误日期";
}
#else // 其他编译器
if (localtime_r(&now, &localTime) == nullptr) {
return "错误日期";
}
#endif
char buffer[80];
strftime(buffer, sizeof(buffer), "%Y-%m-%d", &localTime);
return string(buffer);
}
void LibraryManager::loadData() {
// 从文件加载图书库存
ifstream bookFile("LibraryHouse.txt");
string line;
// 跳过标题行
getline(bookFile, line);
while (getline(bookFile, line)) {
vector<string> tokens = split(line, ',');
if (tokens.size() >= 6) {
books.push_back(Book(
tokens[0], tokens[1], tokens[2], tokens[3],
stod(tokens[4]), stoi(tokens[5])
));
}
}
bookFile.close();
// 从文件加载会员数据
ifstream memberFile("LibraryMember.txt");
// 跳过标题行
getline(memberFile, line);
while (getline(memberFile, line)) {
vector<string> tokens = split(line, ',');
if (tokens.size() >= 6) {
string type = tokens[0];
string name = tokens[1];
int id = stoi(tokens[2]);
string detail = tokens[3];
string address = tokens[4];
double totalPay = stod(tokens[5]);
if (type == "M") { // 会员
buyers.push_back(new Member(name, id, stoi(detail), address, totalPay));
}
else if (type == "H") { // 贵宾
buyers.push_back(new HonouredGuest(name, id, stod(detail), address, totalPay));
}
else if (type == "L") { // 普通人
buyers.push_back(new Layfolk(name, id, address, totalPay));
}
}
}
memberFile.close();
// 从文件加载临时顾客
ifstream tempFile("LibraryTem.txt");
// 跳过标题行
getline(tempFile, line);
while (getline(tempFile, line)) {
vector<string> tokens = split(line, ',');
if (tokens.size() >= 3) {
tempBuyers.push_back(TemporaryBuyer(
tokens[0], tokens[1], stod(tokens[2])
));
}
}
tempFile.close();
// 从文件加载交易记录
ifstream dealFile("LibraryDeal.txt");
// 跳过标题行
getline(dealFile, line);
while (getline(dealFile, line)) {
vector<string> tokens = split(line, ',');
if (tokens.size() >= 7) {
string buyerName = tokens[0];
int buyerID = stoi(tokens[1]);
string date = tokens[2];
string address = tokens[3];
double totalAmount = stod(tokens[4]);
double actualAmount = stod(tokens[5]);
Purchase purchase(buyerName, buyerID, date, address, totalAmount, actualAmount);
// 从第7个元素开始是书号
for (size_t i = 6; i < tokens.size(); i++) {
purchase.addBookID(tokens[i]);
}
purchases.push_back(purchase);
}
}
dealFile.close();
cout << "数据加载完成!" << endl;
}
void LibraryManager::saveData() {
// 保存图书库存到文件
ofstream bookFile("LibraryHouse.txt");
bookFile << "书号,书名,作者,出版社,价格,库存\n";
for (const auto& book : books) {
bookFile << book.getBookID() << ","
<< book.getBookName() << ","
<< book.getAuthor() << ","
<< book.getPublishing() << ","
<< book.getPrice() << ","
<< book.getStock() << "\n";
}
bookFile.close();
// 保存会员数据到文件
ofstream memberFile("LibraryMember.txt");
memberFile << "类型,姓名,编号,会员级别/折扣率,地址,总消费金额\n";
for (const auto& buyer : buyers) {
memberFile << buyer->getType() << ","
<< buyer->getBuyerName() << ","
<< buyer->getID() << ","
<< buyer->getDetail() << ","
<< buyer->getAddress() << ","
<< buyer->getTotalPay() << "\n";
}
memberFile.close();
// 保存临时顾客到文件
ofstream tempFile("LibraryTem.txt");
tempFile << "姓名,地址,总消费金额\n";
for (const auto& tempBuyer : tempBuyers) {
tempFile << tempBuyer.getBuyerName() << ","
<< tempBuyer.getAddress() << ","
<< tempBuyer.getTotalPay() << "\n";
}
tempFile.close();
// 保存交易记录到文件
ofstream dealFile("LibraryDeal.txt");
dealFile << "购书人姓名,购书人编号,日期,地址,应付金额,实付金额,购买的书号列表\n";
for (const auto& purchase : purchases) {
dealFile << purchase.getBuyerName() << ","
<< purchase.getBuyerID() << ","
<< purchase.getDate() << ","
<< purchase.getAddress() << ","
<< purchase.getTotalAmount() << ","
<< purchase.getActualAmount();
const auto& bookIDs = purchase.getBookIDs();
for (const auto& bookID : bookIDs) {
dealFile << "," << bookID;
}
dealFile << "\n";
}
dealFile.close();
cout << "数据保存完成!" << endl;
}
void LibraryManager::mainMenu() {
while (true) {
system("cls");
cout << "╒═书店购书管理系统═══════════════╕" << endl;
cout << "│ │" << endl;
cout << "│ │" << endl;
cout << "│ 1. 会员管理 │" << endl;
cout << "│ 2. 图书管理 │" << endl;
cout << "│ 3. 交易处理 │" << endl;
cout << "│ 4. 查看交易记录 │" << endl;
cout << "│ 5. 更改主题 │" << endl;
cout << "│ 0. 退出系统 │" << endl;
cout << "│ │" << endl;
cout << "╘════════════════════════════════╛" << endl;
cout << "请输入您的选择: ";
int choice;
cin >> choice;
switch (choice) {
case 1:
buyerManagementMenu();
break;
case 2:
bookManagementMenu();
break;
case 3:
transactionMenu();
break;
case 4:
displayAllPurchases();
system("pause");
break;
case 5:
printf("\033[0m╒════════════════════════════╕\n");
printf("│ 请选择: │\n");
printf("│ │\n");
printf("│ \033[0m默认0 │\n");
printf("│ \033[31m主题1\033[0m │\n");
printf("│ \033[32m主题2\033[0m │\n");
printf("│ \033[33m主题3\033[0m │\n");
printf("│ \033[34m主题4\033[0m │\n");
printf("│ \033[35m主题5\033[0m │\n");
printf("│ \033[36m主题6\033[0m │\n");
printf("│ │\n");
printf("╘════════════════════════════╛\033[0m\n");
cout << "请输入所需主题编号:" << endl;
int themenum;
cin >> themenum;
switch (themenum) {
case 0:
printf("\033[0m1:\033[1m修改成功!\n");
break;
case 1:
cout << "\033[31m修改成功!" << endl;
break;
case 2:
cout << "\033[32m修改成功!" << endl;
break;
case 3:
cout << "\033[33m修改成功!" << endl;
break;
case 4:
cout << "\033[34m修改成功!" << endl;
break;
case 5:
cout << "\033[35m修改成功!" << endl;
break;
case 6:
cout << "\033[36m修改成功!" << endl;
break;
default:
cout << "无效选择,请重新输入!" << endl;
system("pause");
}
system("pause");
break;
case 0:
saveData(); // 退出前保存数据
cout << "感谢使用图书馆管理系统,再见!" << endl;
return;
default:
cout << "无效选择,请重新输入!" << endl;
system("pause");
}
}
}
void LibraryManager::buyerManagementMenu() {
while (true) {
system("cls");
cout << "╒═════════════════会员管理═══╕ " << endl;
cout << "│ │" << endl;
cout << "│ │" << endl;
cout << "│ 1. 显示所有会员 │" << endl;
cout << "│ 2. 按姓名查找会员 │" << endl;
cout << "│ 3. 添加新会员 │" << endl;
cout << "│ 4. 返回主菜单 │" << endl;
cout << "│ │" << endl;
cout << "╘════════════════════════════╛" << endl;
cout << "请输入您的选择: ";
int choice;
cin >> choice;
switch (choice) {
case 1:
displayAllBuyers();
system("pause");
break;
case 2:
searchBuyerByName();
system("pause");
break;
case 3:
addBuyer();
system("pause");
break;
case 4:
return;
default:
cout << "无效选择,请重新输入!" << endl;
system("pause");
}
}
}
void LibraryManager::bookManagementMenu() {
while (true) {
system("cls");
cout << "╒═════════════════图书管理═══╕ " << endl;
cout << "│ │" << endl;
cout << "│ │" << endl;
cout << "│ 1. 显示所有图书 │" << endl;
cout << "│ 2. 按书名查找图书 │" << endl;
cout << "│ 3. 添加新图书 │" << endl;
cout << "│ 4. 返回主菜单 │" << endl;
cout << "│ │" << endl;
cout << "╘════════════════════════════╛" << endl;
cout << "请输入您的选择: ";
int choice;
cin >> choice;
switch (choice) {
case 1:
displayAllBooks();
system("pause");
break;
case 2:
searchBookByName();
system("pause");
break;
case 3:
addBook();
system("pause");
break;
case 4:
return;
default:
cout << "无效选择,请重新输入!" << endl;
system("pause");
}
}
}
void LibraryManager::transactionMenu() {
while (true) {
system("cls");
cout << "╒═════════════════交易处理═══╕ " << endl;
cout << "│ │" << endl;
cout << "│ │" << endl;
cout << "│ 1. 购买图书 │" << endl;
cout << "│ 2. 返回主菜单 │" << endl;
cout << "│ │" << endl;
cout << "╘════════════════════════════╛" << endl;
cout << "请输入您的选择: ";
int choice;
cin >> choice;
switch (choice) {
case 1:
makeTransaction();
system("pause");
break;
case 2:
return;
default:
cout << "无效选择,请重新输入!" << endl;
system("pause");
}
}
}
void LibraryManager::displayAllBuyers() {
system("cls");
cout << "======================== 会员信息列表 ========================" << endl;
cout << left << setw(10) << "姓名" << setw(10) << "编号"
<< setw(15) << "会员类型" << setw(15) << "地址"
<< setw(10) << "消费金额" << endl;
cout << "--------------------------------------------------------------\n" << endl;
for (const auto& buyer : buyers) {
buyer->display();
}
cout << "\n======================== 临时顾客列表 ========================" << endl;
for (const auto& tempBuyer : tempBuyers) {
tempBuyer.display();
}
cout << "--------------------------------------------------------------\n" << endl;
}
void LibraryManager::displayAllBooks() {
system("cls");
cout << "======== 图书信息列表 ================================" << endl;
cout << left << setw(25) << "书号" << setw(20) << "书名"
<< setw(15) << "作者" << setw(15) << "出版社"
<< setw(10) << "定价" << setw(10) << "库存" << endl;
cout << "--------------------------------------------------------------\n" << endl;
for (const auto& book : books) {
book.display();
}
cout << "--------------------------------------------------------------\n" << endl;
}
void LibraryManager::addBuyer() {
system("cls");
cout << "==================== 添加新会员 ====================" << endl;
string name, address;
int id, type, grade;
double discount, initialPay = 0;
cout << "请输入会员姓名: ";
cin >> name;
cout << "请输入会员编号: ";
cin >> id;
cout << "请输入会员地址: ";
cin >> address;
cout << "请输入会员类型 (1: 普通会员, 2: 贵宾会员, 3: 普通用户): ";
cin >> type;
Buyer* newBuyer = nullptr;
if (type == 1) {
cout << "请输入会员级别 (1-5): ";
cin >> grade;
newBuyer = new Member(name, id, grade, address, initialPay);
}
else if (type == 2) {
cout << "请输入折扣率 (0-1): ";
cin >> discount;
newBuyer = new HonouredGuest(name, id, discount, address, initialPay);
}
else if (type == 3) {
newBuyer = new Layfolk(name, id, address, initialPay);
}
else {
cout << "无效的会员类型!" << endl;
return;
}
buyers.push_back(newBuyer);
cout << "会员添加成功!" << endl;
}
void LibraryManager::addBook() {
system("cls");
cout << "==================== 添加新图书 ====================" << endl;
string id, name, author, publishing;
double price;
int stock;
cout << "请输入书号: ";
cin >> id;
cout << "请输入书名: ";
cin >> name;
cout << "请输入作者: ";
cin >> author;
cout << "请输入出版社: ";
cin >> publishing;
cout << "请输入定价: ";
cin >> price;
cout << "请输入库存: ";
cin >> stock;
books.push_back(Book(id, name, author, publishing, price, stock));
cout << "图书添加成功!" << endl;
}
void LibraryManager::searchBuyerByName() {
system("cls");
cout << "==================== 按姓名查找会员 ====================" << endl;
string name;
cout << "请输入会员姓名: ";
cin >> name;
bool found = false;
cout << left << setw(10) << "姓名" << setw(10) << "编号"
<< setw(15) << "会员类型" << setw(15) << "地址"
<< setw(10) << "消费金额" << endl;
cout << "--------------------------------------------------------------\n" << endl;
for (const auto& buyer : buyers) {
if (buyer->getBuyerName() == name) {
buyer->display();
found = true;
}
}
// 查找临时顾客
for (const auto& tempBuyer : tempBuyers) {
if (tempBuyer.getBuyerName() == name) {
tempBuyer.display();
found = true;
}
}
if (!found) {
cout << "未找到该会员!" << endl;
}
}
void LibraryManager::searchBookByName() {
system("cls");
cout << "==================== 按书名查找图书 ====================" << endl;
string name;
cout << "请输入图书名称: ";
cin >> name;
bool found = false;
cout << left << setw(15) << "书号" << setw(20) << "书名"
<< setw(15) << "作者" << setw(15) << "出版社"
<< setw(10) << "定价" << setw(10) << "库存" << endl;
cout << "--------------------------------------------------------------\n" << endl;
for (const auto& book : books) {
if (book.getBookName() == name) {
book.display();
found = true;
}
}
if (!found) {
cout << "未找到该图书!" << endl;
}
}
void LibraryManager::makeTransaction() {
system("cls");
cout << "==================== 购买图书 ====================" << endl;
int buyerId;
cout << "请输入购书人编号 (新顾客请输入0): ";
cin >> buyerId;
Buyer* buyer = nullptr;
TemporaryBuyer* tempBuyer = nullptr;
// 查找正式会员
if (buyerId != 0) {
for (auto b : buyers) {
if (b->getID() == buyerId) {
buyer = b;
break;
}
}
if (!buyer) {
cout << "未找到该购书人!" << endl;
return;
}
}
else {
// 处理临时顾客
string name, address;
cout << "您是新顾客,将被记录为临时顾客" << endl;
cout << "请输入您的姓名: ";
cin >> name;
cout << "请输入您的地址: ";
cin >> address;
// 检查是否已有同名临时顾客
for (auto& tb : tempBuyers) {
if (tb.getBuyerName() == name) {
tempBuyer = &tb;
break;
}
}
// 如果没有,创建新的临时顾客
if (!tempBuyer) {
tempBuyers.push_back(TemporaryBuyer(name, address, 0));
tempBuyer = &tempBuyers.back();
}
}
displayAllBooks();
vector<string> selectedBookIDs;
double totalPrice = 0;
cout << "\n请输入要购买的图书数量: ";
int count;
cin >> count;
for (int i = 0; i < count; i++) {
string bookId;
cout << "请输入第 " << (i + 1) << " 本图书的书号: ";
cin >> bookId;
bool found = false;
for (auto& book : books) {
if (book.getBookID() == bookId) {
if (book.getStock() > 0) {
selectedBookIDs.push_back(bookId);
totalPrice += book.getPrice();
book.setStock(book.getStock() - 1);
found = true;
break;
}
else {
cout << "该图书库存不足!" << endl;
i--;
found = true;
break;
}
}
}
if (!found) {
cout << "未找到该图书!" << endl;
i--;
}
}
// 计算实际支付金额
double actualAmount = totalPrice;
if (buyer) {
buyer->calculatePay(totalPrice);
actualAmount = buyer->getTotalPay();
}
else if (tempBuyer) {
tempBuyer->calculatePay(totalPrice);
actualAmount = tempBuyer->getTotalPay();
}
// 创建交易记录
string buyerName = buyer ? buyer->getBuyerName() : tempBuyer->getBuyerName();
int buyerIdRecord = buyer ? buyer->getID() : 0;
string address = buyer ? buyer->getAddress() : tempBuyer->getAddress();
Purchase purchase(buyerName, buyerIdRecord, getCurrentDate(), address, totalPrice, actualAmount);
for (const auto& bookId : selectedBookIDs) {
purchase.addBookID(bookId);
}
purchases.push_back(purchase);
cout << "\n交易完成!" << endl;
cout << "应付金额: " << totalPrice << " 元" << endl;
cout << "实付金额: " << actualAmount << " 元" << endl;
}
void LibraryManager::displayAllPurchases() {
system("cls");
cout << "╒═════════ 交易记录列表════════════════════════════════════════════════════════════╕\n " << endl;
if (purchases.empty()) {
cout << "当前没有交易记录!" << endl;
return;
}
for (size_t i = 0; i < purchases.size(); i++) {
cout << "\n ═══ 交易记录 " << (i + 1) << " ═══════════════════════════════════════════════════════════════════" << endl;
purchases[i].display(books);
cout << endl;
}
}
int main() {
LibraryManager manager;
manager.mainMenu();
return 0;
}
三、原程序主要问题列表
问题 1:平台兼容性差
原程序在多个菜单中直接调用:
system("cls");
system("pause");
这使程序强依赖 Windows 命令环境。在 Linux/macOS 下运行会出现:
cls: not foundpause: not found
改进思路:
封装跨平台清屏与暂停逻辑;至少应避免把平台相关代码散落在多个函数中,提升可维护性。
问题 2:输入处理不健壮
原代码大量使用:
cin >> name;
cin >> address;
cin >> publishing;
这意味着:
- 地址中不能包含空格
- 书名中不能包含空格
- 出版社名称不能包含空格
- 用户一旦误输入字符到数值字段,程序容易进入异常状态
改进思路:
- 统一封装输入函数
- 文本输入使用
getline(cin >> ws, str) - 数值输入增加循环校验和错误恢复
问题 3:交易金额设计存在逻辑错误
原程序在购买时的处理如下:
buyer->calculatePay(totalPrice);
actualAmount = buyer->getTotalPay();
这里的 getTotalPay() 表示累计消费总额,却被直接赋给了 actualAmount(本次实付金额)。
也就是说:
- 第一次买书时看起来正常
- 第二次买书开始,
actualAmount会混入历史消费,导致交易记录失真
改进思路:
将“本次订单应付金额计算”和“用户累计消费更新”分离:
calculateAmount(price):只计算本次订单的实付金额addConsume(amount):将本次实付金额加入累计消费
问题 4:缺少唯一性与合法性校验
原程序添加会员、图书时没有检查:
- 会员编号是否重复
- 书号是否重复
- 价格是否小于 0
- 库存是否小于 0
- 会员等级是否超出范围
- 贵宾折扣率是否越界
改进思路:
在新增逻辑前加入业务校验,避免无效数据写入文件。
问题 5:搜索功能体验较差
原程序按姓名、按书名查询时,只支持:
if (book.getBookName() == name)
这要求输入必须完全一致,不支持模糊查询。
改进思路:
改为子串匹配,提高使用体验:
if (book.getBookName().find(target) != string::npos)
问题 6:显示逻辑和业务逻辑耦合较重
菜单、输入、数据校验、业务计算、文件保存都集中在 LibraryManager 内,尽管功能完整,但扩展性一般。
改进思路:
本次重构先进行“轻量级重构”:
- 封装输入函数
- 封装查找函数
- 封装平台相关函数
- 明确区分“订单金额”和“累计消费”
四、二次开发与重构方案
1. 重构目标
在保留原系统主要结构和业务流程的前提下,提高:
- 可维护性
- 输入健壮性
- 平台兼容性
- 数据正确性
- 用户使用体验
2. 具体改进内容
(1)新增统一输入函数
增加:
readLine()readInt()readDouble()
作用:
- 支持带空格文本输入
- 支持错误输入恢复
- 避免反复编写相同输入判断逻辑
(2)重构支付计算逻辑
新增:
calculateAmount(double price) constaddConsume(double amount)
作用:
- 订单实付金额单独计算
- 累计消费单独更新
- 修复交易记录中的金额失真问题
(3)增加数据校验
加入以下校验:
- 会员编号不可重复
- 书号不可重复
- 会员级别必须在 1~5
- 折扣率必须在 0~1
- 价格与库存不能小于 0
- 购买数量必须大于 0
(4)提升查询能力
- 会员查询支持模糊匹配
- 图书查询支持模糊匹配
(5)优化跨平台兼容性
把清屏操作封装为 clearScreen(),避免原代码中大量散落 system("cls")。
(6)代码示例
1. 本次订单金额与累计消费分离
virtual double calculateAmount(double price) const = 0;
void addConsume(double amount) { totalPay += amount; }
会员类中:
double calculateAmount(double price) const override {
double discount = 1.0;
switch (memberGrade) {
case 1: discount = 0.95; break;
case 2: discount = 0.90; break;
case 3: discount = 0.85; break;
case 4: discount = 0.80; break;
case 5: discount = 0.70; break;
default: discount = 1.0; break;
}
return price * discount;
}
交易处理中:
double actualAmount = buyer ? buyer->calculateAmount(totalPrice)
: tempBuyer->calculateAmount(totalPrice);
if (buyer) buyer->addConsume(actualAmount);
else tempBuyer->addConsume(actualAmount);
2. 输入函数封装
static string readLine(const string& prompt) {
cout << prompt;
string s;
getline(cin >> ws, s);
return s;
}
static int readInt(const string& prompt) {
int value;
while (true) {
cout << prompt;
if (cin >> value) return value;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "输入无效,请输入整数。\n";
}
}
3. 重复数据校验
bool buyerIdExists(int id) const {
for (auto buyer : buyers) if (buyer->getID() == id) return true;
return false;
}
Book* findBookById(const string& id) {
for (auto& book : books) if (book.getBookID() == id) return &book;
return nullptr;
}
4. 模糊查询
if (book.getBookName().find(target) != string::npos) {
book.display();
}
(7)完整新代码
点击查看源码
#includenamespace UI {
static string g_theme = "\033[0m";
void setTheme(const string& themeCode) {
g_theme = themeCode;
cout << g_theme;
}
void clearScreen() {
cout << "\033[2J\033[H";
}
void pause() {
cout << "\n按回车继续...";
cin.ignore(numeric_limits
cin.get();
}
string border(int width, char ch = '=') {
return string(width, ch);
}
string repeatText(const string& text, int count) {
string result;
for (int i = 0; i < count; ++i) result += text;
return result;
}
void printTitle(const string& title, int width = 60) {
cout << g_theme;
cout << "╒" << repeatText("═", width - 2) << "╕\n";
int inner = width - 2;
int pad = max(0, inner - static_cast
int left = pad / 2;
int right = pad - left;
cout << "│" << string(left, ' ') << title << string(right, ' ') << "│\n";
cout << "╘" << repeatText("═", width - 2) << "╛\n";
}
void printThemeMenu() {
cout << "╒════════════════════════════╕\n";
cout << "│ 请选择主题: │\n";
cout << "│ │\n";
cout << "│ 0. 默认 │\n";
cout << "│ 1. 红色 │\n";
cout << "│ 2. 绿色 │\n";
cout << "│ 3. 黄色 │\n";
cout << "│ 4. 蓝色 │\n";
cout << "│ 5. 紫色 │\n";
cout << "│ 6. 青色 │\n";
cout << "│ │\n";
cout << "╘════════════════════════════╛\n";
}
}
class InputHelper {
public:
static string readLine(const string& prompt) {
cout << prompt;
string s;
getline(cin >> ws, s);
return s;
}
static int readInt(const string& prompt, int minValue = numeric_limits
int value;
while (true) {
cout << prompt;
if (cin >> value) {
if (value < minValue || value > maxValue) {
cout << "输入超出范围,请重新输入。\n";
}
else {
return value;
}
}
else {
cout << "输入无效,请输入整数。\n";
cin.clear();
}
cin.ignore(numeric_limits
}
}
static double readDouble(const string& prompt, double minValue = -numeric_limits
double value;
while (true) {
cout << prompt;
if (cin >> value) {
if (value < minValue || value > maxValue) {
cout << "输入超出范围,请重新输入。\n";
}
else {
return value;
}
}
else {
cout << "输入无效,请输入数字。\n";
cin.clear();
}
cin.ignore(numeric_limits
}
}
};
class Buyer {
protected:
string name;
int buyerID;
string address;
double totalPay;
public:
Buyer() : name(""), buyerID(0), address(""), totalPay(0) {}
Buyer(const string& n, int b, const string& a, double p) : name(n), buyerID(b), address(a), totalPay(p) {}
string getBuyerName() const { return name; }
string getAddress() const { return address; }
double getTotalPay() const { return totalPay; }
int getID() const { return buyerID; }
void addConsume(double amount) { totalPay += amount; }
virtual string getType() const = 0;
virtual string getDetail() const = 0;
virtual void display() const = 0;
virtual double calculateAmount(double price) const = 0;
virtual ~Buyer() {}
};
class Member : public Buyer {
private:
int memberGrade;
public:
Member(const string& n, int b, int l, const string& a, double p)
: Buyer(n, b, a, p), memberGrade(l) {}
string getType() const override { return "M"; }
string getDetail() const override { return to_string(memberGrade); }
double calculateAmount(double price) const override {
double discount = 1.0;
switch (memberGrade) {
case 1: discount = 0.95; break;
case 2: discount = 0.90; break;
case 3: discount = 0.85; break;
case 4: discount = 0.80; break;
case 5: discount = 0.70; break;
default: discount = 1.0; break;
}
return price * discount;
}
void display() const override {
ostringstream typeText;
typeText << "会员(级别:" << memberGrade << ")";
cout << left << setw(12) << name
<< setw(10) << buyerID
<< setw(20) << typeText.str()
<< setw(20) << address
<< fixed << setprecision(2) << totalPay << '\n';
}
};
class HonouredGuest : public Buyer {
private:
double discountRate;
public:
HonouredGuest(const string& n, int b, double r, const string& a, double p)
: Buyer(n, b, a, p), discountRate(r) {}
string getType() const override { return "H"; }
string getDetail() const override {
ostringstream oss;
oss << fixed << setprecision(2) << discountRate;
return oss.str();
}
double calculateAmount(double price) const override {
return price * (1.0 - discountRate);
}
void display() const override {
ostringstream typeText;
typeText << "贵宾(折扣:" << fixed << setprecision(0) << discountRate * 100 << "%)";
cout << left << setw(12) << name
<< setw(10) << buyerID
<< setw(20) << typeText.str()
<< setw(20) << address
<< fixed << setprecision(2) << totalPay << '\n';
}
};
class Layfolk : public Buyer {
public:
Layfolk(const string& n, int b, const string& a, double p)
: Buyer(n, b, a, p) {}
string getType() const override { return "L"; }
string getDetail() const override { return ""; }
double calculateAmount(double price) const override { return price; }
void display() const override {
cout << left << setw(12) << name
<< setw(10) << buyerID
<< setw(20) << "普通用户"
<< setw(20) << address
<< fixed << setprecision(2) << totalPay << '\n';
}
};
class TemporaryBuyer : public Buyer {
public:
TemporaryBuyer(const string& n, const string& a, double p)
: Buyer(n, 0, a, p) {}
string getType() const override { return "T"; }
string getDetail() const override { return ""; }
double calculateAmount(double price) const override { return price; }
void display() const override {
cout << left << setw(12) << name
<< setw(10) << buyerID
<< setw(20) << "临时顾客"
<< setw(20) << address
<< fixed << setprecision(2) << totalPay << '\n';
}
};
class Book {
private:
string bookID;
string bookName;
string author;
string publishing;
double price;
int stock;
public:
Book() : bookID(""), bookName(""), author(""), publishing(""), price(0), stock(0) {}
Book(const string& b_id, const string& b_n, const string& au, const string& pu, double pr, int st)
: bookID(b_id), bookName(b_n), author(au), publishing(pu), price(pr), stock(st) {}
void display() const {
cout << left << setw(15) << bookID
<< setw(24) << bookName
<< setw(18) << author
<< setw(22) << publishing
<< setw(10) << fixed << setprecision(2) << price
<< stock << '\n';
}
string getBookID() const { return bookID; }
string getBookName() const { return bookName; }
string getAuthor() const { return author; }
string getPublishing() const { return publishing; }
double getPrice() const { return price; }
int getStock() const { return stock; }
void setStock(int st) { stock = st; }
};
class Purchase {
private:
string buyerName;
int buyerID;
string date;
string address;
double totalAmount;
double actualAmount;
vector
public:
Purchase(const string& bn, int bid, const string& d, const string& addr, double total, double actual)
: buyerName(bn), buyerID(bid), date(d), address(addr), totalAmount(total), actualAmount(actual) {}
void addBookID(const string& bookID) { bookIDs.push_back(bookID); }
void display(const vector
cout << UI::border(90, '=') << '\n';
cout << "购书人: " << buyerName << " (ID: " << buyerID << ")\n";
cout << "日期: " << date << ",地址: " << address << '\n';
cout << fixed << setprecision(2)
<< "应付金额: " << totalAmount << " 元,实付金额: " << actualAmount << " 元\n";
cout << UI::border(90, '-') << '\n';
cout << left << setw(15) << "书号"
<< setw(24) << "书名"
<< setw(18) << "作者"
<< setw(22) << "出版社"
<< "定价\n";
cout << UI::border(90, '-') << '\n';
for (const string& id : bookIDs) {
bool found = false;
for (const Book& book : books) {
if (book.getBookID() == id) {
cout << left << setw(15) << book.getBookID()
<< setw(24) << book.getBookName()
<< setw(18) << book.getAuthor()
<< setw(22) << book.getPublishing()
<< fixed << setprecision(2) << book.getPrice() << '\n';
found = true;
break;
}
}
if (!found) {
cout << left << setw(15) << id
<< setw(24) << "[未知图书]"
<< setw(18) << ""
<< setw(22) << ""
<< "0.00\n";
}
}
cout << UI::border(90, '=') << '\n';
}
string getDate() const { return date; }
string getBuyerName() const { return buyerName; }
int getBuyerID() const { return buyerID; }
string getAddress() const { return address; }
double getTotalAmount() const { return totalAmount; }
double getActualAmount() const { return actualAmount; }
const vector
};
vector
vector
string token;
istringstream tokenStream(s);
while (getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
class LibraryManager {
private:
vector<Buyer*> buyers;
vector
vector
vector
string getCurrentDate() const {
time_t now = time(nullptr);
tm localTime{};
ifdef _WIN32
localtime_s(&localTime, &now);
else
localtime_r(&now, &localTime);
endif
char buffer[32];
strftime(buffer, sizeof(buffer), "%Y-%m-%d", &localTime);
return string(buffer);
}
void createEmptyFilesIfNotExist() {
ifstream checkFile("LibraryHouse.txt");
if (!checkFile.good()) {
ofstream("LibraryHouse.txt") << "书号,书名,作者,出版社,价格,库存\n";
}
checkFile.close();
checkFile.open("LibraryDeal.txt");
if (!checkFile.good()) {
ofstream("LibraryDeal.txt") << "购书人姓名,购书人编号,日期,地址,应付金额,实付金额,购买的书号列表\n";
}
checkFile.close();
checkFile.open("LibraryMember.txt");
if (!checkFile.good()) {
ofstream("LibraryMember.txt") << "类型,姓名,编号,会员级别/折扣率,地址,总消费金额\n";
}
checkFile.close();
checkFile.open("LibraryTem.txt");
if (!checkFile.good()) {
ofstream("LibraryTem.txt") << "姓名,地址,总消费金额\n";
}
}
bool buyerIdExists(int id) const {
for (const auto buyer : buyers) {
if (buyer->getID() == id) return true;
}
return false;
}
bool bookIdExists(const string& id) const {
for (const auto& book : books) {
if (book.getBookID() == id) return true;
}
return false;
}
Buyer* findBuyerById(int id) {
for (auto buyer : buyers) {
if (buyer->getID() == id) return buyer;
}
return nullptr;
}
Book* findBookById(const string& id) {
for (auto& book : books) {
if (book.getBookID() == id) return &book;
}
return nullptr;
}
TemporaryBuyer* findTempBuyerByName(const string& name) {
for (auto& tb : tempBuyers) {
if (tb.getBuyerName() == name) return &tb;
}
return nullptr;
}
public:
LibraryManager() {
createEmptyFilesIfNotExist();
loadData();
}
~LibraryManager() {
for (auto buyer : buyers) {
delete buyer;
}
}
void loadData() {
string line;
ifstream bookFile("LibraryHouse.txt");
getline(bookFile, line);
while (getline(bookFile, line)) {
vector
if (tokens.size() >= 6) {
books.emplace_back(tokens[0], tokens[1], tokens[2], tokens[3], stod(tokens[4]), stoi(tokens[5]));
}
}
bookFile.close();
ifstream memberFile("LibraryMember.txt");
getline(memberFile, line);
while (getline(memberFile, line)) {
vector
if (tokens.size() >= 6) {
string type = tokens[0];
string name = tokens[1];
int id = stoi(tokens[2]);
string detail = tokens[3];
string address = tokens[4];
double totalPay = stod(tokens[5]);
if (type == "M") buyers.push_back(new Member(name, id, stoi(detail), address, totalPay));
else if (type == "H") buyers.push_back(new HonouredGuest(name, id, stod(detail), address, totalPay));
else if (type == "L") buyers.push_back(new Layfolk(name, id, address, totalPay));
}
}
memberFile.close();
ifstream tempFile("LibraryTem.txt");
getline(tempFile, line);
while (getline(tempFile, line)) {
vector
if (tokens.size() >= 3) {
tempBuyers.emplace_back(tokens[0], tokens[1], stod(tokens[2]));
}
}
tempFile.close();
ifstream dealFile("LibraryDeal.txt");
getline(dealFile, line);
while (getline(dealFile, line)) {
vector
if (tokens.size() >= 7) {
Purchase purchase(tokens[0], stoi(tokens[1]), tokens[2], tokens[3], stod(tokens[4]), stod(tokens[5]));
for (size_t i = 6; i < tokens.size(); ++i) {
purchase.addBookID(tokens[i]);
}
purchases.push_back(purchase);
}
}
dealFile.close();
cout << "数据加载完成!\n";
}
void saveData() {
ofstream bookFile("LibraryHouse.txt");
bookFile << "书号,书名,作者,出版社,价格,库存\n";
for (const auto& book : books) {
bookFile << book.getBookID() << ","
<< book.getBookName() << ","
<< book.getAuthor() << ","
<< book.getPublishing() << ","
<< book.getPrice() << ","
<< book.getStock() << "\n";
}
bookFile.close();
ofstream memberFile("LibraryMember.txt");
memberFile << "类型,姓名,编号,会员级别/折扣率,地址,总消费金额\n";
for (const auto buyer : buyers) {
memberFile << buyer->getType() << ","
<< buyer->getBuyerName() << ","
<< buyer->getID() << ","
<< buyer->getDetail() << ","
<< buyer->getAddress() << ","
<< buyer->getTotalPay() << "\n";
}
memberFile.close();
ofstream tempFile("LibraryTem.txt");
tempFile << "姓名,地址,总消费金额\n";
for (const auto& tempBuyer : tempBuyers) {
tempFile << tempBuyer.getBuyerName() << ","
<< tempBuyer.getAddress() << ","
<< tempBuyer.getTotalPay() << "\n";
}
tempFile.close();
ofstream dealFile("LibraryDeal.txt");
dealFile << "购书人姓名,购书人编号,日期,地址,应付金额,实付金额,购买的书号列表\n";
for (const auto& purchase : purchases) {
dealFile << purchase.getBuyerName() << ","
<< purchase.getBuyerID() << ","
<< purchase.getDate() << ","
<< purchase.getAddress() << ","
<< purchase.getTotalAmount() << ","
<< purchase.getActualAmount();
for (const auto& bookID : purchase.getBookIDs()) {
dealFile << "," << bookID;
}
dealFile << "\n";
}
dealFile.close();
cout << "数据保存完成!\n";
}
void displayAllBuyers() {
UI::clearScreen();
UI::printTitle("会员信息列表", 66);
cout << left << setw(12) << "姓名"
<< setw(10) << "编号"
<< setw(20) << "会员类型"
<< setw(20) << "地址"
<< "消费金额\n";
cout << UI::border(72, '-') << '\n';
for (const auto buyer : buyers) {
buyer->display();
}
cout << "\n";
UI::printTitle("临时顾客列表", 66);
cout << left << setw(12) << "姓名"
<< setw(10) << "编号"
<< setw(20) << "类型"
<< setw(20) << "地址"
<< "消费金额\n";
cout << UI::border(72, '-') << '\n';
for (const auto& tempBuyer : tempBuyers) {
tempBuyer.display();
}
}
void displayAllBooks() {
UI::clearScreen();
UI::printTitle("图书信息列表", 96);
cout << left << setw(15) << "书号"
<< setw(24) << "书名"
<< setw(18) << "作者"
<< setw(22) << "出版社"
<< setw(10) << "定价"
<< "库存\n";
cout << UI::border(96, '-') << '\n';
for (const auto& book : books) {
book.display();
}
}
void addBuyer() {
UI::clearScreen();
UI::printTitle("添加新会员", 54);
string name = InputHelper::readLine("请输入会员姓名: ");
int id = InputHelper::readInt("请输入会员编号: ", 1);
if (buyerIdExists(id)) {
cout << "会员编号已存在,添加失败!\n";
return;
}
string address = InputHelper::readLine("请输入会员地址: ");
int type = InputHelper::readInt("请输入会员类型 (1: 普通会员, 2: 贵宾会员, 3: 普通用户): ", 1, 3);
Buyer* newBuyer = nullptr;
if (type == 1) {
int grade = InputHelper::readInt("请输入会员级别 (1-5): ", 1, 5);
newBuyer = new Member(name, id, grade, address, 0.0);
}
else if (type == 2) {
double discount = InputHelper::readDouble("请输入折扣率 (0-1): ", 0.0, 1.0);
newBuyer = new HonouredGuest(name, id, discount, address, 0.0);
}
else {
newBuyer = new Layfolk(name, id, address, 0.0);
}
buyers.push_back(newBuyer);
cout << "会员添加成功!\n";
}
void addBook() {
UI::clearScreen();
UI::printTitle("添加新图书", 54);
string id = InputHelper::readLine("请输入书号: ");
if (bookIdExists(id)) {
cout << "书号已存在,添加失败!\n";
return;
}
string name = InputHelper::readLine("请输入书名: ");
string author = InputHelper::readLine("请输入作者: ");
string publishing = InputHelper::readLine("请输入出版社: ");
double price = InputHelper::readDouble("请输入定价: ", 0.0);
int stock = InputHelper::readInt("请输入库存: ", 0);
books.emplace_back(id, name, author, publishing, price, stock);
cout << "图书添加成功!\n";
}
void searchBuyerByName() {
UI::clearScreen();
UI::printTitle("按姓名查找会员", 54);
string target = InputHelper::readLine("请输入会员姓名关键字: ");
bool found = false;
cout << left << setw(12) << "姓名"
<< setw(10) << "编号"
<< setw(20) << "会员类型"
<< setw(20) << "地址"
<< "消费金额\n";
cout << UI::border(72, '-') << '\n';
for (const auto buyer : buyers) {
if (buyer->getBuyerName().find(target) != string::npos) {
buyer->display();
found = true;
}
}
for (const auto& tempBuyer : tempBuyers) {
if (tempBuyer.getBuyerName().find(target) != string::npos) {
tempBuyer.display();
found = true;
}
}
if (!found) {
cout << "未找到相关会员!\n";
}
}
void searchBookByName() {
UI::clearScreen();
UI::printTitle("按书名查找图书", 54);
string target = InputHelper::readLine("请输入图书名称关键字: ");
bool found = false;
cout << left << setw(15) << "书号"
<< setw(24) << "书名"
<< setw(18) << "作者"
<< setw(22) << "出版社"
<< setw(10) << "定价"
<< "库存\n";
cout << UI::border(96, '-') << '\n';
for (const auto& book : books) {
if (book.getBookName().find(target) != string::npos) {
book.display();
found = true;
}
}
if (!found) {
cout << "未找到相关图书!\n";
}
}
void makeTransaction() {
UI::clearScreen();
UI::printTitle("购买图书", 54);
int buyerId = InputHelper::readInt("请输入购书人编号 (新顾客请输入0): ", 0);
Buyer* buyer = nullptr;
TemporaryBuyer* tempBuyer = nullptr;
if (buyerId != 0) {
buyer = findBuyerById(buyerId);
if (!buyer) {
cout << "未找到该购书人!\n";
return;
}
}
else {
cout << "您是新顾客,将被记录为临时顾客。\n";
string name = InputHelper::readLine("请输入您的姓名: ");
string address = InputHelper::readLine("请输入您的地址: ");
tempBuyer = findTempBuyerByName(name);
if (!tempBuyer) {
tempBuyers.emplace_back(name, address, 0.0);
tempBuyer = &tempBuyers.back();
}
}
displayAllBooks();
int count = InputHelper::readInt("\n请输入要购买的图书数量: ", 1);
vector
double totalPrice = 0.0;
for (int i = 0; i < count; ++i) {
string bookId = InputHelper::readLine("请输入第 " + to_string(i + 1) + " 本图书的书号: ");
Book* book = findBookById(bookId);
if (!book) {
cout << "未找到该图书,请重新输入。\n";
--i;
continue;
}
if (book->getStock() <= 0) {
cout << "该图书库存不足,请重新输入。\n";
--i;
continue;
}
selectedBookIDs.push_back(bookId);
totalPrice += book->getPrice();
book->setStock(book->getStock() - 1);
}
- double actualAmount = buyer ? buyer->calculateAmount(totalPrice)
- tempBuyer->calculateAmount(totalPrice);
if (buyer) {
buyer->addConsume(actualAmount);
}
else {
tempBuyer->addConsume(actualAmount);
}
string buyerName = buyer ? buyer->getBuyerName() : tempBuyer->getBuyerName();
int buyerIdRecord = buyer ? buyer->getID() : 0;
string address = buyer ? buyer->getAddress() : tempBuyer->getAddress();
Purchase purchase(buyerName, buyerIdRecord, getCurrentDate(), address, totalPrice, actualAmount);
for (const auto& id : selectedBookIDs) {
purchase.addBookID(id);
}
purchases.push_back(purchase);
cout << "\n交易完成!\n";
cout << fixed << setprecision(2)
<< "应付金额: " << totalPrice << " 元\n"
<< "实付金额: " << actualAmount << " 元\n";
}
void displayAllPurchases() {
UI::clearScreen();
UI::printTitle("交易记录列表", 96);
if (purchases.empty()) {
cout << "当前没有交易记录!\n";
return;
}
for (size_t i = 0; i < purchases.size(); ++i) {
cout << "\n═══ 交易记录 " << (i + 1) << " ═══\n";
purchases[i].display(books);
}
}
void buyerManagementMenu() {
while (true) {
UI::clearScreen();
cout << "╒═════════════════会员管理═══╕\n";
cout << "│ │\n";
cout << "│ 1. 显示所有会员 │\n";
cout << "│ 2. 按姓名查找会员 │\n";
cout << "│ 3. 添加新会员 │\n";
cout << "│ 4. 返回主菜单 │\n";
cout << "│ │\n";
cout << "╘════════════════════════════╛\n";
int choice = InputHelper::readInt("请输入您的选择: ", 1, 4);
switch (choice) {
case 1: displayAllBuyers(); UI::pause(); break;
case 2: searchBuyerByName(); UI::pause(); break;
case 3: addBuyer(); UI::pause(); break;
case 4: return;
}
}
}
void bookManagementMenu() {
while (true) {
UI::clearScreen();
cout << "╒═════════════════图书管理═══╕\n";
cout << "│ │\n";
cout << "│ 1. 显示所有图书 │\n";
cout << "│ 2. 按书名查找图书 │\n";
cout << "│ 3. 添加新图书 │\n";
cout << "│ 4. 返回主菜单 │\n";
cout << "│ │\n";
cout << "╘════════════════════════════╛\n";
int choice = InputHelper::readInt("请输入您的选择: ", 1, 4);
switch (choice) {
case 1: displayAllBooks(); UI::pause(); break;
case 2: searchBookByName(); UI::pause(); break;
case 3: addBook(); UI::pause(); break;
case 4: return;
}
}
}
void transactionMenu() {
while (true) {
UI::clearScreen();
cout << "╒═════════════════交易处理═══╕\n";
cout << "│ │\n";
cout << "│ 1. 购买图书 │\n";
cout << "│ 2. 返回主菜单 │\n";
cout << "│ │\n";
cout << "╘════════════════════════════╛\n";
int choice = InputHelper::readInt("请输入您的选择: ", 1, 2);
switch (choice) {
case 1: makeTransaction(); UI::pause(); break;
case 2: return;
}
}
}
void changeTheme() {
UI::clearScreen();
UI::printThemeMenu();
int themeNum = InputHelper::readInt("请输入所需主题编号: ", 0, 6);
switch (themeNum) {
case 0: UI::setTheme("\033[0m"); break;
case 1: UI::setTheme("\033[31m"); break;
case 2: UI::setTheme("\033[32m"); break;
case 3: UI::setTheme("\033[33m"); break;
case 4: UI::setTheme("\033[34m"); break;
case 5: UI::setTheme("\033[35m"); break;
case 6: UI::setTheme("\033[36m"); break;
}
cout << "主题修改成功!\n";
}
void mainMenu() {
while (true) {
UI::clearScreen();
cout << UI::g_theme;
cout << "╒═书店购书管理系统═══════════════╕\n";
cout << "│ │\n";
cout << "│ 1. 会员管理 │\n";
cout << "│ 2. 图书管理 │\n";
cout << "│ 3. 交易处理 │\n";
cout << "│ 4. 查看交易记录 │\n";
cout << "│ 5. 更改主题 │\n";
cout << "│ 0. 退出系统 │\n";
cout << "│ │\n";
cout << "╘════════════════════════════════╛\n";
int choice = InputHelper::readInt("请输入您的选择: ", 0, 5);
switch (choice) {
case 1: buyerManagementMenu(); break;
case 2: bookManagementMenu(); break;
case 3: transactionMenu(); break;
case 4: displayAllPurchases(); UI::pause(); break;
case 5: changeTheme(); UI::pause(); break;
case 0:
saveData();
cout << "感谢使用书店购书管理系统,再见!\n";
return;
}
}
}
};
int main() {
LibraryManager manager;
manager.mainMenu();
return 0;
}
五、重构的软件的测试截图




六、总结
这次二次开发最大的收获,不是简单“把代码改能跑”,而是学会了从软件工程角度审视已有项目。
1. 难点
本次分析和重构中,最有难度的地方主要有两个:
- 理解原有类之间的关系:在 Buyer 的多态设计,以及不同买家类型对支付逻辑的影响。
- 定位隐藏的业务逻辑错误:例如“累计消费”与“本次订单金额”混用的问题,此 bug 并未及时发现,在本次作业接近尾声时偶然发现。
2. 花时间较久的部分
- 阅读原代码并梳理类关系
- 找出输入、文件存储、业务计算之间的关系
3. 对逆向软件工程的思考
阅读别人的代码,和自己从零写代码是完全不同的体验。
自己写代码时,思维连续;而阅读已有项目时,需要先逆向理解,更耗时耗力:
- 这个系统的核心功能是什么
- 各个类分别承担什么职责
- 经常忘记类的作用及关系
- 哪些地方是“表面能跑”,但内部设计并不合理
这让我意识到:
- 养成良好的注释习惯。
- 软件工程不仅是实现功能,更重要的是保证代码可读、可维护、可扩展。
- 好的重构不是盲目推翻重写,而是在深度理解原设计的基础上,找到最关键的问题并逐步优化。
- 测试是二次开发中非常重要的一环,只有通过测试,才能证明改进真正有效。
总体来看,这次作业让我从“写程序”进一步进入到“分析系统、发现问题、改进设计”的层面,对软件工程实践有了更深的理解。

浙公网安备 33010602011771号