实战-图书管理系统
实战-图书管理系统
用面向对象做图书管理系统:抽象类 Member 与子类权限设计、Book 库存管理、JSON 数据加载与主循环
需求
某社区图书馆要开发一个简单的图书管理系统,支持会员登录、图书借阅、图书归还。
| 功能 | 说明 |
|---|---|
| 会员登录 | 卡号 + 密码登录,登录成功后才能使用系统 |
| 借书 | 借阅库存有余量的图书 |
| 还书 | 归还已借阅的图书 |
| 查看我的借阅 | 展示当前会员已借阅的图书列表 |
| 退出系统 | — |
借阅规则:普通会员最多借 3 本;VIP 会员最多借 6 + VIP等级 本(等级默认 1)。库存不足或已达上限时不能借。
类的设计
| 类 | 职责 |
|---|---|
Book | 一本书:编号、标题、作者、总数、可用数量(私有);借出/归还/查可用 |
Member(抽象类) | 会员公共部分:卡号、姓名、密码(私有)、借阅列表(私有);借书/还书/取密码/取借阅列表;抽象方法 get_max_books() |
NormalMember | 普通会员:get_max_books() 返回 3 |
VIPMember | VIP 会员:多一个 vip_level,get_max_books() 返回 6 + vip_level |
LibrarySystem | 图书馆系统:加载数据、登录、借书、还书、查看借阅、主循环 |
抽象类:规定子类必须实现什么
from abc import ABC, abstractmethod
class Member(ABC): # 继承 ABC(Abstract Base Class) ... @abstractmethod def get_max_books(self) -> int: pass # 只有声明,没有实现抽象类是一种只能被继承、不能被直接实例化的类,作用是规定子类必须实现哪些方法,强制子类遵守统一的代码规范。Python 里的抽象类需要继承 abc 模块的 ABC,抽象方法用 @abstractmethod 装饰。
在这里它的价值是:Member 自己说不清”最多能借几本”,但要求每个子类必须说清楚。
关键代码
图书:私有可用数量 + 借还
class Book: def __init__(self, book_id, title, author, total_num): self.book_id = book_id self.title = title self.author = author self.total_num = total_num self.__available_num = total_num # 可用数量(私有)
def borrow_book(self): if self.__available_num > 0: self.__available_num -= 1 return True return False
def return_book(self): self.__available_num += 1
def get_available_num(self): return self.__available_num会员:借书时先查上限,再查库存
class Member(ABC): def borrow_book(self, book: Book): # 1. 达到最大借阅数量就不给借 if len(self.__borrowed_books) >= self.get_max_books(): print("借阅失败,您的借阅数量已达到最大限制!") return False # 2. 书籍还有余量才借 if book.borrow_book(): self.__borrowed_books.append(book) print(f"{self.name} 已成功借阅图书 {book.title}") return True else: print(f"借阅失败,图书 {book.title} 已被借完!") return False两种会员:用多态实现”上限不同”
class NormalMember(Member): def get_max_books(self) -> int: return 3
class VIPMember(Member): def __init__(self, member_id, name, password, vip_level): super().__init__(member_id, name, password) self.vip_level = vip_level
def get_max_books(self) -> int: return 6 + self.vip_level系统:从 JSON 加载数据(按卡号前缀判断会员类型)
class LibrarySystem: def __init__(self): self.books = {} # {"AI001": Book对象, ...} self.members = {} # {"V001": Member对象, ...} self.current_member: Member | None = None self.load_books_data() self.load_members_data()
def load_members_data(self): with open("data/members.json", "r", encoding="utf-8") as f: members_data = json.load(f) for member in members_data: if member['卡号'].startswith('N'): self.members[member['卡号']] = NormalMember(member['卡号'], member['姓名'], member['密码']) elif member['卡号'].startswith('V'): self.members[member['卡号']] = VIPMember(member['卡号'], member['姓名'], member['密码'], member['会员等级'])数据结构对应关系:books.json 里是 [{"编号","标题","作者","数量"}, ...],members.json 里是 [{"卡号","姓名","密码","会员等级"}, ...](普通会员没有”会员等级”字段)。
主循环
def run(self): if self.login(): # 登录成功才进菜单 while True: print("1. 借阅图书 2. 归还图书 3. 查看借阅 4. 退出系统") choice = input("请选择操作(1-4): ") match choice: case "1": self.borrow_book() case "2": self.return_book() case "3": self.show_borrowed_books() case "4": print("退出系统, Bye Bye ~") break case _: print("无效的选项,请重新选择!")相关
练习题
一、回忆填空(写完再展开按答案)
- 抽象类需要继承
abc模块的 ____ 类,抽象方法用@____装饰 - 抽象类的作用:规定子类 ____;它本身 ____(能/不能)被直接实例化
- 普通会员最多借 ____ 本;VIP 会员最多借 ____ 本
- 借书时要先判断会员的 ____ 是否达到上限,再判断图书的 ____ 是否足够
- 加载会员数据时,用卡号的 ____ 判断是普通会员还是 VIP(N 开头/V 开头)
- 图书的可用数量设为 ____ 属性,对外通过
get_available_num()读取 LibrarySystem里self.books和self.members都是 ____(类型),键是编号/卡号,值是对象
填空答案(做完再点开)
ABC/abstractmethod2. 必须实现哪些方法 / 不能 3. 3 / 6 + VIP等级 4. 已借数量 / 库存(可用数量) 5. 前缀(startswith) 6. 私有 7. 字典
二、裸写题
-
2-1 两种会员的借阅上限 写
NormalMember(上限 3)和VIPMember(上限6 + 等级),都继承抽象类Member;分别实例化并打印各自的上限。提示(先自己想,实在想不出再点开)一级 · 思路:父类定规矩(抽象方法),子类各自给答案 二级 · 方法:
class Member(ABC)+@abstractmethod def get_max_books(self)三级 · 骨架:VIP 的__init__里先super().__init__(...)再存vip_level -
2-2 图书库存 写
Book类:总数量 + 私有可用数量;borrow_book()库存为 0 时返回 False,return_book()归还加一。提示一级 · 思路:可用数量只让类内部改,外面只能读 二级 · 方法:
self.__available_num/get_available_num()三级 · 骨架:if self.__available_num > 0: self.__available_num -= 1; return True -
2-3 借书流程 给
Member加borrow_book(book):先判断是否达到上限,再调用书的borrow_book();达到上限时打印提示并返回 False。提示一级 · 思路:两道关卡,先自己的额度、再书的库存 二级 · 方法:
len(self.get_borrowed_books()) >= self.get_max_books()三级 · 骨架:借成功要append到借阅列表里
参考答案(做完再点开)
from abc import ABC, abstractmethod
class Book: def __init__(self, book_id, title, author, total_num): self.book_id = book_id self.title = title self.author = author self.total_num = total_num self.__available_num = total_num
def borrow_book(self): if self.__available_num > 0: self.__available_num -= 1 return True return False
def return_book(self): self.__available_num += 1
def get_available_num(self): return self.__available_num
class Member(ABC): def __init__(self, member_id, name, password): self.member_id = member_id self.name = name self.__password = password self.__borrowed_books = []
def borrow_book(self, book: Book): if len(self.__borrowed_books) >= self.get_max_books(): print(f"{self.name} 借阅失败,已达到最大借阅数量 {self.get_max_books()} 本") return False if book.borrow_book(): self.__borrowed_books.append(book) print(f"{self.name} 已成功借阅图书 {book.title}") return True print(f"{self.name} 借阅失败,图书 {book.title} 已被借完") return False
def get_borrowed_books(self): return self.__borrowed_books
@abstractmethod def get_max_books(self) -> int: pass
class NormalMember(Member): def get_max_books(self) -> int: return 3
class VIPMember(Member): def __init__(self, member_id, name, password, vip_level): super().__init__(member_id, name, password) self.vip_level = vip_level
def get_max_books(self) -> int: return 6 + self.vip_level
# 测试normal = NormalMember("N001", "小王", "123456")vip = VIPMember("V001", "王林", "666888", 6)print(normal.get_max_books(), vip.get_max_books()) # 3 12
book = Book("AI001", "LangChain入门与实践", "李智慧", 2)for i in range(4): normal.borrow_book(book) # 第 4 次会因达到上限而失败print("剩余库存:", book.get_available_num())
book.return_book()print("归还后剩余:", book.get_available_num())评论区
如果你喜欢,那么欢迎来到我的世界!
了解更多













