项目介绍:此项目的业务代码方面比较简单,实现的功能也比较简单,只有查找,删除,增加,借阅,归还书籍这些简单的操作。而借阅,归还等等也只是用书籍的一个boolean数据成员来保存。练习此项目的主要目的是学习巩固Java的接口,类和对象,多态,动态绑定等面向对象的知识。
大致分为几个模块:
1. book包,存储Book.java 和 BookList.java 它的作用从名字就可以看出了
2. operation包,以一个IOperation接口为根本,将那些操作封装为类,这些类都implements那个IOperation接口。主要就是提供那些增,删,查,借阅,归还的操作。详细见下文。
3. user包,User.java GeneralUser.java Administrator.java 用到了继承和多态,细节见下文。
最后就是一个main.cpp 文件,作为以上三个包的对象的汇总,实现这个图书馆管理系统。
注: 此项目的实现逻辑并不一定是最好的,也不一定是合理的,旨在学习面向对象编程。
book包
Book.java
package book;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 15:38
*/
public class Book {
private String bookName;
private String authorName;
private double price;
private String type;
private boolean isBorrowed;
public Book(String bookName, String authorName, double price, String type) {
this.bookName = bookName;
this.authorName = authorName;
this.price = price;
this.type = type;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getBookName() {
return bookName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public String getAuthorName() {
return authorName;
}
public void setPrice(double price) {
this.price = price;
}
public double getPrice() {
return price;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
@Override // 重写Object类的toString方法。
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", authorName='" + authorName + '\'' +
", price=" + price +
", type='" + type + '\'' +
", isBorrowed:" + (isBorrowed ?"Yes":"No") +
'}';
}
}
一个Java文件,建议只写一个类。这个Book类存储了书籍的基本信息,以及构造函数。剩余的就是对于每个数据成员的setter和getter方法。以及为了方便打印Book类对象信息而重写Object类的toString方法。其中的getter和setter方法,是为了实现后面在BookList类的功能而准备的接口,将数据成员封装起来,对外使用接口对这些数据成员进行操作。只有几个是后面用到的。当然,如果你后面想要扩展这个管理系统的功能,剩余的方法也会用到。
BookList.java
package book;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 15:53
*/
public class BookList {
private Book[] books;
private int numOfBook;
public BookList() {
books = new Book[10];
books[0] = new Book("三国演义","施耐庵",18,"小说");
books[1] = new Book("水浒传", "罗贯中", 26.6, "小说");
books[2] = new Book("西游记", "吴承恩", 38, "小说");
numOfBook = 3;
}
public int getNumOfBook() {
return numOfBook;
}
public void setNumOfBook(int numOfBook) {
this.numOfBook = numOfBook;
}
public Book getBook(int index) {
return books[index];
}
// 其实这里完全可以写成addBook,但是因为这个功能实现成了一个类,所以这里做一些更基本的操作。
public void setBook(int index, Book book) {
books[index] = book;
}
}
这里的书单存储Book类对象的方式是使用顺序表-Java的数组,这种数组不像C++的vector可以扩容,功能比较单一。所以添加了一个numOfBook数据成员存储书籍个数。 默认构造函数用于对数组初始化,后面的方法是接口,作为了 后面的增删查改操作的接口,用于对这个书籍数组进行处理。
operation包
为了学习接口,以及重写方法,当然也为了后面实现的方便。这里将每个操作封装成了类,这些类都implements一个IOperation接口,这样,我们就可以将这些操作的对象放在同一个数组中了。当然这里说也不直观,需要和后面的User类结合起来看这个的功能。
IOperation接口
public interface IOperation {
public static final Scanner scanner = new Scanner(System.in);
public abstract void work(BookList bookList);
}
AddOperation.java 实现增加书籍的功能,这是一个类,成员函数work实现对应的业务。
package operation;
import book.*;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 16:07
*/
public class AddOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("添加图书");
System.out.println("请输入书名: ");
String bookName = scanner.nextLine();
System.out.println("请输入作者: ");
String authorName = scanner.nextLine();
System.out.println("请输入价格: ");
double price = scanner.nextDouble();
System.out.println("请输入类型: ");
String type = scanner.nextLine();
Book book = new Book(bookName, authorName, price, type);
int index = bookList.getNumOfBook();
bookList.setBook(index, book);
bookList.setNumOfBook(index + 1);
}
}
BorrowOperation 借阅书籍 - 同样是一个类,implements 接口IOperation
public class BorrowOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("借阅书籍");
System.out.println("请输入要借阅书籍的名字: ");
String bookName = scanner.nextLine();
for(int i = 0; i < bookList.getNumOfBook(); ++i) {
if(bookList.getBook(i).getBookName().equals(bookName)) {
if(bookList.getBook(i).isBorrowed()) {
System.out.println("此书籍已被借阅");
System.out.println(bookList.getBook(i));
return;
} else{
bookList.getBook(i).setBorrowed(true);
System.out.println("借阅成功");
System.out.println(bookList.getBook(i));
return;
}
}
}
System.out.println("此书籍不存在");
}
}
DelOperation 删除书籍 - 同样是一个类,implements 接口IOperation
package operation;
import book.BookList;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 16:07
*/
public class DelOperation implements IOperation {
@Override
public void work(BookList bookList) {
System.out.println("删除书籍");
System.out.println("请输入你要删除的图书的名字");
String name = scanner.nextLine();
for(int i = 0; i < bookList.getNumOfBook(); ++i) {
if(bookList.getBook(i).getBookName().equals(name)) {
for(int j = i; j < bookList.getNumOfBook()-1; ++j) {
bookList.setBook(j, bookList.getBook(j+1));
}
bookList.setBook(bookList.getNumOfBook()-1,null);
bookList.setNumOfBook(bookList.getNumOfBook()-1);
System.out.println("删除成功");
return;
}
}
System.out.println("查无此书");
}
}
DisplayOperation 打印书籍 - 同样是一个类,implements 接口IOperation
package operation;
import book.BookList;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 16:08
*/
public class DisplayOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("打印书籍");
for(int i = 0; i < bookList.getNumOfBook(); ++i) {
System.out.println(bookList.getBook(i));
}
}
}
ExitOperation 退出系统 - 同样是一个类,implements 接口IOperation
package operation;
import book.BookList;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 16:08
*/
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
System.exit(0);
}
}
FindOperation 查找书籍 - 同样是一个类,implements 接口IOperation
package operation;
import book.Book;
import book.BookList;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 16:08
*/
public class FindOperation implements IOperation {
public void work(BookList bookList) {
System.out.println("查找书籍");
System.out.println("请输入要查找图书的书名:");
String name = scanner.nextLine();
for(int i = 0; i < bookList.getNumOfBook(); ++i) {
if(bookList.getBook(i).getBookName().equals(name)) {
System.out.println(bookList.getBook(i));
return;
}
}
System.out.println("查无此书");
return;
}
}
ReturnOperation 返还书籍 - 同样是一个类,implements 接口IOperation
package operation;
import book.BookList;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 16:08
*/
public class ReturnOperation implements IOperation {
@Override
public void work(BookList bookList) {
System.out.println("返回书籍");
System.out.println("请输入要归还书籍的名字: ");
String bookName = scanner.nextLine();
for(int i = 0; i < bookList.getNumOfBook(); ++i) {
if(bookList.getBook(i).getBookName().equals(bookName)) {
bookList.getBook(i).setBorrowed(false);
System.out.println("归还成功");
System.out.println(bookList.getBook(i));
return;
}
}
System.out.println("此书籍不存在");
}
}
整体而言,这里运用了实现接口的知识。其实这些功能都可以实现到那个BookList的类内,作为BookList的成员函数,更方便的对Book[] 操作。不过,这只是不同的实现思路罢了。并且如果实现到一个类的成员函数,那么后面main函数处就需要用switch case语句对用户选择的书籍,调用对应的方法,这也是不方便的。
User包
因为 普通用户和管理员都有一些公有的属性或方法,所以创建一个User类 作为基类/父类,由普通用户类和管理员类继承User类。
User.java
package user;
import book.BookList;
import operation.IOperation;
/**
* Created with IntelliJ IDEA.
* Description:
* User: yangzilong
* Date: 2022-07-03
* Time: 15:58
*/
public abstract class User {
private String userName;
protected IOperation[] operations; // 基类对象引用的数组
public User(String userName) {
this.userName = userName;
}
protected String getUserName() {
return userName;
}
public abstract int menu();
public void doWork(int input, BookList bookList) {
operations[input].work(bookList);
}
}
GeneralUser.java 普通用户类 继承 User
public class GeneralUser extends User {
public GeneralUser(String userName) {
super(userName);
super.operations = new IOperation[] {
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
public int menu() {
System.out.println("======hello "+ super.getUserName() + " welcome=====");
System.out.println("1.查找图书");
System.out.println("2.借阅图书");
System.out.println("3.归还图书");
System.out.println("0.退出系统");
System.out.print("请输入你的操作:>");
Scanner scanner = new Scanner(System.in);
return scanner.nextInt();
}
}
Administrator.java 管理员类 继承 User
public class Administrator extends User {
public Administrator(String name) {
super(name);
super.operations = new IOperation[] {
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new DisplayOperation()
};
}
public int menu(){
System.out.println("======hello "+ super.getUserName() + " welcome=====");
System.out.println("1.查找图书");
System.out.println("2.增加图书");
System.out.println("3.删除图书");
System.out.println("4.打印图书");
System.out.println("0.退出系统");
System.out.print("请输入你的操作:>");
Scanner scanner = new Scanner(System.in);
return scanner.nextInt();
}
}
这里就和operation包结合起来了,可以看到User有一个IOperation对象引用的数组,而operation包中的其他类都implements这个接口。这里的数组就可以存储普通用户类或者管理员类的操作。
而User类有一个抽象方法menu,Administrator和GeneralUser都重写了这个menu。具体怎么用还需要看主函数,不过毋庸置疑的是,这里肯定用到了动态绑定和多态。
Main.java
public class Main {
public static User login() {
System.out.println("请输入你的姓名: ");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("请输入你的身份:1 - 管理员 2 - 普通用户");
while(true) {
int choice = scanner.nextInt();
if (choice == 1) {
return new Administrator(name);
} else if (choice == 2) {
return new GeneralUser(name);
} else {
System.out.println("输入错误,请重新输入");
}
}
}
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login(); // 基类引用引用派生类对象。
while (true) {
int n = user.menu(); // 动态绑定,运行时绑定,多态,运行时多态。
// user.operations[n].work(bookList); // 这里的操作迫使user把operations数据成员更改为public的。
// 但是,user的operations设为protected更为合适。
user.doWork(n, bookList);
}
}
}
不看这个,是很难理解上方那些包的作用的。
首先肯定让你输入数字选择身份,同时需要输入名字。因为上方把不同身份实现了对应的类,所以login函数中new不同的对象,因为这些对象都继承自User,所以返回值为User是合法的。
GeneralUser 和 Administrator的mune方法进行了重写,调用时发生了动态绑定,即多态。menu方法内需要用户选择操作,以int类型返回回去。再根据User类的doWork方法,调用对应的数组中的类的work方法,对传入的bookList进行处理。