关键在于用Java面向对象思想厘清类职责:Book只封装核心字段与业务标识(如isbn),LibrarySystem协调业务逻辑,CommandParser解析输入,数据访问与展示层严格分离,确保单一职责与数据一致性。

图书类(Book)该封装哪些字段和行为?
别一上来就加 id、isbn、publishDate 堆满字段。先想清楚:谁会用它?怎么用?
-
title、author、price是必填且高频访问的,必须有 getter/setter -
isbn建议用String而非long—— 实际 ISBN 有短横线(如"978-7-04-051234-5"),用数字类型会丢格式、转义出错 - 别在
Book里写saveToDatabase()或printInfo()这类越界方法 —— 它只负责“是什么”,不负责“怎么存”或“怎么展示” - 重写
equals()和hashCode()时,只基于业务唯一标识(比如isbn),别把price或title算进去 —— 同一本书价格可能调整,但 ISBN 不变
如何用 ArrayList 管理图书集合?
初学者常把“存书”直接写成 new ArrayList() 然后到处传引用,结果改一处、全乱套。得控制访问入口。
- 把集合声明为
private final List,避免外部直接 add/removebooks = new ArrayList(); - 提供明确语义的方法,比如:
addBook(Book book)(内部校验重复 ISBN)、findBooksByAuthor(String author)(返回新ArrayList,不暴露原始引用) - 别用
for (int i = 0; i 遍历后调books.remove(i)—— 下标会错位,删不干净;改用Iterator或removeIf() - 如果后续要按 ISBN 快速查,现在就该考虑换成
Map,而不是硬撑着用ArrayList+ 循环遍历
用户操作逻辑该放在哪个类里?
很多作业代码把“借书”“还书”“打印列表”全塞进 Main 方法,或者一股脑扔给 Book 类 —— 这违背单一职责。
- 建一个
LibrarySystem类,作为协调者:它持有books集合,也持有当前登录用户(可先用String currentUser模拟),但它不处理界面输入 - 输入解析(比如识别用户敲的是
"add java入门 59.9")单独抽成CommandParser类,返回结构化命令对象(如new AddCommand("java入门", "王磊", 59.9)) - 真正执行动作的,是
LibrarySystem的方法,比如execute(AddCommand cmd)—— 它决定校验规则、是否允许添加、要不要触发日志 - 千万别让
Book自己去读控制台、也不让它调System.out.println()—— 控制台输出属于表现层,和领域模型隔开
public class LibrarySystem {
private final List books = new ArrayList<>();
public void addBook(Book book) {
if (book == null || findBookByIsbn(book.getIsbn()) != null) {
throw new IllegalArgumentException("ISBN 已存在或图书为空");
}
books.add(book);
}
public List findBooksByAuthor(String author) {
return books.stream()
.filter(b -> b.getAuthor().contains(author))
.collect(Collectors.toList());
}
private Book findBookByIsbn(String isbn) {
return books.stream()
.filter(b -> Objects.equals(b.getIsbn(), isbn))
.findFirst()
.orElse(null);
}
}
最易被忽略的点:没有统一的数据一致性检查入口。比如“同一本书不能同时被两人借出”,这个规则如果散落在多个方法里手动判断,很快就会漏。必须有一个中心化的状态管理点,哪怕初期只是个简单的 Map borrowedStatus ,也要从一开始就设计好归属位置。









