【Java】图书管理系统设计详解


一.初识设计模式

1.单例模式

一般,在类定义后,可以实例化出多个对象。而单例模式是指: 一个类只能实例化出一个对象。常用于对资源有严格限制的场景。

单例模式的实现主要有两种: 饿汉式和懒汉式

1.1 饿汉式

指在程序启动时就直接进行初始化,无论后面是否使用。这样写,可能会造成资源的浪费,但优点是不需要考虑多线程下的线程安全。

image-20250715223349325

1.2 懒汉式

指在使用时才去实例化对象,存在线程不安全的问题,优点是节省了资源。

image-20250715230023406

2.工厂模式

让创建对象和使用对象的过程进行分离。工厂模式专门有一个负责创建对象的工厂类,将创建对象的过程封装,以达到解耦的目的。

工厂模式分为: 简单工厂模式,抽象工厂模式,工厂方法模式,这里采用工厂方法模式。

如下,创建1个管理员对象,2个普通用户对象:

image-20250716163706712

//创建抽象工厂
public interface IUserFactory {
    User createrUser(String name, int userId);   //用该方法去创建不同工厂的对象
}
//创建Admin工厂
public class AdminFactory implements IUserFactory{
    @Override
    public User createrUser(String name, int userId) {
        return new AdminUser(name,userId);
    }
}
//创建Normal工厂
public class NormalFactory implements IUserFactory{
    @Override
    public User createrUser(String name, int userId) {
        return new NormalUser(name,userId);
    }
}

//使用工厂生产对象
public static void main(String[] args) {
        IUserFactory normalFactory=new NormalFactory();
        User normalUser=normalFactory.createrUser("刘备",1);

        IUserFactory adminFactory=new AdminFactory();
        User adminUser1=adminFactory.createrUser("关羽",2);
        User adminUser2=adminFactory.createrUser("张飞",3);
        //显然,如果要更改类名,此处也无须变更,因为封装了生产过程
        //并且,可以直接创建多个对象,不用多次new
}

image-20250716172433359

image-20250716173819384

3.代理模式

指创建一个代理类来对实际类进行访问。

代理类就像中介,以保证双方可以正常的进行通信。

image-20250716202206447

代理模式可以分为: 静态代理 动态代理 CLIB代理

image-20250716202505031

代理类的定义:

image-20250716211442389

代理类的使用:

被代理对象通过代理类的构造方法传递给真正的用户 realUser,并且每种方法中都必须进行权限检查。

//代理类的定义
public class ProxyUser {
    
    public User realUser;
    //由于代理的对象可能有两种,因此使用它们的父类去接收  =》向上转型
    public ProxyUser(User realUser) {
        this.realUser = realUser;
    }
    public void addBook(String bookName){
        if(realUser instanceof AdminUser)
            ((AdminUser)realUser).addBook(bookName); //向下转型调用成员方法
        else
            System.out.println("您没有权限添加图书,请切换为管理员");
    }
    public void borrowBook(String bookName){
        if(realUser instanceof NormalUser)
            ((NormalUser)realUser).borrowBook(bookName);
        else
            System.out.println("您没有权限借阅图书,请切换为普通用户");
    }
}
public class UserManagement {
    public static void main(String[] args) {
        IUserFactory adminFactory=new AdminFactory();
        User adminUser1=adminFactory.createrUser("刘备",1);

        IUserFactory normalFactory=new NormalFactory();
        User normalUser1=normalFactory.createrUser("关羽",2);
        User normalUser2=normalFactory.createrUser("张飞",3);

        //代理类实例化时传入不同的对象
        ProxyUser proxyUser=new ProxyUser(adminUser1);  //代理管理员对象
        //可以调用代理类中的方法,但不一定会允许继续执行
        proxyUser.borrowBook("mysql");    //管理员有权调borrowBook
        proxyUser.addBook("mysql");       //管理员没有改方法,虽然可以调用,但权限检查不通过,退出执行
        
    }
}

二.模块划分

该项目分为4个模块: 用户模块,书籍模块,工具模块,常量值模块

2.1 User模块

