目录
前言
学完了javaSE语法,今天就带大家一起实现一个用Java语言写的图书管理系统吧。我们简单讲讲这个图书管理系统的功能。非常适合刚刚学完语法的小白哦~~~~~
我们先来简单的展示一下我们管理系统的页面。不同的身份对应不同的功能。
一、图书管理系统成果展示
开始菜单你需要输入你的姓名:
假如说我叫祁思妙想
回车之后, 你可以确认你的身份,假如你是管理员你就输入1,假如你是普通用户你就输入0。
我们先来看看管理员的菜单都有什么功能:
1.1 管理员:
假如你是管理员,你可以进行
①查找图书 ②新增图书 ③删除图书 ④显示图书 ⑤退出系统。
显示图书功能示例:输入4,回车后便会显示现在我们书架上已有的图书。我们默认包括了以下三本书,每一本书都有书名,作者,价格,类型,是否被借出等指标。每一个功能完成之后会自动跳转会菜单界面,可以继续选择功能。
查找图书功能示例:输入1回车之后,进入查找图书功能。你可以输入你想要查找的书籍的书名,如果找到了会显示出这本书的各种指标,如果没找到会告诉你没有找到。
新增图书功能示例:输入2回车后,进入新增图书功能,你需要输入新增书的书名,作者,价格,类型。回车后,系统会提示你添加成功,并且会告诉你书架此时有几本书。新增的图书默认是未被借出。
删除图书功能示例:输入3回车,之后输入你要删除的书名,若书架上没有你的书名,则返回,没找到你要删除的图书,若有则返回删除成功,并显示此时书架有多少本书。删除后再次显示图书,可以发现已经删除成功!
退出系统功能示例:输入0回车后,程序停止运行。
1.2 普通用户:
普通用户的功能有
①查找图书 ②借阅图书 ③归还图书 ④退出系统
假如我现在名字叫做祁早贪黑。我是普通用户。则可以进行以下操作。
其中查找图书功能,与退出系统功能与管理员身份的功能是一样的,我们就不再演示了。我们看
借阅图书功能示例:输入2回车之后,会提示你输入你想借阅图书的名字,假设要借西游记,回车后返回,借阅成功!,若书架中没有你想借阅的图书,则会返回很抱歉,没有找到你想借阅的图书。我们再查找西游记这本图书,最后面的指标已经是被借出了,若你想借阅的图书已经被借阅,则会返回,图书已经被借阅,您无法再次借阅。
归还图书功能示例:输入3回车之后,会提示你输入你想归还图书的名字,假设要借西游记,回车后返回,归还成功!,若书架中没有你想归还的图书,则会返回很抱歉,没有找到你想归还的图书。我们再查找西游记这本图书,最后面的指标变成了未被借出。
以上就是本次我们要编程的Java版本的一个简易的图书管理系统!!!!
接下来我们看看编写这个图书管理系统需要进行的每一步操作吧!!!!!
了解了我们这个图书管理系统的各个功能之后,相信小伙伴们已经对我们这个图书管理系统有了初步的认知。里面用到了许多我们JavaSE的基础语法,例如:分支循环,数组,类与对象,封装,继承,多态,字符串.......编写这个简易的图书管理系统,有效的复习了我们之前学习过的Java的基础语法知识。
二、 图书管理系统框架的搭建
首先我们在IDEA中新建一个项目,项目名称我们设置成BookMS(book manage system)。
1. 在包src中创建一个主类命名为Main类。我们所有的程序都要在这个类中运行。
2.在包src中以包的形式创建和书相关的包book包,和身份相关的包user包,和操作相关的包operation包等等。因为我们要通过不同的包去组织这些类,在同一包中放同一类型的类。
2.1 book包
在这个包里我们要创建如下类
2.1.1 Book类
成员变量:
1.①在book包中创建一个Book类,用来抽象出一本数。其中包含字符串String类型的书名、作者、类型等变量,整型int类型的价格变量,布尔类型的是否被借出flase未被借出,ture被借出变量,这些成员变量我们对其进行封装用private修饰。保证程序的安全性。
成员方法:
②(快捷创建)并创建getter,setter方法,方便初始化和获取封装的这些变量的内容,可以对这些成员变量进行初始化以及得到这些被封装的变量的值;(一定是快捷键创建哦)不会快捷创建这些方法的小伙伴可以去看看之前讲Java封装的文章,里面详细介绍了创建Getter,Setter等方法的快捷键用法。
③(快捷创建)创建成员变量对应的构造方法,方便后续为实例化出来的对象(每本书)赋值(也是快捷键创建哦,文章类与对象中讲过),在new一个新的书这个对象时。让我们对其成员变量进行初始化,由于是否被借出是boolean类型。默认是flase代表没有被借出,因此我们不对它进行初始化。当然这里面的有些方法可能是我们用不到的,但我们就顺手写了。
④(快捷创建)创建toString方法,方便后面显示图书(也是快捷健创建,也在面向对象系列的文章里。这是为了能直接打印数组名,来打印数组内容,涉及到方法的重写。我们对快捷创建出来的内容进行了修改,以达到我们想要达到的效果)
以下是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 getBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
// ", isBorrowed=" + isBorrowed +
((isBorrowed == true) ? " 被借出" : " 未被借出")+
'}';
}
}
本类中的代码比较简单,将书抽象出来,到时候我们就可以new出许多不同的书了
需要注意的两个地方有
1.定义布尔类型时一定是boolean来定义。而不是Boolean,在我编写代码的时候就犯了这个错,导致布尔变量isBorrowed的默认值编程了null。而不是布尔boolean类型的默认值flase
2.在toString时修改其中内容时用到的三目运算符,要注意条件要添加括号哦!!! 最后再总体加给括号。
2.1.2 BookList类
1.在book包中创建一个BookList类
成员变量:
①创建一个Book类型的数组(就是我们上面定义的Book类)(这个数组中存的就是由Book类实例化出来的对象,也就是每一本书,这个就初步组成了一个书架)。并分配内存,我们初步定义可存的Book类型变量为十个。
②创建一个计数器变量bookCount来表示实际放的书的个数。
private Book[] books = new Book[10]; //定义一个Book类型的数组,分配十块空间,用来存放十本书
private int bookCount; //来记录当前实际放的书的个数
//封装是为了避免该变量与其他包的变量弄混,保证程序的安全性
成员方法:
①(快捷创建)创建BookList构造方法。对里面的成员变量也就是Book类型的数组中的Book类型的对象进行初始化,以及对 bookCount 这个变量进行初始化。我们初始时放入三本书。因此将bookCount的数值初始化为3。
②(自己创建,这是数组需要自己创建,用来操作数组中的每个元素)创建getBook方法和setBook方法代表得到书架上的某本书和在书架中某一位置放一本书。
public Book getBooks(int pos) {
return books [pos] ;
}
public void setBooks(int pos, Book book) {
books [ pos ] = book;
}
③(快捷创建)创建getBookCount和setBookCount方法,用来设置和得到封装的变量bookCount的值
public int getBookCount() {
return bookCount;
}
public void setBookCount(int bookCount) {
this.bookCount = bookCount;
}
以下是BookList类 中的所有代码:
package book;
public class BookList {//定义一个书架类,用来存放许多本书
private Book[] books = new Book[10];//定义一个Book类型的数组,分配十块空间,用来存放十本书
private int bookCount;//来记录当前实际放的书的个数
public BookList() {
//构造方法来初始化成员
this.books[0] = new Book("三国演义","罗贯中",50,"小说");
this.books[1] = new Book("西游记","吴承恩",51,"小说");
this.books[2] = new Book("红楼梦","曹雪芹",49,"小说");
this.bookCount = 3;
}
public Book getBooks(int pos){//得到数组中某一本书
return books[pos];//返回数组中某一本书
}
public void setBooks(int pos, Book book){//在书架某个位置里放一本书。
this.books[pos] = book;
}
public int getBookCount() {
return bookCount;
}
public void setBookCount(int bookCount) {
this.bookCount = bookCount;
}
}
本类中, 也比较简单,稍有难度的就是
1.成员变量类型为之前创建的Book类。并创建了Book类型的数组,那么它存储的元素都是Book类型了,那么就可以存储由Book类new出来的对象。存储许许多多的书了。
2.值得一提的还有setBooks和getBooks这两个方法。这不是由快捷生成的,由于是数组。快捷生成的get和set达不到我们需要的功能。因此我们要自己创建这两个成员方法。目的是从书架Book类型的数组中取书(得到这个Book类型的数组元素)和放书(设置书,在?Book类型数组中存放一我们想存的书籍)。
3.BookList这个构造方法。这个构造方法没有参数的传递。目仅仅是为了初始化我们的成员变量。由于默认的书籍和数目都是我们已知的,因此不需要传入而赋值,只需要在内容中直接初始化我们的成员变量就可以了
2.2 operation包
在这个包里我们要创建如下接口和类,插入的代码就是那个接口或者类中所有的代码。
2.2.0 IOperation接口
0.创建接口,由于这些操作都是对于书架BookList的,因此我们可以把它们规范起来,以接口的形式进行定义,创建一个IOperation接口
public interface IOperation {
void work (BookList bookList);
}
让下面的添加图书,查找图书,删除图书,显示图书,借阅图书,归还图书,退出系统这些类去实现这个接口。其中的work方法便是重写了这个接口中的work方法。到时候我们在User中管理员类和普通用户类中创建这个接口类型的数组。存入对应的功能,便可以用输入进去的数字(下标)来实现对应的某个功能了。这应该也算多态的一种吧,引用不同的对象,调用同一个方法,呈现不同的效果。
package Operation;
import book.BookList;
public interface IOperation {
void work (BookList bookList);
}
因为这个包内都是一些功能方法,因此我们可以在这个包内创建一个接口。用于实现多态。
1.这个包内其他所有类来实现这个接口。并重写接口中的方法。到时候只需要调用接口中的方法便可以访问实现这个接口的所有功能方法中的这个方法了。
2.我们在User用户类中就可以创建一个接口类型的数组,里面分别存储这些Operation包内除接口外的功能方法。 这样我们就可以利用这个数组,传入下标后,来实现在菜单中输入数字几,从而调用不同的方法。
2.2.1 AddOperatoon类
1.添加图书,创建一个AddOperatoon类,用于添加图书。创建一个work方法,传入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("请分别输入你想添加的图书的书名,作者,价格,类型:");
System.out.println("书名:");
String name = scanner.nextLine();
System.out.println("作者:");
String author = scanner.nextLine();
System.out.println("价格:");
int price = scanner.nextInt();
scanner.nextLine(); //这里标记重点回顾!!!!!!!!!!!!!
System.out.println("类型:");
String type = scanner.nextLine();
Book book = new Book(name,author,price,type);
int currentCount = bookList.getBookCount();
for (int i = 0; i< currentCount; i++){
Book book1 = bookList.getBooks(i);
if (book1.getName().equals(name)){
System.out.println("书架已经有这本书了,不需要再次添加!!!");
return;
}
}
bookList.setBooks(currentCount,book);
bookList.setBookCount(currentCount+1);
System.out.println("添加成功!");
System.out.println("此时您可操作的图书有 " + bookList.getBookCount() + " 本!");
}
}
本类是一个功能方法类。是为了实现菜单中的添加图书的功能。
我们将这个业务的功能写在重写方法work方法中。
1.传入BookList类型的参数bookList。传入这个参数的目的是为了调用这个参数中的成员变量。对其进行操作。如获取书架中书的数目。从书架中得到某一本书,或在书架中放入某一本书。
2.添加某本书,在本系统中,需要添加书名,书的作者,书的价格,书的类型。等四个书的成员变量,因此我们首先用sout打印提示词,之后定义四个变量。并用Scanner来从键盘输入来给变量赋值,之后在new好一本书的时候传入,利用已经建好的构造方法来初始化book的成员变量。这样新的book就创建好了。
3.用for循环遍历书架中Book数组,我们利用BookList中的getBooks方法来获取书架中的每本书,并将他存入我们新建的Book类型变量中,在比对书架中已有的图书的名字,如果相等,则书架中已有这本书,则不需要再次添加return返回。如果循环完了都没有相等的,那么我们就利用setBook方法来在bookList中存入我们定义的这本书。下标为书架中已有的书的个数。之后我们更新一下bookCount的数值,让它为currentCount+1。最后添加提示语。添加图书成功!
易错:
1.在我编写代码时,不小心添加图书时将
bookList.setBooks(currentCount,book);
写成了
bookList.setBooks(currentCount+1,book);
我们要时刻注意下标是从0开始的,而书的数目是从1开始的,因此下标为currentCount时,就已经是数组中的空余的位置了。不能再加1,否则会将存储的位置存储错误。
2.当书架已经有这本后,一定要return,不然还会往下执行,将这本书再次添加形成重复的数据。
2.2.2 FindOperation类
2.查找图书,创建一个FindOperation类,用于查找图书,创建一个work方法,传入BookList类型的参数。将你要查找的图书从书架找到
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("查找图书!");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你要查找的图书名:");
String name = scanner.nextLine();
int currentCount = bookList.getBookCount();
for (int i = 0; i< currentCount; i++){
Book book = bookList.getBooks(i);
if (book.getName().equals(name)){
System.out.println("找到了你!!!");
System.out.println(book);
return;
}
}
System.out.println("很抱歉,没找到你想查找的书籍!");
}
}
本类是一个功能方法类。是为了实现菜单中的查找图书的功能。可以说是添加图书的简化版本。如果你看懂了添加图书,那么查找图书就是小菜一碟了
1.我们这个查找图书的功能是通过比对书名来查找。如果书架中的书名与你输入的书名相等,那么就找到了你想要查找的书名,如果循环下来都没有相等的,那么就没有找到你想要的书籍。 代码非常简介就不细说了。
易错:
1.唯一要注意的是不要把最后没找到要查找的书籍的提示语放到循环之内。要放到循环之外,遍历完了数组都没有找到。此时再提示没有找到,这样才合理。
2.2.3 DelOperation类
3.删除图书,创建一个DelOperation类,用于删除图书,创建一个work方法,传入BookList类型的参数。将你要删除的图书从书架中删除。
package Operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class DelOperation implements IOperation{
public void work(BookList bookList){
int currentCount = bookList.getBookCount();
if (currentCount == 0){
System.out.println("书架为空,不能再移除图书了!!!");
return;
}
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你要移除图书名:");
String name = scanner.nextLine();
int index = -1;
for (int i = 0; i< currentCount; i++){
Book book = bookList.getBooks(i);
if (book.getName().equals(name)){
index = i;
break;
}
}
if (index == -1){
System.out.println("很抱歉,没找到你想删除的书籍!");
return;
}
for (int i = index; i < currentCount; i++){
Book book1 = bookList.getBooks(i+1);
bookList.setBooks(i,book1);
}
System.out.println("删除成功!!!!");
bookList.setBookCount(currentCount-1);
System.out.println("如今您可操作的图书有 " + bookList.getBookCount() + " 本!");
}
}
本类是一个功能方法类。是为了实现菜单中的移除图书的功能。
1.类似的我们输入书名,再遍历书架找到移除的书名。找到之后我们将这个书后面的所有书都往前移动一位。这就相当于在书架上将这本书拿走了。没找到则在循环外sout提示词没找到。
2.为了方便代码观赏,这里在找到与之对应的名称的图书之后巧用了临时变量index。要记得找到后是break跳出循环。
当然也可以写成这样的形式:
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("请输入你想移除的图书的书名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int currentBooks = bookList.getBookCount();
int i;
for(i = 0; i<currentBooks; i++ ){
if (bookList.getBooks(i).getName().equals(name)){
for (; i<currentBooks-1; i++){
//为了避免数组越界,因此i<currentBooks-1;,这样虽然导致移除最后一本图书是进不来循环
//但是我们将bookList.setBookCount(currentBooks-1);不影响显示图书和其他功能。
//在用户眼里是被删除了的。
Book book = bookList.getBooks(i+1);
bookList.setBooks(i,book);
}
bookList.setBookCount(currentBooks-1);
System.out.println("删除成功!!!");
System.out.println("此时书架上共有 " + bookList.getBookCount() + " 本书供您操作!");
return;
}
}
System.out.println("很抱歉,没有找到你想要移除的图书!");
}
}
此时找到后,移除完是return。直接跳出这个方法。
易错:
1.找到要移除的书之后,在将这本书后面的书统一往前移的过程中。一定是i<currentBooks-1 。如果i下标访问的是最后一本书,虽然没有进入循环,但是由于我们将bookCount的值修改了
bookList.setBookCount(currentBooks-1);
因此不影响显示图书和其他功能。在用户眼里是被删除了的。如果要添加则直接覆盖上去就行了。
2.2.4 ShowOperation类
4.显示图书,创建一个ShowOperation类,用于显示图书,创建一个work方法,传入BookList类型的参数。将书架中的图书显示出来。
package Operation;
import book.Book;
import book.BookList;
public class ShowOperation implements IOperation{
public void work(BookList bookList){
System.out.println("展示图书!!!!");
int currentCount = bookList.getBookCount();
for (int i = 0; i< currentCount; i++){
Book book = bookList.getBooks(i);
System.out.println(book);
}
System.out.println("共有"+bookList.getBookCount()+"本书!");
}
}
本类是一个功能方法类。是为了实现菜单中的显示图书的功能。
1.由于我们已经用toString方法进行了方法的重写。首先得到书架上的书的数目,之后直接遍历书架sout打印book即可。非常简单,基本不会错。
2.2.5 BorrowedOperation类
5.借阅图书,创建一个BorrowedOperation类,用于借阅图书,创建一个work方法,传入BookList类型的参数。将书架中的图书借阅出来。
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("请输入你想要借阅的图书的名字:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int currentCount = bookList.getBookCount();
for (int i = 0; i< currentCount; i++){
Book book = bookList.getBooks(i);
if (book.getName().equals(name)){
if (book.getBorrowed()){
System.out.println("图书已经被借阅,您无法再次借阅");
return;
}
book.setBorrowed(true);
System.out.println("借阅成功!!!");
return;
}
}
System.out.println("很抱歉,没有找到你想借阅的图书");
}
}
本类是一个功能方法类。是为了实现菜单中的借阅图书的功能。
2.2.6 ReturnOperation类
6.归还图书,创建一个ReturnOperation类,用于归还图书,创建一个work方法,传入BookList类型的参数。将书架中的图书归还。
package Operation;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class ReturnOperation implements IOperation {
public void work(BookList bookList){
System.out.println("请输入你想要归坏的图书的名字:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int currentCount = bookList.getBookCount();
for (int i = 0; i< currentCount; i++){
Book book = bookList.getBooks(i);
if (book.getName().equals(name)){
book.setBorrowed(false);
System.out.println("归还成功!!!");
return;
}
}
System.out.println("很抱歉,没有你想要归还的图书");
}
}
本类是一个功能方法类。是为了实现菜单中的归还图书的功能。
2.2.7 ExitOperation类
7.退出系统,创建一个ExitOperation类,用于退出系统,创建一个work方法,传入BookList类型的参数。用于退出系统。
package Operation;
import book.Book;
import book.BookList;
public class ExitOperation implements IOperation {
public void work(BookList bookList){
System.out.println("退出系统!!!欢迎下次光临!!!");
int currentCount = bookList.getBookCount();
for (int i = 0; i< currentCount; i++){
bookList.setBooks(i,null);
}
bookList.setBookCount(0);
System.exit(0);
}
}
本类是一个功能方法类。是为了实现菜单中的退出图书图书系统的功能。
System.exit(0);直接这样就可以了,不过我们既然传入了BookList参数,因此我们可以将书架清空,都置成空指针。然后将书架中书的数目设置成0。然后再退出系统。也是比较简单。
2.3 User包
在这个包里我们要创建如下类
2.3.1 User类(抽象类)
由于管理员,普通用户都是用户,我们可以将用户定义为一个父类User。
成员变量:
①创建字符串变量name。并创建构造方法对其初始化。之后让管理员和普通用户去继承它。
②创建接口类型数组,存储实现接口的各种方法,如 AddOperatoon,FindOperation,ShowOperation等等这些方法,到时利用动态绑定只需要输入对应的数字,便可以实现这些功能。
成员方法:
①创建meau方法,由于子类都需要用到meau方法,来打印菜单,因此父类需要这个方法,到时候可以实现重写,动态绑定,之后发生多态。也就是不同用户调用这个方法呈现出的结果不同。由于meau在父类中写不写都一样,因此我们可以将这个方法用abstract修饰。那么这个类也需要用abstruct修饰。将这个User类也该为抽象类。不知不觉中,我们就体会到了抽象类的作用。
②创建构造方法,用来初始化name这个成员变量。
③创建doOperation方法,用来传入用户选择的某个功能的对应的数字和书架。再由数组iOperations[下标],去接收这个数字,并调用这个类中的work方法。这样就搭建起了实现各种功能的框架。
以下是User类(抽象类)中的所有代码:
package User;
import Operation.IOperation;
import book.BookList;
abstract public class User {
protected String name;
public IOperation[] iOperations;
//接口类型的数组
public User(String name) {
this.name = name;
}
abstract public int menu();
public void doOperation(int choice, BookList bookList){
iOperations[choice].work(bookList);
}
}
本类是在用户包中创建的一个User父类 。它的作用是引申出不同的身份,例如我们这个系统中的普通用户和管理员这个身份作为子类。去继承这个User父类。这样我们就可以进行向上转型,动态绑定来实现多态。传入不同的身份,来打印不同的菜单。并且建立了doOperation方法。用来在不同身份下,使不同的功能方法得到实现。
易错点:
1.由于在它的子类管理员和普通用户类还会使用name这个成员变量,因此我们可以不对成员变量name进行修饰,或者用protected来进行修饰。
注意此时我们并没有给这个接口类型数组进行赋值。
2.3.2 Administrator类
定义一个Administrator类代表管理员,作为子类继承父类User,继承后要帮助父类进行构造,在这里还有一个专属于管理员的菜单。
成员变量:已经继承了父类User的成员变量,且无需有新的成员变量。因此只需要一个构造方法,帮助继承父类的成员变量进行初始化。
成员方法:
①创建构造方法,用来初始化从父类继承下来的成员变量。在用户选择管理员身份时,会new一个管理员对象,此时便会自动给这个对象进行初始化。以便于后续调用这个对象中的一些变量和方法。
②创建menu方法,重写父类的menu菜单。并sout出管理员的菜单,返回值类型为int类型,并return choice。便于后续在Main函数接收这个数值来调用不同的功能方法。
以下是Administrator类中的所有代码:
package User;
import Operation.*;
import java.util.Scanner;
public class Administrator extends User {
public Administrator(String name) {
super(name);
this.iOperations =new IOperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new ShowOperation(),
};
}
@Override
public int menu() {
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;
}
}
本类是用户User类的一个子类,管理员类,它的作用是使用户可以使用管理员身份来运行这个程序。这样会实现不同的功能。
易错点:
1.由于父类有name的构造方法,因此在子类中也要有构造方法,对继承父类来的name变量进行构造。
2.用this.去引用父类中的接口类型数组iOperations。并对其初始化,输入你想实现的功能方法,以及把控好它们存储的下标位置。
注意:在最开始定义数组时没有初始化的话,后面再初始化时就需要这样来初始化了就是先new再后面{}中进行赋值。
2.3.3 NormalUser类
与Administrator几乎一样,不一样的是接口类型变量中存入的方法,与打印的菜单内容不同。定义一个NormalUser类代表普通用户,作为子类继承父类User,继承后要帮助从父类继承来的变量进行构造初始化,在这里还有一个专属于普通用户的菜单。
成员变量:已经继承了父类User的成员变量,且无需有新的成员变量。因此只需要一个构造方法,帮助继承父类的成员变量进行初始化。
成员方法:
①创建构造方法,用来初始化从父类继承下来的成员变量。在用户选择管理员身份时,会new一个普通用户对象,此时便会自动给这个对象进行初始化。以便于后续调用这个对象中的一些变量和方法。
②创建menu方法,重写父类的menu菜单。并sout出普通用户的菜单,返回值类型为int类型,并return choice。便于后续在Main函数接收这个数值来调用不同的功能方法。因此父类中的抽象方法menu,也需要将返回值设置为int类型。
以下是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(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation(),
};
}
@Override
public int menu() {
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;
}
}
本类是用户User类的一个子类,普通用户类,它的作用是使用户可以使用普通用户身份来运行这个程序。这样会实现不同的功能。
易错点:
1.由于父类有name的构造方法,因此在子类中也要有构造方法,对继承父类来的name变量进行构造。
2.用this.去引用父类中的接口类型数组iOperations。并对其初始化,输入你想实现的功能方法,以及把控好它们存储的下标位置。
注意:在最开始定义数组时没有初始化的话,后面再初始化时就需要这样来初始化了就是先new再后面{}中进行赋值。
2.2.4菜单功能选择的框架实现
在我们创建User时,创建了接口类型的变量。在管理员和普通用户中继承了这个变量,并分别对这个变量进行了各自的构造。各个功能的类被当作数组元素存入了这个数组,当我们想用到这个功能时,我们只需要在这个数组中传入对应的下标,再调用类中的方法就可以了。
当菜单建成,用户输入了1之后,接下来该怎么办呢?我们应该对这个菜单设置一个返回值(管理员和普通用户都需要将菜单的返回值改为int类型,并return choice),返回值类型为int,后续我们在主main中去接收这个值。
之后我们将这个数值用User中的doOperation方法当作下标传入我们之前定义的接口类型的数组当中。传入bookList这个书架的对象是因为在User.doOperation这个方法中有iOperations[choice].work(bookList);会调用对应的功能,在功能的实现里会用到bookList书架。
int choice = user.menu();
User.doOperation (choice,bookList);
Main类
到这里这个图书管理系统的大概框架就写好了,我们去Main方法中,试着让这个代码运行起来,为此我们还需要在Main类中创建以下内容。
1.登录,第一步我们我进行登录,在Main类中创建一个login方法,输入你的姓名。之后输入你的身份。之后确认了姓名与身份,我们就要实例化一个管理员对象或者普通用户对象,并返回这个对象。这个登录方法的返回值类型我们可以设置成User类型,这就用到了向上转型,将子类向上转型为父类。再用父类调用menu这个方法,多态就实现了。
2.创建main方法。
①首先我们实例化书架这个对象,BookList bookList = new BookList();并且调用了构造方法,此时书架上就有了我们初始化的三本书。
②用父类User接收这个管理员或者普通用户对象User user = login();这样就实现了向上转型,将子类的对象传给父类。由于我们父类也有menu这个方法,并与子类形成了方法的重写。因此我们才可以用父类对象去调用menu这个方法,才能实现多态。如果父类没有menu方法,没有形成重写,父类是不可以调用子类的方法的。
3.由于不同用户看到的菜单不同。我们用以下代码来实现我们想要达到的操作。这就是上一点讲到的多态的实现。不过多了个我们将这个menu方法的返回值传给了整型choice这个变量。这就是在接收管理员类和普通用户类中menu方法的返回值。
int choice = user.menu();
通过user和choice我们可以确定此时是哪个用户的哪个方法。此时我们给这两句代码加上循环。这样就可以实现让用户使用完一个功能后继续在选择其他功能,而不是程序停止运行。
while(ture){
int choice = user.menu();
user.doOperation(choice,bookList);}
以下是我们Main类中的所有代码
import Operation.IOperation;
import User.User;
import java.util.Scanner;
import User.NormalUser;
import User.Administrator;
import book.BookList;
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->普通用户");
while (true){
int choice = scanner.nextInt();
if(choice == 1){
return new Administrator(name);
}else if (choice == 0){
return new NormalUser(name);
}else System.out.println("请重新输入:");
}
}
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login();
while (true){
int choice = user.menu();
user.doOperation(choice,bookList);
}
}
}
程序从main中,开始运行, main中我们编写的代码很少,但是其中的逻辑是复杂的。
1.首先我们创建了一个书架类型的变量bookList,用它去接收了我们新建的对象new BookList。此时就有了我们在BookList类中定义的所有成员变量和方法都可以通过这个变量boookList来使用。
2.之后我们调用了login()方法。定义了User类型的变量user,用来接收login()这个方法的返回值可能是管理员也可能是普通用户。
3.此时实现了向上转型。再用user.menu()这个方法在User里面并且被子类继承,形成了方法的重写。就可以实现不同身份,看到不同的菜单。
4.user.doOperation(choice,bookList);方法用于我们传入数字,来实现不同的功能。加上while循环就可以在实现完一个功能后继续选择另一个功能。