18 面向对象综合实战——设计一个图书管理系统

目录

  • [🔷 18 面向对象综合实战------设计一个图书管理系统](#🔷 18 面向对象综合实战——设计一个图书管理系统)

🔷 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面向对象时,觉得最难理解的概念是什么?有没有尝试过用面向对象思想设计一个小系统?欢迎在评论区分享你的经验!


参考资料

相关推荐
凯瑟琳.奥古斯特1 小时前
力扣1002题C++解法详解
开发语言·c++·算法·leetcode·职场和发展
码不停蹄的玄黓1 小时前
旁路缓存(Cache-Aside,CA)
java·开发语言
NGINX开源社区1 小时前
NGINX Ingress Controller 中的 Cache Policy:VirtualServer 实战指南
java·前端·nginx
lld9510271 小时前
(三)本地策略框架
java·服务器·数据库
SoftLipaRZC1 小时前
C语言文件:文件操作完全指南
android·java·c语言
零陵上将军_xdr1 小时前
API 签名防重放机制:基于 HMAC-SHA256 的设计与实现
java·学习·安全架构
ch.ju1 小时前
Java程序设计(第3版)第四章——set-get方法
java·开发语言
lpd_lt1 小时前
如何让AI生成项目的单元测试,propmt技巧详解
java·人工智能·单元测试·ai编程
_日拱一卒1 小时前
LeetCode:17电话号码的字母组合
java·数据结构·算法·leetcode·职场和发展