关于书店管理系统的二次开发

news/2025/2/27 17:33:01/文章来源:https://www.cnblogs.com/mazl/p/18741559

一、来源
来自同学期末大作业。实现了基本的书店业务功能,包括书本信息管理、客户信息管理、购物车操作以及订单生成与保存等。
二、运行环境 + 运行结果的截图
操作系统: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.在功能4结账读取用户输入的客户编号时,没有对输入进行有效性验证,缺少输入验证。如果用户输入非数字字符或不存在的编号,程序会抛出异常导致崩溃。 2.由于没有涉及到书本库存的管理,要是有卖光的书仍被加入购物车并生成订单,会给书店运营带来麻烦。因此添加此功能让书店需要实时掌握书本库存数量,当库存不足时,应阻止相应书本继续被添加到购物车,并提示顾客库存不足。 3.如果客户搬家或者升级为更高等级的会员,在系统中无法进行相应的更新,客户的信息可能会发生变化,导致客户信息不准确。因此还需要提供修改客户信息的功能。 4.只能根据编号查找书本过于单一,用户根据编号很容易输错,缺乏多样化的查询功能会降低系统的使用效率,在没有重名的情况下应该提供根据书名、作者、出版社等多种条件来查找书本。

四、新代码附上
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;}
};
  1. 增加了查询书籍的方法
点击查看代码
   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";}}
五、重构软件测试截图 1.![](https://img2024.cnblogs.com/blog/3607123/202502/3607123-20250227171010360-1324039542.png) 2.![](https://img2024.cnblogs.com/blog/3607123/202502/3607123-20250227171023518-206830143.png) 3.![](https://img2024.cnblogs.com/blog/3607123/202502/3607123-20250227171028732-2092133225.png) 4.![](https://img2024.cnblogs.com/blog/3607123/202502/3607123-20250227171035545-751924393.png)

六、总结

  1. 难点
    理解原有代码逻辑:原代码结构不够清晰,导致我要花费大量时间去看懂功能实现的逻辑,部分功能实现分散在多个类中,需要深入理解各个类之间的关系和数据流向,增加了开发难度。
    设计模式的应用:引入工厂模式优化客户类型判断逻辑时,需要对设计模式有深入的理解和实践经验。确保新的设计能够正确创建不同类型的客户对象,并且与原系统的其他部分兼容,是一个挑战。2. 花时间比较久的部分
  2. 花时间比较久的部分
    库存管理涉及到多个模块的联动,不仅仅要添加一个类,为了书本信息的加载、添加书本数量的变量等等,需要对多个类进行修改和添加,以达到最终效果。我花费了很大的时间去阅读代码和补全代码,当我需要确认库存时我首先要修改book类添加剩余数量的变量,其次还要更改书本信息的读写,每次购买后还需要结算修改库存。类与类之间的联动如同牵一发而动全身,修改量很大。
    3.逆向软件工程的一些思考
    从修改角度说,我深刻认识到良好的代码质量与清晰的代码逻辑对于软件维护和扩展的重要性。原系统中存在的代码质量问题,如类的职责不单一、命名不规范等,增加了理解和修改代码的难度。应遵循良好的编程规范和设计原则,提高代码的可读性和可维护性。
    同时从功能开发角度说,我发现了在输入时异常处理的重要性,很多潜在的问题都是由于缺乏异常处理机制导致的。同时我也意识到要从用户体验的优化,从用户的使用视角出发,通过增加多样化的查询功能和输入验证,系统的易用性得到了提升。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/890729.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CNC数控机床运行状态参数采集联网 对接软件MES 系统

IP 端口 TCP端口 流程任务 当前位置或者目标位置及描述 状态 需要接口内容 请求地址-AGV 请求AGV参数 请求AGV返回信息 PLC-地址 写入PLC值 读取PLC值 EDM-地址 写入EDM值 读取EDM值进入上下料进程 进入EDM上料台动作-动作 即将进入EDM上料台 "1.达…

Redis+Docker集群部署

机器故障了怎么办? Redis 是内存数据库,我们知道可以通过持久化机制,保存快照或者保存记录日志的方式,将数据持久化到磁盘。但是,如果机器故障了或磁盘坏了,数据就不就全没了吗?这种情况应该怎么办呢?别担心,考虑主从模式。 主从模式 给主节点 Master 配置一个从节点 …

【T20天正电气V10.0软件下载与安装教程】

1、安装包 扫描下方二维码关注「软知社」,后台回复【024】三位数字即可免费获取分享链接,无广告拒绝套路; 2、安装教程双击T20天正电气V10.0安装包,弹窗安装对话框选择我接收,点击下一步选择安装位置,点击下一步点击下一步等待安装进度完成安装完成,点击完成按钮点击下…

windows底层激活破解一步到位,TSforge也太暴力了!

windows底层激活破解一步到位,TSforge也太暴力了! windows底层激活破解一步到位,TSforge也太暴力了! 微软系统一直是需要收费的,也是电脑用户们经常遇到的问题,市面上也有很多工具, 但是今天的工具是最新的且**呼声最高、最彻底的**,需要的话赶紧保存下来,实际使用只需…

No.23 CSS--定位

一、定义position属性指定了元素的定位类型。其中,绝对定位和固定定位会脱离文档流. 设置定位之后:可以使用四个方向值进行调整位置:Ieft、top、right、bottom.二、相对定位<head><meta charset="UTF-8"><meta name="viewport" content=&q…

机器人保养指南周期性检修

机器人保养指南——那智不二越机器人日常维护、专业维修与周期性检修在进行那智不二越机器人的日常检查、维修、部件更换或任何其他相关作业时,首要且至关重要的一步是确保已切断电源,只有在完全断电的情况下,方可安全地进行后续操作。此外,还应在一次电源等关键位置设置明…

OERV兴趣探索:模拟器移植

最近看了很多开源项目,主要都集中在模拟器方面,我指的是游戏模拟器比如GameBoy或者PlayStation这一类。现在想玩这系列的游戏可以在手机或者电脑下载相应的模拟器,并且获取对应的ROM文件,不过也有一些模拟器是可以运行在Linux上面的,为了进一步探索,我选择了相对较小的项…

HTTP协议与RESTful API实战手册(二):用披萨店故事说透API设计奥秘

title: HTTP协议与RESTful API实战手册(二):用披萨店故事说透API设计奥秘 🍕 date: 2025/2/27 updated: 2025/2/27 author: cmdragon excerpt: 📦 本系列第二篇通过披萨店创业的完整案例,手把手教你: 用外卖订单理解HTTP协议细节 5个RESTful设计常见误区与修正方案 …

全局注册svg批量自动引入,动态修改svg以及样式配置问题

1.安装依赖npm i vite-plugin-svg-icons2.文件存放svg 3.全局组件svg-icon(直接放到全局组件目录下)<template><svg class="svg-icon"><use :xlink:href="`#icon-${props.name}`" class="mySVG":style="stroke: + props.…

msyql中单表语句

二、聚合函数 (1)max 最小值 select max(math) from student (2)min 最大值 select min(math) from student (3)sum 总数 select sum(math) from student (4)avg平均数 select avg(math) from student (5)count 统计个数 select count(math) from stu…

Java SpringBoot实现简易扫码登录流程 附项目代码

SpringBoot实现简易扫码登录流程,附项目代码先总结流程:移动端请求扫码登录,服务端生成二维码并缓存二维码ID和状态,将二维码的Base64格式返回给前端展示; PC端页面轮询检查二维码状态; 手机扫码后调用扫码接口,携带移动端的Token和二维码ID请求服务端,服务端根据扫码的…

Salesforce宣布2025年不招工程师,技术岗位真的会消失吗?

Salesforce CEO Marc Benioff 最近放出了一条让科技圈热议的消息:2025年,Salesforce将不再招聘新的软件工程师。作为全球最大的CRM软件提供商之一,这一决定引发了许多人对AI对就业市场影响的思考。 AI改变工作模式,工程师岗位需求减少 Marc Benioff 在采访中透露,2024年,…