目录
一、系统介绍
在学完Java基本语法后,我们来实现一个简单的图书借阅系统。
首先对系统进行需求分析,我们将要实现的类分为以下三个种类。每一个种类定义一个包。
1、书籍类包:Books
我们定义下面两个类,分别对单一的图书和整个图书书架进行管理
- Book
- BookShelf
2、用户类包:Users
系统中的角色有三类,分别为
- 抽象用户类:User
- 普通用户:CommonUser
- 管理员用户:Administrator
这两类用户所能使用的系统功能是不同的
3、操作类包:Operations
其中普通用户所实现的功能操作如下:
- 查找图书
- 借阅图书
- 归还图书
- 退出系统
管理员用户所实现的功能操作如下:
- 查询图书
- 增加图书
- 删除图书
- 退出系统
定义好包和类别后的目录状态应如下:
二、书籍类包 Books
在对系统进行完需求分析后,我们开始着手写每一个类。第一个类,我们可以先定义书籍类
1、Book类
这个类用于对单本书的信息进行操作。对于单本书籍的基本信息,我们可以定义以下几种:
name(书名),author(作者),price(),flag(借阅状态)
(1)其中前三种都是书籍常见的信息,而最后一种借阅状态flag将用于书籍的借阅归还操作。false表示“未借阅”,true表示“已经借阅”。
在构造方法中,我们使falg默认状态为false,即“未借阅”。
Books类完整代码如下:
package Books;
public class Book {
private String name;
private String author;
private int price;
private boolean flag;
public Book(){
}
public Book(String name,String author,int price) {
this.name = name;
this.author = author;
this.price = price;
this.flag = false;
}
public void setName(String name){
this.name = name;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public boolean getFlag(){
return this.flag;
}
public void setFlag(boolean status){
this.flag = status;
}
@Override
public String toString() {
return "Book{" +
"书名:" + name +
", 作者:" + author +
", 价格:" + price +
", 借阅状态:" + (flag?"已借出":"未借出") +
'}';
}
}
(2)在上述代码里,我们不仅对定义的几个成员变量分别写出了set和get方法,值得注意的是,我们还重新定义了toString()方法,方便书籍的打印。
(重写某个类的toString方法,在其他代码中调用System.out.println(类名)方法时,打印出的不再是类的地址,而是我们在toString()方法中重写的内容)
并且打印借阅状态时,我们用了三目运算符来表明借阅状态,让打印效果直观。
2、BookShelf类
这个类主要用于存放多本图书。我们定义了两个成员变量,分别为:
usedSize(已存放书籍数量),books[5](书籍数组)
(1)usedSize表明当前书架存放了多少本书,类型为int
(2)books[]数组用Book类类型的数组表示当前书架所存放的所有书,这里5代表了书架能存放的最多书籍数量
完整代码如下:
package Books;
public class BookShelf {
public Book[] books = new Book[5];
int usedSize;
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
public int getUsedSize() {
return usedSize;
}
}
三、用户类包 Users
1、抽象用户类 User
User类用作普通用户类和管理员用户类的父类,定义了成员变量name作为用户名字,抽象方法menu来打印菜单,抽象方法operation来进行用户操作
其中operation()方法是传入的形参为书架bookShelf,用户做出的选择choice。本方法是用来连通Users包、Operations包、Books包三个包里的类的桥梁。
在main方法定义好的Bookshelf通过用户operation()方法的调用,传入不用的操作方法中
完整代码如下:
package Users;
import Books.BookShelf;
import Operations.Operation;
public abstract class User {
String name;
public User(){
super();
}
public User(String name){
this.name = name;
}
public abstract void menu();
public abstract void operations(BookShelf bookShelf,int choice);
}
2、普通用户类 CommonUser
CommonUser是普通用户类,该类的功能菜单有:
查找图书(查找单本图书)、借阅图书、归还图书和退出系统
(1)menu()方法用于打印功能 菜单
(2)该类定一个一个operations数组,用以存放属于普通用户类的功能类。当用户输入某项选择时,重写的operations方法则运行该项对应类中的方法。
完整代码如下:
package Users;
import Books.BookShelf;
import Operations.*;
public class CommonUser extends User{
public Operation[] operations = new Operation[]{new SearchBook(), new LendBook(),new ReturnBook(),new ExitSystem()};
public CommonUser(){
}
public CommonUser(String name){
super(name);
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
@Override
public void menu() {
System.out.println("--------普通用户菜单--------");
System.out.println("--------1、查找图书---------");
System.out.println("--------2、借阅图书---------");
System.out.println("--------3、归还图书---------");
System.out.println("--------4、退出系统---------");
}
@Override
public void operations(BookShelf bookShelf,int choice) {
operations[choice - 1].work(bookShelf);
}
}
3、管理员类Administrator
管理员类原理与普通用户类相同,这里不再赘述
代码如下:
package Users;
import Books.BookShelf;
import Operations.*;
public class Administrator extends User{
public Operation[] operations = new Operation[]{new QueryBook(), new AddBook(),new DeleteBook(),new ExitSystem()};
public Administrator(){
super();
}
public Administrator(String name){
super(name);
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
@Override
public void menu() {
System.out.println("---------管理员菜单---------");
System.out.println("--------1、查询图书---------");
System.out.println("--------2、增加图书---------");
System.out.println("--------3、删除图书---------");
System.out.println("--------4、退出系统---------");
}
@Override
public void operations(BookShelf bookShelf, int choice) {
operations[choice - 1].work(bookShelf);
}
}
四、主函数
在写好书籍类、用户类和操作类主要框架后,我们先先实现主函数,最后再对操作类包进行补充。
(1)在主函数中,我们实现一个BookShelf类,并对BookShelf中的books[ ]数组进行初始化
(2)随后我们在Main类中,书写了一个login()方法,来进行用户登录。
用户输入姓名name和身份选项后,我们根据用户所输入的身份选项,分别返回创建的CommonUser类对象或Administrator对象,用向上转型实现了登录技术,以便之后使用多态进行菜单打印和操作实现。
(3)在进行用户登录后,写一个while循环来反复进行打印和功能实现
代码如下:
import Books.Book;
import Books.BookShelf;
import Users.Administrator;
import Users.CommonUser;
import Users.User;
import java.util.Scanner;
public class Main {
public static User login(){
Scanner input = new Scanner(System.in);
System.out.println("请输入姓名:");
String name = input.nextLine();
System.out.println("--------请选择身份:》------");
System.out.println("--------1、普通用户--------");
System.out.println("--------2、管理员----------");
int choice = input.nextInt();
if(choice == 1){
return new CommonUser(name);
}else {
return new Administrator(name);
}
}
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf();
bookShelf.books[0] = new Book("《呼啸山庄》","艾米莉·勃朗特",20);
bookShelf.books[1] = new Book("《红楼梦》","曹雪芹",56);
bookShelf.books[2] = new Book("《长安之春》","石田千之助",25);
bookShelf.setUsedSize(3);
User user = login();
while (true){
user.menu();
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
user.operations(bookShelf,choice);
}
}
}
五、操作类包 Operations
下面就来到功能最复杂、代码量最多的操作类包。包里的每一个类都对接口Operation中的work()方法进行了重写。
我们将对这里面的类进行一一讲解。
1、operation接口
由于所有的操作类都要实现操作方法,因此我们定义一个接口operation由各个操作类来继承。
操作类中有抽象方法work(),需要继承的类都对这个方法进行重写。
package Operations;
import Books.BookShelf;
public interface Operation {
void work(BookShelf bookShelf);
}
2、ExitSystem 退出系统类
该类是所有操作类中书写最简单的一个类,并且是普通用户和管理员用户都会调用的类。
直接调用系统的exit()方法,传入参数为0即可
package Operations;
import Books.BookShelf;
public class ExitSystem implements Operation{
@Override
public void work(BookShelf bookShelf) {
System.exit(0);
}
}
3、SearchBook 查找图书类
该类属于普通用户功能类,提供给普通用户用以查找单本书籍的信息。
既然是查找单本图书信息,那么我们用一个for循环将输入书名与已有书名进行匹配即可:
当找到匹配的书名后,我们对该书信息进行打印,并且用return结束循环;若没有找到该书,循环结束后会自动打印“未能找到该书”
package Operations;
import Books.BookShelf;
import java.util.Scanner;
public class SearchBook implements Operation{
@Override
public void work(BookShelf bookShelf) {
Scanner input = new Scanner(System.in);
System.out.println("请输入要查找的书籍名字:");
String bookname = input.nextLine();
for (int i = 0; i < bookShelf.getUsedSize(); i++) {
if(bookname.equals(bookShelf.books[i].getName())){
System.out.println(bookShelf.books[i]);
return;
}
}
System.out.println("未能找到该书");
}
}
该功能运行截图如下
4、LendBook 借阅图书类
该类属于普通用户类的功能类,用以给普通用户借阅图书。
(1)在该类重写的work方法中,我们先根据书名对要借阅的书籍进行查找
(2)找到该书后,检查该书的flag状态,若为false则表明该书尚未借出,我们打印“借阅成功”,并将该书的借阅标志flag置为true,表明这本书现在已借出
(3)若找到该书后flag标志为false则表示该书原来已借出,不能再次进行借阅,我们输出“该书已借出,借阅失败!”
(4)若没有找到该书,循环结束后自动打印“未找到该书”
package Operations;
import Books.BookShelf;
import java.util.Scanner;
public class LendBook implements Operation{
@Override
public void work(BookShelf bookShelf) {
Scanner input = new Scanner(System.in);
System.out.println("请输入要借阅的书籍名字:");
String bookname = input.nextLine();
for (int i = 0; i < bookShelf.getUsedSize(); i++) {
if(bookname.equals(bookShelf.books[i].getName())){
if(bookShelf.books[i].getFlag() == false){
bookShelf.books[i].setFlag(true);
System.out.println("借阅成功!");
return;
}else {
System.out.println("该书已借出,借阅失败");
return;
}
}
}
System.out.println("未找到该书");
}
}
该类调用结果如图:
5、ReturnBook 归还图书类
归还图书类同样属于普通用户类的功能类,用以给普通用户归还图书,与LendBook配套使用。
该类原理与LendBook类原理相同,不再赘述
package Operations;
import Books.BookShelf;
import java.util.Scanner;
public class ReturnBook implements Operation{
@Override
public void work(BookShelf bookShelf) {
Scanner input = new Scanner(System.in);
System.out.println("请输入要归还的书籍名字:");
String bookname = input.nextLine();
for (int i = 0; i < bookShelf.books.length; i++) {
if(bookname.equals(bookShelf.books[i].getName())){
bookShelf.books[i].setFlag(false);
System.out.println("归还成功!");
return;
}
}
System.out.println("未能找到该书");
}
}
实现结果如下
6、QueryBook 查询图书类
该类属于管理员用户的功能类,用以查询全部图书信息。
实现原理便是一一打印所有图书的信息。由于我们前面重写了toString()方法,因此我们打印的结果可以显示我们想要的效果
package Operations;
import Books.BookShelf;
public class QueryBook implements Operation{
@Override
public void work(BookShelf bookShelf) {
for (int i = 0; i < bookShelf.getUsedSize(); i++) {
System.out.println(bookShelf.books[i]);
}
}
}
结果如下
7、AddBook 增加图书类
该类也属于管理员用户的功能类。注意的是,在创建新的book对象前,要判断BookShelf是否已经放满,如果usedSize大小与books[]长度相等,那么不再进行存放
package Operations;
import Books.Book;
import Books.BookShelf;
import java.util.Scanner;
public class AddBook implements Operation{
@Override
public void work(BookShelf bookShelf) {
int usedSize = bookShelf.getUsedSize();
Scanner input = new Scanner(System.in);
if(usedSize < bookShelf.books.length){
bookShelf.books[usedSize] = new Book();
System.out.println("请输入书名:");
String name = input.nextLine();
bookShelf.books[usedSize].setName(name);
System.out.println("请输入作者:");
String author = input.nextLine();
bookShelf.books[usedSize].setAuthor(author);
System.out.println("请输入价格:");
int price = input.nextInt();
bookShelf.books[usedSize].setPrice(price);
bookShelf.setUsedSize(usedSize + 1);
bookShelf.books[usedSize].setFlag(false);
}else {
System.out.println("书架满了");
}
}
}
8、DeleteBook 删除图书类
删除图书类也是属于管理员用户的功能类。
实现删除图书可以用到线性表的知识,让一个线性表中的数据依次前移,从而覆盖要删除的数据。
原理如图:
注意:线性表最后一个数据不进行覆盖,而是直接置为null。因此,下面代码的for循环中,下标i最大到usedSize-2,而不是usedSize-1
package Operations;
import Books.BookShelf;
import java.util.Scanner;
public class DeleteBook implements Operation{
@Override
public void work(BookShelf bookShelf) {
Scanner input = new Scanner(System.in);
System.out.println("请输入要删除的书籍名字:");
String bookname = input.nextLine();
int num = 0;
int i = 0;
int uesdSize = bookShelf.getUsedSize();
for (; i < uesdSize; i++) {
if(bookname.equals(bookShelf.books[i].getName())){
num = i;
break;
}
}
if (i == bookShelf.getUsedSize()){
System.out.println("没有找到要删除的书");
}
for (i = num; i < uesdSize-1; i++) {
bookShelf.books[i] = bookShelf.books[i+1];
}
bookShelf.books[uesdSize-1] = null;
bookShelf.setUsedSize(uesdSize-1);
//使书架中已有的书籍数量减一
}
}