在本项目中,对业务的逻辑要求并不高,主要要求设计的架构,和知识的使用
在项目中:找对象—创建对象—使用对象
在图书管理系统中,有书和用户两个对象。
首先创建book
和user
两个包。
在用户对象中,有普通用户和管理员。
首先创建User
类,普通用户和管理员都有姓名,再创建AdminUser
和NormalUser
, 这两个类继承User
类。
将各种操作写道operation
包中,定义IOperation
操作接口,声明work
函数,让各种功能都使用该接口,并重写work
方法。
程序实现了退出操作ExitOperation
、查询图书操作FindOperation
、添加书籍操作AddOperation
、删除书籍操作DelOperation
、展示书籍操作DisplayOperation
、借出书籍操作BorrowOperation
、归还书籍操作ReturnOperation
。
其中AdminUser
包含:退出操作、查询操作、添加书籍操作、删除书籍操作、展示书籍操作。
NormalUser
包含:退出操作、查询操作、借出书籍操作、归还书籍操作。
User
类
public class User {
protected String name;
public User(String name) { //name的构造方法
this.name = name;
}
}
再创建NormalUser
和AdminUser
,让他继承User
类。子类要先帮助父类构造
NormalUser
类
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
}
}
AdminUser
类
public class AdminUser extends User{
public AdminUser(String name) {
super(name);
}
}
在book
包中,首先抽象出一个book
类用来描述书,由private
描述表现出来了封装性,同时要给属性提供构造方法,get和set方法
这里构造方法没有写isBorrowed
,因为是否借出属性默认没有借出。不初始化
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;
}
}
书创建好后,我们还需要一个书架用来存放书籍。创建BookList定义书架
创建一个数组,用来当书架。
默认书架只能放十本书
书架上本身存在三本书【也就是事先往书架中存三本书】写在构造方法中,调用这个类的构造方法时,就直接给books中放书。
按理,这里应该写一些操作数组的方法,但在这我们不这么做,我们把这些行为都写到接口当中
package book;
public class BookList {
public Book[] books = new Book[10]; //默认书架只能放十本书
public int usedSize; //存储当前书的个数
//事先通过构造方法,初始化的时候,给数组里预存三本书。
public BookList() {
// 书架上本身存在三本书
books[0] = new Book("三国演义","罗贯中",89,"小说");
books[1] = new Book("name2","author2",102,"type2");
books[2] = new Book("name3","author3",103,"type3");
this.usedSize = 3;
}
//按理,这里应该写一些操作数组的方法,但在这我们不这么做,我们把这些行为都写到接口当中
}
新建一个operation包,里面用来存放各种接口
package operation;
import book.BookList;
/**
* @ClassName: AddOperation
* @Description: TODO:添加图书
*/
public class AddOperation {
public void work(BookList bookList) {
//添加图书
}
}
package operation;
import book.BookList;
/**
* @ClassName: FindOperation
* @Description: TODO:查找图书
*/
public class FindOperation {
public void work(BookList bookList) {
//查找图书
}
}
在不同的操作中,我们都是使用work方法,传入参数BookList。
可以写成一个接口IOperation
package operation;
import book.BookList;
/**
* @ClassName: IOperation
*/
public interface IOperation {
void work(BookList bookList);
}
这样的话,直接让操作implements IOperation
。
现在看可能会觉得和之前没有接口的时候也没什么区别嘛。
但是当我们所有的操作都实现了这个接口,那么我们就可以很轻易地做到向上转型,动态绑定,多态。
public class AddOperation implements IOperation{
public void work(BookList bookList) {
//添加图书
}
}
public class FindOperation implements IOperation{
public void work(BookList bookList) {
//查找图书
}
}
用同样的方法创建删除图书DelOperation
,展示图书DisplayOperation
,退出系统ExitOperation
,归还图书ReturnOperation
,借阅图书BorrowOperation
结构如下:
接下来,整合程序,让他能够跑起来。
第0步:准备数据
初始化new 一个bookList ,BookList 中的构造函数中初始化了三本书,数据准备完成。
BookList bookList = new BookList();
第1步:登录
在login()函数中,由于选择不同,返回的对象也不同。这个对象可能是admin也可能是normal。
因此这里的返回值写成User类型,利用了向上转型,来确定此时返回的到底是什么对象。
//返回User
//利用了向上转型,来确定此时返回的到底是什么对象。
public static User login() {
System.out.println("please input your name");
Scanner scanner = new Scanner(System.in);
String userName = scanner.nextLine();
System.out.println("please input your id: 1->admin, 0->user");
int choice = scanner.nextInt();
//当引用的对象不一样时,打印的菜单也不一样。将不同的菜单分别写道AdminUser类和NormalUser类中。
if (choice == 1) {
//Admin
return new AdminUser(userName);
} else {
//User
return new NormalUser(userName);
}
}
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login();
}
在这里无法调用menu,因为在这里是用父类User调用,父类引用只能调用自己的方法;user中没有menu,因此在user中加上menu。user中的方法menu没有具体的执行,实际就是一个抽象方法,User类也是一个抽象类
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login();
int choice = user.menu();
}
public abstract int menu();
当引用的对象不一样时,打印的菜单也不一样。将不同的菜单分别写道AdminUser类和NormalUser类中。
通过这个user去调用menu。他引用谁,调用的就是谁的menu()。调用的是谁的菜单,在这里choice选择的就是谁的数字。
【在这里,怎么去根据choice确定调用的是那个方法?】
让每个对象,把自己对应的操作存到数组中,
在user抽象类中,定义数组 protected IOperation[] iOperations;
protected IOperation[] iOperations;
此时只定义数组,但没初始化,内存都没分配,因为不知道要存储几个操作。
在admin和normal中分别初始化操作数组,放在构造函数中,使其在new对象时直接初始化完成
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 class NormalUser extends User{
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[] {
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
}
数组定义好后,现在需要写一个操作接口数组的方法,使其引用admin和normal时都可以调用。所以把这个方法写道user中
//根据选择,调用booklist里面数组的某个下标
public void doOperation(int choice, BookList bookList) {
//iOperations[choice]相当于拿到了一个对象【iOperations数组的一个元素】
//调用这个对象的work方法并传入bookList
iOperations[choice].work(bookList);
}
public static void main(String[] args) {
//0. 准备数据
BookList bookList = new BookList();
//1. 登录
User user = login();
int choice = user.menu();
user.doOperation(choice, bookList); //使用接口数组
}
各个功能的实现:
AddOperation
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class AddOperation implements IOperation{
public void work(BookList bookList) {
//添加图书
System.out.println("add book");
System.out.println();
System.out.println("please input add book name");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("please input add book author");
String author = scanner.nextLine();
System.out.println("please input add book price");
int price = scanner.nextInt();
scanner.nextLine(); //把回车读进去
//nextInt和nextLine 要先输入nextLine,否则输入nextInt后的回车会被nextLine读进去
//如果必须先输入nextLine,就在nextLine后面把回车读进去 scanner.nextLine();
System.out.println("please input add book type");
String type = scanner.nextLine();
Book book = new Book(name, author, price, type); //得到了一本书
//1. 获取当前可以存放书的位置
int currentSize = bookList.getUsedSize();
//2. 把书放入指定位置
bookList.setBooks(book,currentSize);
//3. 书的有效个数+1
bookList.setUsedSize(currentSize + 1);
System.out.println("aa");
}
}
BorrowOperation
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class BorrowOperation implements IOperation{
@Override
public void work(BookList bookList) {
//借阅书籍
System.out.println("borrowed book");
System.out.println("please input book you want to borrowed");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
if (book.isBorrowed()) {
System.out.println("this book already borrowed");
} else {
book.setBorrowed(true);
System.out.println("borrow success");
}
return;
}
}
System.out.println("not found borrow book");
}
}
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("delete book");
System.out.println("please input want delete book name");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
//遍历数组当中,是否有你要删除的书,如果有,记录下标
int index = -1;
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
index = i;
break;
}
}
if (index == -1) {
System.out.println("not found");
return;
}
for (int i = index; i < currentSize - 1; i++) {
Book book = bookList.getPos(i + 1);
bookList.setBooks(book, i); //将i+1的book放到i下
}
//在Java中,只有没人引用的对象,才会回收
bookList.setBooks(null, currentSize - 1); //每次删除都要置为空
bookList.setUsedSize(currentSize - 1); //存放发currentSize - 1
System.out.println("delete success !");
}
}
DisplayOperation
package operation;
import book.Book;
import book.BookList;
public class DisplayOperation implements IOperation{
@Override
public void work(BookList bookList) {
//显示所有图书
System.out.println("display book");
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
System.out.println(book);
}
}
}
ExitOperation
package operation;
import book.BookList;
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
//退出系统
System.out.println("exit system");
System.exit(0);
}
}
FindOperation
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class FindOperation implements IOperation{
public void work(BookList bookList) {
//查找图书
System.out.println("find book");
System.out.println("please input book name");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
System.out.println("---find it ---");
System.out.println(book);
return;
}
}
System.out.println("---not found---");
}
}
ReturnOperation
package operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class ReturnOperation implements IOperation{
@Override
public void work(BookList bookList) {
//归还图书
System.out.println("return book");
System.out.println("please input book name you want to return");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
if (book.isBorrowed()) {
book.setBorrowed(false);
System.out.println("return book success");
return;
} else {
System.out.println("this book is not borrowed");
return;
}
}
}
System.out.println("not found book to return ");
}
}