【项目】图书管理系统
目录
前言:
项目要求:
知识储备:
代码实现:
Main:
Books包:
Book:
BookList:
Operate包:
Operate:
addOperate:
deleteOperate:
exitOperate:
findOperate:
showOperate:
Persion包:
User:
Admin:
Reader:
前言:
随着javaSE的学习深入,我们已经明白了什么是类和对象,学会了继承和多态,抽象类和接口,那么我们就可以利用以上几个知识点来完成一个小项目图书管理系统来检验一下我们学习的成果,我们主要完成其框架和一些基本点(起到复习作用,不是为了业务)。
项目要求:
实现一个图书管理系统,有两个用户,普通用户和管理员,两个用户的业务不一样,实现其业务,书有书名,作者,价格,书的类型,是否被借出。
普通用户:0.退出系统 1.查找图书 2.借阅图书 3.归还图书
管理员用户:0.推出系统 1.查找图书 2.新增图书 3.删除图书 4.显示图书
知识储备:
java基本语法,类和对象,继承和多态,抽象类和接口。
具体效果如下动图所示。

代码实现:
为了培养优良的代码风格,我们将各个模块区分开来,故我们需要创建3个包(有关包如果不太了解的话可以看看封装和包)分别是Books和Operate,Person,功能和其的英文名一样,最后用一个Main类把他们串在一起。

