一、来源
来自同学期末大作业。实现了基本的书店业务功能,包括书本信息管理、客户信息管理、购物车操作以及订单生成与保存等。
二、运行环境 + 运行结果的截图
操作系统:Windows 11
开发工具:Visual Studio 2022
// BookStore.h
点击查看代码
#ifndef BOOKSTORE_H
#define BOOKSTORE_H
#include <iostream>
#include "ShoppingCart.h"
#include <sstream>
#include <fstream>
#include "Book.h"
#include "buyer.h"
#include "layfolk.h"
#include "honoured_guest.h"
#include "member.h"// 图书商店类,用于管理图书和客户信息
class BookStore {
public:std::vector<Book> books; // 图书列表std::vector<buyer *> buyers; // 客户列表// 从文件中加载图书信息void loadBooksFromFile(const std::string& filename) {std::ifstream file(filename);std::string line, isbn, title, author, publishing, price;if (file.is_open()) {while (getline(file, line)) {std::istringstream iss(line);getline(iss, isbn, ',');getline(iss, title, ',');getline(iss, author, ',');getline(iss, publishing, ',');getline(iss, price);books.push_back(Book(isbn, title, author, std::stod(price), publishing));}file.close();cout << "图书信息获取成功" << endl;}// 分配 ID 给图书Book book1 = findBookByISBN(books[0].getbood_id());Book book2 = findBookByISBN(books[1].getbood_id());ShoppingCart cart1; // 购物车 1ShoppingCart cart2; // 购物车 2ShoppingCart cart3; // 购物车 3// 将图书添加到购物车cart1.addItem(CartItem(book1, 2));cart1.addItem(CartItem(book2, 1));cart2.addItem(CartItem(book1, 2));cart2.addItem(CartItem(book2, 2));cart3.addItem(CartItem(book1, 1));cart3.addItem(CartItem(book2, 1));// 为客户分配购物车buyers[0]->setcar(cart1);buyers[1]->setcar(cart2);buyers[2]->setcar(cart3);}// 更新图书信息void updatebooks() {string id;cout << "请输入需要更新的图书 ID:";cin >> id;Book * b = nullptr;string name;double price;for (int i = 0; i < books.size(); i++) {if (id == books[i].id) {b = &(books[i]);}}if (!b) {cout << "未找到该图书\n";} else {cout << "请输入新的图书名称:";cin >> name;cout << "请输入新的图书价格:";cin >> price;b->name = name;b->price = price;}}// 从文件中加载客户信息void loadCustomersFromFile(const std::string& filename) {std::ifstream file(filename);std::string line, id, name, address, bgrade, pay, dis;if (file.is_open()) {while (getline(file, line)) {std::istringstream iss(line);getline(iss, bgrade, ',');getline(iss, name, ',');getline(iss, id, ',');// 创建普通用户if (bgrade == "普通") {getline(iss, address, ',');getline(iss, pay);buyers.push_back(new layfolk(name, id, address, std::stod(pay)));}// 创建贵宾else if (bgrade == "贵宾") {getline(iss, dis, ',');getline(iss, address, ',');getline(iss, pay);buyers.push_back(new honoured_guest(name, id, address, std::stod(pay), std::stod(dis)));}// 创建会员else if (bgrade == "会员") {getline(iss, bgrade, ',');getline(iss, address, ',');getline(iss, pay);buyers.push_back(new member(name, id, address, std::stod(pay), std::stoi(bgrade)));}}file.close();cout << "客户信息获取成功" << endl;}}void findallbook() {cout << "图书信息如下:\n";for (auto book : books) {book.display();}}void findallcustomer() {cout << "客户信息如下:\n";for (auto buyer : buyers) {buyer->display();}}// 根据 ISBN 查找图书Book findBookByISBN(const std::string& isbn) {for (auto& book : books) {if (book.id == isbn) {return book;}}throw std::runtime_error("Book not found");}// 根据 ID 查找客户buyer* findCustomerByID(const std::string& id) {for (auto* ber : buyers) {if (ber->getid() == id) {return ber;}}throw std::runtime_error("Customer not found");}
};
#endif// main.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <codecvt>
#include "BookStore.h"
#include "ShoppingCart.h"
#include "Order.h"BookStore store;void pur() {std::string id;// 查询某个用户的订单std::cout << "请输入用户的 ID 号进行查询:";std::cin >> id;buyer* by = store.findCustomerByID(id);Order order(by);order.saveToFile(by->getid() + "order.txt");std::cout << "用户" + by->getbuyname() + "的订单信息已经保存到 " + by->getid() + "order.txt\n";
}void cleanFile() {std::ofstream file1("books.txt", std::ios::trunc); // 打开文件 1 并使用截断模式std::ofstream file2("customers.txt", std::ios::trunc); // 打开文件 2 并使用截断模式// 检查文件是否成功打开if (file1.is_open() && file2.is_open()) {// 关闭文件 1 确保成功打开file1.close(); file1.open("books.txt", std::ios::out | std::ios::trunc); // 重新打开文件 1 并使用截断模式// 关闭文件 2 确保成功打开file2.close(); file2.open("customers.txt", std::ios::out | std::ios::trunc); // 重新打开文件 2 并使用截断模式// 检查文件 2 是否成功打开if (file1.is_open() && file2.is_open()) {std::cout << "文件清空成功!\n";} else {std::cerr << "无法清空文件!\n";}// 关闭文件file1.close();file2.close();} else {std::cerr << "无法清空文件!\n";}
}int main() {int choose;cout << "欢迎使用图书管理系统\n";do {cout << "1.客户信息获取\n" << "2.图书信息获取\n"<< "3.信息查询\n"<< "4.生成订单\n"<< "5.图书信息更新\n"<< "6.清空文件\n"<< "0.退出\n"<< "请选择选项:";cin >> choose;switch (choose) {case 1:store.loadCustomersFromFile("customers.txt"); break;case 2:store.loadBooksFromFile("books.txt"); break;case 3:int xname;cout << "1.查询客户信息\n"<< "2.查询图书信息\n"<< "请输入选择:";cin >> xname;if (xname == 1) {store.findallcustomer();} else {store.findallbook();}break;case 4: pur(); break;case 5:store.updatebooks();break;case 6:cleanFile();break;case 0:return 0;default:return 0;}} while (choose != 0); return 0;
}
四、新代码附上
1.结账时对用户编号有效性验证
点击查看代码
void pur() {std::cout << "请输入用户的编号进行结账:";std::string id;while (!(std::cin >> id) || id.find_first_not_of("0123456789") != std::string::npos) {std::cin.clear();std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');std::cout << "输入无效,请输入数字编号:";}try {buyer* by = store.findCustomerByID(id);Order order(by);order.saveToFile(by->getid() + "order.txt");std::cout << "用户" + by->getbuyname() + "的订单详情已经保存至: " + by->getid() + "order.txt\n";}catch (const std::runtime_error& e) {std::cout << "错误: " << e.what() << std::endl;}
}
2.新增了对于库存书籍的数量的管理,监管书本数量是否有售罄
点击查看代码
#include <iostream>
#include <unordered_map>
#include "Book.h"
class BookInventory {
private:std::unordered_map<std::string, int> inventory; // 书号 -> 库存数量public:// 添加书本到库存void addBook(const Book& book, int quantity) {if (inventory.find(book.getbood_id()) != inventory.end()) {inventory[book.getbood_id()] += quantity;}else {inventory[book.getbood_id()] = quantity;}}// 检查书本库存是否充足bool checkStock(const Book& book, int quantity) {auto it = inventory.find(book.getbood_id());if (it != inventory.end()) {return it->second >= quantity;}return false;}// 减少书本库存bool reduceStock(const Book& book, int quantity) {if (checkStock(book, quantity)) {inventory[book.getbood_id()] -= quantity;return true;}return false;}// 获取书本库存数量int getStock(const Book& book) {auto it = inventory.find(book.getbood_id());if (it != inventory.end()) {return it->second;}return 0;}
};
- 增加了查询书籍的方法
点击查看代码
void findBookByAuthor() {cout << "请输入作者姓名:";string author;cin >> author;bool found = false;cout << "查询结果如下:\n";for (auto& book : books) {if (book.author == author) {book.display();found = true;}}if (!found) {cout << "未找到该作者的图书。\n";}}void findBookByName() {cout << "请输入书名:";string name;cin >> name;bool found = false;cout << "查询结果如下:\n";for (auto& book : books) {if (book.name == name) {book.display();found = true;}}if (!found) {cout << "未找到该书。\n";}}
六、总结
- 难点
理解原有代码逻辑:原代码结构不够清晰,导致我要花费大量时间去看懂功能实现的逻辑,部分功能实现分散在多个类中,需要深入理解各个类之间的关系和数据流向,增加了开发难度。
设计模式的应用:引入工厂模式优化客户类型判断逻辑时,需要对设计模式有深入的理解和实践经验。确保新的设计能够正确创建不同类型的客户对象,并且与原系统的其他部分兼容,是一个挑战。2. 花时间比较久的部分 - 花时间比较久的部分
库存管理涉及到多个模块的联动,不仅仅要添加一个类,为了书本信息的加载、添加书本数量的变量等等,需要对多个类进行修改和添加,以达到最终效果。我花费了很大的时间去阅读代码和补全代码,当我需要确认库存时我首先要修改book类添加剩余数量的变量,其次还要更改书本信息的读写,每次购买后还需要结算修改库存。类与类之间的联动如同牵一发而动全身,修改量很大。
3.逆向软件工程的一些思考
从修改角度说,我深刻认识到良好的代码质量与清晰的代码逻辑对于软件维护和扩展的重要性。原系统中存在的代码质量问题,如类的职责不单一、命名不规范等,增加了理解和修改代码的难度。应遵循良好的编程规范和设计原则,提高代码的可读性和可维护性。
同时从功能开发角度说,我发现了在输入时异常处理的重要性,很多潜在的问题都是由于缺乏异常处理机制导致的。同时我也意识到要从用户体验的优化,从用户的使用视角出发,通过增加多样化的查询功能和输入验证,系统的易用性得到了提升。