图书管理系统主干类为Book、Reader、BorrowRecord和Library,各司其职:Book管理自身借还状态,Reader管控借阅配额,BorrowRecord封装借阅时间与罚金计算,Library仅负责协调调度;泛型集合确保类型安全与角色协作可信。

用最纯粹的面向对象思维设计图书管理系统,关键不是堆砌类或套用语法,而是让每个类真正“像一个活生生的角色”——有明确身份、清晰职责、自主行为,并只和它该打交道的对象说话。泛型集合不是技术点缀,而是支撑这种角色协作的自然容器:它不替你做决策,但让你能干净地持有同类对象,不丢失类型语义,也不引入强制转换风险。
聚焦真实角色,从Book、Reader、BorrowRecord开始
别一上来就写BookRepository或IDataService。先问:系统里有哪些能独立做事的“人”或“物”?答案很朴素:书(Book)、读者(Reader)、借阅这件事本身(BorrowRecord),以及负责协调的图书馆(Library)。这四个就是主干类,其他全是它们的延伸或辅助。
-
Book 管自己能不能被借(
isAvailable())、借出/归还时如何更新状态(borrow()/return()),但不管“谁来借”或“借多久” -
Reader 管自己最多能借几本(
maxBorrow)、当前借了几本(borrowedBooks.size())、能否再借(canBorrow()),但不管图书库存或逾期逻辑 -
BorrowRecord 知道自己的借期、应还日、是否已逾期(
isOverdue())、按天算罚金(getFine()),所有时间与金额计算全由它自己完成 - Library 不存数据,只做调度:接收 Reader 的请求 → 查 Book 状态 → 查 Reader 配额 → 创建 BorrowRecord → 更新双方状态
用泛型集合承载角色关系,不装“万能Object”
泛型不是为了炫技,而是让集合真正成为角色协作的“可信媒介”。比如:
- 用
List<Book>存图书馆全部藏书——你调用get(0)得到的就是 Book,不用 cast,也不怕误操作 - Reader 持有
List<BorrowRecord>记录自己所有借阅历史——每条记录自带计算能力,直接遍历调用record.isOverdue()即可,逻辑不外泄 - Library 内部用
Map<String, Book>按 ISBN 快速索书——键是语义明确的标识,值是完整角色,查完就能直接问它“你能被借吗?”
避免用 List<Object> 或 ArrayList 原生类型——那等于主动放弃编译期检查,把类型错误拖到运行时,违背面向对象“封装+明确契约”的初衷。
构造即约束,拒绝非法对象存在
面向对象的边界从对象诞生那一刻就开始守护。泛型集合能帮你持守这个边界,但前提是对象本身得“生而合法”:
- Book 构造函数必须校验 ISBN 格式、标题非空;缺一不可,否则不许实例化
- Reader 构造时强制传入有效 readerId 和 name,不允许出现“空名字读者”
- BorrowRecord 创建时必须指定借出日期和应还日期,且 dueDate ≥ borrowDate,否则抛异常
这样,放进 List<Book> 的每一本,都是可用、合规、可信赖的实体——集合不再是“筐”,而是“队伍”,成员个个合格。
扩展靠组合与协议,不靠继承爆炸
未来要加学生读者、VIP读者、管理员?别搞 StudentReader extends Reader 堆出一长串子类。更纯粹的做法是:
- Reader 类内含一个
Role枚举(如STUDENT、VIP、ADMIN) - 借阅规则由 Library 根据 role 动态判断,比如
if (reader.getRole() == VIP) maxDays = 60; - 通知方式要从短信换成微信?定义
Notifier接口,让Library调用notifier.send(record),具体实现交给WeChatNotifier,主流程完全无感
泛型集合在这里依然可靠:List<Notifier> 可以容纳任意实现类,Map<String, Reader> 不关心里面是谁,只认它是 Reader——松耦合,高内聚,改起来不伤筋动骨。

















