目录
- [🔷 18 面向对象综合实战------设计一个图书管理系统](#🔷 18 面向对象综合实战——设计一个图书管理系统)
-
- [📑 目录](#📑 目录)
- 一、系统需求分析
-
- [1.1 功能需求](#1.1 功能需求)
- [1.2 核心业务规则](#1.2 核心业务规则)
- 二、类图设计
-
- [2.1 类关系概览](#2.1 类关系概览)
- [2.2 设计模式应用](#2.2 设计模式应用)
- 三、实体类实现
-
- [3.1 图书类(Book)](#3.1 图书类(Book))
- [3.2 读者类(Reader)](#3.2 读者类(Reader))
- [3.3 借阅记录类(BorrowRecord)](#3.3 借阅记录类(BorrowRecord))
- 四、数据访问层
-
- [4.1 图书仓库(BookRepository)](#4.1 图书仓库(BookRepository))
- [4.2 读者仓库(ReaderRepository)](#4.2 读者仓库(ReaderRepository))
- 五、业务逻辑层
-
- [5.1 借阅服务(BorrowService)](#5.1 借阅服务(BorrowService))
- 六、用户界面层
-
- [6.1 主系统类(LibrarySystem - 单例模式)](#6.1 主系统类(LibrarySystem - 单例模式))
- [6.2 程序入口](#6.2 程序入口)
- 七、系统集成与测试
-
- [7.1 运行效果示例](#7.1 运行效果示例)
- [7.2 系统测试要点](#7.2 系统测试要点)
- 八、面向对象设计原则回顾
- 九、常见面试题解析
- 十、总结与下篇预告
-
- 本篇要点
- [📢 下篇预告](#📢 下篇预告)
- [💬 互动话题](#💬 互动话题)
🔷 18 面向对象综合实战------设计一个图书管理系统
更新日期 :2026年5月 | Java入门到精通系列 · 第二阶段·面向对象核心
© 版权声明:本文为原创技术文章,转载请联系作者并注明出处。
📑 目录
一、系统需求分析
1.1 功能需求
| 功能模块 | 描述 | 优先级 |
|---|---|---|
| 图书管理 | 增删改查图书信息 | ⭐⭐⭐ |
| 读者管理 | 注册、查看读者信息 | ⭐⭐⭐ |
| 借阅管理 | 借书、还书、续借 | ⭐⭐⭐ |
| 查询功能 | 按书名、作者、ISBN查询 | ⭐⭐ |
| 逾期管理 | 逾期提醒、罚款计算 | ⭐⭐ |
| 统计报表 | 借阅排行、库存统计 | ⭐ |
1.2 核心业务规则
- 每位读者最多同时借阅 5本 图书
- 借阅期限为 30天,可续借一次(再加30天)
- 逾期罚款:每天 0.1元
- 图书状态:可借出 / 已借出 / 维修中
二、类图设计
2.1 类关系概览
┌──────────────┐ ┌──────────────┐
│ Book │ │ Reader │
├──────────────┤ ├──────────────┤
│ -isbn │ │ -readerId │
│ -title │ │ -name │
│ -author │ │ -phone │
│ -category │ │ -maxBorrow │
│ -status │ │ -borrowedBooks│
├──────────────┤ ├──────────────┤
│ +getInfo() │ │ +canBorrow() │
└──────┬───────┘ └──────┬───────┘
│ │
│ ┌──────────────┐ │
└───>│ BorrowRecord │<─┘
├──────────────┤
│ -recordId │
│ -book │
│ -reader │
│ -borrowDate │
│ -dueDate │
│ -returnDate │
│ -status │
├──────────────┤
│ +isOverdue() │
│ +getFine() │
└──────────────┘
2.2 设计模式应用
| 设计模式 | 应用场景 | 说明 |
|---|---|---|
| 单例模式 | LibrarySystem | 整个系统只有一个实例 |
| 策略模式 | 罚款计算 | 不同类型的罚款策略 |
| 观察者模式 | 逾期提醒 | 逾期时通知读者 |
| 工厂模式 | 创建记录 | 根据类型创建不同记录 |
三、实体类实现
3.1 图书类(Book)
java
/**
* 图书实体类
*/
public class Book {
private String isbn; // ISBN编号
private String title; // 书名
private String author; // 作者
private String publisher; // 出版社
private String category; // 分类
private double price; // 价格
private BookStatus status; // 图书状态
private LocalDate publishDate;// 出版日期
// 图书状态枚举
public enum BookStatus {
AVAILABLE("可借出"),
BORROWED("已借出"),
REPAIRING("维修中"),
LOST("已丢失");
private final String description;
BookStatus(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
// 构造方法
public Book(String isbn, String title, String author,
String publisher, String category, double price) {
this.isbn = isbn;
this.title = title;
this.author = author;
this.publisher = publisher;
this.category = category;
this.price = price;
this.status = BookStatus.AVAILABLE;
this.publishDate = LocalDate.now();
}
// 借出图书
public boolean borrowBook() {
if (status != BookStatus.AVAILABLE) {
System.out.println("《" + title + "》当前不可借出,状态:" + status.getDescription());
return false;
}
this.status = BookStatus.BORROWED;
return true;
}
// 归还图书
public void returnBook() {
this.status = BookStatus.AVAILABLE;
}
// 获取图书详情
public String getInfo() {
return String.format("ISBN: %s | 书名: %s | 作者: %s | 状态: %s",
isbn, title, author, status.getDescription());
}
// Getter和Setter
public String getIsbn() { return isbn; }
public String getTitle() { return title; }
public String getAuthor() { return author; }
public BookStatus getStatus() { return status; }
public double getPrice() { return price; }
// ... 其他getter/setter省略
@Override
public String toString() {
return "Book{" + isbn + ", " + title + ", " + author + ", " + status + "}";
}
}
3.2 读者类(Reader)
java
import java.util.ArrayList;
import java.util.List;
/**
* 读者实体类
*/
public class Reader {
private String readerId; // 读者编号
private String name; // 姓名
private String phone; // 手机号
private String email; // 邮箱
private ReaderType type; // 读者类型
private int maxBorrow; // 最大借阅数
private List<BorrowRecord> borrowedRecords; // 借阅记录
// 读者类型枚举
public enum ReaderType {
STUDENT("学生", 5),
TEACHER("教师", 10),
VIP("VIP会员", 15);
private final String description;
private final int maxBorrow;
ReaderType(String description, int maxBorrow) {
this.description = description;
this.maxBorrow = maxBorrow;
}
public String getDescription() { return description; }
public int getMaxBorrow() { return maxBorrow; }
}
public Reader(String readerId, String name, String phone, ReaderType type) {
this.readerId = readerId;
this.name = name;
this.phone = phone;
this.type = type;
this.maxBorrow = type.getMaxBorrow();
this.borrowedRecords = new ArrayList<>();
}
// 判断是否可以继续借阅
public boolean canBorrow() {
long currentBorrowed = borrowedRecords.stream()
.filter(r -> r.getStatus() == BorrowRecord.BorrowStatus.BORROWING)
.count();
return currentBorrowed < maxBorrow;
}
// 添加借阅记录
public void addBorrowRecord(BorrowRecord record) {
borrowedRecords.add(record);
}
// 获取当前借阅数量
public int getCurrentBorrowCount() {
return (int) borrowedRecords.stream()
.filter(r -> r.getStatus() == BorrowRecord.BorrowStatus.BORROWING)
.count();
}
// 获取读者信息
public String getInfo() {
return String.format("编号: %s | 姓名: %s | 类型: %s | 当前借阅: %d/%d",
readerId, name, type.getDescription(),
getCurrentBorrowCount(), maxBorrow);
}
// Getter
public String getReaderId() { return readerId; }
public String getName() { return name; }
public List<BorrowRecord> getBorrowedRecords() { return borrowedRecords; }
@Override
public String toString() {
return "Reader{" + readerId + ", " + name + ", " + type + "}";
}
}
3.3 借阅记录类(BorrowRecord)
java
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
/**
* 借阅记录实体类
*/
public class BorrowRecord {
private String recordId; // 记录编号
private Book book; // 借阅图书
private Reader reader; // 借阅读者
private LocalDate borrowDate; // 借阅日期
private LocalDate dueDate; // 应还日期
private LocalDate returnDate; // 实际归还日期
private BorrowStatus status; // 借阅状态
private boolean renewed; // 是否已续借
private static final double FINE_PER_DAY = 0.1; // 每天罚款
private static final int BORROW_DAYS = 30; // 借阅天数
// 借阅状态枚举
public enum BorrowStatus {
BORROWING("借阅中"),
RETURNED("已归还"),
OVERDUE("已逾期"),
RENEWED("已续借");
private final String description;
BorrowStatus(String description) {
this.description = description;
}
public String getDescription() { return description; }
}
public BorrowRecord(String recordId, Book book, Reader reader) {
this.recordId = recordId;
this.book = book;
this.reader = reader;
this.borrowDate = LocalDate.now();
this.dueDate = borrowDate.plusDays(BORROW_DAYS);
this.status = BorrowStatus.BORROWING;
this.renewed = false;
}
// 判断是否逾期
public boolean isOverdue() {
if (status == BorrowStatus.RETURNED) {
return false;
}
return LocalDate.now().isAfter(dueDate);
}
// 计算罚款
public double calculateFine() {
LocalDate endDate = (returnDate != null) ? returnDate : LocalDate.now();
if (endDate.isAfter(dueDate)) {
long overdueDays = ChronoUnit.DAYS.between(dueDate, endDate);
return overdueDays * FINE_PER_DAY;
}
return 0;
}
// 续借
public boolean renew() {
if (renewed) {
System.out.println("记录 " + recordId + " 已经续借过,不能再次续借");
return false;
}
if (status != BorrowStatus.BORROWING) {
System.out.println("记录 " + recordId + " 当前状态不可续借");
return false;
}
this.dueDate = dueDate.plusDays(BORROW_DAYS);
this.renewed = true;
this.status = BorrowStatus.RENEWED;
return true;
}
// 归还
public double returnBook() {
this.returnDate = LocalDate.now();
this.status = BorrowStatus.RETURNED;
book.returnBook(); // 更新图书状态
double fine = calculateFine();
if (fine > 0) {
System.out.println("⚠️ 逾期罚款:¥" + fine);
}
return fine;
}
// 获取记录详情
public String getInfo() {
return String.format("记录: %s | 图书: %s | 读者: %s | 借期: %s | 应还: %s | 状态: %s",
recordId, book.getTitle(), reader.getName(),
borrowDate, dueDate, status.getDescription());
}
// Getter
public String getRecordId() { return recordId; }
public Book getBook() { return book; }
public Reader getReader() { return reader; }
public BorrowStatus getStatus() { return status; }
public LocalDate getDueDate() { return dueDate; }
@Override
public String toString() {
return "BorrowRecord{" + recordId + ", " + book.getTitle() + ", " + status + "}";
}
}
四、数据访问层
4.1 图书仓库(BookRepository)
java
import java.util.*;
import java.util.stream.Collectors;
/**
* 图书数据仓库 - 管理所有图书数据
*/
public class BookRepository {
private Map<String, Book> bookMap; // ISBN -> Book
public BookRepository() {
this.bookMap = new HashMap<>();
}
// 添加图书
public void addBook(Book book) {
if (bookMap.containsKey(book.getIsbn())) {
throw new IllegalArgumentException("ISBN " + book.getIsbn() + " 已存在");
}
bookMap.put(book.getIsbn(), book);
System.out.println("✅ 添加图书成功:" + book.getTitle());
}
// 删除图书
public boolean removeBook(String isbn) {
Book removed = bookMap.remove(isbn);
if (removed != null) {
System.out.println("✅ 删除图书成功:" + removed.getTitle());
return true;
}
System.out.println("❌ 未找到ISBN:" + isbn);
return false;
}
// 根据ISBN查找
public Book findByIsbn(String isbn) {
return bookMap.get(isbn);
}
// 按书名模糊查询
public List<Book> findByTitle(String keyword) {
return bookMap.values().stream()
.filter(b -> b.getTitle().contains(keyword))
.collect(Collectors.toList());
}
// 按作者查询
public List<Book> findByAuthor(String author) {
return bookMap.values().stream()
.filter(b -> b.getAuthor().equals(author))
.collect(Collectors.toList());
}
// 按分类查询
public List<Book> findByCategory(String category) {
return bookMap.values().stream()
.filter(b -> b.getCategory().equals(category))
.collect(Collectors.toList());
}
// 获取所有图书
public List<Book> findAll() {
return new ArrayList<>(bookMap.values());
}
// 获取可借图书
public List<Book> findAvailable() {
return bookMap.values().stream()
.filter(b -> b.getStatus() == Book.BookStatus.AVAILABLE)
.collect(Collectors.toList());
}
// 统计各状态图书数量
public Map<Book.BookStatus, Long> countByStatus() {
return bookMap.values().stream()
.collect(Collectors.groupingBy(Book::getStatus, Collectors.counting()));
}
}
4.2 读者仓库(ReaderRepository)
java
import java.util.*;
import java.util.stream.Collectors;
/**
* 读者数据仓库
*/
public class ReaderRepository {
private Map<String, Reader> readerMap;
public ReaderRepository() {
this.readerMap = new HashMap<>();
}
// 注册读者
public void register(Reader reader) {
if (readerMap.containsKey(reader.getReaderId())) {
throw new IllegalArgumentException("读者编号 " + reader.getReaderId() + " 已存在");
}
readerMap.put(reader.getReaderId(), reader);
System.out.println("✅ 读者注册成功:" + reader.getName());
}
// 根据ID查找
public Reader findById(String readerId) {
return readerMap.get(readerId);
}
// 按姓名查询
public List<Reader> findByName(String name) {
return readerMap.values().stream()
.filter(r -> r.getName().contains(name))
.collect(Collectors.toList());
}
// 获取所有读者
public List<Reader> findAll() {
return new ArrayList<>(readerMap.values());
}
// 获取有逾期记录的读者
public List<Reader> findOverdueReaders() {
return readerMap.values().stream()
.filter(r -> r.getBorrowedRecords().stream()
.anyMatch(BorrowRecord::isOverdue))
.collect(Collectors.toList());
}
}
五、业务逻辑层
5.1 借阅服务(BorrowService)
java
import java.util.*;
import java.util.stream.Collectors;
/**
* 借阅服务 - 核心业务逻辑
*/
public class BorrowService {
private BookRepository bookRepo;
private ReaderRepository readerRepo;
private List<BorrowRecord> allRecords;
private int recordCounter;
public BorrowService(BookRepository bookRepo, ReaderRepository readerRepo) {
this.bookRepo = bookRepo;
this.readerRepo = readerRepo;
this.allRecords = new ArrayList<>();
this.recordCounter = 1;
}
/**
* 借书
* @param isbn 图书ISBN
* @param readerId 读者编号
* @return 借阅记录
*/
public BorrowRecord borrowBook(String isbn, String readerId) {
// 1. 查找图书
Book book = bookRepo.findByIsbn(isbn);
if (book == null) {
System.out.println("❌ 未找到ISBN为 " + isbn + " 的图书");
return null;
}
// 2. 查找读者
Reader reader = readerRepo.findById(readerId);
if (reader == null) {
System.out.println("❌ 未找到编号为 " + readerId + " 的读者");
return null;
}
// 3. 检查读者是否可以继续借阅
if (!reader.canBorrow()) {
System.out.println("❌ 读者 " + reader.getName() + " 已达到最大借阅数量");
return null;
}
// 4. 检查图书是否可借
if (!book.borrowBook()) {
return null;
}
// 5. 创建借阅记录
String recordId = "BR" + String.format("%06d", recordCounter++);
BorrowRecord record = new BorrowRecord(recordId, book, reader);
// 6. 关联记录
reader.addBorrowRecord(record);
allRecords.add(record);
System.out.println("✅ 借阅成功!");
System.out.println(" " + record.getInfo());
return record;
}
/**
* 还书
* @param recordId 借阅记录编号
* @return 罚款金额
*/
public double returnBook(String recordId) {
BorrowRecord record = findRecordById(recordId);
if (record == null) {
System.out.println("❌ 未找到记录 " + recordId);
return -1;
}
if (record.getStatus() != BorrowRecord.BorrowStatus.BORROWING &&
record.getStatus() != BorrowRecord.BorrowStatus.RENEWED) {
System.out.println("❌ 记录 " + recordId + " 当前状态不可归还");
return -1;
}
double fine = record.returnBook();
System.out.println("✅ 归还成功!图书:《" + record.getBook().getTitle() + "》");
return fine;
}
/**
* 续借
* @param recordId 借阅记录编号
*/
public boolean renewBook(String recordId) {
BorrowRecord record = findRecordById(recordId);
if (record == null) {
System.out.println("❌ 未找到记录 " + recordId);
return false;
}
boolean success = record.renew();
if (success) {
System.out.println("✅ 续借成功!新到期日:" + record.getDueDate());
}
return success;
}
// 查找记录
private BorrowRecord findRecordById(String recordId) {
return allRecords.stream()
.filter(r -> r.getRecordId().equals(recordId))
.findFirst()
.orElse(null);
}
// 获取所有逾期记录
public List<BorrowRecord> getOverdueRecords() {
return allRecords.stream()
.filter(BorrowRecord::isOverdue)
.collect(Collectors.toList());
}
// 获取读者的借阅记录
public List<BorrowRecord> getReaderRecords(String readerId) {
return allRecords.stream()
.filter(r -> r.getReader().getReaderId().equals(readerId))
.collect(Collectors.toList());
}
// 统计借阅排行
public Map<String, Long> getBorrowRanking() {
return allRecords.stream()
.collect(Collectors.groupingBy(
r -> r.getBook().getTitle(),
Collectors.counting()
));
}
// 打印逾期提醒
public void printOverdueReminders() {
List<BorrowRecord> overdueList = getOverdueRecords();
if (overdueList.isEmpty()) {
System.out.println("📋 当前没有逾期记录");
return;
}
System.out.println("\n⚠️ ====== 逾期提醒 ======");
for (BorrowRecord record : overdueList) {
System.out.printf("读者: %s | 图书: 《%s》 | 应还: %s | 罚款: ¥%.2f%n",
record.getReader().getName(),
record.getBook().getTitle(),
record.getDueDate(),
record.calculateFine());
}
System.out.println("========================\n");
}
}
六、用户界面层
6.1 主系统类(LibrarySystem - 单例模式)
java
import java.util.*;
/**
* 图书管理系统主类 - 单例模式
*/
public class LibrarySystem {
private static LibrarySystem instance;
private BookRepository bookRepo;
private ReaderRepository readerRepo;
private BorrowService borrowService;
private Scanner scanner;
// 私有构造方法(单例模式)
private LibrarySystem() {
this.bookRepo = new BookRepository();
this.readerRepo = new ReaderRepository();
this.borrowService = new BorrowService(bookRepo, readerRepo);
this.scanner = new Scanner(System.in);
}
// 获取单例
public static LibrarySystem getInstance() {
if (instance == null) {
instance = new LibrarySystem();
}
return instance;
}
// 启动系统
public void start() {
initTestData();
System.out.println("╔══════════════════════════════════╗");
System.out.println("║ 📚 图书管理系统 v1.0 ║");
System.out.println("╚══════════════════════════════════╝");
boolean running = true;
while (running) {
showMenu();
int choice = readInt("请选择操作:");
switch (choice) {
case 1: addBook(); break;
case 2: queryBooks(); break;
case 3: borrowBook(); break;
case 4: returnBook(); break;
case 5: renewBook(); break;
case 6: viewReaderInfo(); break;
case 7: borrowService.printOverdueReminders(); break;
case 8: showStatistics(); break;
case 0:
running = false;
System.out.println("👋 感谢使用图书管理系统,再见!");
break;
default:
System.out.println("❌ 无效选择,请重新输入");
}
}
scanner.close();
}
private void showMenu() {
System.out.println("\n┌──────────── 主菜单 ────────────┐");
System.out.println("│ 1. 📖 添加图书 │");
System.out.println("│ 2. 🔍 查询图书 │");
System.out.println("│ 3. 📤 借阅图书 │");
System.out.println("│ 4. 📥 归还图书 │");
System.out.println("│ 5. 🔄 续借图书 │");
System.out.println("│ 6. 👤 查看读者信息 │");
System.out.println("│ 7. ⚠️ 逾期提醒 │");
System.out.println("│ 8. 📊 统计报表 │");
System.out.println("│ 0. 🚪 退出系统 │");
System.out.println("└────────────────────────────────┘");
}
// 初始化测试数据
private void initTestData() {
// 添加图书
bookRepo.addBook(new Book("978-7-111-40701-0", "Java编程思想", "Bruce Eckel",
"机械工业出版社", "计算机", 108.0));
bookRepo.addBook(new Book("978-7-111-21382-6", "深入理解Java虚拟机", "周志明",
"机械工业出版社", "计算机", 79.0));
bookRepo.addBook(new Book("978-7-115-41730-5", "Spring实战(第5版)", "Craig Walls",
"人民邮电出版社", "计算机", 89.0));
bookRepo.addBook(new Book("978-7-115-54608-1", "算法导论", "Thomas H.Cormen",
"机械工业出版社", "算法", 128.0));
bookRepo.addBook(new Book("978-7-108-00982-1", "活着", "余华",
"生活·读书·新知三联书店", "文学", 28.0));
// 注册读者
readerRepo.register(new Reader("R001", "张三", "13800001111", Reader.ReaderType.STUDENT));
readerRepo.register(new Reader("R002", "李四", "13800002222", Reader.ReaderType.TEACHER));
readerRepo.register(new Reader("R003", "王五", "13800003333", Reader.ReaderType.VIP));
}
// 添加图书
private void addBook() {
System.out.println("\n--- 添加图书 ---");
String isbn = readString("ISBN:");
String title = readString("书名:");
String author = readString("作者:");
String publisher = readString("出版社:");
String category = readString("分类:");
double price = readDouble("价格:");
Book book = new Book(isbn, title, author, publisher, category, price);
bookRepo.addBook(book);
}
// 查询图书
private void queryBooks() {
System.out.println("\n--- 查询图书 ---");
System.out.println("1. 按书名查询 2. 按作者查询 3. 查看所有 4. 查看可借图书");
int choice = readInt("选择查询方式:");
List<Book> results;
switch (choice) {
case 1:
String keyword = readString("请输入书名关键词:");
results = bookRepo.findByTitle(keyword);
break;
case 2:
String author = readString("请输入作者名:");
results = bookRepo.findByAuthor(author);
break;
case 3:
results = bookRepo.findAll();
break;
case 4:
results = bookRepo.findAvailable();
break;
default:
System.out.println("无效选择");
return;
}
if (results.isEmpty()) {
System.out.println("📭 未找到匹配的图书");
} else {
System.out.println("\n查询结果(共 " + results.size() + " 本):");
results.forEach(b -> System.out.println(" " + b.getInfo()));
}
}
// 借书
private void borrowBook() {
System.out.println("\n--- 借阅图书 ---");
String isbn = readString("图书ISBN:");
String readerId = readString("读者编号:");
borrowService.borrowBook(isbn, readerId);
}
// 还书
private void returnBook() {
System.out.println("\n--- 归还图书 ---");
String recordId = readString("借阅记录编号:");
double fine = borrowService.returnBook(recordId);
if (fine > 0) {
System.out.printf("请缴纳逾期罚款:¥%.2f%n", fine);
}
}
// 续借
private void renewBook() {
System.out.println("\n--- 续借图书 ---");
String recordId = readString("借阅记录编号:");
borrowService.renewBook(recordId);
}
// 查看读者信息
private void viewReaderInfo() {
String readerId = readString("读者编号:");
Reader reader = readerRepo.findById(readerId);
if (reader == null) {
System.out.println("❌ 未找到该读者");
return;
}
System.out.println("\n" + reader.getInfo());
List<BorrowRecord> records = borrowService.getReaderRecords(readerId);
if (!records.isEmpty()) {
System.out.println("借阅记录:");
records.forEach(r -> System.out.println(" " + r.getInfo()));
}
}
// 统计报表
private void showStatistics() {
System.out.println("\n📊 ====== 统计报表 ======");
System.out.println("\n图书库存统计:");
bookRepo.countByStatus().forEach((status, count) ->
System.out.println(" " + status.getDescription() + ":" + count + " 本"));
System.out.println("\n借阅排行榜:");
Map<String, Long> ranking = borrowService.getBorrowRanking();
ranking.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(e -> System.out.println(" 《" + e.getKey() + "》被借阅 " + e.getValue() + " 次"));
}
// 工具方法
private String readString(String prompt) {
System.out.print(prompt);
return scanner.nextLine().trim();
}
private int readInt(String prompt) {
System.out.print(prompt);
try {
int value = Integer.parseInt(scanner.nextLine().trim());
return value;
} catch (NumberFormatException e) {
return -1;
}
}
private double readDouble(String prompt) {
System.out.print(prompt);
try {
return Double.parseDouble(scanner.nextLine().trim());
} catch (NumberFormatException e) {
return 0;
}
}
}
6.2 程序入口
java
public class Main {
public static void main(String[] args) {
LibrarySystem.getInstance().start();
}
}
七、系统集成与测试
7.1 运行效果示例
╔══════════════════════════════════╗
║ 📚 图书管理系统 v1.0 ║
╚══════════════════════════════════╝
✅ 添加图书成功:Java编程思想
✅ 添加图书成功:深入理解Java虚拟机
✅ 添加图书成功:Spring实战(第5版)
✅ 添加图书成功:算法导论
✅ 添加图书成功:活着
✅ 读者注册成功:张三
✅ 读者注册成功:李四
✅ 读者注册成功:王五
┌──────────── 主菜单 ────────────┐
│ 1. 📖 添加图书 │
│ 2. 🔍 查询图书 │
│ 3. 📤 借阅图书 │
│ ... │
└────────────────────────────────┘
请选择操作:3
--- 借阅图书 ---
图书ISBN:978-7-111-40701-0
读者编号:R001
✅ 借阅成功!
记录: BR000001 | 图书: Java编程思想 | 读者: 张三 | 借期: 2026-05-26 | 应还: 2026-06-25 | 状态: 借阅中
7.2 系统测试要点
| 测试场景 | 测试内容 | 预期结果 |
|---|---|---|
| 正常借书 | 可借图书 + 可借读者 | 借阅成功,状态更新 |
| 重复借书 | 已借出的图书 | 提示不可借出 |
| 超额借书 | 已达上限的读者 | 提示达到最大借阅数 |
| 正常还书 | 未逾期的记录 | 归还成功,无罚款 |
| 逾期还书 | 超过应还日期 | 归还成功,计算罚款 |
| 续借 | 首次续借 | 成功,延期30天 |
| 重复续借 | 已续借过的记录 | 提示不可再次续借 |
八、面向对象设计原则回顾
通过本项目,我们实践了以下面向对象核心原则:
| 原则 | 体现 |
|---|---|
| 封装 | Book/Reader的属性私有化,通过方法访问 |
| 继承 | ReaderType/BookStatus使用枚举继承 |
| 多态 | 不同ReaderType有不同的maxBorrow |
| 单一职责 | Book管图书、Reader管读者、BorrowService管借阅 |
| 开闭原则 | 新增图书类型无需修改已有代码 |
| 依赖倒转 | BorrowService依赖Repository接口 |
九、常见面试题解析
Q1:为什么使用单例模式实现LibrarySystem?
图书管理系统通常只有一个入口和运行实例,单例模式确保全局唯一访问点,避免重复创建资源。
Q2:如何扩展支持不同类型的借阅规则?
可以使用策略模式 ,定义
BorrowStrategy接口,为不同读者类型实现不同的借阅规则策略。
Q3:这个系统有哪些可以改进的地方?
- 引入数据库持久化替代内存存储
- 使用MVC分层架构
- 增加用户登录和权限管理
- 使用设计模式进一步解耦
十、总结与下篇预告
本篇要点
| 要点 | 说明 |
|---|---|
| 需求分析 | 明确功能需求和业务规则 |
| 类图设计 | 规划类之间的关系 |
| 实体类 | Book、Reader、BorrowRecord |
| 数据仓库 | 内存中的CRUD操作 |
| 业务服务 | 借阅、归还、续借的核心逻辑 |
| 系统集成 | 单例模式 + 菜单交互 |
📢 下篇预告
第19篇:集合框架之List------我们将学习Java集合框架中最常用的List接口,包括ArrayList、LinkedList的使用与区别!
💬 互动话题
你在学习Java面向对象时,觉得最难理解的概念是什么?有没有尝试过用面向对象思想设计一个小系统?欢迎在评论区分享你的经验!
参考资料: