目录
整体代码在本文最底部
1.想法
首先,关于系统的开发,我们第一步的是搭构整体的框架,再分步实现各个具体的功能。
对于这个图书管理系统的开发,我想达到的目的大致为:
用户分为:1.普通用户
2.管理者
根据用户分类的不同,我们会有相不同的菜单展示。菜单上展示有编号的操作供选择,根据选择的编号调用相应的操作。
每一本书的属性分为:书名,作者,价格,类型,借阅状态。
创建一个数组作为书架,存放书。
2.框架的搭构
创建三个包,分类好。因为我们从上面的导图中可以看出,此系统分为三个大类再相互调用链接。
2.1图书
2.1.1Book类
对于图书,我们要先创建一个类,定义其属性。
package book;
public class Book {
private String name;//书名
private String author;//作者
private int price;//价格,此处定义为整数,可以自行决定
private String type;//类型
private boolean isBorrow;//借阅状态
//写出相应的构造方法,因为后续我们要添加书,需要有传参的操作
//借阅状态在创建书的时候就不用放进去了,boolean默认值为false我们可以将其认定为‘未借阅’
public Book(String name, String author, int price, String type){
this.name = name;
this.author = author;
this.price = price;
this.type = type;
}
//因为成员属性都用private修饰符进行了封装,相应的创建出setter与getter
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 isBorrow() {
return isBorrow;
}
public void setBorrow(boolean borrow) {
isBorrow = borrow;
}
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
(isBorrow ? ", 已借阅" : ", 未借阅") + isBorrow +
'}';
}
}
2.1.2BookList类
package book;
public class BookList {
//我们之前创建了一个Book类型,代表一本书
//此处我们就可以创建Book[]类型的数组,代表数组中每一个元素都为Book类型,
//即每一个元素都能代表一本书
private Book[] books = new Book[10];//引用名为books,暂定能存放为10本
private int useSize;//创建一个引用存放书架上存放的图书数量
//我们可以提前将图书放进去
public BookList() {//BookList的构造方法,到时候创建BookList对象的时候会调用,生成三本书。
books[0] = new Book("三国演义","罗贯中",19,"小说");
books[1] = new Book("西游记","吴承恩",29,"小说");
books[2] = new Book("水浒传","施耐庵",8,"小说");
this.useSize = 3;
}
//Book[]和useSize的setter与getter
//public Book[] getBooks() {
// return books;
//}
public Book getBooks(int pos) {
return books[pos];
}
//public void setBooks(Book[] books) {
// this.books = books;
//}
public void setBooks(int pos,Book books) {
this.books[pos] = books;
}
public int getUseSize() {
return useSize;
}
public void setUseSize(int useSize) {
this.useSize = useSize;
}
}
2.2用户
对于用户,在屏幕前的人选择之前,我们是无法得知下一步要选择的类型是哪一个。这时候我们就可以运用上我们的抽象类。抽象类规定了每个用户下一定具有的成员,此外子类还可以根据作为不同的用户类型来构建新的专属的成员/成员方法。
所以第一步
2.2.1User抽象类
package user;
public abstract class User {
protected String name;//用户名
//构造方法
public User(String name) {
this.name = name;
}
//打印菜单
public abstract int menu();
}
2.2.2AdminUser类(管理者)
package user;
import java.util.Scanner;
public class AdminUser extends User{
//构造方法,要先构造父类的
public AdminUser(String name) {
super(name);
}
//每一个用户类型都要有不同的菜单
//管理者菜单为:
public int menu() {
System.out.println("管理员菜单!");
System.out.println("****************************");
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. 退出系统!");
System.out.println("****************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();//获取所选择的功能编号
return choice;//返回功能编号
}
}
2.2.3NormalUser
package user;
import java.util.Scanner;
public class NormalUser extends User{
//构造方法
public NormalUser(String name) {
super(name);
}
//普通用户的菜单
public int menu() {
System.out.println("普通用户的菜单!");
System.out.println("****************************");
System.out.println("hello " + this.name +" 欢迎来到图书馆");
System.out.println("1. 查找图书");
System.out.println("2. 借阅图书");
System.out.println("3. 归还图书");
System.out.println("0. 退出系统!");
System.out.println("****************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
2.3操作
对于操作,我们可以创建一个接口来规范方法。因为我们不知道具体调用的是哪一个方法,通过接口来达到类似于继承的状态。
因为所有操作都是对书架上的书进行操作,所以参数上均为书架
此环节只是搭构框架,所以方法均没有实现,再后文中会逐一实现。
操作接口
package operation;
import book.BookList;
public class AddOperation implements IOperation {
@Override
public void work(BookList bookList) {//重写接口的方法
System.out.println("新增图书");
}
}
借阅操作
package operation;
import book.BookList;
public class BorrowOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("借阅图书");
}
}
删除操作
package operation;
import book.BookList;
public class DelOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("删除图书");
}
}
查询操作
package operation;
import book.BookList;
public class FindOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("查询图书");
}
}
归还图书
package operation;
import book.BookList;
public class ReturnOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("归还图书");
}
}
展示图书
package operation;
import book.BookList;
public class ShowOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("展示图书");
}
}
退出系统
package operation;
import book.BookList;
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
}
}
2.4小结
到了此处,我们已经把框架搭构完毕了,剩下的就是靠方法将他们联系起来构成一个整体
3.主函数的编写
因为我们还不知道要怎么将这一堆类链接起来,所以我们可以先试着写主函数。从头开始走一遍,查缺补漏。
第一步,我们创建的用户的登录方法,根据选择的不同可以创建不同的用户类型对象并接收。
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Test {
public static User login(){
//输入姓名
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您的姓名:");
String name = scanner.nextLine();//读取姓名
System.out.println("请选择您的用户类型 1 -> ‘管理者’ 0 -> ‘普通用户’:");
int choice = scanner.nextInt();//接收用户类型
//得到了用户类型,就可以根据用户所选的编号创建用户对象
if(choice == 1){//如果选择1,创建管理者对象
return new AdminUser(name);
}else{//如果选择0,创建普通用户对象
return new NormalUser(name);
}
//在类中创建了一个对象,请问我们怎么得知创建的是普通用户还是管理者呢??
//这时候我们就需要把这个方法的返回值设为‘User’,再将新建出的对象返回接收就好了
}
public static void main(String[] args) {
//第一步,要做的是用户登录,输入信息,选择用户类型
//我们可以创建一个类名为login来实现
User user = login();//创建一个引用来接收新创建的对象,并发生了向上转型,子类对象给父类引用
}
}
第二步,人有了,书还没呢。所以我们在主函数中new一个书架对象
在主函数中加上此语句即可。
BookList bookList = new BookList();//新建书架对象,并已经存放了三本书
第三步,我们选择好了用户类型,就该打印不同类型的菜单了。
//第三步,创建菜单
while(true){
int choice = user.menu();//向上转型,发生动态绑定,产生多态。
//虽是通过父类调用方法,得到的是相应子类对象的方法
//获取用户选择的操作编号
}
第四步,根据所选编号调用相应的操作
我们该怎么根据标号选择相应的方法呢??我们可以创建一个IOperation[]类型的数组,数组中存放的下标对应菜单中的操作编号。
因为我们的操作方法都为IOperation接口的实现方法,所以使用IOperation类型来存放没有问题(其之间的关系可以看成”类继承“)。
既然用户和菜单之间区分了类型,我们存放操作的数组肯定也要根据菜单的不同来区分一二。通过这种想法我们可以在AdminUser类和NormalUser类所继承的抽象类User中,定义一个IOperation[]类型的成员属性。
再分别在两个子类中的构造方法中,创建存放不同操作的数组。
User抽象类,变更为:
package user;
import operation.IOperation;
public abstract class User {
protected String name;//用户名
//变更:增加
protected IOperation[] iOperations;//定义一个IOperation[]类型,但还没有分配空间
//构造方法
public User(String name) {
this.name = name;
}
//打印菜单
public abstract int menu();
}
抽象类多了一个成员属性,相应的在子类的构造方法也要改变
AdminUser的构造方法变更为:
public AdminUser(String name) {
super(name);
this.iOperations = new IOperation[]{//实例化不同的对象,有了对象才能调用相应的方法
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new ShowOperation()
};
}
NormalUser的构造方法变更为:
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[]{//分别实例化不同的操作方法
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
此时,我们已经创建了对应的对象,但还没使用方法来调用他。但我们并不知道用户的类型以及要使用的方法是什么,所以我们可以在抽象类User中创建doOperation方法来调用。
User抽象类新增:
public void doOperation(int choice ,BookList bookList){
this.iOperations[choice].work(bookList);//调用iOperation[]下标为choice的方法,
//每一个元素为IOperation类型,都有接口重写的work方法
//这就是接口规范的意义了
}
}
在主函数调用方法
public static void main(String[] args) {
BookList bookList = new BookList();//新建书架对象,并已经存放了三本书
//第一步,要做的是用户登录,输入信息,选择用户类型
//我们可以创建一个类名为login来实现
User user = login();//创建一个引用来接收新创建的对象,并发生了向上转型,子类对象给父类引用
//第三步,创建菜单
while(true){
int choice = user.menu();//向上转型,发生动态绑定,产生多态。虽是通过父类调用方法,得到的是相应子类对象的方法
//获取用户选择的操作编号
user.doOperation(choice,bookList);//根据choice调用对应操作方法
}
}
目前大致的框架以及构建起来了,剩下的操作逐一实现就可以了。
4.操作类的实现
bookList的getter和setter有所改变,记得回到上面看看噢。
增加图书的实现
思路:创建一个新的Book对象,再存放到bookList中
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);
//查看图书馆目前的存放数量,再放到末尾
int curSize = bookList.getUseSize();
bookList.setBooks(curSize,book);//存放到末尾
bookList.setUseSize(curSize+1);//数量+1
System.out.println("新增完毕");
}
}
借阅图书的实现
思路:先获取所要借阅的图书的书名,再根据书名遍历bookList,查看借阅状态,如果为false将相应书的借阅状态改为true。如果没有图书或状态为true(即已被借阅)则返回相应语句提醒且对数组不进行操作。
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("借阅图书");
System.out.println("请输入要借阅的图书书名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int curSize = bookList.getUseSize();
for(int i = 0;i < curSize; i++){
Book book = bookList.getBooks(i);//创建一个暂时的Book类型引用存放在数组中的元素
if(book.getName().equals(name)){//比较书名
if(book.getBorrow()){//如果进入则证明已经被借阅
System.out.println("此书已被借阅");
return;
}else{
book.setBorrow(true);
System.out.println("借阅成功");
return;
}
}
}
System.out.println("馆内无此书");//循环结束了 则证明没有此书
return;
}
}
删除图书的实现
思路:我们一般在数组中达成删除,就是将后面的元素移位到要删除的数组的下标位置上进行覆盖,达到删除的效果。所以我们先获取要删除的书名,遍历,找到相应的下标位置,将下标往后的元素全部向前移动一位,再将原本的数组最后一位置空,且图书数量-1。找不到则返回相应语句
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 curSize = bookList.getUseSize();
int index = 0;
int i = 0;
for(i = 0; i < curSize; i++){
Book book = bookList.getBooks(i);
if(book.getName().equals(name)){
System.out.println("已找到相应图书,正在进行删除");
index = i;//获取下标
break;
}
}
//判断循环结束的原因
if(i == curSize){//如果已经将图书全部遍历一遍
System.out.println("没有要删除的图书");
return;
}
for(int j = index; i < curSize - 1; j++){//最后一位不用移动,后面之间置空
Book book = bookList.getBooks(i+1);//得到下标i+1的图书
bookList.setBooks(i,book);//把i+1放到i进行覆盖
}
bookList.setBooks(curSize,null);//最后一位置空,因为我们已经整体往前移动了一位
bookList.setUseSize(curSize-1);//总数-1
return;
}
}
退出系统的实现
直接退出就行,也可以在主函数进行break跳出while循环再retur结束
package operation;
import book.BookList;
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
System.exit(0);
}
}
查找图书的实现
思路:根据书名,遍历
package operation;
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 curSize = bookList.getUseSize();//获取长度
for(int i = 0; i < curSize; i++){
Book book = bookList.getBooks(i);
if(book.getName().equals(name)){
//找到了,打印,使用book的toString
System.out.println("已找到,如下:");
System.out.println(book.toString());
return;
}
}
System.out.println("没有此书");
}
}
归还图书的实现
思路:和借阅的想法差不多,只要查看其状态再更改就好了。
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("归还图书");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入书名");
String name = scanner.nextLine();
int curSize = bookList.getUseSize();
for(int i = 0; i < curSize; i++){
Book book = bookList.getBooks(i);
if(book.getName().equals(name)){
if(book.getBorrow()){
//进入if证明为true,即已被借阅
book.setBorrow(false);
System.out.println("归还成功");
}else{
System.out.println("此书不用归还");
}
}
}
System.out.println("没有要归还的书");
return;
}
}
展示图书的实现
思路:遍历再打印即可
package operation;
import book.Book;
import book.BookList;
public class ShowOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("展示图书");
int curSize = bookList.getUseSize();
for(int i = 0; i < curSize; i++){
Book book = bookList.getBooks(i);
System.out.println(book);
}
return;
}
}