Main:
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体 调用那个类的方法.
先创建一个书架BookList(具体代码后续给出,重要的是思路),User是Admin(管理员)和Reader(普通用户)的父类,使用User来接受这是因为在代码编译的时候程序并不知道是普通用户还是管理员,只有在我们输入后才确定下来(动态绑定),发生向上转型。用一个while来实现循环输入,因为两个用户的菜单不一样,故我们可以在User中定义一个抽象方法,在两个具体子类中实现,放回的k即为我们的选择操作。user.doOperate(books,k)是我觉的这个项目最精彩的地方,这里先简单理解为调用user,对books进行第k个操作,具体我会在Operate部分详细解释。
import Person.*;
import java.util.Scanner;
import Books.*;public class Main {private static User Logon(){Scanner scanner = new Scanner(System.in);System.out.print("请输入你的姓名: ");String name = scanner.next();System.out.print("请输入你的身份: 1: 管理员 2: 普通用户-> : ");int index = scanner.nextInt();if(index == 1){return new Admin(name);}else if(index == 2){return new Reader(name);}else{System.out.println("输入错误");System.exit(0);return null;}}public static void main(String[] args) {BookList books = new BookList();User user = Logon();//动态绑定while(true){int k = user.menu();user.doOperate(books,k);}}
}
Books包:

在Books包中存储这两个类Book类中存储书的一般属性,BookList就是书架。
Book:
为了更加安全和代码的封装性我们把变量用private修饰,在下面用set和get方法来进行修改。构造方法不用构造isBorrowed因为没有初始化的话java默认为false。
package Books;/*** 书的基本参数*/
public class Book {private String name;private String author;private int price;private String type;//书的类型private boolean isBorrowed;//是否被借出 默认值是falsepublic 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;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", type='" + type + '\'' +", isBorrowed=" + ((isBorrowed == false) ? "未借出" : "已借阅") +//不确定加括号'}';}
}
要想使用println来直接打印Book的话必须要重写toString方法,下图是println的源码,在valueof中有obj.toStirng的参数,我们基本类型的toString系统已经实现,Book为我们自己定义的一个类所以要自己实现一下。
BookList:
书架上不仅要能放书还要能记录书本的个数,一开始直接初始化3本书方便我们后续调试。
package Books;/*** 书架*/
public class BookList {private Book[] books;//能放书private int BookSize;//记录书本的个数public BookList() {books = new Book[10];this.books[0] = new Book("三国演义","罗贯中",10,"小说");this.books[1] = new Book("西游记","吴承恩",9,"小说");this.books[2] = new Book("红楼梦","曹雪芹",19,"小说");this.BookSize = 3;}public Book[] getBooks() {return books;}public void setBooks(int index,Book books) {this.books[index] = books;}public int getBookSize() {return BookSize;}public void setBookSize(int bookSize) {BookSize = bookSize;}
}
Operate包:

Operate:
这里不是包是一个接口,因为每个操作都只要实现work功能故我们定义一个接口来规范我们的代码,方便后面进行向上转型,work前面可以不用加public abstract系统默认会给你加上。
package Operate;
import Books.*;public interface Operate {void work(BookList books);
}
addOperate:
由于本项目难点并不在业务的实现,主要集中在一个框架,故下面的借阅图书和归还图书就由读者自行实现(很简单的)。
package Operate;
import Books.*;
import java.util.*;public class addOperate implements Operate {@Overridepublic void work(BookList books) {Scanner scanner = new Scanner(System.in);System.out.println("请输入书名: ");String name = scanner.next();System.out.println("请输入作者: ");String author = scanner.next();System.out.println("请输入价格: ");int price = scanner.nextInt();System.out.println("请输入书的类型: ");String type = scanner.next();Book book = new Book(name,author,price,type);int usedSize = books.getBookSize();books.setBooks(usedSize,book);books.setBookSize(usedSize + 1);System.out.println("添加成功");System.out.println();}
}

deleteOperate:
package Operate;
import Books.*;
import java.util.Scanner;
public class deleteOperate implements Operate {public void work(BookList books){Scanner scanner = new Scanner(System.in);System.out.print("请输入你要删除书的书名: ");String name = scanner.next();Book[] book = books.getBooks();//浅拷贝int bookSize = books.getBookSize();for(int i = 0;i < bookSize;i++){if(name.equals(book[i].getName())){for(int j = i;j < bookSize - 1;j++){book[j] = book[j + 1];}book[bookSize - 1] = null;System.out.println("删除成功");System.out.println();books.setBookSize(bookSize - 1);return;}}System.out.println("该图书不存在,删除失败");System.out.println();}
}

exitOperate:
package Operate;
import Books.BookList;
public class exitOperate implements Operate{@Overridepublic void work(BookList books) {System.out.println("退出系统");System.exit(0);}
}

findOperate:
package Operate;
import Books.BookList;
import Books.Book;
import java.util.Scanner;
public class findOperate implements Operate {@Overridepublic void work(BookList books) {Scanner scanner = new Scanner(System.in);System.out.print("请输入你要查找书的名字: ");String name = scanner.next();Book[] book = books.getBooks();int usedSize = books.getBookSize();for(int i = 0;i < usedSize;i++){if(name.equals(book[i].getName())){System.out.println("找到了,信息如下: ");System.out.println(book[i]);System.out.println();return;}}System.out.println("该图书不存在");System.out.println();}
}

showOperate:
package Operate;
import Books.BookList;
import Books.Book;
public class showOperate implements Operate{@Overridepublic void work(BookList books) {int usedSize = books.getBookSize();Book[] book = books.getBooks();for(int i = 0;i < usedSize;i++){System.out.println(book[i]);}System.out.println();}
}

Persion包:
User是Admin和Reader的父类。

User:
用一个Operate[]的数组来存储我们上面实现的方法类,因为两个用户对于的方法是不一样的故使用Operate放在User中那个用户需要哪个方法直接new一个方法类在该数组中(向上转型),要调用的时候通过下标访问即可。因为菜单要根据具体是那个用户来具体实现故要把它抽象就可以不用实现,故我们要把User定义成抽象类。

package Person;
import Operate.*;
import Books.*;
public abstract class User {protected String name;protected Operate[] operates;public void doOperate(BookList books,int choice){operates[choice].work(books);}public User(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public abstract int menu();//菜单
}
Admin:
利用super来调用父类的构造方法,在operates中需要什么方法类就直接new上那个方法类,需要注意的是下标的映射关系。继承一个抽象类其子类必须要重写抽象方法。
package Person;
import Operate.*;
import java.util.Scanner;
public class Admin extends User{public Admin(String name){super(name);this.operates = new Operate[]{new exitOperate(),new findOperate(),new addOperate(),new deleteOperate(),new showOperate()};}@Overridepublic int menu() {Scanner scanner = new Scanner(System.in);System.out.println("***********管理员***********");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.print("请输入你的操作: ");int index = scanner.nextInt();return index;}
}
Reader:
和上面的Admin一样这里就不再赘述。
package Person;
import java.util.Scanner;
import Operate.*;
public class Reader extends User{public Reader(String name){super(name);this.operates = new Operate[]{new exitOperate(),new findOperate(),new borrowOperate(),new returnOperate()};}@Overridepublic int menu() {Scanner scanner = new Scanner(System.in);System.out.println("***********读者***********");System.out.println("1.查找图书");System.out.println("2.借阅图书");System.out.println("3.归还图书");System.out.println("0.推出系统");System.out.println("**************************");System.out.print("请输入你的操作: ");int index = scanner.nextInt();return index;}
}
总结:大家最好自己实现一遍,实现的时候最好要明白自己在做什么,可以看看最后的结果来捋捋思路,可以看到我们使用到了接口,抽象类,包和继承的相关知识,只有在你使用他们的时候才会明白那里缺了。
结语:
其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。
相关文章:
【项目】图书管理系统
目录 前言: 项目要求: 知识储备: 代码实现: Main: Books包: Book: BookList: Operate包: Operate: addOperate: deleteOperate: exitOperate: findOperate:…...
华为OD机试 - 疫情扩散时间计算 - 矩阵(Java 2024 C卷 200分)
目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷&am…...
[数据集][图像分类]棉花叶子病害分类数据集2293张4类别
数据集类型:图像分类用,不可用于目标检测无标注文件 数据集格式:仅仅包含jpg图片,每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数):2293 分类类别数:4 类别名称:["diseased_cotton_leaf"…...
《辐射4》是一款什么样的游戏 怎样在mac电脑上玩到《辐射4》辐射4攻略 辐射4开局加点 怎么在Mac电脑玩Steam游戏
辐射4(Fallout 4)是由Bethesda开发的一款动作角色扮演类游戏,为《辐射》系列游戏作品的第四代,于2015年11月10日发行。游戏叙述了主角一家在核爆当天(2077年10月23日),被Vault-Tec(避…...
视频推拉流EasyDSS平台直播通道重连无法转推的原因排查与解决
视频推拉流EasyDSS视频直播点播平台,集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体,可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务。 用户使用EasyDSS平台对直播通道进行转推,发现只要关闭…...
Javaweb之SpringBootWeb案例之自动配置案例的自定义starter测试的详细解析
3.2.4.3 自定义starter测试 阿里云OSS的starter我们刚才已经定义好了,接下来我们就来做一个测试。 今天的课程资料当中,提供了一个自定义starter的测试工程。我们直接打开文件夹,里面有一个测试工程。测试工程就是springboot-autoconfigurat…...
java包的相关概念
包:有效地管理类的一个机制。 包名的目的:通过隶属不同的包有效的区分不同源文件中名字相同的类 包语句 声明:通过关键字 package声明包语句。 位置:源文件中的第一条语句。 作用:为该源文件中声明的类指定包名。 …...
window搭建本地mongo数据库并导入数据
1 window下载mongo数据库 官网:www.mongodb.com 选择 Products > Community Edition 就能进入社区版 在这里下载 windows 版对应的安装包 注意:6.0.1 版本的 MongoDB 配置环境变量有问题,并且我不知道怎么解决,如果想要避免出…...
如何为Android车载应用开发通知?
如何为Android车载应用开发通知?在开发车载应用的通知时,开发者需要考虑到驾驶安全,确保通知不会分散驾驶员的注意力。这通常意味着通知应该是非侵入性的,或者在不影响驾驶的情况下提供信息。开发者可以使用Android的通知API来创建…...
centos上部署k8s
环境准备 四台Linux服务器 主机名 IP 角色 k8s-master-94 192.168.0.94 master k8s-node1-95 192.168.0.95 node1 k8s-node2-96 192.168.0.96 node2 habor 192.168.0.77 镜像仓库 三台机器均执行以下命令: 查看centos版本 [rootlocalhost Work]# cat /…...
网络安全: Kali Linux 进行 MSFvenom 程序利用
目录 一、实验 1.环境 2. Kali Linux 进行 MSFvenom 程序利用 3. 创建计划任务自动运行 MSFvenom 程序 二、问题 1.在线加密解密 2.MSF 运行失败 3.MobaXterm 连接Ubuntu 失败 一、实验 1.环境 (1)主机 表1 主机 系统版本IP备注Kali Linux20…...
浅显易懂C语言指针!!!(三)
文章目录 Pointers as function arguments - call by reference//函数传值vs传引用 Pointers as function arguments - call by reference//函数传值vs传引用 #include<stdio.h> void Increment(int a){//increment 增加 a a 1;//;函数中的是形式参数 形参…...
01 LM 算法及 Cpp 实现
文章目录 01 LM 算法及 Cpp 实现1.1 应用1.2 阻尼法推导1.3 Cpp 算法实现 01 LM 算法及 Cpp 实现 1.1 应用 LM 算法用于解决非线性最小二乘问题 min x F ( x ) 1 2 ∥ f ( x ) ∥ 2 2 (1) \min _x F(x)\frac{1}{2}\|f(\boldsymbol{x})\|_2^2 \tag{1} xminF(x)21∥f(x…...
【网络安全架构】互联网正对中国社会、经济、文化等各个领域产生巨大影响‘
摘 要: 中国互联网近年来飞速发展,普及率达到38.4%。已稳居世界第一网民大国的地位。互联网正对社会、经济、文化等各个领域产生巨大影响。2011年12月21日“泄密门”事件,再次敲响网络安全的警钟。网络攻击和入侵都是根据网络模型不同层次的特…...
【笔记】Android ServiceStateTracker 网络状态变化逻辑及SPN更新影响
业务简介 在网络状态变化的时候(数据或WiFi),会更新SPN。 基于Android U的代码分析。 分类:SPN Data_Dic-的博客-CSDN博客 功能逻辑 状态说明 飞行模式下注册上WFC的话,注册状态MD上报 regState: NOT_REG_MT_NOT…...
2PC和3PC的区别是什么
2PC提交协议是什么 二阶段提交是指,在计算机网络一级数据库领域内,为了使基于分布式系统的架构下的所有节点在进行事务提交时保持一致性而设计的一种算法。在分布式系统中,每个节点虽然可以知晓自己操作的成功和失败,但是无法知道…...
redis未设置密码被植入挖矿脚本
最近一台测试linux响应速度贼慢,检查发现cpu消耗高达100%!查看进程杀死后过段时间又重启了,一时间也摸不到头绪。无意间发现启动redis的时候cpu瞬间拉到了100%,主要就是zzh和newinit.sh两个脚本。百度了一下说是被植入了挖矿脚本&…...
轮询--一起学习吧之架构
一、定义 轮询(Polling)是一种CPU决策如何提供周边设备服务的方式,又称“程控输出入”(Programmed I/O)。这种方式是由CPU定时发出询问,依序询问每一个周边设备是否需要其服务,有即给予服务&am…...
【开发工具】Git模拟多人开发场景理解分支管理和远程仓库操作
我们来模拟一个多人多分支的开发场景。假设你有一个新的空白远程仓库,假设地址是 https://github.com/user/repo.git。 克隆远程仓库到本地 $ git clone https://github.com/user/repo.git这会在本地创建一个 repo 目录,并自动设置远程主机为 origin。 创建本地开发分支并推送…...
从零学习Linux操作系统 第三十一部分 ansible常用模块介绍
一、ansible运行模块的两种方式 Ad-Hoc方式 ##利用ansible命令直接完成管理,主要用于临时命令使用场景 playbook方式 ##ansible脚本,主要用于大型项目场景,需要前期的规划,相当于shell当中的脚本 二、如何查看模块帮助 ansible…...
ADS差分传输线前仿真:从S参数模板到信号完整性快速评估
1. 差分传输线前仿真入门:为什么需要S参数模板? 刚入行那会儿,我最头疼的就是每次新项目都要从头搭建仿真环境。直到发现ADS里藏着现成的4端口S参数模板,工作效率直接翻倍。这就像做菜时有了预制高汤,不用再从熬骨头汤…...
STM32F103精英板实战:手把手教你移植开源Modbus主机库,实现稳定主从通信
STM32F103精英板实战:手把手教你移植开源Modbus主机库,实现稳定主从通信 Modbus协议作为工业自动化领域最常用的通信协议之一,其简单可靠的特性使其在各种嵌入式设备中广泛应用。对于使用STM32F103系列开发板的工程师来说,如何快速…...
Vue3 + Cornerstone3D:从零构建支持本地Nifti文件上传与四视图联动的医学影像查看器
1. 为什么选择Vue3Cornerstone3D开发医学影像查看器 医学影像处理一直是前端开发中颇具挑战性的领域,特别是当需要处理专业格式如Nifti时。我在实际项目中尝试过多种技术方案后,发现Vue3和Cornerstone3D的组合特别适合快速构建高性能的医学影像应用。 …...
多策略融合改进蜣螂算法:Fuch混沌初始化与自适应变异优化MATLAB实现
1. 蜣螂算法基础与改进需求 蜣螂优化算法(Dung Beetle Optimizer, DBO)是受自然界蜣螂行为启发而设计的一种新型群体智能算法。它通过模拟蜣螂的滚球、繁殖、觅食和偷窃四种核心行为,实现了对解空间的高效探索。但在处理高维复杂函数优化问题…...
DeepFace模型预加载优化指南:从延迟痛点到秒级启动的全方案解析
DeepFace模型预加载优化指南:从延迟痛点到秒级启动的全方案解析 【免费下载链接】deepface A Lightweight Face Recognition and Facial Attribute Analysis (Age, Gender, Emotion and Race) Library for Python 项目地址: https://gitcode.com/GitHub_Trending/…...
告别指标混乱:衡石科技指标管理平台的AI自治之路
指标混乱的根源在数字化时代,企业决策依赖的指标体系正面临前所未有的混乱:63%的企业存在指标定义不统一问题,58%的团队因数据口径差异导致决策冲突。这种"指标地狱"不仅消耗大量人力进行数据对齐,更直接导致战略执行偏移。某制造企业的案例极具代表性:其生产部门与财…...
数据可视化避坑指南:当产品经理要你做Echarts版丝带图时,这3个技术难点要注意
Echarts丝带图实战:破解企业级数据可视化的三个高阶难题 当医药企业的销售总监盯着大屏上跳动的数字,突然提出"能不能做成Power BI那种丝带图效果"时,开发团队的沉默往往不是因为技术难度,而是对未知领域的本能警惕。这…...
从图片预览需求看H5监听浏览器返回事件的3种实现方案(含history API避坑指南)
从图片预览需求看H5监听浏览器返回事件的3种实现方案(含history API避坑指南) 在移动端H5开发中,图片预览功能几乎是标配需求。随着全面屏手势操作的普及,用户越来越习惯通过滑动返回退出预览,而非点击关闭按钮。这种交…...
Phi-3 Forest Lab企业应用:金融研报关键数据提取+趋势归纳AI助理
Phi-3 Forest Lab企业应用:金融研报关键数据提取趋势归纳AI助理 1. 金融研报处理的行业痛点 金融分析师每天需要处理大量研报,从中提取关键数据并归纳趋势。传统人工处理方式面临三大挑战: 效率瓶颈:阅读一份20页的研报平均耗时…...
Obsidian-i18n插件终极指南:一站式解决Obsidian插件国际化难题
Obsidian-i18n插件终极指南:一站式解决Obsidian插件国际化难题 【免费下载链接】obsidian-i18n 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-i18n 你是否曾为Obsidian插件的英文界面感到困扰?面对功能强大的插件却因为语言障碍而无法…...
