【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 饿汉式
指在程序启动时就直接进行初始化,无论后面是否使用。这样写,可能会造成资源的浪费,但优点是不需要考虑多线程下的线程安全。
1.2 懒汉式
指在使用时才去实例化对象,存在线程不安全的问题,优点是节省了资源。
2.工厂模式
让创建对象和使用对象的过程进行分离。工厂模式专门有一个负责创建对象的工厂类,将创建对象的过程封装,以达到解耦的目的。
工厂模式分为: 简单工厂模式,抽象工厂模式,工厂方法模式,这里采用工厂方法模式。
如下,创建1个管理员对象,2个普通用户对象:
//创建抽象工厂
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
}
3.代理模式
指创建一个代理类来对实际类进行访问。
代理类就像中介,以保证双方可以正常的进行通信。
代理模式可以分为: 静态代理 动态代理 CLIB代理
代理类的定义:
代理类的使用:
被代理对象通过代理类的构造方法传递给真正的用户 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,用户角色三个属性。
User模块的详细划分:
整合到LibraySystem中:
2.2 constant模块
在整个项目当中,会发现有许多大量出现的常量,大量出现意味着如果要修改它们可能会进行大范围的修改,可能会漏掉或者改错,比如写入的文件名。因此使用constant模块来处理这样的常量;
一般,项目中尽可能避免使用常数;
2.3 book模块
2.3.1 book类的定义
book的属性如下:
代码如下:
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,文件等介质中,这里采用的是文件。
整体设计流程为:
2.3.2 工具模块AnalyzingBook
字符串序列化: 将对象转换为字符串。
将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.将数据写入文件:
-
统计Book数组的实际大小
-
遍历数组,首先通过toJson进行序列化,之后添加\n加入下一本书
-
将获得的字符串写入到指定文件
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.从文件中读数据:
-
如果文件存在或不为空,将读入的字符串以\n进行分割
-
分割出来的每个部分是一个Book对象的字符串,通过parseBookJson进行构造Book对象
-
返回数据(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类的设计
文件数据读到内存后,经过工具出来后转换为Book数组,因此将其作为成员变量。
public class Libary {private Book[] books; //书籍数组private int bookCount; //书的实际数量private AnalyzingBook analyzingBook=new AnalyzingBook(); //工具类public Libary() {//调用构造方法时,初始化books数组,数据来源为工具类中的loadObject方法}
}
读取文件解析:
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.用户交互菜单
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整体的框架:
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.更新书籍
//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.删除书籍
//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中的部分属性;
//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.归还书籍
//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类的原理均同借阅书籍
六. 总结
以上就是本文所有内容,如果对您有帮助的话就点个赞吧;以上的源码可以在如下码云链接获得:项目链接