本系统的用户分为两类: 普通用户和管理员。每个用户包含 用户名,用户ID,用户角色三个属性。

image-20250717101150521

User模块的详细划分:

image-20250717103411393

整合到LibraySystem中:

image-20250717104003941

2.2 constant模块

在整个项目当中,会发现有许多大量出现的常量,大量出现意味着如果要修改它们可能会进行大范围的修改,可能会漏掉或者改错,比如写入的文件名。因此使用constant模块来处理这样的常量;

一般,项目中尽可能避免使用常数

2.3 book模块

2.3.1 book类的定义

book的属性如下:

image-20250717105916547

代码如下:

public class Book {
    private int bookId; //书id
    private String title; // 书名
    private String author; // 作者
    private String category; // 类别
    private int publishYear; // 出版年份
    private boolean isBorrowed; // 借阅状态
    private int borrowCount; // 借阅次数
    private LocalDate shelfDate; // 上架时间

    // 构造函数,初始化图书对象 书籍ID、借阅状态和 借阅次数不⽤进⾏参数传递
    public Book(String title, String author, String category,
                int publishYear, LocalDate shelfDate) {
        this.title = title;
        this.author = author;
        this.category = category;
        this.publishYear = publishYear;
        this.isBorrowed = false;
        this.borrowCount = 0;
        this.shelfDate = shelfDate;
    }

    //--------------------------拿到和设置bookId-----------------------------


    //--------------------------拿到和设置book书名-----------------------------


    //--------------------------拿到和设置book作者-----------------------------

    
    //--------------------------拿到和设置book类别-----------------------------

    
    //--------------------------拿到和设置book出版日期-----------------------------


    //--------------------------拿到和设置book借阅状态-----------------------------


    //--------------------------拿到和设置book借阅次数-----------------------------


    //--------------------------拿到和设置book上架时间-----------------------------
    
    @Override
    public String toString() {
        return "Book{" +
                "bookId='" + bookId + '\'' +
                ",title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", category='" + category + '\'' +
                ", publishYear=" + publishYear +
                ", isBorrowed=" + isBorrowed +
                ", borrowCount=" + borrowCount + ", shelfDate=" + shelfDate +
                '}';
    }

}

注意点:

  • 基本的get,set方法直接可以通过编译器给出
  • 构造方法中不包含bookId,因为希望其能在新增书籍时实现自增,而暂时不知道当前Id,故后面设置
  • 构造方法中不包含isBorrowed,因为书的默认一定是为借出状态,故不需要初始化
  • 构造方法中不包含borrowCount,因此一开始肯定没有借阅次数

2.3 Libary类的设计

2.3.1 总思路

我们希望实现数据的持久化,因此需要将书籍数据存储到mysql,文件等介质中,这里采用的是文件。

整体设计流程为:

image-20250717161923878

2.3.2 工具模块AnalyzingBook

字符串序列化: 将对象转换为字符串。

image-20250717164657584

将Book对象转为字符串,对象的属性间用’,'分割; 将多个Book对象用\n进行分割,最终Book数组转换为字符串,将该字符串写入文件。

进一步说,从文件中读出的是一个字符串,将字符串以\n进行分割,每个部分都是一个Book对象的字符串,字符串以’,'进行分割,之后就可以获得Book对象。

1.将Book对象转为字符串:

//Book类
public String toJson(){
        StringBuilder json=new StringBuilder();
        json.append(bookId).append(",");

        json.append(title).append(",");
        json.append(author).append(",");
        json.append(category).append(",");
        json.append(publishYear).append(",");
        json.append(isBorrowed).append(",");
        json.append(borrowCount).append(",");
        json.append(shelfDate!=null?shelfDate.format(DateTimeFormatter.ISO_LOCAL_DATE):null);
        return json.toString();
 }

