📢 文章前提:
相信大家都有去过图书馆,当我们要借阅或者归还该图书馆的图书的时候,会用到一个机器,机器上有借阅图书,归还图书,查找图书……功能
如下图:👇
☝️ 我们可以看到界面里包含图书名,作者名,图书的借阅情况……
📌 今天本博客将借助 Java 来实现类似这样的一个简化版图书馆管理系统
📑 文章目录:
1️⃣ 思路分析
图书管理系统,该项目是 JavaSE 语法以及数据结构的简单综合应用,该项目用到了以下知识:👇
类,对象,抽象类,接口,封装,继承,多态,顺序表
👉 所以这个小项目可以综合复习运用到以上知识,并让我们真正的去了解面向对象编程这个概念
现在正式分析该项目的思路:
- 首先我们需要定义一个 book 类,这个类代表的是一本书的基本信息,包括该书的书名,作者名,价格,是否在馆,并编写构造方法,对图书的基本信息进行初始化,提供 Get Set 接口实现信息的输入输出,重写 toString 方法,便于一会打印图书的信息,该 book 类需要自己动手代码很少,除了图书基本信息的定义,其他内容都可以使用快捷键(Alt + Ins)快速生成
- 图书馆一般都是成千上万的图书,这时候需要我们把每一本书组织起来,这时候用到顺序表,所以第二步需要定义一个 bookList,,这里我们可以把这样的一个顺序表看作一个书架,书架用于存放组织图书
- 在编写操作(操作的是 bookList 顺序表)时,我们稍微的增大难度,不在 bookList 中实现对图书的操作,我们让操作也面向对象,这就意味着,每一个操作都是一个类,所以第三步就是根据不同的操作去创建不同的类
- 由于用户中存在普通用户以及后台管理人员,所以第四步我们需要定义一个 user 包,里面定义三个类,一个用户类(父类),一个普通用户类(子类),一个管理员类(子类),用户类作为两种具体身份类的父类,普通用户类和管理员类可以继承父类属性及方法,在子类中提供构造方法,构造方法中构造好操作类数组,然后根据不同的身份去定义菜单,由于用户需要根据菜单去进行选择实现的功能,所以菜单里面需要返回用户输入的选项,切记在父类中也要定义一个 menu 方法,方便一会进行动态绑定
- 提供一个 Main 类作为整个程序的入口,输入初始化信息,姓名以及管理员用户的身份信息,根据不同的身份去调用不同的类,根据不同类再去调用不同的菜单,这里会发生动态绑定和向上转型,调用菜单会返回一个操作的选项,根据此选项去实现不同的操作
- 每一个操作都设计成一个类,最后就是实现每一个功能的实现
📄 图解:👇
2️⃣ 代码分析
步骤一、先编写一个图书类(代表的是一本图书),定义图书的基本属性+构造方法+重写 toString 方法,由于图书本身的属性不需要外界的操作,所以这里使用私有属性 private 进行成员属性的修饰 👇
private String name;
private String author;
private int money;
private String type;
private boolean isBorrow;
public Book(String name, String author, int money, String type) {
this.name = name;
this.author = author;
this.money = money;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isBorrow() {
return isBorrow;
}
public void setBorrow(boolean borrow) {
isBorrow = borrow;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", money=" + money +
", type='" + type + '\'' +
((isBorrow == true) ? " 该书未在馆 " : " 该书在馆 ") +
'}';
}
}
步骤二、(拆解讲解)👇
①.定义 bookList (书架),即是定义一个顺序表,顺序表底层是一个数组,先初步搭建一个顺序表,这里默认书架上可以存放十本图书,定义一个大小为 10 的图书(Book)类的数组,再定义一个 usedSize 去记录目前书架的现有图书数量
public class BookList {
private Book[] books = new Book[10];
private int usedSize;
②.提供书架 bookList 的构造方法,这里先默认在书架上放了三本书,按照 Book 类的构造方法初始化三本书,再把计数器赋值成 3
public BookList() {
books[0] = new Book("三国演义","罗贯中",17,"小说");
books[1] = new Book("西游记","吴承恩",47,"小说");
books[2] = new Book("水浒传","施耐庵",37,"小说");
usedSize = 3;
}
③.提供计数器 usedSize 的输入输出的接口,由于图书在后面有单独的插入展示操作,所以这里不需要提供数组的输入输出接口
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
④.提供两个方法,分别是用来得到指定下标的图书,在指定位置插入图书,由于书架是一个顺序表(数组),所以这里可以利用下标对书架进行操作,两个操作过于简单不做展开
public Book getBook(int pos){
if (pos < 0 || pos > usedSize){
System.out.println("位置不合法");
return null;
}
return books[pos];
}
public void setBook(int pos, Book book){
if (pos < 0 || pos > usedSize){
System.out.println("位置不合法");
return;
}
this.books[pos] = book;
}
步骤三、以上的代码都是关于图书的所以把 Book 类和 BookList 类都放在 book 包中,之后定义一个 operation 包里面,实现对图书的操作
①.先定义一个接口 IOperation,里面定义一个 Scanner 类便于其他操作类输入信息,在接口中实现减少代码重复,再定义一个 work 方法参数是bookList(书架),因为需要对书架上的书进行操作,在接口中定义 work 方法是为了方便通过多态去对实现不同的操作
public interface IOperation {
Scanner scanner = new Scanner(System.in);
void work(BookList bookList);
}
②.新增图书,重写 work 类实现增加图书,输入新增图书的属性,把这些属性初始化成一本书,利用上面写好的插入方法把该书插入到书架上,然后书架书的数目增加一本
public class AddOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("新增图书!");
System.out.println("请输入图书的名字:");
String name = scanner.nextLine();
System.out.println("请输入图书的作者:");
String author = scanner.nextLine();
System.out.println("请输入图书的类型:");
String type = scanner.nextLine();
System.out.println("请输入图书的价格:");
int price = scanner.nextInt();
Book book = new Book(name,author,price,type);
int size = bookList.getUsedSize();
bookList.setBook(size,book);
bookList.setUsedSize(size+1);
System.out.println("新增图书成功!");
}
}
③.借阅图书,输入借阅的书名,循环在书架上进行查找,找到了把 isBorrow 赋值为 true 证明该书被此人借阅出去了,循环结束时还没找到证明没有这本书
public class BorrowOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("正在进行借阅图书操作");
System.out.println("输入你想要借阅的图书名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int i = 0;
for (i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(name)){
System.out.println("该书在馆可以借阅");
book.setBorrow(true);
System.out.println(book);
break;
}
}
if (i == bookList.getUsedSize()){
System.out.println("该书没有或未在馆内无法借阅");
return;
}
}
}
④.删除图书,输入想要删除的图书名,循环去进行查找如果找到了就把该书的位置 i 赋值给 pos 记录好当前图书的位置,如果循环结束没有找到就是没有这本书,最后进行删除操作,即把该书后面的数组元素都向前赋值一个位置,为了防止越界访问,删除的时候循环的终止条件是书架的图书总数减 1
最后把最后一个数组元素指向空对象并把图书的个数减少一本
public class DelOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("正在进行删除图书操作");
System.out.println("输入想要进行删除操作的图书名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int pos = 0;
int i = 0;
for (i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(name)){
pos = i;
}
}
if (i >= bookList.getUsedSize()){
System.out.println("没有此书");
}
for (int j = pos; j < bookList.getUsedSize() - 1; j++) {
Book book = bookList.getBook(j + 1);
bookList.setBook(j,book);
}
bookList.setBook(bookList.getUsedSize(), null);
bookList.setUsedSize(bookList.getUsedSize() - 1);
System.out.println("删除图书成功");
}
}
⑤.展示图书,循环打印出对应下标位置的图书即可
public class DisplayOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("正在进行展示图书操作");
for (int i = 0; i < bookList.getUsedSize(); i++) {
System.out.println(bookList.getBook(i));
}
}
}
⑥.退出界面,使用 System.exit(0) 退出 0 代表正常程序结束
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("正在进行退出操作");
System.exit(0);
}
}
⑦.查找指定名字的图书,循环和输入的图书名进行比对,找到了打印这本书的信息程序结束,循环结束证明没找到
public class FindOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("正在进行查找图书操作");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(name)){
System.out.println("该书在馆");
System.out.println(book);
return;
}
}
System.out.println("图书不存在");
}
}
⑧.归还图书,输入归还的图书名,循环进行比对,找到了把 isBorrow 赋值为 false 证明图书在馆,循环结束没找到,证明归还的不是本图书馆的图书
public class ReturnOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("归还图书");
System.out.println("请输入你要归还的图书的名字:");
String name = scanner.nextLine();
int size = bookList.getUsedSize();
for (int i = 0; i < size; i++) {
Book book = bookList.getBook(i);
if(name.equals(book.getName())) {
book.setBorrow(false);
System.out.println("归还成功!");
System.out.println(book);
return;
}
}
System.out.println("没有你要归还的这本书!");
}
}
步骤四、定义一个 user 包,里面包括两种不同的身份和一个父类 User 用来存储二者共同属性
①.定义父类 User ,定义姓名,构造方法对名字进行初始化
protected String name;
public User(String name) {
this.name = name;
}
②.定义一个菜单方法,两种身份的人都需要进行调用,父类的菜单方法不需要写任何内容,所以把其定义为抽象类,菜单的实现交给子类重写,方便实现动态绑定
public abstract int menu();
③.定义一个操作类数组,通过该数组可以去实现对应菜单标号的操作
protected IOperation[] iOperations;
④.提供一个实现操作的方法,通过用户/管理员的选择数字去对顺序表实现操作
public void doWork(int choice, BookList bookList){
iOperations[choice].work(bookList);
}
⑤.定义一个普通用户类,先重写父类的菜单方法,定义一个供用户选择的 choice 根据选项实现不同的功能
public int menu() {
System.out.println("===========普通用户的菜单===========");
System.out.println("hello " + this.name +" 欢迎来到这里!");
System.out.println("1.查找图书");
System.out.println("2.借阅图书");
System.out.println("3.归还图书");
System.out.println("0.退出系统");
System.out.println("==============================");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
⑥.帮助父类进行构造,这里也把操作数组进行初始化,根据菜单的编号的顺序(注意这里一定要保证顺序否则实现的操作对不上号)去实例化
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
⑦.定义一个管理员类,编写的方法和上方一致(不赘述),在初始化操作数组的时候,实例化的对象不一致(二者实现的操作不一样),
public class AdminUser extends User {
public AdminUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new DisplayOperation()
};
}
public int menu(){
System.out.println("===========管理员菜单===========");
System.out.println("hello " + this.name +" 欢迎来到这里!");
System.out.println("1.查找图书");
System.out.println("2.新增图书");
System.out.println("3.删除图书");
System.out.println("4.显示图书");
System.out.println("0.退出系统");
System.out.println("==============================");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
步骤五、①.定义程序的入口,先定义一个 login 登录方法,这个方法主要判断的是此人的身份,所以这里的返回值是一个 User 类,根据选项去返回不同的身份
public static User login(){
System.out.println("输入姓名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("身份识别:0--->用户 || 1--->管理员");
int chioce = scanner.nextInt();
if(chioce == 0){
return new NormalUser(name);
}
else{
return new AdminUser(name);
}
}
②.主方法中实例化一个书架,调用登录方法,返回的是一个对象,这里使用 User 类去结束这里发生向上转型,父类引用子类对象,循环去实现对书架的操作,通过 user 去访问子类的菜单(动态绑定),这时候的 user 是 NormalUser / AdminUser 所以通过 doWork 去实现各自不同的操作即可,这里传入选择的操作以及顺序表本身(操作的是顺序表)
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login();
while (true)
{
int choice = user.menu();
user.doWork(choice,bookList);
}
}
3️⃣ 源代码
一、book包
public Book(String name, String author, int money, String type) {
this.name = name;
this.author = author;
this.money = money;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isBorrow() {
return isBorrow;
}
public void setBorrow(boolean borrow) {
isBorrow = borrow;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", money=" + money +
", type='" + type + '\'' +
((isBorrow == true) ? " 该书未在馆 " : " 该书在馆 ") +
'}';
}
}
package book;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2021-11-21
* Time: 10:52
*/
public class BookList {
private Book[] books = new Book[10];
private int usedSize;
public BookList() {
books[0] = new Book("三国演义","罗贯中",17,"小说");
books[1] = new Book("西游记","吴承恩",47,"小说");
books[2] = new Book("水浒传","施耐庵",37,"小说");
usedSize = 3;
}
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
public Book getBook(int pos){
if (pos < 0 || pos > usedSize){
System.out.println("位置不合法");
return null;
}
return books[pos];
}
public void setBook(int pos, Book book){
if (pos < 0 || pos > usedSize){
System.out.println("位置不合法");
return;
}
this.books[pos] = book;
}
}
二、操作包(上面都是整理的展示)
三、用户包
package user;
import operation.*;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2021-11-21
* Time: 11:14
*/
public class AdminUser extends User {
public AdminUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new DisplayOperation()
};
}
public int menu(){
System.out.println("===========管理员菜单===========");
System.out.println("hello " + this.name +" 欢迎来到这里!");
System.out.println("1.查找图书");
System.out.println("2.新增图书");
System.out.println("3.删除图书");
System.out.println("4.显示图书");
System.out.println("0.退出系统");
System.out.println("==============================");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
package user;
import operation.*;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2021-11-21
* Time: 11:15
*/
public class NormalUser extends User {
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
public int menu() {
System.out.println("===========普通用户的菜单===========");
System.out.println("hello " + this.name +" 欢迎来到这里!");
System.out.println("1.查找图书");
System.out.println("2.借阅图书");
System.out.println("3.归还图书");
System.out.println("0.退出系统");
System.out.println("==============================");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
package user;
import book.Book;
import book.BookList;
import operation.IOperation;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2021-11-21
* Time: 11:14
*/
public abstract class User {
public abstract int menu();
protected String name;
public User(String name) {
this.name = name;
}
protected IOperation[] iOperations;
public void doWork(int choice, BookList bookList){
iOperations[choice].work(bookList);
}
}
四、程序入口
import book.Book;
import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2021-11-21
* Time: 11:03
*/
public class Main {
public static User login(){
System.out.println("输入姓名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("身份识别:0--->用户 || 1--->管理员");
int chioce = scanner.nextInt();
if(chioce == 0){
return new NormalUser(name);
}
else{
return new AdminUser(name);
}
}
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login();
while (true)
{
int choice = user.menu();
user.doWork(choice,bookList);
}
}
}
此项目用于到了很多知识,基本博主的往期博客都有讲解,需要的关注博主主页,如果有帮助还请一键三连
💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