- 完整代码链接:https://gitee.com/zeng-xuehui/Java_repository/tree/master/test_11_27_1/src
- 我们在写这个系统时,首先需要搭建框架,再实现业务逻辑;
- 图书管理系统是用户通过各种功能对图书进行操作的一个系统;
- 我们需要通过三方面进行编写代码:1、用户 2、功能 3、图书,所以代码大的分为了这三部分;
1、代码主要就分为三大模块和一个Main类来测试图书管理系统;
2、 book包中的Book类和BookList类
Book类:是用来描述书这个对象的;
BookList类:用来描述书架上的书;
Book类代码:
package book;
public class Book {
// book的属性
private String name; // 名字
private String author; // 作者
private int price; // 价格
private String type; // 类型
private Boolean isBorrow = false; // 是否借阅->初始值false
// 如果这里不初始化,后面有些地方使用到isBorrow这个属性就会报错;
// 书的初始化
public Book() {
}
public Book(String name, String author, String type, int price) {
this.name = name;
this.author = author;
this.type = type;
this.price = price;
}
// 方法
public void setBorrow(Boolean isBorrow) {
this.isBorrow = isBorrow;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
public int getPrice() {
return price;
}
public String getType() {
return type;
}
public Boolean getBorrow() {
return isBorrow;
}
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
public void setType(String type) {
this.type = type;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
((isBorrow == true)? " 已借阅":" 未借阅") +
'}';
}
}
BookList类代码:
package book;
/**
* 难点:数组的初始化、数组应该如何使用
* 1、this.books = new Book[10]; // 将书架初始化为10,可以存放10本书
*
*/
public class BookList {
// 存放书本
private Book[] books; // 这是书架,存放书本
private int useSize; // 存放数量
// 初始化
public BookList() {
this.books = new Book[10]; // 将书架初始化为10,可以存放10本书
// 书架上有两本书,所以可以通过实例代码块实现,或者构造代码块实现
this.books[0] = new Book("java","高斯林","编程",32);
this.books[1] = new Book("C语言","xxxx","编程",45);
this.useSize = 2; // 书架上有两本书
}
public Book getBooks(int pos) {
return this.books[pos];
// 这里返回的是一本书,所以返回值是Book
}
public void setBook(Book book, int pos) {
// 书架上新增一本书,新增到哪个位置
this.books[pos] = book;
}
public int getUseSize() {
return useSize;
}
public void setUseSize(int useSize) {
this.useSize = useSize;
}
}
3、 user包中的User类、Administractor类、OrdinaryUser类
User类:用来描述用户这个对象的;
Administractor类:主要写的是管理员用户的特有方法和属性;
OrdinaryUser类:主要写的是普通用户的特有方法和属性;
在这里的有一个难点:我最初写的时候不理解功能数组的初始化;
User类代码:
package user;
import book.BookList;
import function.Function;
/**
* 难点:在用户中定义功能数组
* 1、protected Function[] functions; // 数组并没有初始化,没有为数组分配空间
*/
public abstract class User {
protected Function[] functions; // 数组并没有初始化,没有为数组分配空间
//用户属性
private String name; // 这是用户的姓名
public User(String name) {
this.name = name;
}
// 方法
public abstract int menu();
// 功能实现的方法
public void function(int choose, BookList bookList) {
// this.functions[] -> 这是一个功能对象
// this.functions[choose].work() -> 调用对象中的方法
// this.functions[choose].work(bookList);
// 接口不能new,但是接口可以引用对象,这里接口是应用的对象
Function function = this.functions[choose]; // 这是功能对象
function.work(bookList);
}
}
Administractor类代码:
package user;
import function.*;
import java.util.Scanner;
/**
* 难点:功能数组初始化
* // this既可以调用子类的成员,也可以调用父类的成员
* this.functions = new Function[]{
* new ExitSystem(),
* new AddFunction(),
* new ReturnFunction(),
* new DeleteFunction(),
* new ShowFunction()
* };
* 难点:选择功能之后为什么没有实现对应的功能
*/
public class Administrator extends User{
public Administrator(String name) {
super(name);
// this既可以调用子类的成员,也可以调用父类的成员
this.functions = new Function[]{
new ExitSystem(),
new AddFunction(),
new ReviseFunction(),
new DeleteFunction(),
new ShowFunction()
};
}
@Override
public int menu() {
System.out.println(".........管理员.........");
System.out.println("0、退出系统");
System.out.println("1、增加图书");
System.out.println("2、修改图书");
System.out.println("3、删除图书");
System.out.println("4、显示图书");
System.out.println(".......................");
System.out.print("请选择功能:");
Scanner scanner = new Scanner(System.in);
int choose = scanner.nextInt();
return choose;
}
}
OrdinaryUser类代码:
package user;
import function.*;
import java.util.Scanner;
/**
* 难点:数组的初始化
* // this既可以调用子类的成员,也可以调用父类的成员
* this.functions = new Function[]{
* new ExitSystem(),
* new BorrowFunction(),
* new ReturnFunction(),
* new ShowFunction()
* };
* 难点:选择功能之后为什么没有实现对应的功能
*/
public class OrdinaryUser extends User{
public OrdinaryUser(String name) {
super(name);
// this既可以调用子类的成员,也可以调用父类的成员
this.functions = new Function[]{
new ExitSystem(),
new BorrowFunction(),
new ReturnFunction(),
new ShowFunction(),
new FindFunction()
};
}
// 方法
@Override
public int menu() {
System.out.println("........普通用户........");
System.out.println("0、退出系统");
System.out.println("1、借阅图书");
System.out.println("2、归还图书");
System.out.println("3、显示图书");
System.out.println("4、查找图书");
System.out.println(".......................");
System.out.print("请选择功能:");
Scanner scanner = new Scanner(System.in);
int choose = scanner.nextInt();
return choose;
// 选择之后为什么没有实现功能呢?
}
}
4、function包中的各种操作类和一个Function接口
操作类:管理员的操作类、普通用户的操作类;
Function接口:通过操作类实现这个Function接口,目的就是使操作分离;
Function接口代码:
package function;
import book.BookList;
public interface Function {
// 这些功能都是对书架上的书进行操作
// 所以在操作时需要将书架传过来
void work(BookList bookList);
}
操作类代码:
新增图书代码:
package function;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class AddFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("增加图书");
Scanner scanner = new Scanner(System.in);
System.out.print("请输入新增图书书名:");
String name = scanner.nextLine();
System.out.print("请输入新增图书作者:");
String author = scanner.nextLine();
System.out.print("请输入新增图书类型:");
String type = scanner.nextLine();
System.out.print("请输入新增图书价格:");
int price = scanner.nextInt();
// 新增了书本,所以我们需要构造出一个书的对象
Book book = new Book(name, author, type, price);
// 新增图书所放的位置
// 可以放在数组的开头,也可以放在数组的中间,还可以放在数组的末尾
// 但是所放的位置,不允许当前位置之前为空!!!前一个位置必须有数据
// 但是我们在放这本书之前需要判断书架中是否存在这本书
for (int i = 0; i < bookList.getUseSize(); i++) {
Book systemBook = bookList.getBooks(i);
if(systemBook.getName().equals(name)) {
System.out.println("书架中已存在此书,新增失败!");
return ;
}
}
// 走到这里说明书架上没有这本书,新增成功
// 但是我们应该怎么在书架中新增呢?
// 将书放到数组中的某个下标就新增成功
bookList.setBook(book, bookList.getUseSize());
bookList.setUseSize(bookList.getUseSize() + 1);
System.out.println("新增成功!");
}
}
借阅图书代码:
package function;
import book.Book;
import book.BookList;
import java.util.Scanner;
/**
* 发现一个问题:借阅图书和归还图书都没有实际的操作,并没有使书架上的书减少,仅仅只是显示借阅和归还
* 借阅、归还图书操作并没有改变书架上的书
*/
public class BorrowFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("借阅图书");
System.out.print("请输入借阅图书的书名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
// 再进行比较,存在这本书、不存在这本书;
int i = 0;
for (i = 0; i < bookList.getUseSize(); i++) {
if(bookList.getBooks(i).getName().equals(name)) {
// 进入这里面说明书架中有这本书
bookList.getBooks(i).setBorrow(true);
System.out.println("借阅成功!");
return; // 这里直接return,下面就不需要再进行判断
}
}
System.out.println("图书中没有这本书:" + name);
}
}
删除图书代码:
package function;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class DeleteFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("删除图书");
int index = -1; // 用来记录要删除图书的下标
System.out.print("请输入要删除图书书名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int i = 0;
for (i = 0; i < bookList.getUseSize(); i++) {
// 先找到对应下标的书
Book book = bookList.getBooks(i);
if(book.getName().equals(name)) {
// 走到这儿说明已经找到了这本图书
// 当找到这本书就跳出循环
// 将找到书的下标给到index
index = i;
break;
}
}
// 走到这里说明在书架中没有找到这本书
if(i >= bookList.getUseSize()) {
System.out.println("书架中没有要删除的这本书!");
return ; // 结束当前这个方法
}
// 如何删除一本书,先在已经有了这本书的下标index
// 这里还需要考虑的是j小于多少,如果不减1的话会出现数组越界
for (int j = index; j < bookList.getUseSize()-1; j++) {
// 写到这里,怎么调用数组呀?
// 现在通过getBooks这个方法拿到了j+1位置处的下标
Book book = bookList.getBooks(j+1);
// 现在这个setBook方法,将book这本书放到j位置
bookList.setBook(book,j);
}
// 还需要将最后没有使用的对象置为空
bookList.setBook(null, bookList.getUseSize()-1);
bookList.setUseSize(bookList.getUseSize()-1);
}
}
退出系统代码:
package function;
import book.BookList;
public class ExitSystem implements Function{
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
System.exit(0);
// 应该要对bookList手动回收
}
}
查找图书代码:
package function;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class FindFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("查找图书");
// 查找图书需要输入查找内容
System.out.print("请输入要查找的图书书名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
// 输入的数需要与书架上的书进行对比
// 难点:怎么和书架上的书进行比较
// 现在就是要遍历书架上的书
// 每遍历一次就要拿到一本书
// 拿到一本书后返回它的下标进行比较
for (int i = 0; i < bookList.getUseSize(); i++) {
// Book book = bookList[i];
// 这样写是错的,bookList是一个类,类中的Book对象才是一个数组
// 由于Book数组对象是一个私有的对象,所以需要提供一个方法来获取到i下标的对象
Book book = bookList.getBooks(i);
// 上面是查找的书名,所以比较的也是书名,需要获取到当前下标的书名
if(book.getName().equals(name)) {
System.out.print("存在这本书,信息如下:");
// 还有这里为什么直接就调用了Book类中的toString方法呢?
System.out.println(book);
return ; // 当我们找到了就要结束这个方法
}
}
System.out.println("没有你要找的书:" + name);
}
}
归还图书代码:
package function;
import book.BookList;
import java.util.Scanner;
public class ReturnFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("归还图书");
System.out.print("请输入要归还图书的书名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
// 再进行比较,存在这本书、不存在这本书;
int i = 0;
for (i = 0; i < bookList.getUseSize(); i++) {
if(bookList.getBooks(i).getName().equals(name)) {
// 进入这里面说明书架中有这本书
bookList.getBooks(i).setBorrow(false);
System.out.println("归还成功!");
return; // 这里直接return,下面就不需要再进行判断
}
}
System.out.println("图书中没有要归还的这本书:" + name);
}
}
修改图书代码:
package function;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class ReviseFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("修改图书");
// 请输入要修改的图书
System.out.print("请输入要修改的图书:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
// 判断书架上是否有这本书
for (int i = 0; i < bookList.getUseSize(); i++) {
Book book = bookList.getBooks(i);
if(book.getName().equals(name)) {
// 走到这里说明书架上有这本书
System.out.print("请输入要修改的图书的书名:");
String bookName = scanner.nextLine();
book.setName(bookName);
System.out.print("请输入要修改的图书的作者:");
String bookAuthor = scanner.nextLine();
book.setAuthor(bookAuthor);
System.out.print("请输入要修改的图书的类型:");
String bookType = scanner.nextLine();
book.setType(bookType);
System.out.print("请输入要修改的图书的价格:");
int bookPrice = scanner.nextInt();
book.setPrice(bookPrice);
System.out.println("修改成功!");
return;
}
}
System.out.println("书架上没有要删除的这本书:" + name);
}
}
显示图书代码:
package function;
import book.Book;
import book.BookList;
public class ShowFunction implements Function{
@Override
public void work(BookList bookList) {
System.out.println("显示图书");
// 显示图书就是拿到一本书的下标就打印一本书
for (int i = 0; i < bookList.getUseSize(); i++) {
// 先拿到这本书的下标
Book book = bookList.getBooks(i);
System.out.println(book);
}
}
}
5、Main类测试图书管理系统
Main类代码:
import book.Book;
import book.BookList;
import function.Function;
import user.Administrator;
import user.OrdinaryUser;
import user.User;
import java.util.Scanner;
/**
* * 1、找对象、创建对象、实现对象
* * 2、最容易想到的两个对象->书、人
* * 3、实现书这个对象,但是书不止一本,所以需要书架
* * 4、书架是用来存放书的,其中涉及的数组是难点(!)
* * 5、操作人员->普通用户、管理员用户
* * 6、不用的用户所提供的操作不相同,如何实现各自操作的分离
* * 7、每一个操作都写成一个类当中,每一个类都是对书进行操作,将这个对书的操作写成一个接口,每个类再去实现接口中的方法
* * 8、实现一个接口数组,一个是普通用户的操作接口数组,一个书管理员用户的操作接口数组,这样就将各自的操作分离了出来,目的就是为了类型统一
* * 9、用户是一个类,用户的基本信息应该包含;但是用户分为->普通用户、管理员用户;这两个类是用户类的子类;这三个类应该如何协同操作呢?
* * 10、我们需要一个登录页面进行操作
*/
public class Main {
public static User login() {
System.out.print("请输入你的姓名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("请选择你的身份:1、管理员用户 2、普通用户");
int choose = scanner.nextInt();
if(choose == 1) {
return new Administrator(name);
}else {
return new OrdinaryUser(name);
}
}
public static void main(String[] args) {
BookList bookList = new BookList();
// 登录页面
User user = login();
while(true) {
// 循环操作
int choose = user.menu(); // 返回了一个功能选择,所以需要接收
// 难点:那么需要怎样调用这些功能呢?
user.function(choose,bookList);
}
}
}