说明
这是一个完善了但又不完善的笔记,或许以后会更新
可以参考但请务必超越
源文件
Tools
图书管理系统
前面较难的面向对象确实是很难消化
所以来写一个图书管理系统加深理解
这篇文章只会简单的写一个小系统,太复杂的当然没有...
说不定以后会更新扩展
涉及到的知识点:
包,类,对象,抽象类,接口,封装,继承,多态,顺序表
可以说一个小练习就全部练习到位
注意
- 图书馆的管理系统,因为现实中肯定是有业务员管理员在的,所以对于业务和系统功能的判定,每个人想法可能都不一样
在工作中自然有产品经理去决定
这篇文章因为只是要拿来练习,所以业务上的处理不是重点
- 因为要面向对象,所以程序所要实现的功能,也就是类、接口什么的,都会分开写成单独的文件,当然全部都写到表里也是可以的
1.创建包
首先,我们要写的管理系统肯定是要有书和用户吧
他们在程序里都是数据
那我们就创建两个包来存放
一个是书(book),一个是用户(user)
当然后面还要实现功能,或许还会创建operation等包
2.书
图书馆嘛
核心必然是书
那我们就先把一本书所具备的数据写出来,到后面才可以创建新书,实现功能
2.1 书的数据
图书馆存的书,首先把要存入的数据写出来
种类价格书名作者,当然因为要外借,所以还要有一个是否借出的布尔类型数据
当然是写成一个public
类,数据是private
封装起来。别忘了构造方法
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;
}
}
注意哦布尔类型的isBorrowed
,我们每次新存入一本书的时候,默认肯定是未借出的对吧,所以不写isBorrowed
也可以。如果一定要写那每次就要多传一个参数false
2.2 提供公开方法
存书要使用数据的嘛,肯定得提供getter and setter
很简单
快捷添加
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;
}
2.3 打印信息
存入了一本书,肯定要打印看看书的信息吧
也很简单
快捷添加toString()
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
", isBorrowed=" + isBorrowed +
'}';
}
2.4 焯
通过上面几个步骤,可以看到书Book
这个类就有了
就简单输入一点内容,idea快捷点几下
几十行代码就有了...
3.书架
前面写好了Book
,接下来就是重点了
图书馆自然是有书架来管理
那么我们就可以使用单链表或者顺序表来充当这个书架,管理图书
这里就用顺序表来写,当然是写在book
包里
3.1 书架数据
自然,我们需要空间来存放书,先简单来一点
private Book[] books = new Book[10];
书的数量也要记下
private int usedSize;
默认存书,得来一点书先存着对吧
public BookList() {
books[0] = new Book("《HTML》", "我自", 11, "教育");
books[1] = new Book("《CSS》", "己瞎", 45, "教育");
books[2] = new Book("《JS》", "编的", 14, "教育");
this.usedSize = 3;//3本书嘛
}
3.2 提供公开方法
书的数量应当提供getter and setter
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
找书,给个下标得需要找到这本书吧,写一个位置pos
参数的getPos
方法。不合法的情况就不管了
public Book getPos(int pos) {
return this.books[pos];
}
存书,肯定得存书的吧
public void setBooks(int pos, Book book) {
this.books[pos] = book;
}
4.用户
图书馆,图书管理系统,那当然是有用户来操作的
我们眼光放长远一些,说不定会有各种身份的人来使用
那我们直接写一个父类User
,让其他身份的用户继承就好
User
public class User {
protected String name;
public User(String name) {
this.name = name;
}
}
当然是都需要姓名的,同类中要使用姓名,那protected
即可
AdminUser
注意别忘了帮助父类构造构造方法
public class AdminUser extends User {
public AdminUser(String name) {
super(name);
}
}
NormalUser
和前面一样
public class NormalUser extends User {
public NormalUser(String name) {
super(name);
}
}
5.菜单
有了用户,那自然是要提供用户菜单
管理员菜单和普通用户菜单还不一样
要是普通用户也可以管理图书馆的核心内容,那要不了多久就会寄
而且也是需要指明操作功能才可以使用吧
写菜单也不难,我们直接写
管理员菜单
public void 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("==============================");
}
普通用户菜单
public void 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("==============================");
}
6.登陆
写完菜单,就会发现其实少了个重要的功能
那就是登陆
合着压根就没登陆,根本就用不了
主函数
要进入程序,首先要登陆
那么程序的主入口,自然也是main函数
Main
文件是独立于其他包的,也是整个程序入口的地方
public class Main {
}
首先要登陆,还要确认身份
写一个login
方法
这里我们就直接把管理员和普通用户都列出来吧
public static User login() {
System.out.println("请输入你的姓名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("请输入你的身份:");
System.out.println("0.管理员 1.普通用户");
int choice = scanner.nextInt();
if (choice == 0) {
return new AdminUser(name);
} else {
return new NormalUser(name);
}
}
public static void main(String[] args) {
User user = login();//向上转型
}
我们直接判断输入的数字
直接返回new
一个用户类型
注意,这里main函数中的user引用,是不是返回那个用户类型就引用那个
但是!还要注意,User这个父类,他里面是没有菜单的
所以这时候使用user
去.
一个menu()
,必然是错误
这时,就要用到动态绑定了
打印菜单
现在User
没有menu()
,user
没得调用
解决方法也非常简单
前面不是在各身份用户中写好了菜单吗,而且都是User
的子类
那我们就直接在User
里写一个没内容的menu()
,这样就相当于子类重写了menu()
,发生了动态绑定
改法1:
public void menu() {
}
改法2:
直接改成抽象类
public abstract class User {
public abstract void menu();
}
在这里我们使用方法2,改成抽象类,更加合适
现在再回到主函数,user
就可以调用menu()
了
如果返回了管理员身份,就调用的是管理员菜单。如果返回普通用户就调用普通用户菜单
user.menu();//动态绑定
效果
idea:
其他终端(cmd、powershell、windows terminal):
7.选择(重要)
现在大致的系统框架有了
接下来,就是最重点的内容了
我们需要根据菜单选择功能
虽然现在功能没有实现,但是选择这一步,才是最难的一步
如何根据输入的数字调用合适的方法
7.1 输入
打印完菜单,那就要输入数字
我们写在两个用户的菜单里
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
注意,现在是有返回值的,我们需要修改返回类型
需要修改所有menu()
的返回值
7.2 接收
menu()
返回了一个值
那么我们就接收
int choice = user.menu();
现在再来看这两行代码,就会觉得他们的意义很深重
User user = login();//向上转型
int choice = user.menu();//动态绑定
7.3 IOperation
注意!这一步很重要,对于具体功能实现,先超前涉及一点
我们需要一个接口,其他的具体功能可以看后面的Operation
public interface IOperation {
public void work(BookList bookList);
}
来讲一下为什么要先创建一个接口?
注意图片中框起来的部分
想一下,操作这些功能的无非就是管理员和普通用户对吧
那如果后续,我们直接使用一个接口,是不是就可以想用哪个就直接调用?管理员用那个,普通用户用那个,是不是就可以分清了
非常巧妙,一个接口就可以调用全部
- 这个接口中写一个方法
work
用来链接后面功能的实现 - 每一个功能都会重写一个
work
,具体可以看后面的Operation,比如选择添加图书AddOperation
会打印:新增图书!
这就是接口的好处,只需要在其他Operation功能implements
这个接口即可
写这个接口,就是为了后面多态而做准备。如果看不太明白或者直接迷掉了,建议结合后面全部内容理解。
7.4 组装(很重要)
这一步,很重要
一步一步来看
我们现在有一个接口IOperation
直接用她在父类抽象类User
里创建数组
protected IOperation[] iOperations;
那么我们再new
出来AdminUser
和NormalUser
时
就可以对这个数组进行一个初始化,直接写在构造方法里
在我们打印菜单new
出对象的时候,就把相对应的功能准备好放到IOperation
数组当中了
AdminUser
:
public AdminUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),//0下标
new FindOperation(),//1
new AddOperation(),//2
new DelOperation(),//3
new DisplayOperation()//4
};
}
NormalUser
:
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),//0下标
new FindOperation(),//1
new BorrowOperation(),//2
new ReturnOperation()//3
};
}
7.5 链接
现在我们登陆进来会打印菜单,相对应用户身份的功能方法在IOperation
数组当中
输入数字选择功能,也就是数组IOperation[]
加上下标,然后调用前面写好的work
方法就可以了。这个work
会被后面的功能全部重写使用嘛
这一步在User
中写一个方法doWork
,因为无论有多少个子类用户身份,都是通过user
来调用嘛
public void doWork(int choice, BookList bookList) {
iOperations[choice].work(bookList);
}
main函数new
一个前面写好的BookList
,使用user
调用doWork
,传入参数choice
和bookList
BookList bookList = new BookList();
user.doWork(choice, bookList);
这个时候new
出来个这个书架,默认是有3本书的嘛
7.6 效果(视频)
检验一下,可以写个死循环看看
while (true) {
int choice = user.menu();//动态绑定
//根据输入的choice来调用合适的方法
user.doWork(choice, bookList);
}
8.Operation
最难的过去了,终于要开始实现功能了,大致是有
- 添加图书
- 借出图书
- 删除图书
- 显示图书
- 退出程序
- 查找图书
- 归还图书
这样的7个功能,当然其中有管理员和普通用户各自能操作的功能
一个一个来写,写成各自单独的文件,也就是面向对象(也可以放到顺序表中)
首先创建一个新的包,在里面创建这些文件
8.1 IOperation补充
前面先把IOperation写了,这里还可以再补充
后面的功能肯定涉及到了输入内容
那么我们干脆直接写在接口里
Scanner scanner = new Scanner(System.in);
8.2 AddOperation
public class AddOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("新增图书!");
}
}
首先,work
。主功能方法,每一个功能当然都有,也要调用的嘛
然后,添加书的话,需要输入一些信息吧
书名,作者,价格,类型
System.out.println("请输入书名:");
String name = scanner.nextLine();
System.out.println("请输入作者:");
String author = scanner.nextLine();
System.out.println("请输入价格:");
int price = scanner.nextInt();
System.out.println("请输入类型:");
String type = scanner.nextLine();
然后new
出这本书,把参数都加上
获取顺序表也就是书架中存放书的末位置,usedSize
嘛,用size接收上
放完后再加1
Book book = new Book(name, author, price, type);
int size = bookList.getUsedSize();
bookList.setBooks(size, book);
bookList.setUsedSize(size + 1);
就添加成功了
System.out.println("添加成功!");
效果
8.3 DisplayOperation
public class DisplayOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("打印图书!");
}
}
得打印看看嘛
直接for循环打印,长度就是usedSize
嘛,还是size接收
前面也有写好的getPos
方法
int size = bookList.getUsedSize();
for (int i = 0; i < size; i++) {
Book book = bookList.getPos(i);
System.out.println(book);
}
效果
借出信息还是默认的显示
我们可以改一改
修缮
原本自动生成的toString方法就是字符串的拼接嘛
那我们稍微改一下就好
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
((isBorrowed == false) ? ", 未借出" : ", 已借出") +
'}';
}
改一个三目运算符
测试一下
8.4 FindOperation
根据书名查找嘛
这里就不写的太复杂了,简单写一下
public class FindOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("查找图书!");
System.out.println("请输入要查找的书名:");
String name = scanner.nextLine();
int size = bookList.getUsedSize();
for (int i = 0; i < size; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
System.out.println("找到了!信息如下:");
System.out.println(book);
return;
}
}
System.out.println("没有找到这本书!请速速添加进来。");
}
}
只涉及到了一个字符串的比较
效果
8.5 ExitOperation
退出系统就最简单了
正常的退出code码就是0嘛
public class ExitOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("退出系统!");
System.exit(0);
}
}
效果
8.6 DelOperation
public class DelOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("删除图书!");
//1.和查找一样,先定位下标找到位置
System.out.println("请输入要删除的书名:");
String name = scanner.nextLine();
int currentSize = bookList.getUsedSize();//长度接收一下
int index = 0;//存储找到书的下标
int i = 0;
for (; i < currentSize; i++) {
Book book = bookList.getPos(i);
if (book.getName().equals(name)) {
index = i;
break;
}
}
if (i >= currentSize) {
System.out.println("没有找到这本书!那就不用删喽~");
return;
}
//2.走到这里那就是找到了,进行一个删除
for (int j = index; j < currentSize-1; j++) {
Book book = bookList.getPos(j + 1);
bookList.setBooks(j, book);
}
bookList.setBooks(currentSize, null);
bookList.setUsedSize(currentSize - 1);
System.out.println("删除成功!");
}
}
注意bookList
是一个类,不可以像数组一样直接j = j + 1
最后j走完记得置空,长度减1
效果
8.7 BorrowOperation
public class BorrowOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("借阅图书!");
System.out.println("请输入要借阅的书名:");
String name = scanner.nextLine();
int size = bookList.getUsedSize();
for (int i = 0; i < size; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
book.setBorrowed(true);
System.out.println("借阅成功,记得归还哦!");
return;
}
}
System.out.println("没有找到这本书!请联系管理员。");
}
}
还是先找,找到了改成已借出
效果
8.8 ReturnOperation
public class ReturnOperation implements IOperation{
public void work(BookList bookList) {
System.out.println("归还图书!");
System.out.println("请输入要归还的书名:");
String name = scanner.nextLine();
int size = bookList.getUsedSize();
for (int i = 0; i < size; i++) {
Book book = bookList.getPos(i);
if (name.equals(book.getName())) {
book.setBorrowed(false);
System.out.println("归还成功,下次再借哦!");
return;
}
}
System.out.println("这本书不是本图书馆的!请联系管理员。");
}
}
这个就简单了,借阅图书反转一下就好
效果
9总结
通过这个图书管理系统的练习,可以很好的巩固知识并且理解知识
其中的多态,还有借口的使用,是最难的部分
仅仅一两行代码,却有那么多意义
等后面讲完数据库后,就可以把书的信息存放在数据库当中了
就像我现在的博客,其中的所有文章内容等都存储在数据库和服务器文件中。
小头图版权:《繋がる青い糸》by 京田スズカ 2021年12月7日晚上11点00分 pid:94635088
《闪婚老公竟是我上司》短片剧高清在线免费观看:https://www.jgz518.com/xingkong/14790.html
你的才华让人惊叹,请继续保持。 http://www.55baobei.com/yTgpYcgpt0.html
《鳄鱼河》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/84947.html
《闪婚老公竟是我上司》短片剧高清在线免费观看:https://www.jgz518.com/xingkong/14790.html
你的文章充满了智慧,让人敬佩。 https://www.yonboz.com/video/43169.html
真好呢
不错不错,我喜欢看 https://www.ea55.com/