2.将数据写入文件:

  1. 统计Book数组的实际大小

  2. 遍历数组,首先通过toJson进行序列化,之后添加\n加入下一本书

  3. 将获得的字符串写入到指定文件

    public void storeObject(Book[] books,String filename){
            //计算实际有多少本书
            int bookLen=0;
            for(int i=0;i<books.length;i++){
                if(books[i]!=null)
                    bookLen++;
            }
            //遍历books
            StringBuilder jsonArray=new StringBuilder();
            for(int i=0;i<bookLen;i++){
                jsonArray.append(books[i].toJson());  //toJson进行序列化
                if(i<bookLen-1)
                    jsonArray.append("\n");
            }
            FileUtils.writeFile(jsonArray.toString(),filename);
    }
    

3.将字符串构造为Book对象(解析数据):

public Book parseBookJson(String json){
        if(json.isEmpty())
            return null;
        String[] pairs=json.split(",");  //Book对象的字符串以','进行分割

        //获得书籍属性
        int bookId = Integer.parseInt(pairs[0]);
        String title = pairs[1];
        String author = pairs[2];
        String category = pairs[3];
        int publishYear = Integer.parseInt(pairs[4]);
        boolean isBorrowed = Boolean.parseBoolean(pairs[5]);
        int borrowCount = Integer.parseInt(pairs[6]);
        LocalDate shelfDate = LocalDate.parse(pairs[7]);

        //构造书籍对象
        if (title != null && author != null && category != null && shelfDate !=null) {
            Book book = new Book(title, author, category, publishYear, shelfDate);
            book.setBorrowed(isBorrowed);
            book.setBorrowCount(borrowCount);
            book.setBookId(bookId);
            return book;
        }
        return null;
}

4.从文件中读数据:

  1. 如果文件存在或不为空,将读入的字符串以\n进行分割

  2. 分割出来的每个部分是一个Book对象的字符串,通过parseBookJson进行构造Book对象

  3. 返回数据(Book数组)

    public Book[] loadObject(String filename){
            String content=FileUtils.readFile(filename);
            //文件不存在||文件无内容
            if(content==null||content.isEmpty()){
                System.out.println(filename+" is not exist");
                return null;
            }
            String[] bookString=content.split("\n");
            int len=bookString.length;
            Book[] books=new Book[len];
            for(int i=0;i<len;i++) {
                books[i]=parseBookJson(bookString[i]);
            }
            return books;
    }
    
2.3.3 Libary类的设计

image-20250717222437601

文件数据读到内存后,经过工具出来后转换为Book数组,因此将其作为成员变量。

public class Libary {
    private Book[] books;   //书籍数组
    private int bookCount;  //书的实际数量
    private AnalyzingBook analyzingBook=new AnalyzingBook();  //工具类
    public Libary() {
        //调用构造方法时,初始化books数组,数据来源为工具类中的loadObject方法
    }
}

读取文件解析:

image-20250718151837613

   private void loadAllBook(){
        //将文件的数据读入到allBook临时数组中
        Book[] allBook=analyzingBook.loadObject(constant.ALL_BOOK_FILE_NAME);
        //书籍数组分配默认大小空间
        this.books=new Book[constant.DEFAULT_CAPACITY];
        if(allBook==null)
            bookCount=0;
        else{
            int allBookLen= allBook.length;
            //如果读入的数据数量>当前书的数量,重新分配大小
            if(allBookLen>books.length)
                this.books=new Book[allBookLen];
            //更新书籍
            for(int i=0;i<allBookLen;i++)
                this.books[i]=allBook[i];
            //更新当前书籍数量
            bookCount= allBookLen;
        }
    }

三.业务逻辑完善

1.ProxyUser类业务完善

ProxyUser中主要的方法: 1.AdiminUser和NormalUser的方法 2.用户交互菜单

image-20250721200903642

1.权限检查: 前面说过,ProxyUser作为代理类,拥有可能成为代理对象的方法,因此对每个方法的访问都需要进行权限检查。

//管理员权限检查
private void checkAdminUser(String msg){
        if(!(realUser instanceof AdminUser)){
            throw new PermissionException(msg);
        }
 }
//普通用户权限检查
private void checkNormalUser(String msg){
        if(!(realUser instanceof NormalUser)){
            throw new PermissionException(msg);
        }
}

2.用户交互菜单:

