
作者: 当战神遇到编程
文章专栏:<<项目专栏>>欢迎大家点赞👍评论📝收藏⭐文章



文章目录
- [一 项目前置知识](#一 项目前置知识)
-
- [1 单例模式](#1 单例模式)
- [2 工厂模式(本文讲工厂方法模式)](#2 工厂模式(本文讲工厂方法模式))
- [3 代理模式](#3 代理模式)
-
- [3.1 基本概念](#3.1 基本概念)
- [4 关于jar包的使用](#4 关于jar包的使用)
-
- [4.1 什么是jar包?](#4.1 什么是jar包?)
- [4.2 项目引入jar包](#4.2 项目引入jar包)
- [二 图书管理系统](#二 图书管理系统)
-
- 1.模块划分介绍
- [2. User模块](#2. User模块)
-
- [2.1 User类](#2.1 User类)
- [2.2 AdminUser(role---管理员写死)](#2.2 AdminUser(role---管理员写死))
- [2.3 NormalUser(role---普通用户写死)](#2.3 NormalUser(role---普通用户写死))
- [2.4 引入工厂模式](#2.4 引入工厂模式)
- [2.5 User模块-引⼊代理模式控制对象权限](#2.5 User模块-引⼊代理模式控制对象权限)
- 3.book模块
-
- [3.1 Book类的定义](#3.1 Book类的定义)
- [3.2 Library类的定义](#3.2 Library类的定义)
-
- [3.2.1 Library中的设计思路](#3.2.1 Library中的设计思路)
- [3.2.2 AnalyzingBook 类实现⽂件内容的写⼊](#3.2.2 AnalyzingBook 类实现⽂件内容的写⼊)
- [3.2.3 Book类的toJSON的实现](#3.2.3 Book类的toJSON的实现)
- [3.2.4 AnalyzingBook 类实现⽂件内容的读取](#3.2.4 AnalyzingBook 类实现⽂件内容的读取)
- [3.2.5 Library⽂件&读取存储具体细节设计](#3.2.5 Library⽂件&读取存储具体细节设计)
-
- [3.2.5.1 ⽂件内容读取到内存中进⾏存储](#3.2.5.1 ⽂件内容读取到内存中进⾏存储)
- [3.2.5.2 内存中的书籍数组进⾏存储到⽂件](#3.2.5.2 内存中的书籍数组进⾏存储到⽂件)
- 4业务操作逻辑框架分解
- [5 管理员端业务实现](#5 管理员端业务实现)
- [6 普通⽤户端业务实现](#6 普通⽤户端业务实现)
一 项目前置知识
1 单例模式
单例模式是一种设计模式,核心目标是:确保某一个类只有一个实例,并提供一个全局唯一的访问点。
单例模式的实现主要有两种⽅式:饿汉式和懒汉式。
(1)饿汉式(EagerInitialization) :在应⽤程序启动 时就进⾏单例对象的初始化,⽆论是否会被使⽤。优点是不需要考虑多线程环境下的线程安全性,访问单例对象时不会引⼊额外的性能开销。缺点是可能会浪费系统资源,因为单例对象在应⽤程序启动时就被创建,如果⼀直未被使⽤,可能会占⽤内存
java
public class Singleton {
private static Singleton instance = new Singleton();
//控制实例个数
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
(2)懒汉式(LazyInitialization):延迟加载,即单例对象在⾸次访问时才进⾏初始化。优点是节省了系统资源,只有在需要时才创建单例对象。缺点是在多线程环境下,可能会出现竞态条件,需要额外的线程安全措施来确保只创建⼀个实例。
java
public class Singleton2 {
private static Singleton2 instance;
private Singleton2(){
}
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
单例模式(懒汉式)的应用
java
public class Principal {
private static Principal instance;
private String name;
private Principal(){
this.name = "王校长";
}
public static Principal getInstance(){
if(instance == null){
instance = new Principal();
}
return instance;
}
public void announcement(String message){
System.out.println(name + "通知" + message);
}
public void approveDocument(String file){
System.out.println(name + "审批通过" + file);
}
}
class School {
public static void main(String[] args) {
Principal principal1 = Principal.getInstance();
principal1.announcement(" 全校明天开始放假 3 天 ");
Principal principal2 = Principal.getInstance();
principal2.approveDocument("⻝堂伙⻝改善⽂件 ");
//检查是否是同⼀个校⻓实例
System.out.println("上述两个是同⼀位校⻓吗? " + (principal1 == principal2));
}
}
//运行结果
王校长通知 全校明天开始放假 3 天
王校长审批通过⻝堂伙⻝改善⽂件
上述两个是同⼀位校⻓吗? true
2 工厂模式(本文讲工厂方法模式)
⼯⼚模式(FactoryPattern)是最常⽤的设计模式之⼀,它提供了⼀种创建对象的⽅式,使得创建对象的过程与使⽤对象的过程分离。
简单来说,⼯⼚模式通过创建⼀个专⻔负责创建对象的⼯⼚类,将对象的创建过程封装起来,以此达到解耦的⽬的。从⽽达到了解耦。

使⽤⼯⼚⽅法模式:
(1)创建⼯⼚接⼝【抽象⼯⼚】
java
package user.factory;
import user.User;
public interface IUserFactory {
User createUser(String name, int ID);
}
(2)具体⼯⼚
java
package user.factory;
import user.AdminUser;
import user.User;
public class AdminUserFactory implements IUserFactory{
@Override
public User createUser(String name, int ID) {
return new AdminUser(name,ID);
}
}
java
package user.factory;
import user.NormalUser;
import user.User;
public class NormalUserFactory implements IUserFactory {
@Override
public User createUser(String name, int ID) {
return new NormalUser(name,ID);
}
}
(3)抽象产品
java
package user;
public abstract class User {
protected String name; // ⽤户名
protected int userID; // ⽤户ID
public User(String name, int userID) {
this.name = name;
this.userID = userID;
}
}
(4)具体产品
java
package user;
public class NormalUser extends User{
public NormalUser(String name, int userID) {
super(name, userID);
}
}
java
package user;
public class AdminUser extends User {
public AdminUser(String name, int userID) {
super(name, userID);
}
}
(5)实现方式
java
package user;
import user.factory.AdminUserFactory;
import user.factory.IUserFactory;
import user.factory.NormalUserFactory;
public class UserManagement {
public static void main(String[] args) {
IUserFactory adminFactory = new AdminUserFactory();
User adminUser = adminFactory.createUser(" 刘备 ", 1);
IUserFactory normalFactory = new NormalUserFactory();
User normalUser1 = normalFactory.createUser(" 关⽻ ", 2);
User normalUser2 = normalFactory.createUser(" 张⻜ ",3);
}
}
• 在⼯⼚⽅法模式中,每种⽤户类型都有⾃⼰的⼯⼚类。要添加新的⽤户类型,只需创建新的⼯⼚类,⽆需修改现有代码。
• 代码不会重复,创建对象的过程,封装到了⼯⼚当中
• 更加解耦
3 代理模式
3.1 基本概念
简单说,代理模式就是找个 "中间人" 替目标对象干活 .
举个生活例子:你想租房,不直接找房东(目标对象),而是通过中介(代理对象)。中介会先帮你筛选房源、带看房子(预处理),你确定后中介再联系房东办手续(转发请求),最后还可能帮你交接房屋(事后处理),你全程不用直接对接房东,中介就起到了控制访问和辅助的作用。
java
package user;
public class ProxyUser {
private User realUser;
public ProxyUser(User user){
realUser = user;
}
public void borrowBook(String bookName){
if(realUser instanceof NormalUser){
((NormalUser)realUser).borrowBook(bookName);
}else if(realUser instanceof AdminUser){
System.out.println("你没有权限借阅书籍,请以普通用户的方式借阅书籍");
}
}
public void addBook(String bookName){
if(realUser instanceof AdminUser){
(( AdminUser)realUser).addBook(bookName);
}else if(realUser instanceof NormalUser){
System.out.println("你没有权限上架书籍,请以管理员用户的方式上架书籍");
}
}
}
4 关于jar包的使用
4.1 什么是jar包?
JAR(JavaArchive)包是⼀种⽤于打包Java应⽤程序和相关组件的⽂件格式。它基本上是⼀个ZIP
格式的压缩⽂件,但是专⻔⽤于Java平台。
4.2 项目引入jar包
1.打开项⽬,创建⼀个⽂件夹为:lib



下一步具体步骤如下:
• 点击File,选择"ProjectStru..."
• 在左侧⾯板中,选择"Libraries",点击"+"按钮,选择"Java"

• 浏览并选择你刚刚创建的JAR⽂件


测试导⼊是否成功:

导⼊jar包没有问题了!
二 图书管理系统
1.模块划分介绍
图书系统中模块的划分共划分为4块:⽤⼾模块、书籍相关模块、⼯具相关模块、常量值相关模块。我
们依次将4个模块在IDEA当中进⾏创建,供后续使⽤。

其中LibrarySystem模块为程序的⼊⼝。
2. User模块
从⻆⾊上我们将图书系统划分为管理员模块和普通⽤户模块,同时我们⽀持多普通⽤户进⾏登录。每个⽤户的属性包含:姓名、ID、⻆⾊3个属性。抽取AdminUser与NormalUser的共同属性与方法,将User类定义为抽象类.
2.1 User类
java
package user;
public abstract class User {
protected String name; // 用户名
protected int userID; // 用户ID
protected String role; //管理员 普通用户
public User(String name, int userID,String role) {
this.name = name;
this.userID = userID;
this.role = role;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public abstract int display();
}
2.2 AdminUser(role---管理员写死)
java
package user;
import java.util.Scanner;
public class AdminUser extends User {
public Scanner scanner = new Scanner(System.in);
public AdminUser(String name, int userID) {
super(name, userID,"管理员");
}
@Override
public int display() {
System.out.println("管理员 " + name + " 的操作菜单:");
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. 查看最受欢迎的前K本书");
System.out.println("9. 查看库存状态");
System.out.println("10. 检查超过一年未下架的图书");
System.out.println("请选择你的操作: ");
return scanner.nextInt();
}
//上架图书
public void addBook(String bookName) {
System.out.println(" 管理员 " + name + " 上架了 " + bookName);
}
//图书修改 支持修改书名 作者 类别
public void updateBook(){
}
//删除书籍
public void removeBook(){
}
//查询每本书的借阅次数
public void borrowCount(){
}
//查询最受欢迎的前n本书
public void generateBook(){
}
//查看库存状态
public void checkInventoryStatus(){
}
//移除上架超过一年的图书
public void checkAndRemoveOldBooks(){
}
//退出系统
public void exit(){
}
}
2.3 NormalUser(role---普通用户写死)
java
package user;
import java.util.Scanner;
public class NormalUser extends User{
Scanner scanner = new Scanner(System.in);
public NormalUser(String name, int userID) {
super(name, userID,"普通用户");
}
private void loadBorrowedBook() {
}
private void storeBorrowedBook() {
}
@Override
public int display() {
System.out.println(" 普通⽤户 " + name + " 的操作菜单:");
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("请选择你的操作: ");
return scanner.nextInt();
}
public void borrowBook(String bookName) {
System.out.println(" 普通⽤户 " + name + " 借阅了 " + bookName);
}
//借阅图书
public void borrowBook() {
}
//归还图书
public void returnBook() {
}
// 查看个⼈借阅情况
public void viewBorrowHistory() {
}
}
2.4 引入工厂模式
在user包下创建factory包
1.创建⼯⼚接⼝
java
package user.factory;
import user.User;
public interface IUserFactory {
User createUser(String name, int ID);
}
2.创建具体的⼯厂
管理员工厂
java
package user.factory;
import user.AdminUser;
import user.User;
public class AdminUserFactory implements IUserFactory{
@Override
public User createUser(String name, int ID) {
return new AdminUser(name,ID);
}
}
普通用户工厂
java
package user.factory;
import user.NormalUser;
import user.User;
public class NormalUserFactory implements IUserFactory {
@Override
public User createUser(String name, int ID) {
return new NormalUser(name,ID);
}
}
修改LibrarySystem类
java
import user.User;
import user.factory.AdminUserFactory;
import user.factory.IUserFactory;
import user.factory.NormalUserFactory;
public class LibrarySystem {
public static void main(String[] args) {
IUserFactory adminFactory = new AdminUserFactory();
User adminUser = adminFactory.createUser(" 刘备 ", 1);
IUserFactory normalFactory = new NormalUserFactory();
User normalUser1 = normalFactory.createUser(" 关⽻ ", 2);
User normalUser2 = normalFactory.createUser(" 张⻜ ",3);
}
}
2.5 User模块-引⼊代理模式控制对象权限
java
package user;
public class ProxyUser {
private User realUser;
public ProxyUser(User user){
realUser = user;
}
public User getRealUser() {
return realUser;
}
//调用菜单
public int display(){
return -1;
}
//添加书籍操作
public void addBook(){
}
//更新实书籍操作
public void updateBook(){
}
//移除书籍
public void removeBook(){
}
//查看借阅次数
public void borrowCount(){
}
//查看最受欢迎的前n本书
public void generateBook(){
}
//查看库存状态
public void checkInventoryStatus(){
}
//移除上架超过一年的书籍
public void checkAndRemoveOldBooks(){
}
//...........................................普通相关法.................................................//
//借阅图书
public void borrowBook( ){
}
//归还图书
public void returnBook(){
}
//查看个人借阅情况
public void viewBorrowHistory(){
}
}
LibrarySystem类中进⾏整合
java
import user.ProxyUser;
import user.User;
import user.factory.AdminUserFactory;
import user.factory.IUserFactory;
import user.factory.NormalUserFactory;
public class LibrarySystem {
public static void main(String[] args) {
IUserFactory adminFactory = new AdminUserFactory();
User adminUser = adminFactory.createUser(" 刘备 ", 1);
IUserFactory normalFactory = new NormalUserFactory();
User normalUser1 = normalFactory.createUser(" 关⽻ ", 2);
User normalUser2 = normalFactory.createUser(" 张⻜ ",3);
ProxyUser proxyUserAdmin = new ProxyUser(adminUser);
ProxyUser proxyUserNormal1 = new ProxyUser(normalUser1);
ProxyUser proxyUserNormal2 = new ProxyUser(normalUser2);
}
}
3.book模块
3.1 Book类的定义
关于书籍类我们书籍的属性如下:

注意构造⽅法的实现对于某些字段可以不加⼊参数:
1.bookId【这⾥后续会进⾏累加/⾃增操作,此时在构造Book对象的时候,并不知道当前ID】
-
isBorrowed 【任何⼀种书籍,默认都是未借出状态,此时可以不进⾏处理】
-
borrowCount【借阅次数默认为0,此时可以不进⾏处理】
java
package book;
import java.time.LocalDateTime;
public class Book implements Comparable<Book>{
private int bookId; //书Id
private String title; //书名
private String author; //作者
private String category; //类别
private int publishYear; //出版年份
private boolean isBorrowed; //借阅状态
private int borrowCount; //借阅次数
private LocalDateTime shelfDate; //上架日期
public Book(String title, String author, String category, int publishYear, LocalDateTime shelfDate) {
this.title = title;
this.author = author;
this.category = category;
this.publishYear = publishYear;
this.isBorrowed = false;
this.borrowCount = 0;
this.shelfDate = shelfDate;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public int getPublishYear() {
return publishYear;
}
public void setPublishYear(int publishYear) {
this.publishYear = publishYear;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
public int getBorrowCount() {
return borrowCount;
}
public void setBorrowCount(int borrowCount) {
this.borrowCount = borrowCount;
}
public LocalDateTime getShelfDate() {
return shelfDate;
}
public void setShelfDate(LocalDateTime shelfDate) {
this.shelfDate = shelfDate;
}
public void incrementBorrowCount() {
this.borrowCount++;
}
public void decreaseBorrowCount() {
this.borrowCount--;
}
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", title='" + title + '\'' +
", author='" + author + '\'' +
", category='" + category + '\'' +
", publishYear=" + publishYear +
", isBorrowed=" + isBorrowed +
", borrowCount=" + borrowCount +
", shelfDate=" + shelfDate +
'}';
}
@Override
public int compareTo(Book o) {
return 0;
}
}
3.2 Library类的定义
3.2.1 Library中的设计思路
我们期望书籍等数据最好可以进⾏持久化,所谓持久化就是将数据存储到MySQL、⽂件等介质中,不会因为断电等情况影响数据。否则每次运⾏程序数据都需要重新进⾏存储等⽐较繁琐。由于⽬前知识储备,我们这⾥会采⽤⽂件进⾏存储,把⽂件相关操作封装到jar包,借助已经写好的⼯具来进⾏操作。我们这⾥先把给定的jar包进⾏导⼊项⽬。接下来我们来看整体的设计流程。实例化Library-》加载⽂件当中的内容-》对⽂件进⾏操作-》将操作后的数据写⼊⽂件

3.2.2 AnalyzingBook 类实现⽂件内容的写⼊
在util包下创建AnalyzingBook 类:实现的功能如下
java
public class AnalyzingBook {
//给文件写数据
public void storeObject(Book[] books, String filename){
}
//给文件读数据
public Book[] loadObject(String filename){
return null;
}
//把读出来的数据进行解析
private Book parseBookJson(String json){
return null;
}
}
现有⼀组书籍进⾏⽂件的存储
java
Book[] books = new Book[4];
books[0] = new Book("java", "zhangsan", " 编程 ", 1994, LocalDateTime.of(2023, 9, 24,12,3,1));
books[1] = new Book("mysql", "lisi", " 编程 ", 1999, LocalDateTime.of(2024, 2, 10,12,3,4));
books[2] = new Book("php", "wangwu", " 编程 ", 2020, LocalDateTime.of(2023, 9, 23,4,2,1));
books[3] = new Book(" 西游记 ", " 吴承恩 ", "⼩说 ", 2024,LocalDateTime.of(2023, 9,23,13,2,1));
当存⼊⽂件之后,⽂件⼀⾏代表⼀本书籍的书籍对象。写⼊书籍思路:
1.实现AnalyzingBook 类
-
先将书籍数组对象中的每个书籍对象进⾏字符串的序列化。
-
每本书籍与书籍之间使⽤\n进⾏换⾏分割
books代表书籍数组对象
filename 代表⽂件名称【如果不存在该⽂件,会⾃动创建该⽂件】
java
public void storeObject(Book[] books, String filename){
//需要先计算有多少本有效书籍
int booksUserLen = 0;
for(int i = 0;i < books.length;i++){
if(books[i] != null){
booksUserLen++;
}
}
StringBuilder jsonArray = new StringBuilder();
for(int i = 0;i < booksUserLen;i++){
if(books[i] != null){
jsonArray.append(books[i].toJSON());
if(i != booksUserLen-1){
//一本书籍完成后以\n进行分割
jsonArray.append("\n");
}
}
}
//数据写入文件
FileUtils.writeFile(jsonArray.toString(),filename);
}
注意:
• 上述代码当中toJSON需要我们⾃⼰实现
• FileUtils中的writeFile⽅法已经实现好,可以直接使用
在项目里新建allbooks文本文件
测试一下
java
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("java", "zhangsan", " 编程 ", 1994, LocalDateTime.of(2023, 9, 24,12,3,1));
books[1] = new Book("mysql", "lisi", " 编程 ", 1999, LocalDateTime.of(2024, 2, 10,12,3,4));
books[2] = new Book("php", "wangwu", " 编程 ", 2020, LocalDateTime.of(2023, 9, 23,4,2,1));
books[3] = new Book(" 西游记 ", " 吴承恩 ", "⼩说 ", 2024,LocalDateTime.of(2023, 9,23,13,2,1));
AnalyzingBook analyzingBook = new AnalyzingBook();
analyzingBook.storeObject(books, Constant.ALL_BOOK_FILE_NAME);
}

3.2.3 Book类的toJSON的实现
在Book类当中实现toJSON ⽅法,实现逻辑是将每个属性使⽤逗号进⾏拼接,存储到⽂件即可
java
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_TIME) : "null");
//条件:shelfDate != null(检查日期是否为空)。
//结果A(不为空时):shelfDate.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)。
//这会将日期对象转换为标准格式字符串,例如 2023-10-27T14:30:00。
//结果B(为空时):直接拼接字符串 "null"。
return json.toString();
}
3.2.4 AnalyzingBook 类实现⽂件内容的读取
读取⽂件的每⼀⾏字符串,转化为书籍对象。
1.先读取⽂件当中的所有内容
-
使⽤\n作为分隔符进⾏字符串分割,⽅便得到每⼀个书籍对象对应的字符串
-
把对应字符串"组装"成书籍对象
java
public Book[] loadObject(String filename){
String content = FileUtils.readFile(filename);//读取到内容的时候会自动在末尾加\n
if(content == null || content.isEmpty()){
System.out.println("File is empty or does not exist: " + filename);
return null;
}
//2. 使用\n作为分隔符进行字符串分割
String[] bookJsonStrings = content.split("\n");//如果分隔符出现在字符串的末尾,生成的末尾空字符串会被自动丢弃(忽略)
//把字符串"组装"成书籍对象
Book[] bookList = new Book[bookJsonStrings.length];
for (int i = 0; i < bookJsonStrings.length; i++) {
Book book = parseBookJson(bookJsonStrings[i]);
bookList[i] = book;
}
return bookList;
}
java
public static void main(String[] args) {
AnalyzingBook analyzingBook = new AnalyzingBook();
Book[] ret = analyzingBook.loadObject(Constant.ALL_BOOK_FILE_NAME);
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
}

parseBookJson
⽅法实现
1.检查json是否是空的
-
使⽤逗号分割出每个属性的值
-
每个属性进⾏转化赋值
-
构造书籍对象
java
private Book parseBookJson(String json){
//1.检查json是否是空的
//加这个方法防止:
//如果文件损坏,只有一堆换行符。
//如果有人手动编辑了文件,不小心敲了回车。
if(json.isEmpty()) {
return null;
}
//2.使⽤逗号分割出每个属性的值
String[] pairs = json.split(",");
//3.每个属性进⾏转化赋值
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]);
LocalDateTime shelfDate = LocalDateTime.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;
}
3.2.5 Library⽂件&读取存储具体细节设计
3.2.5.1 ⽂件内容读取到内存中进⾏存储

既然我们要把解析的数据存储到内存当中,那么我们需要在内存当中定义⼀个数组来存储读取到的书籍对象。
定义Library类
java
public class Library {
private Book[] books;//当前图书数组
private int bookCount;//实际存储的图书数量
private final AnalyzingBook analyzingBook = new AnalyzingBook();//书籍解析相关类
public Library() {
loadAllBook();
}
}
那么问题来了,books数组初始化多⼤合适呢?我们的思路是:
1.默认数组容量给⼀个默认值,⽐如5
- 然后根据实际读取到的⽂件内容,来确定⼤⼩
这个默认值是⼀个常量,我们在constant包下定义一个常量类Constant来存储这些变量
java
public class Constant {
//内存中的书籍数组初识容量
public static final int CAPACITY = 5;
}

代码实现
java
private void loadAllBook(){
//1.读取文件内容
Book[] allBook = analyzingBook.loadObject(Constant.ALL_BOOK_FILE_NAME);
//2.默认大小为5
books = new Book[Constant.CAPACITY];
//3.判断是否是有数据 没有有效书籍为0
if(allBook == null){
bookCount = 0;
}else{
//查看实际书籍大小为多少 是否大于默认的长度5
int allBookLen = allBook.length;
//大于默认长度 books数组分配实际的大小
if(allBookLen > books.length){
books = new Book[allBook.length];
}
//把读到的元素进行赋值
for (int i = 0; i < allBookLen; i++) {
books[i] = allBook[i];
}
//修改实际有效书籍个数
bookCount = allBookLen;
}
}
3.2.5.2 内存中的书籍数组进⾏存储到⽂件
java
private void storeBook() {
analyzingBook.storeObject(books,Constant.ALL_BOOK_FILE_NAME);
}
常量类添加常量:Constant.ALL_BOOK_FILE_NAME
java
public class Constant {
//内存中的书籍数组初识容量
public static final int CAPACITY = 5;
//存储所有图书的⽂件
public static final String ALL_BOOK_FILE_NAME = "allbook.txt";
}
4业务操作逻辑框架分解
接下来我们需要完成业务逻辑的实现,⾸先我们需要对框架进⾏梳理,在正式梳理之前,我们需要完
善遗留⼯作:根据⽤户不同选择进⼊不同等级的⽤户⻆⾊下
之前的LibrarySystem类
java
import user.ProxyUser;
import user.User;
import user.factory.AdminUserFactory;
import user.factory.IUserFactory;
import user.factory.NormalUserFactory;
public class LibrarySystem {
public static void main(String[] args) {
IUserFactory adminFactory = new AdminUserFactory();
User adminUser = adminFactory.createUser(" 刘备 ", 1);
IUserFactory normalFactory = new NormalUserFactory();
User normalUser1 = normalFactory.createUser(" 关⽻ ", 2);
User normalUser2 = normalFactory.createUser(" 张⻜ ",3);
ProxyUser proxyUserAdmin = new ProxyUser(adminUser);
ProxyUser proxyUserNormal1 = new ProxyUser(normalUser1);
ProxyUser proxyUserNormal2 = new ProxyUser(normalUser2);
}
}
此时的proxyUserAdmin、proxyUserNormal1、proxyUserNormal2,是我们的代理对象,我们需要根据⽤户的选择,来确定最终的⻆⾊。
在LibrarySystem类中实现selectProxyRole⽅法:
java
public static ProxyUser selectProxyRole(ProxyUser proxyUserAdmin,ProxyUser proxyUserNormal1,ProxyUser proxyUserNormal2){
System.out.println("选择角色进行登录: ");
System.out.println("1.管理员\n2.普通用户(关羽)\n3.普通用户(张飞)\n4.退出系统");
ProxyUser currentUser = null;
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
switch(choice){
case 1:
currentUser = proxyUserAdmin;
break;
case 2:
currentUser = proxyUserNormal1;
break;
case 3:
currentUser = proxyUserNormal2;
break;
case 4:
//在 Java 中,System.exit(0); 是一个非常直接且强力的指令,它的核心作用是强制终止当前正在运行的 Java 虚拟机(JVM)。
//0 代表"正常退出":表示程序已经完成了它的任务,没有发生任何错误。
//非 0(如 1, -1, 2 等)代表"异常退出":表示程序因为某种错误或异常情况而不得不停止。
System.out.println("系统已退出..");
System.exit(0);
break;
}
return currentUser;
}
完善LibrarySystem类:
java
public static void main(String[] args) {
IUserFactory adminFactory = new AdminUserFactory();
User adminUser = adminFactory.createUser(" 刘备 ", 1);
IUserFactory normalFactory = new NormalUserFactory();
User normalUser1 = normalFactory.createUser(" 关⽻ ", 2);
User normalUser2 = normalFactory.createUser(" 张⻜ ",3);
ProxyUser proxyUserAdmin = new ProxyUser(adminUser);
ProxyUser proxyUserNormal1 = new ProxyUser(normalUser1);
ProxyUser proxyUserNormal2 = new ProxyUser(normalUser2);
//选择对应⻆⾊进⾏登录
ProxyUser currentUser = selectProxyRole(proxyUserAdmin,proxyUserNormal1,proxyUserNormal2);
while(true){
int choice = currentUser.getRealUser().display();
//此时⽆需关心是管理员还是普通⽤户,代理类会做权限判断
currentUser.handleOperation(choice);
}
}
handleOperation ⽅法会在ProxyUser类中进行实现
业务框架搭建

整个业务逻辑从ProxyUser 类中进⾏管理触发,整个框架为:

在utils包下定义一个异常类
java
package utils;
public class PermissionException extends RuntimeException{
public PermissionException() {
}
public PermissionException(String message) {
super(message);
}
}
ProxyUser类完善业务逻辑框架
ProxyUser 类添加⽅法:普通用户权限检查方法和管理员权限检查方法
• 每个业务需要判断该代理对象是否是有权限的
• 调⽤对应⽤户当中的⽅法进⾏操作
• 注意:查找图书,显⽰图书,退出系统是2个⻆⾊都有的⽅法,这些⽅法可以提出到Library当中,不需要区分
java
//管理员用户权限检查方法
private void checkRealUserWhetherAdminUser(String msg) {
if(!(realUser instanceof AdminUser)) {
//⾃定义异常
throw new PermissionException(msg);
}
}
//普通用户检查方法
private void checkRealUserWhetherNormalUser(String msg) {
if(!(realUser instanceof NormalUser)){
throw new PermissionException(msg);
}
}
handleOperation ⽅法,根据选择进⾏对应操作
查找图书、显⽰图书、退出系统三种操作对于管理员和普通⽤户来说都是共⽤的,所以直接定义在Library当中
先定义框架
java
public void handleOperation(int choice) {
if(realUser instanceof AdminUser){
switch(choice){
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
default:
break;
}
}else if(realUser instanceof NormalUser){
switch(choice){
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
default:
break;
}
}
}
继续完善Constant 类:
java
package constant;
public class Constant {
//内存中的书籍数组初识容量
public static final int CAPACITY = 5;
//存储所有图书的⽂件
public static final String ALL_BOOK_FILE_NAME = "allbooks.txt";
//------------------管理员相关操作管理----------------//
//查找图书
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 REMOVE_BOOK = 6;
//查看图书的借阅次数
public static final int BORROWED_BOOK_COUNT = 7;
//查看受欢迎的图书
public static final int GENERATE_BOOK = 8;
//查看库存状态
public static final int CHECK_INVENTORY_STATUS = 9;
//移除上架超过1年的书籍
public static final int CHECK_AND_REMOVE_OLD_BOOK = 10;
//------------------普通⽤⼾相关操作管理----------------//
//借阅图书
public static final int BORROWED_BOOK = 4;
//归还图书
public static final int RETURN_BOOK = 5;
//查看个⼈借阅情况
public static final int VIEW_BORROW_HISTORY_BOOK = 6;
}
123这种也被称为magicnumber(幻数),缺点在于如果只是使⽤数字,别的程序员可能并不
能读懂甚⾄过⼀段时间,⾃⼰也可能看不懂。所以定义为常量可以增加代码的可读性。
java
public void handleOperation(int choice) {
if(realUser instanceof AdminUser){
switch(choice){
case Constant.SEARCH_BOOK:
break;
case Constant.DISPLAY_BOOK:
break;
case Constant.EXIT:
break;
case Constant.ADD_BOOK:
break;
case Constant.UPDATE_BOOK:
break;
case Constant.REMOVE_BOOK:
break;
case Constant.BORROWED_BOOK_COUNT:
break;
case Constant.GENERATE_BOOK:
break;
case Constant.CHECK_INVENTORY_STATUS:
break;
case Constant.CHECK_AND_REMOVE_OLD_BOOK:
break;
default:
break;
}
}else if(realUser instanceof NormalUser){
switch(choice){
case Constant.SEARCH_BOOK:
break;
case Constant.DISPLAY_BOOK:
break;
case Constant.EXIT:
break;
case Constant.BORROWED_BOOK:
break;
case Constant.RETURN_BOOK:
break;
case Constant.VIEW_BORROW_HISTORY_BOOK:
break;
default:
break;
}
}
}
在Library类中添加查找图书,显示图书和退出系统方法
java
public void searchBook(){
System.out.println("查找图书");
}
public void disPlayBook(){
System.out.println("显示书籍");
}
public void exit(){
System.out.println("退出系统");
}
在ProxyUser类中添加成员变量,以便使用Library类的查找图书,显示图书和退出系统方法(后文会将Library类设计成单例模式)
java
private Library library = new Library();
完善handleOperation方法
java
public void handleOperation(int choice) {
if(realUser instanceof AdminUser){
switch(choice){
case Constant.SEARCH_BOOK:
library.searchBook();
break;
case Constant.DISPLAY_BOOK:
library.disPlayBook();
break;
case Constant.EXIT:
library.exit();
break;
case Constant.ADD_BOOK:
addBook();
break;
case Constant.UPDATE_BOOK:
updateBook();
break;
case Constant.REMOVE_BOOK:
removeBook();
break;
case Constant.BORROWED_BOOK_COUNT:
borrowCount();
break;
case Constant.GENERATE_BOOK:
generateBook();
break;
case Constant.CHECK_INVENTORY_STATUS:
checkInventoryStatus();
break;
case Constant.CHECK_AND_REMOVE_OLD_BOOK:
checkAndRemoveOldBooks();
break;
default:
System.out.println("⽆效的操作。 ");
break;
}
}else if(realUser instanceof NormalUser){
switch(choice){
case Constant.SEARCH_BOOK:
library.searchBook();
break;
case Constant.DISPLAY_BOOK:
library.disPlayBook();
break;
case Constant.EXIT:
library.exit();
break;
case Constant.BORROWED_BOOK:
borrowBook();
break;
case Constant.RETURN_BOOK:
returnBook();
break;
case Constant.VIEW_BORROW_HISTORY_BOOK:
viewBorrowHistory();
break;
default:
System.out.println("⽆效的操作。 ");
break;
}
}
}
在AdminUser类中加Libray类对象(后文会将Library类设计成单例模式)
java
public Library library = new Library();
完善AdminUser类中的addBook方法
java
public void addBook() {
scanner.nextLine();//如果不加这行,直接调用下面的 nextLine(),程序可能会直接跳过书名输入,因为它会读取到上一次操作留下的回车符。
System.out.println(" 请输⼊书名: ");
String title = scanner.nextLine(); //输⼊书名
System.out.println(" 请输⼊作者: ");
String author = scanner.nextLine(); //输⼊作者
System.out.println(" 请输⼊类别: ");
String category = scanner.nextLine(); //输⼊图书类别
System.out.println(" 请输⼊出版年份: ");
int year = scanner.nextInt(); //输⼊出版年份 //scanner.nextInt() 只会读取整数部分。风险点:它不会读取末尾的回车符,回车符会残留在缓冲区里。
scanner.nextLine(); //吞掉换⾏符
LocalDateTime shelfDate = LocalDateTime.now(); //当前时间作为上架时间
Book newBook = new Book(title, author, category, year, shelfDate);//创建新书对象
//调⽤图书类添加图书
library.addBook(newBook);
}
在Library类中添加addBook方法
java
public void addBook(Book book) {
System.out.println("上架书籍....");
}
单例模式设计Library类
确保Library类只有一个实例
把构造方法访问修饰符改为privare,在Library类添加
java
private static Library library;
public static Library getLibrary() {
if(library == null){
library = new Library();
}
return library;
}
修改用到使用到Library的地方
java
private Library library = Library.getLibrary();//AdminUser类改为这个
private Library library = Library.getLibrary();//ProxyUser类改为这个
完善ProxyUser类中的addBook方法
java
public void addBook(){
checkRealUserWhetherNormalUser("普通用户没有权限上架书籍");
((AdminUser)realUser).addBook();
}
NormalUser 类完善业务逻辑框架
在设计该类的时候,我们需要想清楚⼀个逻辑。
• ⽤户借书怎么设计?
• 多个⽤户借书怎么设计?
• 借书之后存储到⽂件当中的格式是什么?
PairOfUidAndBookId 类设计
我们的设计是这样的:
• ⽂件当中存储借阅书籍信息为:⽤户ID,书籍ID的形式,每⼀⾏是⼀个借阅信息
1,101 :表⽰ID为1的⽤户借阅了ID为101的书籍
2,111
1,301
所以我们就涉及到了读取⽂件后,内存当中需要存储这些借阅信息。我们定义类PairOfUidAndBookId 来表⽰⼀条借阅信息,多条信息使⽤数组即可。
在book包当中定义
java
package book;
public class PairOfUidAndBookId {
private int userId;
private int bookId;
public PairOfUidAndBookId(int userId, int bookId) {
this.userId = userId;
this.bookId = bookId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userID) {
this.userId = userID;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
//把对象序列化为JSON字符串的形式
public String toJson() {
StringBuilder json = new StringBuilder();
json.append(userId).append(",");
json.append(bookId);
return json.toString();
}
}
AnalyzingBorrowedBook类的设计
util包中定义
该设计⽅案和AnalyzingBook设计是类似的
java
package utils;
import book.Book;
import book.PairOfUidAndBookId;
import com.bit.utils.FileUtils;
public class AnalyzingBorrowedBook {
/**
* 存到文件当中
* @param pairOfUidAndBookIds
* @param filename
*/
public void storeObject(PairOfUidAndBookId[] pairOfUidAndBookIds, String filename){
//先遍历pairOfUidAndBookIds数组当中不为空的数据多少个?
int booksUseLen = 0;
for (int i = 0; i < pairOfUidAndBookIds.length; i++) {
if(pairOfUidAndBookIds[i] != null) {
booksUseLen++;
}
}
StringBuilder jsonArray = new StringBuilder();
for(int i = 0;i < booksUseLen;i++){
if(pairOfUidAndBookIds[i] != null){
jsonArray.append(pairOfUidAndBookIds[i].toJSON());
if(i != booksUseLen-1){
//一本书籍完成后以\n进行分割
jsonArray.append("\n");
}
}
}
FileUtils.writeFile(jsonArray.toString(),filename);
}
public PairOfUidAndBookId[] loadObject(String filename){
String content = FileUtils.readFile(filename);
if(content == null || content.isEmpty()){
System.out.println("已借阅书籍列表无数据,表示用户没有借阅过书籍");
return null;
}
//2. 使用\n作为分隔符进行字符串分割
String[] JsonStrings = content.split("\n");
PairOfUidAndBookId[] pairOfUidAndBookIds = new PairOfUidAndBookId[JsonStrings.length];
for (int i = 0; i < JsonStrings.length; i++) {
PairOfUidAndBookId pairOfUidAndBookId = new PairOfUidAndBookId();
String[] uidAndBookIds = JsonStrings[i].split(",");
pairOfUidAndBookId.setUserId(Integer.parseInt(uidAndBookIds[0]));
pairOfUidAndBookId.setBookId(Integer.parseInt(uidAndBookIds[1]));
pairOfUidAndBookIds[i] = pairOfUidAndBookId;
}
return pairOfUidAndBookIds;
}
}
在PairOfUidAndBookId类中添加无参构造方法
java
public PairOfUidAndBookId(){
}
在项目里添加borrowedbook文本文件

在Content类中添加
java
public static final String BORROWED_BOOK_FILE_NAME = "borrowedbook.txt";
测试一下storeObject方法
java
public static void main(String[] args) {
PairOfUidAndBookId[] pairOfUidAndBookIds = new PairOfUidAndBookId[2];
pairOfUidAndBookIds[0] = new PairOfUidAndBookId(1,1001);
pairOfUidAndBookIds[1] = new PairOfUidAndBookId(2,1002);
AnalyzingBorrowedBook analyzingBorrowedBook = new AnalyzingBorrowedBook();
analyzingBorrowedBook.storeObject(pairOfUidAndBookIds, Constant.BORROWED_BOOK_FILE_NAME);
}

在PairOfUidAndBookId类中添加toString方法
java
@Override
public String toString() {
return "PairOfUidAndBookId{" +
"userId=" + userId +
", bookId=" + bookId +
'}';
}
测试一下loadObject方法
java
public static void main(String[] args) {
AnalyzingBorrowedBook analyzingBorrowedBook = new AnalyzingBorrowedBook();
PairOfUidAndBookId[] ret = analyzingBorrowedBook.loadObject(Constant.BORROWED_BOOK_FILE_NAME);
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
}

在NormalUser类中添加成员变量
java
// ⽤户已借阅的图书相关信息
private PairOfUidAndBookId[] pairOfUidAndBookIds;
//当前书籍的借阅量
private int borrowedCount;
private final AnalyzingBorrowedBook analyzingBorrowedBook = new AnalyzingBorrowedBook();
在Constant类中添加
java
//最多借阅的图书数量
public static final int BORROW_BOOK_MAX_NUM = 5;
在NormalUser类中完善loadBorrowedBook方法
java
private void loadBorrowedBook() {
//1.读取文件内容
PairOfUidAndBookId[] allBorrowedBook = analyzingBorrowedBook.loadObject(Constant.BORROWED_BOOK_FILE_NAME);
//2.默认大小为5
pairOfUidAndBookIds = new PairOfUidAndBookId[Constant.BORROW_BOOK_MAX_NUM];
//3.判断是否是有数据 没有有效书籍为0
if(allBorrowedBook == null){
borrowedCount = 0;
}else{
//查看实际书籍大小为多少 是否大于默认的长度5
int allBorrowedBookLen = allBorrowedBook.length;
//大于默认长度 books数组分配实际的大小
if( allBorrowedBookLen > pairOfUidAndBookIds.length){
pairOfUidAndBookIds = new PairOfUidAndBookId[allBorrowedBookLen];
}
//把读到的元素进行赋值
for (int i = 0; i < allBorrowedBookLen; i++) {
pairOfUidAndBookIds[i] = allBorrowedBook[i];
}
//修改实际有效书籍个数
borrowedCount = allBorrowedBookLen;
}
}
在NormalUser类中完善storeBorrowedBook方法
java
private void storeBorrowedBook() {
analyzingBorrowedBook.storeObject(pairOfUidAndBookIds,Constant.BORROWED_BOOK_FILE_NAME);
}
修改NormalUser类的构造方法(调构造方法时调用loadBorrowedBook)
java
public NormalUser(String name, int userID) {
super(name, userID,"普通用户");
loadBorrowedBook();
}
5 管理员端业务实现
添加书籍
检查权限是否合法-》调⽤管理员内部添加⽅法准备数据-》调⽤Libary⽅法进⾏业务具体实现

在前面这个我们已经实现了前两步
我们现在实现Library类的addBook方法
java
public void addBook(Book book) {
if(bookCount >= books.length) {
System.out.println(" 图书馆已满,⽆法上架更多图书! ");
//TODO:扩容
return;
}
books[bookCount] = book;//将书籍对象存入数组
//当前书籍为第一本书
if(bookCount == 0){
book.setBookId(1);
}else{
Book bookLast = books[bookCount - 1];
book.setBookId(bookLast.getBookId() + 1);
}
bookCount++;
storeBook();
System.out.println(" 图书 "+book.getTitle()+" 上架成功! ");
}
我们在LibrarySystem类中测试一下

更新书籍

1.ProxyUser类:
java
public void updateBook(){
checkRealUserWhetherAdminUser("普通用户没有权限更新书籍");
((AdminUser)realUser).updateBook();
}
完成上面这一步我们要完善Library类的disPlay方法还有添加searchById方法
java
public void disPlayBook(){
for (int i = 0; i < bookCount; i++) {
System.out.println(books[i]);
}
}
java
public Book searchById(int bookId){
loadAllBook();
for (int i = 0; i < bookCount; i++) {
if(books[i].getBookId() == bookId){
return books[i];
}
}
return null;
}
2.AdminUser类:
java
public void updateBook(){
System.out.println("目前所有书籍信息如下: ");
library.disPlayBook();
System.out.println(" 请输⼊要修改的图书 id: ");
int bookId = scanner.nextInt();
//吞掉换⾏符
scanner.nextLine();
//获取对应的图书
Book book = library.searchById(bookId);
if(book == null) {
System.out.println(" 没有 Id 为: "+bookId+" 的书籍! ");
return;
}
System.out.println(" 当前书名: " + book.getTitle());
System.out.println(" 请输⼊新的书名: ");
String newTitle = scanner.nextLine(); //输⼊新的书名
System.out.println(" 当前作者: " + book.getAuthor());
System.out.println(" 请输⼊新的作者: ");
String newAuthor = scanner.nextLine(); //输⼊新的作者
System.out.println(" 当前类别: " + book.getCategory());
System.out.println(" 请输⼊新的类别: ");
String newCategory = scanner.nextLine(); //输⼊新的类别
//更新对应书籍的信息
book.setTitle(newTitle);
book.setAuthor(newAuthor);
book.setCategory(newCategory);
library.updateBook(book);
}
Library类
java
public void updateBook(Book book) {
//⼀定要进⾏存储
storeBook();
System.out.println("更新书籍成功,更新后书籍信息如下: ");
System.out.println(book);
}
我们完成一下Library类的exit方法
java
public void exit(){
System.exit(0);
}
移除(下架)书籍

ProxyUser类
java
public void removeBook(){
checkRealUserWhetherNormalUser("普通用户没有权限移除书籍");
((AdminUser)realUser).removeBook();
}
AdminUser类
java
public void removeBook(){
System.out.println("目前所有书籍信息如下: ");
library.disPlayBook();
System.out.println(" 请输⼊要移除的图书的 Id: ");
int bookId = scanner.nextInt();
scanner.nextLine(); //吞掉换⾏符
//记录⼀下删除的图书对象
Book removeBook = library.searchById(bookId);
if(removeBook == null){
System.out.println("没有你要移除的图书");
return;
}
//开始删除
library.removeBook(bookId);
}
Library类
java
public void removeBook(int bookId) {
int index = searchByIdReturnIndex(bookId);//开始删除从当前位置的后边往前移动
if(index == -1){
System.out.println("没有你要删除的书籍");
return;
}
//bookCount-1防止越界
for (int i = index; i < bookCount-1; i++) {
books[i] = books[i+1];
}
books[bookCount-1] = null;//把最后一个元素置为null
storeBook();
bookCount--;
}
在Library类中添加searchByIdReturnIndex方法
java
private int searchByIdReturnIndex(int bookId) {
loadAllBook();
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
if(book.getBookId() == bookId) {
return i;
}
}
return -1;
}
图示

查看图书借阅次数

ProxyUser类
java
public void borrowCount(){
checkRealUserWhetherAdminUser("普通用户没有权限查看借阅次数");
((AdminUser)realUser).borrowCount();
}
AdminUser
java
public void borrowCount(){
library.borrowCount();
}
Library类
java
public void borrowCount() {
loadAllBook();
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
System.out.println("书籍名称 " + book.getTitle() + " 借阅次数 " + book.getBorrowCount());
}
}
查看最受欢迎的前K本书

ProxyUser类
java
public void generateBook(){
checkRealUserWhetherAdminUser("普通用户没有权限查看最受欢迎的前k本书");
((AdminUser)realUser).generateBook();
}
我们要比较最受欢迎的书,所以我们采用比较借阅次数从大到小,在Book类中的compareTo方法写入比较方式
java
public int compareTo(Book o) {
return o.borrowCount - this.borrowCount;
}
在Library类中添加getBookCount方法
java
public int getBookCount() {
return bookCount;
}
AdminUser类
java
public void generateBook(){
System.out.println(" 请输⼊你要查看的最受欢迎的前 K 本书 , 注意 k 值不能超 过: "+library.getBookCount());
int k = scanner.nextInt();
if(k <= 0 || k > library.getBookCount()) {
System.out.println(" 没有最受欢迎的前 "+k+" 本书!");
return;
}
library.generateBook(k);
}
Library类
在Library类中添加generateBook方法
java
public void generateBook(int k) {
loadAllBook();
//把所有的书放在临时数据
Book[] tmp = new Book[getBookCount()];
for (int i = 0; i < getBookCount(); i++) {
tmp[i] = books[i];
}
Arrays.sort(tmp);
//把前k本书拷贝到数组
Book[] generateBook = new Book[k];
for (int i = 0 ;i < k; i++){
generateBook[i] = tmp[i];
}
System.out.println("最受欢迎的前K本书如下: ");
for (int i = 0; i < k; i++) {
Book book = generateBook[i];
System.out.println("书名 " + book.getTitle() + " 作者 " + book.getAuthor() + " 借阅次数 " + book.getBorrowCount());
}
}
查看库存状态

ProxyUser类:
java
public void checkInventoryStatus(){
checkRealUserWhetherAdminUser("普通用户没有权限查看查看库存状态");
((AdminUser)realUser).checkInventoryStatus();
}
AdminUser
java
public void checkInventoryStatus(){
library.checkInventoryStatus();
}
在Library类添加checkInventoryStatus方法
java
public void checkInventoryStatus() {
loadAllBook();
System.out.println("=============================");
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
String status = book.isBorrowed() ? "已借出" : "在馆";
System.out.println(" 书名: "+book.getTitle()+"⽬前状态: "+status);
}
System.out.println("=================================");
}
移除上架超过1年的书籍

ProxyUser类:
java
public void checkAndRemoveOldBooks(){
checkRealUserWhetherAdminUser("普通用户没有权限移除上架超过一年的书籍");
((AdminUser)realUser).checkAndRemoveOldBooks();
}
AdminUser类
java
public void checkAndRemoveOldBooks(){
library.checkAndRemoveOldBooks();
}
Library类
在Library类中添加Scanner对象
java
public Scanner scanner = new Scanner(System.in);
在Libray类中添加checkAndRemoveOldBooks方法
java
public void checkAndRemoveOldBooks(){
//确保操作的是最新数据
loadAllBook();
//获取当前时间戳
long currentTimestamp = System.currentTimeMillis();//获取当前距离 1970 年的毫秒数
// 将当前时间戳为转换为 LocalDateTime 将毫秒数转为瞬时时间点 关联本地时区 最终转为不含时区的日期时间格式
LocalDateTime currentDate = Instant.ofEpochMilli(currentTimestamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
boolean flg = false;//标记位,用来记录是否找到了满足条件的旧书
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
//获取当前书籍的上架时间
LocalDateTime specifiedDate = book.getShelfDate();
//计算两个日期之间的差值(以年为单位)
long yearsBetween = ChronoUnit.YEARS.between(specifiedDate,currentDate);
if(yearsBetween >= 1){
System.out.println("图书 " + book.getTitle() + " 已经上架一年,是否移除?(y/n): ");
String response = scanner.nextLine();// 读取用户的输入
if(response.equalsIgnoreCase("y")){
//确认删除调用remove方法进行删除
removeBook(book.getBookId());
i--;//因为后面的书已经向前移动所以要重新检查当前索引位置
}
flg = true;// 标记找到了旧书
}
}
if(!flg){
System.out.println("没有上架超过一年的书籍! ");
}else{
System.out.println("删除成功");
}
storeBook();
}
6 普通⽤户端业务实现
借阅图书

ProxyUser类
java
public void borrowBook( ){
checkRealUserWhetherNormalUser("管理员用户没有权限借阅书籍");
((NormalUser)realUser).borrowBook();
}
NormalUser类
在NormalUser类中添加
java
private Library library;
把构造方法改为
java
public NormalUser(String name, int userID) {
super(name, userID,"普通用户");
library = Library.getLibrary();
loadBorrowedBook();
}
java
public void borrowBook() {
System.out.println("目前书籍信息如下: ");
library.disPlayBook();
System.out.println("请输入你要借阅的书籍Id: ");
int bookId = scanner.nextInt();
//1.检查如果没有书籍,就不能借阅
if(library.getBookCount() == 0){
System.out.println("书架没有书籍不能借阅");
return;
}
//加载已借阅书籍信息
loadBorrowedBook();
//判断要借阅的书 是否存在
Book book = library.searchById(bookId);
if(book == null){
System.out.println("没有该Id的相关书籍: " +bookId);
return;
}
//加载 是否当前要借阅的书籍 之前被自己 或者 别人借阅过
for (int i = 0; i < borrowedCount; i++) {
PairOfUidAndBookId pairOfUidAndBookId = pairOfUidAndBookIds[i];
//找到对应的书籍
if(pairOfUidAndBookId.getBookId() == book.getBookId()){
if(getUserID() == pairOfUidAndBookId.getUserId()){
System.out.println("该书已经被你借阅过了,你的ID是: " +getUserID());
return;
}else{
System.out.println("该书已经被人借阅过了.他的Id是: " + pairOfUidAndBookId.getUserId());
return;
}
}
}
library.borrowBook(bookId);
//封装对象写到借阅表当中
PairOfUidAndBookId pairOfUidAndBookId = new PairOfUidAndBookId(userID, book.getBookId());
pairOfUidAndBookIds[borrowedCount] = pairOfUidAndBookId;
borrowedCount++;
//存储借阅图书
storeBorrowedBook();
System.out.println(" 借阅成功! ");
}
Library类
添加borrowBook方法
java
public void borrowBook(int bookId) {
loadAllBook();
for (int i = 0; i < getBookCount(); i++) {
Book book = books[i];
if(book.getBookId() == bookId) {
book.setBorrowed(true);
book.incrementBorrowCount();
}
}
storeBook();
}
归还图书
ProxyUser类
java
public void returnBook(){
checkRealUserWhetherNormalUser("管理员请以普通用户的身份归还书籍");
((NormalUser)realUser).returnBook();;
}
NormalUser类
• 归还图书需要注意,内存中的数组pairOfUidAndBookIds 也需要删除,同时有效记录数borrowedCount 也要相应改变
• 对借阅书籍⽂件和全部书籍⽂件都要进⾏更新操作
java
public void returnBook() {
System.out.println("目前书籍信息如下: ");
library.disPlayBook();
System.out.println("请输入你要归还的书籍Id: ");
int bookId = scanner.nextInt();
//1.检查如果没有书籍,就不能归还
if(library.getBookCount() == 0){
System.out.println("书架没有书籍不能归还");
return;
}
//加载已借阅书籍信息
loadBorrowedBook();
//判断要归还的书 是否存在
Book book = library.searchById(bookId);
if(book == null){
System.out.println("没有归还的书籍: " +bookId);
return;
}
for (int i = 0; i < borrowedCount; i++) {
//如果2本书的ID,则认为是同⼀本书
if (pairOfUidAndBookIds[i].getBookId() == book.getBookId()) {
//借阅⽤户也⼀样
if (getUserID() == pairOfUidAndBookIds[i].getUserId()) {
library.returnBook(bookId);
System.out.println(" 图书 '" + book.getTitle() + "' 已成功归还 ");
// ⽤最后⼀本替换归还的书
pairOfUidAndBookIds[i] = pairOfUidAndBookIds[borrowedCount - 1];
//清空最后⼀个
pairOfUidAndBookIds[borrowedCount - 1] = null;
borrowedCount--;
storeBorrowedBook();
}else{
System.out.println(" 该书籍不是你借阅的书籍,不能归还: "+book.getTitle());
}
return;
}
}
System.out.println(" 你没有借阅该书籍,不需要归还,书籍 ID 为: "+bookId);
}
Library类
添加returnBook方法
java
public void returnBook(int bookId) {
loadAllBook();
for (int i = 0; i < getBookCount(); i++) {
Book book = books[i];
if(book.getBookId()==bookId) {
book.setBorrowed(false);
book.decreaseBorrowCount();
}
}
storeBook();
}
查看个⼈借阅情况
ProxyUser类
java
public void viewBorrowHistory(){
checkRealUserWhetherNormalUser("管理员请以普通用户的身份查看个人借阅情况");
((NormalUser)realUser).viewBorrowHistory();
}
NormalUser类:
• 读取数据到内存数组
• 遍历内存数组即可
java
public void viewBorrowHistory() {
//读取当前借阅所有用户的借阅书籍的情况
loadBorrowedBook();
System.out.println("您的借阅情况如下: ");
if (borrowedCount == 0) {
System.out.println("目前没有借阅记录.....");
} else {
boolean flg = false;
for (int i = 0; i < borrowedCount; i++) {
//这里只能查看属于自己借阅的情况
//用户ID相同的情况下,使用书籍ID查询书籍
if(pairOfUidAndBookIds[i].getUserId() == userID) {
flg = true;
Book book = library.searchById(pairOfUidAndBookIds[i].getBookId());
System.out.println(book);
}
}
if(!flg) {
System.out.println("你没有借阅过书籍! ");
}
}
}
Library类
不进行实现
查找图书
java
public void searchBook(){
System.out.println("请输入你要查找的图书的名称: ");
String title = scanner.nextLine();
Book book = searchByTitle(title);
if(book == null) {
System.out.println("没有你要找的这本书,你查找的书名为: "+title);
return;
} else {
System.out.println("找到了你要查找的书,书的详细信息如下: ");
System.out.println(book);
}
}
在Library类中添加
java
private Book searchByTitle(String title) {
loadAllBook();
for (int i = 0; i < getBookCount(); i++) {
Book book = books[i];
if(book.getTitle().equals(title)) {
return book;
}
}
return null;
}
为了更好的观看,我们将Book类的toString方法修改一下
java
public String toString() {
return "Book{" +
"bookId=" + bookId +
", 书名: '" + title + '\'' +
", 作者: '" + author + '\'' +
", 类别: '" + category + '\'' +
", 出版年份: " + publishYear +
", 是否被借出: " + ((isBorrowed) ? "已借出" : "未借出") +
", 借阅次数: " + borrowCount +
", 上架日期: " + shelfDate +
'}';
}
这是学完JavaSE的第一个项目,到此整个项目便完成了,文章篇幅较长,欢迎各位读者在评论区指出本文代码的其他问题.