当前位置: 首页 > news >正文

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

文章目录

  • 一.初识设计模式
    • 1.单例模式
      • 1.1 饿汉式
      • 1.2 懒汉式
    • 2.工厂模式
    • 3.代理模式
  • 二.模块划分
    • 2.1 User模块
    • 2.2 constant模块
    • 2.3 book模块
      • 2.3.1 book类的定义
      • 2.3 Libary类的设计
        • 2.3.1 总思路
        • 2.3.2 工具模块AnalyzingBook
        • 2.3.3 Libary类的设计
  • 三.业务逻辑完善
    • 1.ProxyUser类业务完善
    • 2.AdminUser类业务完善
      • 2.1 单例模式设计Scanner
      • 2.2 单例模式设计Libary
    • 3.NormalUser类业务完善
      • 3.1 PairOfUidAndBookId类
      • 3.2 AnalyingBorrowBook工具类
      • 3.3 NormalUser类完善
  • 四.管理员端业务的部分实现
    • 1.更新书籍
    • 2.删除书籍
    • 3.删除超过上架1年的书籍
  • 五.普通用户端业务的部分实现
    • 1.借阅书籍
    • 2.归还书籍
  • 六. 总结


一.初识设计模式

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{@Overridepublic User createrUser(String name, int userId) {return new AdminUser(name,userId);}
}
//创建Normal工厂
public class NormalFactory implements IUserFactory{@Overridepublic 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); //向下转型调用成员方法elseSystem.out.println("您没有权限添加图书,请切换为管理员");}public void borrowBook(String bookName){if(realUser instanceof NormalUser)((NormalUser)realUser).borrowBook(bookName);elseSystem.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");    //管理员有权调borrowBookproxyUser.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; //书idprivate 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上架时间-----------------------------@Overridepublic 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++;}//遍历booksStringBuilder 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;  //用户IDprivate int bookId;  //书籍IDpublic PairOfUidAndBookId(int userId, int bookId) {this.userId = userId;this.bookId = bookId;}//get and setpublic 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]=newPairOfUidAndBookId(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数组中的indexpublic 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()+"已经成功删除!!!");}elseSystem.out.println("书籍不存在,无法删除");
}//Libary类
public void removeBook(int bookId){loadAllBook();//获取删除书籍的indexint index = getBooksIndex(bookId);//覆盖书籍for(int i=index;i<bookCount-1;i++){books[i]=books[i+1];}books[bookCount-1]=null;//书籍删除,数量减1bookCount--;//写回文件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();//转为LocalDateLocalDate 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类的原理均同借阅书籍

六. 总结

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

http://www.dtcms.com/a/301460.html

相关文章:

  • 《 集成异步任务与定时调度:线程池与任务中心设计》
  • C++--继承
  • 设计模式(六)创建型:单例模式详解
  • VINS外参精确自标定飘的问题
  • 2025.7.22总结-幸福的力量
  • 模型评估的介绍
  • 探秘CommonJS:Node.js模块化核心解析
  • macOS配置 GO语言环境
  • Python测试框架之pytest(一)
  • 数学基础薄弱者的大数据技术学习路径指南
  • 一、搭建springCloudAlibaba2021.1版本分布式微服务-父工程搭建
  • LeetCode 76:最小覆盖子串
  • 分布式事务:二阶段提交和三阶段提交底层原理
  • AI时代,我们更需要自己的开发方式与平台
  • java--函数式接口全面总结与使用场景指南
  • LeetCode 611.有效三角形的个数
  • python---eval函数
  • Ashampoo Background Remover(照片去背景工具) v2.0.2 免费版
  • Oracle EBS 库存期间关闭状态“已关闭未汇总”处理
  • 【成功经验分享】Github Education (Github学生认证)认证
  • 【NLP实践】一、中文短句情感二分类实现并提供RestfulApi服务调用
  • 创建属于自己的github Page主页
  • 数据结构第1问:什么是数据结构?
  • 重做日志-redo log
  • 决策树(Decision Tree)完整解析:原理 + 数学推导 + 剪枝 + 实战
  • 无向图的连通性问题
  • Qt C++ GUI 函数参数速查手册:基础与布局
  • Android 调试桥 (adb) 基础知识点
  • 通过knn算法实现识别数字
  • 【n8n教程笔记——工作流Workflow】文本课程(第一阶段)——5.4 计算预订订单数量和总金额 (Calculating booked orders)