public void handelOperation(int choice){
        if(realUser instanceof AdminUser){
            switch (choice){
                case constant.SEARCH_BOOK:
                    libary.searchBook();
                    break;
                case constant.DISPLAY_BOOK:
                    libary.display();
                    break;
                case constant.EXIT:
                    libary.exit();
                    break;
                case constant.ADD_BOOK:
                    addBook();
                    break;
                case constant.UPDATE_BOOK:
                    updateBook();
                    break;
                case constant.DELETE_BOOK:_BOOK:
                    removeBook();
                    break;
                case constant.BORROW_COUNT:
                    borrowBook();
                    break;
                case constant.GENERATE_BOOK:
                    generateBook();
                    break;
                case constant.CHECK_STATUS:
                    checkInventoryStatus();
                    break;
                case constant.REMOVE_OLD_BOOK:
                    checkAndRemoveOldBooks();
                    break;
            }
        }
        else if(realUser instanceof NormalUser){
            switch (choice){
                case constant.SEARCH_BOOK:
                    libary.searchBook();
                    break;
                case constant.DISPLAY_BOOK:
                    libary.display();
                    break;
                case constant.EXIT:
                    libary.exit();
                    break;
                case constant.BORROW_BOOK:
                    borrowBook();
                    break;
                case constant.RETURN_BOOK:
                    returnBook();
                    break;
                case constant.VIEW_STATUS:
                    viewBorrowHistory();
                    break;
            }
        }
 }

为了减少数字的使用,用常量来代替,在Constant模块中添加:

    //constant类
    //---------------------------管理员相关操作--------------------------------
    //查找图书
    public static final int SEARCH_BOOK=1;
    //显示图书
    public static final int DISPLAY_BOOK=2;
    //退出系统
    public static final int EXIT=3;
    //上架图书
    public static final int ADD_BOOK=4;
    //更新图书
    public static final int UPDATE_BOOK=5;
    //删除图书
    public static final int DELETE_BOOK=6;
    //查看书籍借阅次数
    public static final int BORROW_COUNT=7;
    //查看受欢迎的图书
    public static final int GENERATE_BOOK=8;
    //查看库存状态
    public static final int CHECK_STATUS=9;
    //移除上架超过1年的书籍
    public static final int REMOVE_OLD_BOOK=10;

    //---------------------------普通用户相关操作--------------------
    //借阅图书
    public static final int BORROW_BOOK=4;
    //归还图书
    public static final int RETURN_BOOK=5;
    //查看借阅情况
    public static final int VIEW_STATUS=6;

ProxyUser整体的框架:

image-20250727100238681

2.AdminUser类业务完善

AdminUser中,主要完善的是菜单中的相关方法,这些方法的设计直接见源码,不予讨论;

这里,主要对AdminUser的设计进行部分优化;

2.1 单例模式设计Scanner

可以发现,Scanner在多处均被使用,因此在工具模块utils下创建ScannerSingleton工具类,并且将其设计为单例模式;

//utils.ScannerSingleton
public class ScannerSingleton {
    private static Scanner sc;

    private ScannerSingleton(Scanner sc) {
        ;
    }
    public static Scanner getScanner(){
        if(sc==null)
            sc=new Scanner(System.in);
        return sc;
    }
}
//AdminUser
private  Scanner sc;
public AdminUser(String name, int userId) {
     super(name, userId,"管理员");
     sc= ScannerSingleton.getScanner();
}

2.2 单例模式设计Libary

我们希望,libary只有1个;

//utils.LibarySingleton
public class LibarySingleton {
    private static Libary libary;
    private LibarySingleton() {
    }

    public static Libary getLibary(){
        if(libary==null)
            libary=new Libary();
        return libary;
    }
}
//proxyUser
private User realUser;
private Libary libary;
//由于代理的对象可能有两种,因此使用它们的父类去接收  =》向上转型
public ProxyUser(User realUser) {
     this.realUser = realUser;
     libary= LibarySingleton.getLibary();
 }

3.NormalUser类业务完善

NormalUser类中除了各个用户接口,还需要重点考虑的是借阅信息;

当用户借了书后,显然书和用户的信息都要保持,因此用文件存储这些信息;

3.1 PairOfUidAndBookId类

该类主要用于处理借阅信息。

