在当今信息化的时代,图书管理已经越来越自动化,使得图书馆和读者都更加方便了。针对这一需求,我们进行了Java图书管理小练习,学习了如何运用Java语言去实现基本的图书管理功能。
一、确定方向
首先,我给大家看一个实现完成的例子,由于导入不了视频,只能给图片了
这是用户登录的界面,普通的和管理员的就不一样了,下面这些选项也都是可以完成的,只不过不方便展示。
首先,我们要确定好有几个对象,然后我们再对这些对象进行更细致的实现与串联。通过上面这张图,我们至少可以确定两个对象吧,一个是区分用户的,一个是实现操作的。
但其实我们的对象是有三个:关于书的、关于用户的,还有一个是操作的(例如增加删除这些)。
二、基本框架
确定好方向之后,就可以搭建基本框架了,也就是说,方法体内部可以先不用实现(比如添加书本方法,可以先不写具体是怎么增加的),按照这种思路来写代码是很重要的,是从面向过程到面向对象的一个转型。
(1)’书‘软件包
首先,是图书信息管理模块。我们先定义一个软件包,这个包里面专门放关于书本的类,如下:
包名一定要小写,这是一种编码规范。
在这个书的软件包里面,有什么是关于书的呢?首先,这里面肯定要有个书的类,这是毋庸置疑的,那还有呢?我们放书,是不是还需要有书架呀,所以我们可以定义两个类,其中一个类我们就叫Book
,里面包括书籍名称、作者、价格、类型等属性。代码如下:
package book;
public class Book {
private String name;//书名
private String author;//作者
private double price;//价格
private String type;//类型
private boolean isBorrowed;//是否被借出
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
}
注:这里我建议用private
来修饰,需要改动的话就用get
和set
修改,提高代码安全性和可读性。
另外一个类,我们就叫BookList
,书架上的书籍我们就用数组给它串起来(主要是我们存多种类型相同的数据只学过数组,后面用链表啊这些就会简单很多)代码如下:
package book;
public class BookList {
private Book[] books = new Book[10];//设置一个Book类型的数组,不初始化,因为不知道要放几本书
private int bookSize;//放的实际的书本数
public BookList() {
}
}
有很多小伙伴会想了,那我要把我的书传给Book
啊(比如姓名,作者这些东西),不然怎么初始化呢?唉,说的很对,所以我们要在Book
里面把构造方法给补上,Book
构造方法如下:
public Book(String name, String author, double price, String type) {
= name;
this.author = author;
this.price = price;
this.type = type;
}
所以,这更加说明了,我们写代码只是先想好一个思路,至于实现,那是一个字一个字敲出来的,需要增删查改的地方我们再写,总之就是边写边看,最重要的是先动手。
那我们BoolList
就可以这样写了:
package book;
public class BookList {
private Book[] books = new Book[10];
private int bookSize;
public BookList() {
books[0] = new Book("樱花庄的宠物女孩", "鸭志田一", 29.9, "轻小说");
books[1] = new Book("约会大作战", "橘公司&Tsunako", 69.9, "轻小说");
books[2] = new Book("龙王的牢饭", "白鸟士郎", 29.9, "轻小说");
bookSize = 3;
}
}
(不好意思,这里都是博主比较喜欢的日本小说)
(2)‘用户’软件包
写完这些,关于书的框架就基本上搭好了,然后是关于用户的,和上面的书的包一样,先定义一个user
的包,如下:
这个软件包呢我们就存放两个类,一个是关于用户的,一个是关于管理员的,那定义好这两个类之后,我们第一步,是不是要写个菜单方法呢?我们这个方法就叫menu
吧,我们只需把一开始的那张图上显示出来的东西打印出来就好了,但是有一个问题,就是那里面的名字,他怎么知道我就叫稚名不带撇呢?就算是我输入的,那该怎么写呢?不能在用户的这个类里面写哦,因为我是先输入名字,再输入身份的,你没确定我的身份之前,怎么知道要调用的是管理员,还是普通用户呢?
所以我们可以在软件包的外面定义一个Main
方法体,这里面就是专门干这些东西的,并且,我们要写一个用户的抽象类User
,这个类我们就写一个菜单方法和构造函数来接收我们的name
,Main
的外面写一个方法login
,返回值就是User
,结合向下转型,你能想到什么?没错,就是返回的是哪个子类的类型,我们就调用哪个的菜单,理论结束,下面是Main
的代码实现:
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {
public static User login() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入你的姓名->");
String name = sc.nextLine();
System.out.print("1:管理员 0:普通用户" + "\n" + "请输入你的身份->");
int ues = sc.nextInt();
if (ues == 1) {
return new AdminUser(name);//将返回的类型强转为User
}
else {
return new NormalUser(name);
}
}
public static void main(String[] args) {
User user = login();
user.menu();//返回什么类型,就调用什么类型的menu
}
}
然后是用户的抽象类、管理员和普通用户的:
//User
package user;
abstract public class User {
public String name;
abstract public void menu();
public User(String name) {
= name;
}
}
//管理员的
package user;
public class AdminUser extends User{
public AdminUser(String name) {
super(name);
}
@Override
public void menu() {
System.out.println("管理员菜单");
System.out.println("=====================");
System.out.println("Hello " + + " 欢迎来到图书管理小练习!");
System.out.println("1、查找图书");
System.out.println("2、新增图书");
System.out.println("3、删除图书");
System.out.println("4、显示图书");
System.out.println("0、退出系统");
System.out.println("=====================");
}
}
//普通用户
package user;
import java.util.Scanner;
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
}
@Override
public void menu() {
System.out.println("管理员菜单");
System.out.println("=====================");
System.out.println("Hello " + + " 欢迎来到图书管理小练习!");
System.out.println("1、查找图书");
System.out.println("2、借阅图书");
System.out.println("3、归还图书");
System.out.println("0、退出程序");
System.out.println("=====================");
}
}
定义好这些之后,我们的用户大致框架也差不多搭建好了,就可以爽一下了,结果如下:
接下来就是那些查找书籍这写操作实现了
(3)‘操作’软件包
老样子,我们还是定义一个包,包的名字我们就叫operation
吧,统计一下需要实现的操作<查找图书;新增图书;删除图示;显示图书;借阅图书;归还图书;退出程序>,还需要定义一个接口,里面放一个实现的方法,,后面的操作全部引用这个接口,定义一个叫shiXian
的方法,形参先放着不写,用来他的子类写实现这些具体操作的内部代码的,这样子就不会忘记哪个操作没有实现方法了,所以我们就得到以下的包:
下面这是IOperation
接口的代码:
public interface IOperation {
void shiXian(BookList bookList);
}
三、串联对象小技巧
(4)对象的连接
那我们,到底要怎么把这些包给连起来呢???
这是个很严重的问题,好兄弟们,我们可以在User
定义一个方法,这个方法连接我们的操作包,连接上,就好办了嘛,所以我们要定义一个BookList
类型的数据传过去,把书架传过去,才好对书籍进行增删查改,还有,我们不是要选择执行第几个操作么,所以我们选择的数字也要返回来,和BookList
类型一起传过去,我们的代码就变成这样了:
//Main
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {
public static User login() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入你的姓名->");
String name = sc.nextLine();
System.out.print("1:管理员 0:普通用户" + "\n" + "请输入你的身份->");
int ues = sc.nextInt();
if (ues == 1) {
return new AdminUser(name);//将返回的类型强转为User
}
else {
return new NormalUser(name);
}
}
public static void main(String[] args) {
User user = login();
int choice = user.menu();//返回什么类型,就调用什么类型的menu
}
}
//用户父类
package user;
abstract public class User {
public String name;
abstract public int menu();
public User(String name) {
= name;
}
}
//管理员用户类
//普通用户类
package user;
import java.util.Scanner;
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
}
@Override
public int menu() {
System.out.println("管理员菜单");
System.out.println("=====================");
System.out.println("Hello " + + " 欢迎来到图书管理小练习!");
System.out.println("1、查找图书");
System.out.println("2、借阅图书");
System.out.println("3、归还图书");
System.out.println("0、退出程序");
System.out.println("=====================");
System.out.print("请输入->");
Scanner sc = new Scanner(System.in);
return sc.nextInt();
}
}
那我们的这些选择的操作该怎么办呢?,就算返回了,我们的操作该怎么访问到呢?怎么样才能调用这些操作呢?
我知道你很急,但你先别急,我们可以定义一个IOperation
类型的数组,然后这个数组去new
该用户所拥有的对象方法,等会传过来的choice
就直接是这个数组的下标,直接就能引用了,如下:
//管理员用户类
package user;
import operation.*;
import java.util.Scanner;
public class AdminUser extends User{
public AdminUser(String name) {
super(name);
this.iOperation = new IOperation[] {
new ExitOperation(),
new FindOperation(),
new AddOperaiton(),
new DelOperation(),
new ShowOperation()
};
}
@Override
public int menu() {
System.out.println("管理员菜单");
System.out.println("=====================");
System.out.println("Hello " + + " 欢迎来到图书管理小练习!");
System.out.println("1、查找图书");
System.out.println("2、新增图书");
System.out.println("3、删除图书");
System.out.println("4、显示图书");
System.out.println("0、退出系统");
System.out.println("=====================");
System.out.print("请输入->");
Scanner sc = new Scanner(System.in);
return sc.nextInt();
}
}
//普通用户
package user;
import operation.*;
import java.util.Scanner;
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
this.iOperation = new IOperation[] {
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
@Override
public int menu() {
System.out.println("管理员菜单");
System.out.println("=====================");
System.out.println("Hello " + + " 欢迎来到图书管理小练习!");
System.out.println("1、查找图书");
System.out.println("2、借阅图书");
System.out.println("3、归还图书");
System.out.println("0、退出程序");
System.out.println("=====================");
System.out.print("请输入->");
Scanner sc = new Scanner(System.in);
return sc.nextInt();
}
}
做完这些工作之后,还记得我说的什么吗?那就是需要把这三个给串起来,把你的选选择和这本创建好的书给User
传过去,这个方法的名称是shiXian
,所以它的形参又得改了,如下:
public interface IOperation {
void shiXian(int i, BookList bookList);
}
所以又验证了博主的那句话:”边写边看。“
于是Main
类和User
类的代码就变成了这样->
//Main类
import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {
public static User login() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入你的姓名->");
String name = sc.nextLine();
System.out.print("1:管理员 0:普通用户" + "\n" + "请输入你的身份->");
int ues = sc.nextInt();
if (ues == 1) {
return new AdminUser(name);//将返回的类型强转为User
}
else {
return new NormalUser(name);
}
}
public static void main(String[] args) {
User user = login();
int choice = user.menu();//返回什么类型,就调用什么类型的menu
BookList bookList = new BookList();
user.chuanLian(choice, bookList);
}
}
//User类
package user;
import book.BookList;
import operation.IOperation;
abstract public class User {
public String name;
abstract public int menu();
IOperation[] iOperation;
public User(String name) {
= name;
}
public void chuanLian(int i, BookList bookList) {
//谁调用这个函数,就调用谁的接口数组i是表示这是数组里面的第几个元素,也就是new哪个方法,
//每个操作方法里面都有实现这个方法,把书架传过去,才能操作这些书
this.iOperation[i].shiXian(bookList);
}
}
其实写到这儿,你已经可以爽一下了,就是这个shiXian
方法里面,随便写点,比如我这样
感觉自己是写了,其实啥都没写,好了,玩笑到此为止。
四、操作具体内部实现
(1)退出程序代码实现
首先,我们先挑软柿子捏,直接写退出程序这个方法,很简单,如下;
package operation;
import book.BookList;
public class ExitOperation implements IOperation{
@Override
public void shiXian(BookList bookList) {
System.out.println("退出程序!");
System.exit(0);
}
}
你甚至还可以不要打印,就一行代码,然后我们再挑软一点的,显示图书,这个就要使用到我们的get、set、toString
方法了,下面是代码实现:
(2)显示所有书籍代码实现
//书架类
package book;
public class BookList {
private Book[] books = new Book[10];
private int bookSize;
public BookList() {
books[0] = new Book("樱花庄的宠物女孩", "鸭志田一", 29.9, "轻小说");
books[1] = new Book("约会大作战", "橘公司&Tsunako", 69.9, "轻小说");
books[2] = new Book("龙王的牢饭", "白鸟士郎", 29.9, "轻小说");
bookSize = 3;
}
public int getBookSize() {
return bookSize;
}
public void setBookSize(int bookSize) {
this.bookSize = bookSize;
}
public Book getBooks(int i) {
return books[i];
}
public void setBooks(Book[] books) {
this.books = books;
}
}
//书类
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
", isBorrowed=" + ((isBorrowed) ? "已借出" : "未借出") +
'}';
}
Book
这个类要在原有基础上再加上一个toString
方法
//显示所有书籍
package operation;
import book.Book;
import book.BookList;
public class ShowOperation implements IOperation{
@Override
public void shiXian(BookList bookList) {
int count = bookList.getBookSize();
for (int i = 0; i < count; i++) {
Book book = bookList.getBooks(i);
System.out.println(book);
}
}
}
(3)查找书籍代码实现
会显示所有书籍的话,那查找书籍就好做了,加个if
判断条件就行了,下面是代码实现:
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class FindOperation implements IOperation{
@Override
public void shiXian(BookList bookList) {
System.out.println("查找图书!");
int count = bookList.getBookSize();
Scanner sc = new Scanner(System.in);
System.out.print("请输入你需要查找的书籍->");
String name = sc.nextLine();
for (int i = 0; i < count; i++) {
Book book = bookList.getBooks(i);
if (book.getName().equals(name)) {
System.out.println(book);
return;
}
}
System.out.println("未找到");//到了这儿,就是for寻找完了,所以没找到
}
}
(4)借/还 书代码实现
然后是借书和还书,修改它们的isBorrowed
就可以了,下面是代码实现:
//借书
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class BorrowOperation implements IOperation{
@Override
public void shiXian(BookList bookList) {
int count = bookList.getBookSize();
for (int i = 0; i < count; i++) {
System.out.println(bookList.getBooks(i));
}
Scanner sc = new Scanner(System.in);
System.out.print("请输入你需要借的书->");
String name = sc.nextLine();
for (int i = 0; i < count; i++) {
Book book = bookList.getBooks(i);
if (book.getName().equals(name)) {
if (book.isBorrowed()) {
System.out.println("该书已经被借出!");
}
book.setBorrowed(true);
return;
}
}
System.out.println("未找到你需要借的书籍!");//走到这里说明没有书了
}
}
//还书
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class ReturnOperation implements IOperation{
@Override
public void shiXian(BookList bookList) {
int count = bookList.getBookSize();
for (int i = 0; i < count; i++) {
System.out.println(bookList.getBooks(i));
}
Scanner sc = new Scanner(System.in);
System.out.print("请输入你需要借的书->");
String name = sc.nextLine();
for (int i = 0; i < count; i++) {
Book book = bookList.getBooks(i);
if (book.getName().equals(name)) {
book.setBorrowed(false);
System.out.println("已归还")
return;
}
}
System.out.println("未找到你需要还的书籍!");
}
}
(5)添加书籍代码实现
然后我们下一步是要进行,这个要比较难亿点,你需要传两个东西给书架,一个是书本的参数,一个是最后一个书本的下标,所有就需要改动编译器给你自动重写的setBooks
方法了,下面是代码实现:
//setBooks
要改成这样
public void setBooks(int i, Book books) {
this.books[i] = books;
}
//添加书籍
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class AddOperaiton implements IOperation{
@Override
public void shiXian(BookList bookList) {
int count = bookList.getBookSize();
Scanner sc = new Scanner(System.in);
System.out.print("书名->");
String name = sc.nextLine();
System.out.print("作者->");
String author = sc.nextLine();//作者
System.out.print("类型->");
String type = sc.nextLine();//类型
System.out.print("价格->");
double price = sc.nextDouble();//价格
Book book = new Book(name,author,price,type);//传给书,让他再初始化一本,然后传给Book这个结构体
bookList.setBooks(bookList.getBookSize(), book);//更改Book
bookList.setBookSize(bookList.getBookSize() + 1);//再传给setSize让他+1
}
}
(6)删除书籍代码实现
删除书籍和添加书籍差不多,可以用迭代覆盖想法,就是先找到想删的这本书,然后一直把他的后一本覆盖掉他的前一本,最后size--
,下面是代码实现
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class DelOperation implements IOperation{
@Override
public void shiXian(BookList bookList) {
int count = bookList.getBookSize();
Scanner sc = new Scanner(System.in);
System.out.print("请输入你需要删除的书籍->");
String name = sc.nextLine();
int i = 0;
for (i = 0; i < count; i++) {
Book book = bookList.getBooks(i);
if (book.getName().equals(name)) {
break;
}
}
if (i >= bookList.getBookSize()) {
System.out.println("未找到要删除的书籍!");
return;
}
else {
//利用for循环,i是那本书的位置,把i+1的书给i这里,迭代往后走
for (int j = i + 1; j < bookList.getBookSize(); j++) {
Book book = bookList.getBooks((j));
bookList.setBooks(i,book);
i++;
}
bookList.setBookSize(bookList.getBookSize() - 1);
System.out.println("删除成功!");
}
}
}
写到这儿就算完成了,不过还有点瑕疵,就是不能循环使用,每次都要重写开始太麻烦了,所以我们可以用死循环控制,直到选择0强行退出,改一点点代码就可以了,如下:
public static void main(String[] args) {
User user = login();
BookList bookList = new BookList();
while (true){
int choice = user.menu();//返回什么类型,就调用什么类型的menu
user.chuanLian(choice, bookList);
}
}
在main
函数中把这两行输入给死循环就ok了。感谢大家能看到这里,今天的心灵鸡汤肯定也少不了咯
五、心灵鸡汤
Java是一门不断发展和变革的编程语言。在学习和掌握它的过程中,我们需要不断拥抱新技术、保持创新和进步的决心。无论是开发桌面应用程序、企业级应用、Web应用还是移动端应用,Java都能为我们提供强大的支持和优秀的应用体验。对于Java程序员而言,挑战和机遇始终存在。让我们继续保持孜孜不倦的追求,不忘初心,砥砺前行,秉承着 "Write Once, Run Anywhere" 的原则,为塑造更美好的IT世界而努力奋斗。