一、需求设计
1、登录功能
---------- 欢迎来到图书管理系统 ----------
请输入您的姓名:
(输入一个字符串)
请选择访问角色:1. 普通用户 2. 管理员
(输入 1 or 2)
(根据选择,进入角色对应系统,打印功能菜单)
--------------------- 1. xxx ---------------------
--------------------- 2. xxx ---------------------
……
2、角色操作功能
普通用户:
- 查询图书
- 借阅图书
- 归还图书
- 退出系统
管理员:
- 查询图书
- 增加图书
- 删除图书
- 显示图书
- 退出系统
(进入角色后,可反复执行不同操作,直到退出系统)
二、需求分析
我们要使用的对象分为这3类,角色操作书籍。
1、User
- 分为 NormalUser 和 AdminUser。
- 包含 userName、OperationList 成员变量。应设置为 public ,因为子类需要访问它们。
- menu 成员方法(打印操作菜单,接收选项输入,并返回选项编号)。
- doOperations 成员方法(根据选项编号,执行 OperationList 中的操作)。
- userName 的 getter 方法和 setter 方法(在未来可以扩展 “修改用户名” 功能)。
- 由于不同的角色所拥有的操作不同,menu 方法在 User 中无法实现,因此 User 可设定为抽象类,menu 设定为抽象方法,由不同的角色继承 User 类后,重写 menu 方法。
2、Operation
- 分为 7 种操作。
- 包含 work 成员方法,用于实现操作。
- 由于不同操作的实现不同,work 方法无法在 Operation 中实现,因此可将 Operation 设定为接口,由不同的操作类实现该接口,重写 work 方法。
3、Book
- 包含 bookName、authorName、price、isBorrowed 、bookType 成员变量。
- 构造方法,初始化成员变量。
- 包含所有成员变量的 getter、setter 方法(在未来可以扩展 “管理员修改书籍信息” 功能)。
- 重写 toString 方法,打印 book 对象。
4、BookShelf
- 为了方便管理所有的 Book 对象,设置 BookShelf 类,因此包含 bookList 成员变量。(为什么不设置 OperationList 类?operationList 在确定角色的时候,就已经确定所有操作,且不可更改,不需要对其进行增删改,只需对列表进行访问即可;而 bookList 中的元素在变化、长度也在变化,为了避免冗余代码,需要将 bookList 包装为 BookShelf 类)
- DEFAULT_SIZE 成员常量,即书架容量默认值。
- usedSize 成员变量,已使用的书架容量。
- 构造方法,初始化成员变量。
- 包含所有成员变量的 getter 和 setter 方法(查询、增加、删除、显示、借阅、归还操作需要用到)。
5、Main 类
- 包含 login 方法,实现用户名输入、角色选择操作,并返回用户对象。
- 包含 main 方法,作为程序入口,实现登录功能,然后循环执行对应角色操作。
综上所述,项目分为 user 包、operation 包、book 包,默认包(根包)包含以上三种包,并包含 Main 类用于控制主逻辑,目录如下:
三、代码实现
代码链接:test_2025_1_20 · 小猪咪/JavaSE Practice - 码云 - 开源中国
1、user 包
(1)User 抽象类
package user;
import book.BookShelf;
import operation.IOperational;
public abstract class User {
public String userName;
public IOperational[] operationList;
public User(String userName) {
this.userName = userName;
}
public abstract int menu();
public void doOperation(int choice, BookShelf bookShelf){
this.operationList[choice].work(bookShelf);
}
}
(2)NormalUser 类
package user;
import operation.*;
import java.util.Scanner;
public class NormalUser extends User{
public NormalUser(String userName) {
super(userName);
this.operationList = new IOperational[] {
new ExitSystem(),
new FindBook(),
new BorrowBook(),
new ReturnBook()
};
}
@Override
public int menu() {
System.out.println("--------------- 普通用户 ---------------");
System.out.println("-------------- 1.查询图书 --------------");
System.out.println("-------------- 2.借阅图书 --------------");
System.out.println("-------------- 3.归还图书 --------------");
System.out.println("-------------- 0.退出系统 --------------");
Scanner scanner = new Scanner(System.in);
int choice;
while (true) {
System.out.println("请选择您的操作:");
choice = scanner.nextInt();
scanner.nextLine(); // 吃掉回车
if (choice >= 0 && choice <= 3)
break;
else
System.out.println("没有该选项,请重新选择!");
}
return choice;
}
}
(3)AdminUser 类
package user;
import operation.*;
import java.util.Scanner;
public class AdminUser extends User{
public AdminUser(String userName) {
super(userName);
this.operationList = new IOperational[] {
new ExitSystem(),
new FindBook(),
new AddBook(),
new DeleteBook(),
new ShowBooks()
};
}
@Override
public int menu() {
System.out.println("--------------- 管理员 ---------------");
System.out.println("-------------- 1.查询图书 --------------");
System.out.println("-------------- 2.增加图书 --------------");
System.out.println("-------------- 3.删除图书 --------------");
System.out.println("-------------- 4.显示图书 --------------");
System.out.println("-------------- 0.退出系统 --------------");
Scanner scanner = new Scanner(System.in);
int choice;
while (true) {
System.out.println("请选择您的操作:");
choice = scanner.nextInt();
scanner.nextLine(); // 吃掉回车
if (choice >= 0 && choice <= 4)
break;
else
System.out.println("没有该选项,请重新选择!");
}
return choice;
}
}
2、operation 包
(1)IOperational 接口
package operation;
import book.BookShelf;
public interface IOperational {
void work(BookShelf bookShelf);
}
(2)FindBook 类
package operation;
import book.Book;
import book.BookShelf;
import java.util.Scanner;
public class FindBook implements IOperational{
@Override
public void work(BookShelf bookShelf) {
System.out.println("请输入您要查询的书籍名称:");
Scanner scanner = new Scanner(System.in);
String bookName = scanner.nextLine();
// 遍历书架
int usedSize = bookShelf.getUsedSize();
for (int i = 0; i < usedSize; i++) {
Book book = bookShelf.getBook(i);
// 找到图书,打印书籍信息
if(book.getBookName().equals(bookName)) {
System.out.println("查询成功,书籍信息如下:");
System.out.println(book);
return;
}
}
// 未找到书籍
System.out.println("查询失败,本系统没有此书。");
}
}
(3)BorrowBook 类
package operation;
import book.Book;
import book.BookShelf;
import java.util.Scanner;
public class BorrowBook implements IOperational{
@Override
public void work(BookShelf bookShelf) {
System.out.println("请输入您要借阅的书籍名称:");
Scanner scanner = new Scanner(System.in);
String bookName = scanner.nextLine();
// 遍历书架
int usedSize = bookShelf.getUsedSize();
for (int i = 0; i < usedSize; i++) {
Book book = bookShelf.getBook(i);
// 找到图书,查询是否被借阅
if(book.getBookName().equals(bookName)) {
// 未被借阅,则借出
if(!book.isBorrowed()){
book.setBorrowed(true);
System.out.println("借阅成功!");
System.out.println(book);
}
else System.out.println("该书已被借出!");
return;
}
}
// 未找到
System.out.println("本系统没有此书!");
}
}
(4)ReturnBook 类
package operation;
import book.Book;
import book.BookShelf;
import java.util.Scanner;
public class ReturnBook implements IOperational{
@Override
public void work(BookShelf bookShelf) {
System.out.println("请输入您要归还的书籍名称:");
Scanner scanner = new Scanner(System.in);
String bookName = scanner.nextLine();
// 遍历书架
int usedSize = bookShelf.getUsedSize();
for (int i = 0; i < usedSize; i++) {
Book book = bookShelf.getBook(i);
// 找到图书,查询是否被借阅
if(book.getBookName().equals(bookName)) {
// 未被借阅,则不需要归还
if(!book.isBorrowed())
System.out.println("该书未被借出,请不要重复归还!");
// 归还书籍
else {
book.setBorrowed(false);
System.out.println("归还成功!");
System.out.println(book);
}
return;
}
}
// 未找到
System.out.println("本系统没有收录此书,不需要归还!");
}
}
(5)AddBook 类
package operation;
import book.Book;
import book.BookShelf;
import java.util.Arrays;
import java.util.Scanner;
public class AddBook implements IOperational{
@Override
public void work(BookShelf bookShelf) {
// 书架已经放满,扩容
if(isFull(bookShelf)) {
Book[] bookList = bookShelf.getBookList();
double newLength = bookList.length * 1.5;
// 大于 bookList 长度的部分,Arrays.copyOf 会设置为数组元素的默认值
bookShelf.setBookList(Arrays.copyOf(bookList, (int)newLength));
}
Scanner scanner = new Scanner(System.in);
System.out.println("请输入书名:");
String bookName = scanner.nextLine();
System.out.println("请输入作者:");
String authorName = scanner.nextLine();
System.out.println("请输入书籍类型:");
String bookType = scanner.nextLine();
System.out.println("请输入书籍价格:");
float price = scanner.nextFloat();
int usedSize = bookShelf.getUsedSize();
// 遍历书架
for (int i = 0; i < usedSize; i++) {
Book book = bookShelf.getBook(i);
// 书籍已存在
if(book.getBookName().equals(bookName)) {
System.out.println("该书已被收录,请勿重复添加!");
return;
}
}
// 添加书籍
bookShelf.setBook(usedSize, new Book(bookName, authorName, bookType, price));
bookShelf.setUsedSize(usedSize + 1);
}
public boolean isFull(BookShelf bookShelf){
return bookShelf.getBookList().length == bookShelf.getUsedSize(); // 书架容量 == 已用容量
}
}
(6)DeleteBook 类
package operation;
import book.Book;
import book.BookShelf;
import java.util.Scanner;
public class DeleteBook implements IOperational{
@Override
public void work(BookShelf bookShelf) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您要删除的书籍名称:");
String bookName = scanner.nextLine();
int usedSize = bookShelf.getUsedSize();
// 遍历书架
for (int i = 0; i < usedSize; i++) {
Book book = bookShelf.getBook(i);
// 书籍存在,删除
if (book.getBookName().equals(bookName)) {
for(int j = i; j < usedSize - 1; j++)
bookShelf.setBook(j, bookShelf.getBook(j + 1));
bookShelf.setUsedSize(usedSize - 1);
bookShelf.setBook(usedSize - 1, null);
return;
}
}
// 书籍不存在
System.out.println("没有此书,无需删除!");
}
}
(7)ShowBook 类
package operation;
import book.Book;
import book.BookShelf;
public class ShowBooks implements IOperational{
@Override
public void work(BookShelf bookShelf) {
// 遍历书架
int usedSize = bookShelf.getUsedSize();
for (int i = 0; i < usedSize; i++) {
Book book = bookShelf.getBook(i);
System.out.println(book);
}
}
}
(8)ExitSystem 类
package operation;
import book.BookShelf;
public class ExitSystem implements IOperational{
@Override
public void work(BookShelf bookShelf) {
// 释放书架空间
int usedSize = bookShelf.getUsedSize();
for (int i = 0; i < usedSize; i++)
bookShelf.setBook(i,null);
bookShelf.setUsedSize(0);
// 退出系统
System.exit(0);
}
}
3、book 包
(1)Book 类
package book;
public class Book {
private String bookName;
private String authorName;
private String bookType;
private float price;
private boolean isBorrowed; // 默认设置为 false 没有被借出
public Book(String bookName, String authorName, String bookType, float price) {
this.bookName = bookName;
this.authorName = authorName;
this.bookType = bookType;
this.price = price;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public String getBookType() {
return bookType;
}
public void setBookType(String bookType) {
this.bookType = bookType;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
@Override
public String toString() {
return "Book{" +
"bookName:'" + bookName + '\'' +
", authorName:'" + authorName + '\'' +
", bookType:'" + bookType + '\'' +
", price:" + price +
", isBorrowed:'" + (isBorrowed ? "已被借出" : "未被借出") + '\'' +
'}';
}
}
(2)BookList 类
package book;
public class BookShelf {
private Book[] bookList;
private static final int DEFAULT_SIZE = 4;
private int usedSize;
public BookShelf() {
this.bookList = new Book[DEFAULT_SIZE];
this.bookList[0] = new Book("三体", "刘慈欣", "科幻", (float)83.8);
this.bookList[1] = new Book("射雕英雄传", "金庸", "武侠", (float)94.25);
this.bookList[2] = new Book("倾城之恋", "张爱玲", "情感", (float)24.69);
this.usedSize = 3;
}
public Book[] getBookList() {
return bookList;
}
public void setBookList(Book[] bookList) {
this.bookList = bookList;
}
public Book getBook(int pos) {
return this.bookList[pos];
}
public void setBook(int pos, Book book) {
this.bookList[pos] = book;
}
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
}
4、Main 类
import book.BookShelf;
import user.*;
import java.util.Scanner;
public class Main {
public static User login(){
System.out.println("---------- 欢迎来到图书管理系统 ----------");
System.out.println("请输入用户名:");
Scanner scanner = new Scanner(System.in);
String userName = scanner.nextLine();
while(true){
System.out.println("请选择角色 (1.普通用户 or 2.管理员):");
int choice = scanner.nextInt();
if(choice == 1)
return new NormalUser(userName);
else if(choice == 2)
return new AdminUser(userName);
else System.out.println("没有此选项,请重新输入!");
}
}
public static void main(String[] args) {
User user = login(); // 登录
BookShelf bookShelf = new BookShelf();
while (true) {
int choice = user.menu();
user.doOperation(choice, bookShelf);
}
}
}
四、功能测试
1、登录功能测试
(1)普通用户登录
(2)管理员登录
2、操作功能测试
(1)查询图书
查询不存在的书籍:
查询存在的书籍:
(2)借阅图书
借阅不存在的书籍:
借阅存在且被未借出的书籍:
借阅存在且被借出的书籍:
(3)归还图书
归还不存在的书籍:
归还存在且被借出的书籍:
归还存在且被未借出的书籍:
(4)添加图书及显示图书
书架容量,默认为 4,以初始化放入三本书。
添加已存在的书籍:
书架未满,添加图书:
书架已满,添加图书:
显示图书:
(5)删除图书
删除图书不存在:
删除图书存在:
(6)退出系统
五、总结
本图书管理系统用到了 Java 的基本语法、继承、抽象类、接口、动态规划等知识,是个不错的小练习。
六、补充 -- Statistic 插件
File >> settings >> Plugins >> 搜索 Statistic >> install >> Apply,刷新,可以看到项目有 363 行代码: