图书系统练习
文章目录
- 图书系统练习
-
- 前言
- 整体思路
-
- 具体的包和类
- Book包
-
- book
- BookList
- User 包
-
- User
- AdminUser
- NormalUser
- Operation包
-
- IOperation接口
- AddOperation
- BorrowOperation
- DelOperation
- DisplayOperation
- FindOperation
- ReturnOperation
- ExitOperation
- 小总结
- Main
-
- **user.doOperation(choice, bookList);**到底是有什么用
-
- 文字+代码解释
- 图片解释
- 实际运行
大家好哇,之前一直在学习Java的一系列语法,虽然知道了语法的规则,但是还是对语法的应用还不是很清楚,于是就有了今天的图书管理小练习。
前言
1、本次的图书系统小练习只是针对Java语法的简单应用,并不包含数据结构与数据库的知识。
2、本次的图书小练习对于一些具体的实现逻辑并不算严谨,它的重点在于整体框架的搭建与整合,是对之前学习的Java基本语法的一种简单实现,主要目的是熟悉Java语法的应用。
整体思路
要想要实现一个图书管理系统,首先要有书的属性,其次要有借书换书新增书的一系列操作,这也就意味着这个图书管理系统需要有两套不同的菜单对应着不同的用户(管理员与普通用户),最后要将书的属性与具体操作和对应的用户身份进行整合,这就是一个图书管理系统的大致思路。
具体的包和类
Book包
book
book类描述的是一本书的基本属性
首先要想管理书,最起码要有书的一些基本属性,比如书的书名、作者、价格、类型等等。
此处直接定义出一个书的类
package book;
//一本书的属性
public class Book {
private String name;//书名
private String author;
private int price;
private String type;//书的类型
private boolean isBorrowed;//书是否被借出
public Book(String name, String author, int price, String type) {
this.name = name;
this.author = author;
this.price = price;
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 getPrice() {
return price;
}
public void setPrice(int 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;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +","+
((isBorrowed==true)?"已借出":"未借出")+"}";
}
}
注意点:
1、构造方法里面不加 Isborrowed,是因为isBorrowed默认就是false(也就是未借出)
2、此处为了简化问题,假设图书馆里面每一种书只有一本,一旦借出并且未归还,就显示已借出,不能再借这种书,于是在toString方法里面就可以通过使用三目运算符,切换书的借出状态
在完成了一本书的属性的定义之后,就可以考虑实现多本书的存放与操作了
BookList
此处的BookList类就像是一个书架一样,要有几本最初始的书,以及一些对书的操作(统计书的书目、添加一本书),之后我们就是对BookList进行操作
package book;
public class BookList {
//定义一个Book类型的数组
private Book[] books = new Book[100];//书架里面可以放上100本书
private int usedSize;//用于统计书的数目
//构造方法---在实例化的时候就已经有了3本书
public BookList() {
books[0] = new Book("红楼梦", "曹雪芹", 35, "小说");
books[1] = new Book( "围城", "钱钟书", 45, "小说");
books[2] = new Book("水浒传", "施耐庵", 42, "小说");
usedSize=3;
}
//以下就是get和set方法
//拿到某一本书
//pos表示书的下标(此时假设pos都是合法的)
public Book getBook(int pos) {
return books[pos];
}
//新增一本书book
public void setBooks(int pos, Book book) {
books[pos] = book;
}
//拿到当前的书的数目
public int getUsedSize() {
return usedSize;
}
//实时修改书架上的书的数目
public void setUsedSize(int size) {
usedSize=size;
}
}
在完成了book包之后,事实上,就已经完成了书的基本的属性
接下来就要开始考虑如何根据用户的不同的身份来采取不同的菜单和操作。
很显然,管理员身份与普通用户是平行的地位一致的的,要想要实现切换就要使用继承的关系,再创建一个User的父类,让管理员与普通用户继承这个父类,就可以继承User的name
User 包
User
package User;
import Operation.IOperation;
import book.BookList;
public abstract class User {
protected String name;
protected IOperation[] iOperations;//定义一个IOperation类型的数组,里面记录的是具体操作的类
//这里使用protected是因为protected在不同包的子类里面都是可以访问的
public User(String name) {
this.name = name;
}
public abstract int menu();
public void doOperation(int choice, BookList bookList) {
this.iOperations[choice].work(bookList);
}
}
注意点:
1、此处的name是由protected来修饰的,就是因为protected不仅可以在一个包里面访问,还可以在不同包的子类中访问,正好对应着接下来要实现的管理员子类与普通用户子类
2、由于之后的两个子类要实现两种不一样的菜单,由于之后还要在具体的子类中进行menu方法的重写,所以此时就在父类的menu方法就可以定义为抽象方法(不必具体实现menu),所以User类就变成了了抽象类
3、此处的IOperation[]数组以及doOperation方法暂时先不解释,之后用到再解释
接下来就要具体实现管理员以及普通用户的具体的菜单栏
AdminUser
package User;
import Operation.*;
import java.util.Scanner;
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("hello" + this.name + ",欢迎来到图书小练习");
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);
System.out.println("请输入你的操作:");
int choice = scanner.nextInt();
return choice;
}
}
注意点:
1、AdminUser继承了父类User,要使用extends
2、子类在实现自己的构造方法之前一定要帮助父类完成构造方法,所以就会用到super
3、menu方法的返回值是int,并不是void,原因就是menu还要接收一下用户的选择
4、此处的iOperation数组的实例化的部分依然是之后用的时候进行解释
NormalUser
package User;
import Operation.*;
import java.util.Scanner;
public class NormalUser extends User {
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),//之所以要将 退出类 放在数组下标为0的位置,就是因为刚好对应了操作数字0
new FindOperation(),
new BorrowOperation(),
new ReturnOperation(),
};
//之所以能放这些类就是因为这些类都已经实现了iOperation接口
}
public int menu() {
System.out.println("hello" + this.name + ",欢迎来到图书小练习");
System.out.println("1. 查找图书");
System.out.println("2. 借阅图书");
System.out.println("3. 归还图书");
System.out.println("0. 退出系统");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的操作:");
int choice = scanner.nextInt();
return choice;
}
}
注意点:
其实AdminUSer与NormalUser的结构几乎一样。
在写完菜单之后,就可以开始着手写具体的操作的方法了
但是要思考一下,用户输入一个操作的数字,我就要去调用对应的方法,但是要写出所有的方法在主函数里面,就会显得太臃肿,于是就可以采用实现接口+重写的方法,来实现调用不同的操作方法
Operation包
首先写一个接口,里面写一个work方法,之后方便重写
IOperation接口
package Operation;
import book.BookList;
public interface IOperation {
void work(BookList bookLsit);
}
接下来就是具体操作的方法的实现
AddOperation
package Operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class AddOperation implements IOperation {
@Override
public void work(BookList bookList) {
System.out.println("新增图书");
Scanner scanner = new Scanner(System.in);
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);//实例化book
int currenntSize = bookList.getUsedSize();
bookList.setBooks(currenntSize,book);//新增图书
bookList.setUsedSize(currenntSize+1);//修改书本数
System.out.println("新增书籍成功");
}
}
注意点:
1、接口的实现要使用implements
2、因为nextline会读入空格,就会吃掉下面一个要输入的字符串,所以要先录入字符串,最后放数字类型
3、新增图书其实就是调用之前的setBooks方法,并且改一下书的书目就行了
3、其实现在就可以感受到Java面向对象的优点,不必关心get和 set方法的具体实现,只需要调用去完成我想要的操作就可以了
BorrowOperation
import book.BookList;
import java.util.Scanner;
public class BorrowOperation implements IOperation {
@Override
public void work(BookList bookList) {
Scanner scanner = new Scanner(System.in);
System.out.println("借阅图书");
System.out.println("请输入你要借阅的图书");
String name = scanner.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i <currentSize ; i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(name)) {
book.setBorrowed(true);
System.out.println("借阅成功");
return;
}
}
}
}
注意点:
要想要实现借书的操作,首先要按照书名查找出这本书,也就是遍历一遍currentSize,再使用equals进行书名的匹配,之后再将书的状态改为true(已借出)即可
package Operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
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 currentSize = bookList.getUsedSize();
for (int i = 0; i <currentSize ; i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)) {
for (int j = i; j <currentSize ; j++) {
bookList.setBooks(j, bookList.getBook(j + 1));
}
bookList.setUsedSize(currentSize-1);
System.out.println("删除成功");
return;
}
}
System.out.println("没有找到这本书");
}
}
DelOperation
package Operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
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 currentSize = bookList.getUsedSize();
for (int i = 0; i <currentSize ; i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)) {
for (int j = i; j <currentSize-1 ; j++) { //j不能等于currentSize-1,否则j+1就会越界
bookList.setBooks(j, bookList.getBook(j + 1));
}
bookList.setBooks(currentSize-1,null );//为了防止内存泄漏,手动将最后一个多出来的位置置空
bookList.setUsedSize(currentSize-1);
System.out.println("删除成功");
return;
}
}
System.out.println("没有找到这本书");
}
}
注意点:
删除某一本书其实还是要先遍历找到这本书,之后只需要将之后的每一本书一次向前挪一个位置,就可以取代被删除的书的位置,再将书的数目-1即可
DisplayOperation
package Operation;
import book.BookList;
public class DisplayOperation implements IOperation {
@Override
public void work(BookList bookList) {
System.out.println("显示图书");
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
System.out.println(bookList.getBook(i));
}
}
}
要显示所有的书,只要遍历一遍所有的书再打印即可
FindOperation
import book.Book;
import book.BookList;
import java.util.Scanner;
public class FindOperation 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 currentSize= bookList.getUsedSize();//usedSize是有private封装的,所以要调用getUsedSize
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(name)) {
System.out.println("找到这本书了");
System.out.println(book);
return;
}
}
System.out.println("没有这本书");
}
}
查找一本书其实就是之前新增书代码的一个部分,只需要遍历,再使用equals匹配即可
ReturnOperation
package Operation;
import book.BookList;
import java.util.Scanner;
import book.Book;
public class ReturnOperation implements IOperation {
@Override
public void work(BookList bookList) {
System.out.println("归还图书");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你要归还的图书");
String name = scanner.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(name)) {
book.setBorrowed(false);
System.out.println("归还成功");
return;
}
}
}
}
归还图书首先要遍历一遍找到要归还的书。之后再将书的状态置为false(未借出)
ExitOperation
package Operation;
import book.BookList;
public class ExitOperation implements IOperation {
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
System.exit(0);
}
}
退出系统要调用System.exit(0);即可
小总结
1、上面的具体的操作方法的实现可能会存在一些逻辑上的不足,但是我们这个图书管理系统的重点并不是业务逻辑的精确实现,而是在于整个系统的搭建
2、由上面具体操作的实现方法,就可以体现出封装与面向对象的好处
在完成了以上所有的准备工作(书的属性、不同的菜单和具体的操作)之后,接下来就是要进行整合
Main
import User.AdminUser;
import User.NormalUser;
import User.User;
import book.BookList;
import java.util.Scanner;
public class Main {
public static User login() {
System.out.println("请输入你的名字");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("请选择你的身份:1.-->管理员,0.-->普通用户");
int choice = scanner.nextInt();
if (choice == 1) {
return new AdminUser(name);
}else {
return new NormalUser(name);
}
//不管返回的是什么,我使用User都能接收,此时就发生了向上转型
}
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login();//(向上转型)这样就可以实例化不同的对象
// user.menu;//注意:此时user无法调用menu方法,就是因为User里面根本就没有menu方法,在User的子类里面才有menu方法
//此时就可以使用抽象方法,将User变为抽象类,下面的两个子类就算是重写,这样子User就有了menu方法
while(true){
int choice=user.menu();//注意:menu的返回值是int
//但是,不同身份输入的同一个数字表示不同的操作(eg:普通用户输入一个2,就是想要借阅图书,但是管理员输入一个2就是想要新增图书)
user.doOperation(choice, bookList);
}
}
}
注意点:
首先先进行BookList的实例化,使图书馆里面有3本最基本的书。接下来要判断用户是管理员还是普通用户,于是就有了login方法,要是用户输入1,就返回new AdminUser(name),否则就返回new NormalUser(name),由于这两个类都是User的子类,就可以使用User作为返回值
接下来使用choice来接收用户输入的操作,接下来调用user的doOperation方法即可
你可能会十分好奇哪里来的doOperation?为什么要调用doOperation方法?
还记得之前在User、AdminUser和NormalUSer里面的IOperation吗?首先,由之前的User user = login();就已经确定了用户是管理员还是普通用户,之所以要进行区分就是因为他们的操作菜单不同。
**user.doOperation(choice, bookList);**到底是有什么用
文字+代码解释
确定身份之后,要做的就是如何根据用户输入的数字调用对应的操作方法
//USer类
public abstract class User {
protected String name;
protected IOperation[] iOperations;//定义一个IOperation类型的数组,里面记录的是具体操作的类
//这里使用protected是因为protected在不同包的子类里面都是可以访问的
public User(String name) {
this.name = name;
}
public abstract int menu();
public void doOperation(int choice, BookList bookList) {
this.iOperations[choice].work(bookList);
}
}
在User里面调用doOperation就会进入iOperations数组
//AdminUser类
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("hello" + this.name + ",欢迎来到图书小练习");
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);
System.out.println("请输入你的操作:");
int choice = scanner.nextInt();
return choice;
}
}
很显然,iOperations数组里面放的是一系列的操作类,这样就可以根据下标调用不同的操作类,从而调用不同的操作方法
图片解释
要是你还是觉得抽象,那就直接画图来理解
现在是不是豁然开朗!其实,只要多去思考理解这段代码,就可以明白它背后的逻辑。
实际运行
管理员:
普通用户:
以上就是整个图书管理小练习的全部代码实现,尽管它并不完美,但是这个它十分简洁并且有趣,而且它对于我们理解Java的一些基本语法和一些整体的框架搭建十分有帮助,等以后学习了更多的知识以后,我也会进一步完善这个图书管理系统,不断前进。
感谢你的耐心阅读!我们一起加油。