public class PairOfUidAndBookId {
    private int userId;  //用户ID
    private int bookId;  //书籍ID

    public PairOfUidAndBookId(int userId, int bookId) {
        this.userId = userId;
        this.bookId = bookId;
    }

    //get and set

    public String toJson(){
        StringBuilder str=new StringBuilder();
        str.append(userId).append(',');
        str.append(bookId);
        return str.toString();
    }
}

3.2 AnalyingBorrowBook工具类

书籍的借阅信息需要被保存,同时,以后也需要读取这些信息,因此定义工具类AnalyingBorrowBook来进行数据处理;

该工具类与AnalyingBook的思想基本一致;

public class AnalyingBorrowBook {

    //读取借阅信息
    public PairOfUidAndBookId[] loadObject(String fileName){
        String content=FileUtils.readFile(fileName);
        if(content==null||content.isEmpty()){
            System.out.println("数据不存在");
            return null;
        }
        //拿到每条借阅信息
        String[] s=content.split("\n");
        PairOfUidAndBookId[] pairOfUidAndBookId=new PairOfUidAndBookId[s.length];
        for(int i=0;i<s.length;i++){
            //将每条信息构造成PairOfUidAndBookId类对象
            String[] tmp=s[i].split(",");
            pairOfUidAndBookId[i]=new
                PairOfUidAndBookId(Integer.parseInt(tmp[0]),Integer.parseInt(tmp[1]));
        }
        return pairOfUidAndBookId;

    }
    //存储借阅信息
    public void storeObject(PairOfUidAndBookId[] pairOfUidAndBookIds,String fileName){
        StringBuilder str=new StringBuilder();
        int n=0;
        //统计实际大小
        for(int i=0;i<pairOfUidAndBookIds.length;i++){
            if(pairOfUidAndBookIds[i]!=null)
                n++;
        }
        for(int i=0;i<n;i++){
            if(pairOfUidAndBookIds[i]!=null) {
                //借阅信息序列化
                str.append(pairOfUidAndBookIds[i].toJson());
                if (i != pairOfUidAndBookIds.length - 1)
                    str.append("\n");
            }
        }
        FileUtils.writeFile(str.toString(),fileName);
    }
}

3.3 NormalUser类完善

因为有了借阅书籍的场景,因此对于普通用户其也需要有相关的成员来表示自己的借阅情况

public class NormalUser extends User{
    private Scanner scanner;
    //User实际借阅次数
    private int borrowCount;
    //借阅书籍的信息数组
    private PairOfUidAndBookId[] borrowBooks;
    //借阅书籍的最大容量
    public static final int BORROW_BOOK_MAX_NUM=5;
    //借阅书籍分析工具
    private  AnalyingBorrowBook analyingBorrowBook=new AnalyingBorrowBook();
    private Libary libary;

    public NormalUser(String name, int userId) {

        super(name, userId,"普通用户");
        scanner=ScannerSingleton.getScanner();
        libary=
        loadBooks(constant.BORROW_BOOK_FILE_NAME);

    }


    public void borrowBook(String bookName){
        System.out.println("普通用户"+name+"借阅了"+bookName);
    }

    //读取借阅书籍信息
    public void loadBooks() {
        PairOfUidAndBookId[] tmpBooks;
        tmpBooks = analyingBorrowBook.loadObject(constant.BORROW_BOOK_FILE_NAME);
        if (tmpBooks == null)
            borrowCount = 0;
        else {
            int len = tmpBooks.length;
            if (len > BORROW_BOOK_MAX_NUM) {
                len = BORROW_BOOK_MAX_NUM;
            }
            borrowBooks = new PairOfUidAndBookId[len];
            for (int i = 0; i < len; i++) {
                borrowBooks[i] = tmpBooks[i];
            }
            borrowCount = len;
        }
    }

    //存储书籍信息
    public void storeBooks(){
        analyingBorrowBook.storeObject(borrowBooks,constant.BORROW_BOOK_FILE_NAME);
    }

    //普通人员菜单
    //归还图书
    //借阅图书
    //查看个人借阅情况
}

四.管理员端业务的部分实现

