目录
目录
前言
🔔1.library包
1.1 Book类
1.2 BookList类
🔔2.user包
2.1User类(父类)
2.2Admin(管理员)
2.3 NormalUser(普通用户)
🔔3.Operation包
🕐3.1 IOperation接口
🕑3.2ListOperation(查看操作)
🕒3.3AddOperation(增加操作)
🕓3.4BorrowOperation(借书操作)
🕔3.5ReturnOperation(还书操作)
🕕3.6DelOperation(删除操作)
🕖3.7FindOperation(查找操作)
🕗3.8ExitOperation(退出操作)
🔔4.Main类
🔔5.效果展示
(ps:✨在本篇文章中我们介绍了图书管理系统📖,但是功能很少,所以在下一篇文章中,我又增加了几个功能:大家可以点击链接移步到下一篇文章(无讲解的))
https://blog.csdn.net/2401_84024092/article/details/147874135?fromshare=blogdetail&sharetype=blogdetail&sharerId=147874135&sharerefer=PC&sharesource=2401_84024092&sharefrom=from_link
前言
🌈本篇文章会实现一个控制台版本的“图书管理系统”,涉及到 JavaSE中的继承,多态,抽象类,接口。(代码部分附有详细的讲解✨)
在这个系统中:
1.能够表示多本图书的信息📘
2.提供两种用户:管理员和普通用户
3.普通用户可以查看书籍列表,查找图书📖,借书,还书
4.管理员可以查看书籍列表,查找图书📖,新增图书,删除图书
整体框架如下:🎉
程序目录如下:🎉
🔔1.library包
1.1 Book类
👉每本书📕都被定义为一个类,其中包含书名、作者、类型、价格和借阅状态等属性。这些属性均被设置为private访问权限,并通过getter和setter方法进行访问和修改。在类的构造方法中,我们会对这些属性进行初始化,其中借阅状态默认设置为未借出(false)。
package library;
//一本书
public class Book {//现实世界的书private String name;private String author;private String type;private double price;private boolean isBorrowed;public Book(String name, String author, String type, double price){this.name=name;this.author=author;this.type=type;this.price=price;this.isBorrowed=false;}//alt+ins自动生成
//get,set方法可以随时更改属性,但是构造方法只能初始化一次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 String getType() {return type;}public void setType(String type) {this.type = type;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public boolean isBorrowed() {return isBorrowed;}public void setBorrowed(boolean borrowed) {isBorrowed = borrowed;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", type='" + type + '\'' +", price=" + price +", isBorrowed=" + (isBorrowed?"已借出":"未借出") +'}';}
}
1.2 BookList类
👉用来管理多个书籍对象
首先定义一个Book类类型的数组books,共分配1024个空间
✨注意:我们约定好,所有有效的书籍,都是从0开始连续递增排列的,以便可以通过size来描述有效书籍数目
package library;public class BookList {private Book[] books=new Book[1024];//此数组中每个类型都是Book类类型//长度不方便灵活调整,预先创造大空间//把booklist想象为一个书架,书架总共有1024个位置,不能修改大小,所以设置为private//长度不方便灵活调整,预先创造大空间private int size =0;//有效元素public BookList(){books[0]=new Book("西游记","吴承恩","古典小说",100);//books[0]中存放的是一组实例对象books[1]=new Book("红楼梦","曹雪芹","古典小说",90);books[2]=new Book("高等数学","高斯","数学",40);books[3]=new Book("Java入门","詹姆斯高斯林","计算机",70);books[4]=new Book("红楼梦","曹雪芹","古典小说",90);size=5;}public Book getBook(int index) {//得到序号为index的书籍return books[index];//不会越界,因为此时还没满}public void setBook(int index,Book book) {books[index] = book;}//将序号index处设置为××书public int getSize() {return size;//有效书籍数量}public void setSize(int size) {this.size = size;//设置有效书籍数量}
}
🔔2.user包
两种用户:普通用户🙎♀️+管理员👩🏫
✨注意:普通用户与管理员的操作即存在重复的部分,也存在不同的部分,因此可以通过继承,把相同的部分通过父类(User)提取出来
2.1User类(父类)
将抽象菜单方法(menu)定义在父类中,供子类重写实现,并通过 IOperation[] 数组存储管理员和用户可执行的功能操作。
package library.user;import library.BookList;
import library.IOperation;public abstract class User {//不同 的用户不同的操作protected String name;//各个子类都有的内容,直接放在父类中//protected子类可以直接获取到,不必再去用getter setterprotected IOperation[] operations;//当前这个类能进行那些操作,就往这个数组里添加对应的对象public User(String name){this.name=name;}public abstract int menu();//不知道父类的菜单(父类就没有菜单),我知道的只有管理员和用户的菜单// 所以使用abstract,子类再进行重写//为了避免父类被不小心创建出实例,所以要抽象(因为不能出现“父类菜单”)public void work(int choice, BookList bookList){//3.进入到父类的work方法if(choice<0||choice>=operations.length){System.out.println("输入的选项非法");return;}operations[choice].work(bookList);//4.调用我选择的方法里面的work方法,就能用此方法对booklist进行操作了}
}
2.2Admin(管理员)
🔔管理员应继承父类User,通过重写父类的 menu
方法,实现了自定义菜单功能,用户可通过输入选择进入相应功能模块。在子类构造函数中,首先调用父类构造方法完成名称初始化,随后对用户操作进行配置(包括退出,查看,查找、新增、删除的功能)。
注意:IOperation[]中的顺序已经和菜单中的选项对应了
package library.user;import library.IOperation;
import library.Operation.*;import java.util.Scanner;public class Admin extends User{//private IOperation[] operations;//存放管理员的方法,这是什么类型呢,接口类型public Admin(String name) {super(name);operations=new IOperation[]{new ExitOperation(),new ListOperation(),new FindOperation(),new AddOperation(),new DelOperation(),};}@Overridepublic int menu() {System.out.println("==============================");System.out.println("欢迎您,"+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.3 NormalUser(普通用户)
🔔普通用户应继承父类User,通过重写父类的 menu
方法,实现了自定义菜单功能,用户可通过输入选择进入相应功能模块。在子类构造函数中,首先调用父类构造方法完成名称初始化,随后对用户操作进行配置(包括退出,查看,查找、借书、还书的功能)。
package library.user;import library.Operation.IOperation;
import library.Operation.*;import java.util.Scanner;public class NormalUser extends User {//private IOperation[] operations;public NormalUser(String name) {super(name);//对所要的方法进行初始化operations = new IOperation[]{//普通用户进行的操作new ExitOperation(),//这是一个数组,此处下标为0new ListOperation(),new FindOperation(),new BorrowOperation(),new ReturnOperation(),};}@Overridepublic int menu() {//打印菜单System.out.println("==============================");System.out.println("欢迎你,"+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;}
}
🔔3.Operation包
👓此包中包括所有需要进行的操作类
🔔🔔🔔看到这里我们发现,书籍和用户并没有建立起联系,那么如何将BookList与用户实现“交互”呢?⬇
通过IOperation接口把用户和书给关联起来
🕐3.1 IOperation接口
增加这个接口后,所有的操作类都要实现自IOperation接口,并重写其中的work方法,在每个操作类中的work方法的具体实现各不相同。
✨注意:这里有人可能会问:如果不设置接口,只在每个类中都写上work方法,将参数BookList作为参数传递进去不就可以进行书籍与操作的联系吗,为什么还要设置接口呢?
原因:简单来说就是限制代码的灵活性
解释:理论上是可行的,但是不加接口的话,无法保证所有的类都提供了work方法,也没法保证work方法的参数都是相同的。而加上后就能强制统一,方便后续的调用,否则如果大家提供的方法各不相同,就会显得很乱。
package library.Operation;import library.BookList;public interface IOperation {//也可以使用抽象类,但是我这个接口我只想保存一些方法,并没有什么实例属性要继承的//并且不能多继承//而User中的类是抽象性,因为我们需要继承name的属性void work(BookList bookList);
}
🕑3.2ListOperation(查看操作)
✨在每一次循环中都会创建一次book对象
✨接着调用booklist中的getBook方法获取到第i本书
当i为0时,创建的对象就是
Book book = new Book("西游记","吴承恩","古典小说",100);
最后实现打印操作,当打印book时,会自动调用Book类中的toString方法(打印格式可以自行调整)
package library.Operation;import library.Book;
import library.BookList;public class ListOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("查看书籍列表");for(int i=0;i<bookList.getSize();i++){Book book = bookList.getBook(i);//拿到第i本书System.out.println("["+i+"]"+book);}}
}
🕒3.3AddOperation(增加操作)
➡让用户输入新的书籍📕的信息,然后把这个新的书放到BookList中
➡这本新书存放到数组的最后一个位置上,在BookList中已经存在N本书了(size),这些书对应的下标[0,N-1],新的图书📕就放到N的位置即可,在相应位置传入书后,有效元素size也要加一。
package library.Operation;import library.Book;
import library.BookList;import java.util.Scanner;public class AddOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("新增图书");Scanner scanner=new Scanner(System.in);System.out.println("请输入书名:");String name = scanner.next();System.out.println("请输入作者:");String author =scanner.next();System.out.println("请输入价格");double price = scanner.nextDouble();System.out.println("请输入类别");String type=scanner.next();Book book =new Book(name,author,type,price);int size=bookList.getSize();bookList.setBook(size,book);//传入book就相当于传入引用的空间bookList.setSize(size+1);//不能忘了修改sizeSystem.out.println("新增图书完成!");}
}
🕓3.4BorrowOperation(借书操作)
✨在借书操作时,要注意判断是否被借出
package library.Operation;import library.Book;
import library.BookList;import java.util.Scanner;public class BorrowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("借书");Scanner scanner=new Scanner(System.in);System.out.println("请输入要借阅的图书编号:");int id= scanner.nextInt();if(id<0||id>=bookList.getSize()){System.out.println("输入错误");return;}Book book=bookList.getBook(id);//获取第id本书对象if(book.isBorrowed()){//先判断一下是否被借出System.out.println("该书已经被借出了");//如果真就被借出了return;}book.setBorrowed(true);//没借出我就可以借了System.out.println("借书成功!");}
}
🕔3.5ReturnOperation(还书操作)
✨在借书操作时,也要注意判断书是否已经被归还了
package library.Operation;import library.Book;
import library.BookList;import java.util.Scanner;public class ReturnOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("还书");Scanner scanner=new Scanner(System.in);System.out.println("请输入要归还的图书编号:");int id= scanner.nextInt();if(id<0||id>=bookList.getSize()){System.out.println("输入错误");return;}Book book=bookList.getBook(id);if(!book.isBorrowed()){//先判断一下是否被借出falseSystem.out.println("该书没借出,不能归还");//如果没被借出了,就不能换return;}book.setBorrowed(false);System.out.println("还书成功!");}
}
🕕3.6DelOperation(删除操作)
✨在进行删除操作时,如果是最后一本书📕,直接将有效元素size-1即可
如果是中间位置元素,可以把最后一本书📕放在待删除元素的位置上,然后再size-1即可。
package library.Operation;import library.Book;
import library.BookList;import java.util.Scanner;public class DelOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("删除书籍");Scanner scanner=new Scanner(System.in);System.out.println("请输入要删除书籍的序号:");int index=scanner.nextInt();if(index<0||index>=bookList.getSize()) {System.out.println("序号超出范围");return;}if(index == bookList.getSize()-1){bookList.setSize(bookList.getSize()-1);//如果是最后一本书,直接将有效元素设置为size-1即可}else{//如果删除中间元素,就可以把最后一个元素,复制到待删除元素的位置上,然后size-1即可Book lastBook = bookList.getBook(bookList.getSize()-1);//先获取到最后一本书bookList.setBook(index,lastBook);bookList.setSize(bookList.getSize()-1);}System.out.println("删除书籍完成!");}
}
🕖3.7FindOperation(查找操作)
✨查找操作只需验证输入内容与书籍列表中的条目是否一致。
package library.Operation;import library.Book;
import library.BookList;import java.util.Scanner;public class FindOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("查找操作");Scanner scanner=new Scanner(System.in);System.out.println("请输入查找的书名");String name =scanner.next();for(int i=0;i<bookList.getSize();i++){Book book = bookList.getBook(i);if(book.getName().equals(name)){//比较字符串用这个System.out.println(book);}}System.out.println("查找完毕");}
}
🕗3.8ExitOperation(退出操作)
package library.Operation;import library.BookList;public class ExitOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("goodbye!");System.exit(0);//退出整个程序}
}
🔔4.Main类
✨在主类中根据用户输入跳转到具体的用户
package library;import library.user.NormalUser;
import library.user.User;
import library.user.Admin;
import java.util.Scanner;
public class Main {private static User login(){System.out.println("请输入您的姓名:");Scanner scanner =new Scanner(System.in);String name = scanner.next();System.out.println("请输入您的角色(1.普通用户2.管理员)");int role = scanner.nextInt();if (role==1){return new NormalUser(name);}else if(role==2){return new Admin(name);}else{System.out.println("输入的角色有误");return null;}}public static void main(String[] args) {//书记管理library.BookList booklist=new BookList();//管理员和普通用户让用户选择User user = login();//User user=new NormalUser(name)//User user=new Admin(name)//向上转型while(true){int choice = user.menu();//多态user.work(choice,booklist);//将选择的菜单与书籍列表传入,假如是查找,普通用户}}
}