1.更新书籍

image-20250723174024108

//ProxyUser类
public void updateBook() {
    checkAdminUser("您没有权限执行此操作,请更换权限");
    ((AdminUser)realUser).updateBook();
}

//AdminUser类
public void updateBook() {
    libary.display();
    System.out.println("请输入要修改书籍的Id:");
    int id=sc.nextInt();
    Book book=libary.searchBookId(id);
    if(book!=null){
        System.out.println("请输入书名:");
        String title=sc.nextLine();
        System.out.println("请输入作者:");
        String author=sc.nextLine();
        System.out.println("请输入类别:");
        String category=sc.next();

        book.setTitle(title);
        book.setAuthor(author);
        book.setCategory(category);

        libary.updateBook(book);
    }
    else{
        System.out.println("该书籍Id不存在!!!");
    }
 }

//Libary

   //判断bookId是否合法
    public Book searchBookId(int bookId){
        loadAllBook();
        for(int i=0;i<bookCount;i++){
            if(bookId==books[i].getBookId())
                return books[i];
        }
        return null;
    }

    //根据bookId返回其在books数组中的index
    public int getBooksIndex(int bookId){
        loadAllBook();
        for(int i=0;i<bookCount;i++){
            if(bookId==books[i].getBookId())
                return i;
        }
        return -1;
    }
    //更新书籍
    public void updateBook(Book book) {

        //获取书籍在books中的下标
        int index=getBooksIndex(book.getBookId());
        books[index]=book;

        //books数组内容改变,重新将整个数组存入到文件
        storeBook();
    }

2.删除书籍

image-20250723204352981

//ProxyUser类
public void removeBook() {
    checkAdminUser("您没有权限执行此操作,请更换权限");
    ((AdminUser)realUser).removeBook();
}

//AdminUser类
public void removeBook() {
    //打印所有书籍
    libary.display();
    System.out.println("请输入删除书籍的Id:");
    int bookId=sc.nextInt();
    sc.nextLine();   //吞掉换行符
    //获取要删除书籍的对象
    Book book=libary.searchBookId(bookId);
    if(book!=null) {
        libary.removeBook(bookId);
        System.out.println("书籍"+book.getTitle()+"已经成功删除!!!");
    }
    else
        System.out.println("书籍不存在,无法删除");
}

//Libary类
public void removeBook(int bookId){
    loadAllBook();
    //获取删除书籍的index
    int index = getBooksIndex(bookId);
    //覆盖书籍
    for(int i=index;i<bookCount-1;i++){
            books[i]=books[i+1];
    }
    books[bookCount-1]=null;
    //书籍删除,数量减1
    bookCount--;
    //写回文件
    storeBook();
}

3.删除超过上架1年的书籍

//ProxyUser类
public void checkAndRemoveOldBooks() {
    checkAdminUser("您没有权限执行此操作,请更换权限");
    ((AdminUser)realUser).checkAndRemoveOldBooks();
}

//AdminUser类
public void checkAndRemoveOldBooks() {
    libary.checkAndRemoveOldBooks();
}

//Libary类
public void checkAndRemoveOldBooks(){
    loadAllBook();
    //获取时间戳
    long currentTime=System.currentTimeMillis();
    //转为LocalDate
    LocalDate localDate= Instant.ofEpochMilli(currentTime).atZone(ZoneId.systemDefault()).toLocalDate();
    boolean flag=false;
    for(int i=0;i<bookCount;i++){
        //获取书籍的上架时间
        LocalDate tmp=books[i].getShelfDate();
        //计算时间差值
        long yearBetween= ChronoUnit.YEARS.between(localDate,tmp);

        //删除书籍
        if(yearBetween>=1){
            System.out.println("书籍"+books[i].getTitle()+"已经上架超过1年,是否删除?(Y/N)");
            scanner.nextLine();
            char ch=scanner.nextLine().charAt(0);
            if(ch!='N'&&ch!='n')
                removeBook(books[i].getBookId());
            i--;   //由于删除书籍后,后面书籍往前覆盖,因此删除后,i位置仍需要判断,因此i--,循环后i++,继续判断i位置
            flag=true;
        }
    }
    if(flag==false)
        System.out.println("没有上架超过1年的书籍,删除失败");
}

  • Instant.ofEpochMilli(currentTime)是将毫秒级的时间戳转换为Instant对象(UTC时间,正常使用的时间)
  • Instant对象根据系统时间转换为带时区的ZonedDateTime对象
  • toLocalDate()将ZonedDateTime对象转换为Local

五.普通用户端业务的部分实现

1.借阅书籍

PairOfUidAndBookId类记录了借阅信息,Book类中也包含了借阅信息;

因此如果可以借阅书籍,需要更改 PairOfUidAndBookId数组以及Book中的部分属性;

image-20250726161330898

//ProxyUser类
public void borrowBook() {
    checkNormalUser("您没有权限执行此操作,请更换权限");
    ((NormalUser)realUser).borrowBook();
}
//NormalUser类
public void borrowBook() {
    libary.display();
    System.out.println("请输入借阅的书籍编号:");
    int bookId=scanner.nextInt();
    scanner.nextLine();

    //检查是否存在书籍
    if(libary.getBookCount()==0){
        System.out.println("当前没有书籍,无法借阅");
    }

    //加载借阅书籍信息
    loadBooks();

    //检查bookId是否合法
    Book book=libary.searchBookId(bookId);
    if(book==null){
        System.out.println("没有符合条件的书籍!!!");
    }

    //判断该书籍是否已经被借出
    for(int i=0;i<borrowCount;i++){
        PairOfUidAndBookId pairOfUidAndBookId=borrowBooks[i];
        if(pairOfUidAndBookId.getBookId()==book.getBookId()){
           if(pairOfUidAndBookId.getUserId()==userId){
               System.out.println("您已经借阅过该书籍");
               return ;
           }
           else{
               System.out.println("该书籍已被别人借出,用户Id是:"+pairOfUidAndBookId.getUserId());
               return ;
           }
        }
    }

    //未被借出,则借用
    libary.borrowBook(bookId);


    //将借阅信息写入借阅数组
    PairOfUidAndBookId pairOfUidAndBookId=new PairOfUidAndBookId(userId,book.getBookId());
    borrowBooks[borrowCount++]=pairOfUidAndBookId;
    //将借阅数组信息写入文件中
    storeBooks();
    System.out.println("借阅成功!!!");
}
//Libary类
public void borrowBook(int bookId) {
    loadAllBook();
    for(int i=0;i<bookCount;i++){
        //找到借阅书籍
        if(books[i].getBookId()==bookId){
            books[i].setBorrowed(true);
            books[i].incrementBorrowCount();
        }
    }
    storeBook();
}

2.归还书籍

image-20250726164618133

//NormalUser类
public void returnBook() {
    loadBooks();
    if(borrowCount==0){
        System.out.println("当前没有用户借出过书籍");
    }
    libary.display();
    System.out.println("请输入要归还书籍的Id:");
    int bookId=scanner.nextInt();

    Book book=libary.searchBookId(bookId);
    if(book==null){
        System.out.println("您输入的Id不合法");
    }

    //查找借阅的书籍
    for(int i=0;i<borrowCount;i++){
        if(book.getBookId()==borrowBooks[i].getBookId()){
            if(borrowBooks[i].getUserId()!=userId){
                System.out.println("您不是该书籍的借阅人,无法借阅");
            }
            else{
                //当是自己借的,删除该位置的借阅信息
                //用最后一个元素来覆盖该位置,也可以将后面的元素依次往前覆盖(arr[i]=arr[i+1])
                libary.returnBook(bookId);
                borrowBooks[i]=borrowBooks[borrowCount-1];
                borrowBooks[borrowCount-1]=null;
                borrowCount--;
                storeBooks();
                System.out.println("归还成功!!!");
            }
            return ;
        }
    }
    System.out.println("您未借阅过该书籍");
}
//Libary类和ProxyUser类的原理均同借阅书籍

六. 总结

以上就是本文所有内容,如果对您有帮助的话就点个赞吧;以上的源码可以在如下码云链接获得:项目链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值