【Java】—— 图书管理系统

基于往期学习的类和对象、继承、多态、抽象类和接口来完成一个控制台版本的 “图书管理系统”

在控制台界面中实现用户与程序交互

任务目标:

1、系统中能够表示多本图书的信息

2、提供两种用户(普通用户,管理员)

3、普通用户:查看书籍列表,查找图书,借书,还书

4、管理员:查看书籍列表,查找图书,新增图书,删除图书

任务实现:

1、图书类

创建一个包 library 用来表示 图书管理系统 ,再创建 Book 类表示 一本的图书信息

在类里创建需要用到的属性(书名,作者,价格,类型,是否被借出)

package library;public class Book {private String name;    //书名private String author;  //作者private double price;   //价格private String type;    //类型private Boolean isBorrowed; //是否被借出//构造方法//当新增图书时,默认是未被借出public Book(String name, String author, double price, String type) {this.name = name;this.author = author;this.price = price;this.type = type;this.isBorrowed = false;}//提供 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 double getPrice() {return price;}public void setPrice(double 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;}
}

2、图书列表类

创建一个 BookList 类用来管理多个书籍对象

package library;public class BookList {//创建数组来记录多本书的信息private Book[] books = new Book[100];private int size = 0;//当前数组中有效元素的个数//构造方法public BookList(){//默认添加几本书,方便后续测试books[0] = new Book("西游记","吴承恩",100.0,"古典名著");books[1] = new Book("高等数学","高斯",90.0,"自然科学");books[2] = new Book("福尔摩斯探案集","阿瑟·柯南·道尔",110,"悬疑推理小说");size = 3;}//提供 get/set 方法public int getSize() {return size;}public void setSize(int size) {this.size = size;}public Book getBook(int index){return books[index];}public void setBooks(int index,Book book){books[index] = book;}
}

3、用户类

因为 普通用户 和 管理员 是从 用户 中根据不同的权限分离出来的,这里就涉及到了 继承 的知识,让 子类 继承 父类 来减少代码量

package library.User;import library.IOperation;//用户父类,派生出子类管理员和普通用户
public abstract class User {//这里用 protected 修饰 name,可以让子类直接获取到,不用 get/set 方法protected String name;//当前这个类能够进行哪些操作,就往这个数组中添加对应的对象protected IOperation[] operations;//构造方法public User(String name) {this.name = name;}//管理员和普通用户的权限不一样,菜单面板也有所不同,//但是在父类中没有办法确定使用哪个菜单,所以可以写成抽象类,让子类去进行重写//通过返回用户输入的序号来决定执行不同的操作,所以使用 int 类//写成 抽象方法 后就需要将这个父类写成 抽象类public abstract int menu();
}

父类写到这,我们就可以去创建子类

4、普通用户类(NormalUser)

import java.util.Scanner;public class NormalUser extends User{public NormalUser(String name) {super(name);}@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;}
}

5、管理员类(Admin)

import java.util.Scanner;public class NormalUser extends User{public NormalUser(String name) {super(name);}@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;}
}

写到这里 书 和 用户 的代码还没有进行交互,这就是面向对象程序设计的典型特点,先创建核心的类/对象,把 核心类/对象属性、方法 搞出来,再通过主逻辑把多个 类/对象 串起来。

6、基本操作接口

创建接口是为了保证所有的类都提供 work 方法,保证 work 的参数都是一致的,也方便之后调用

(这里不使用 接口 使用 抽象类 也是可以的,主要是因为当前没有什么实例属性需要子类来继承(前文中的用户,有 name 属性需要被继承,所以所以使用了抽象类),当两种写法都可以时,优先考虑使用接口)

通过 Operation 把 用户 和 书 关联起来

package library.operation;import library.BookList;//通过这个接口来表示用户的一种基本操作
public interface IOperation {//给出抽象方法//此处操作的 work 方法,是针对 “多本书” 来进行操作的//后续再创建操作相关的具体的类,实现这个接口,就要进一步实现这里的操作void work(BookList bookList);}

把操作单独提取成类

这些类都要实现自 IOperation 接口,并且重写其中的 work 方法

package library.operation;import library.BookList;public class AddOperation implements IOperation{@Overridepublic void work(BookList bookList) {}
}

 由于当前每个操作都实现了 IOperation 接口,就只需要给这两种用户添加一个 IOperation[ ] 的数组保存能够支持的操作有什么就可以了

回到 普通用户 和 管理员 创建好数组,并在数组里写上要实现的操作

普通用户的操作

数组是 普通用户 和 管理员 都需要,所以直接在父类创建即可

    public NormalUser(String name) {super(name);operations = new IOperation[]{new ExitOperation(),new ListOperation(),new FindOperation(), new BorrowOperation(), new ReturnOperation()};}

注意这里创建的是数组,元素和元素直接用 “,”隔开。

数组创建写在构造方法内,实例化一个用户,都要操作可以调用

管理员的操作

    public Admin(String name) {super(name);operations = new IOperation[]{new ExitOperation(),new ListOperation(),new FindOperation(),new AddOperation(),new DelOperation()};}

7、Main 类

当我们准备好了所有对象(书、用户、操作),就可以通过一个主逻辑将所有内容串起来

7.1 创建书籍管理对象

BookList bookList = new BookList();

7.2 创建用户对象

这里的身份有两个,所以需要写一个方法,让用户自己选择一个身份

//实例化用户对象
User user = login();//选择身份方法
private static User login(){//让用户输入自己的身份Scanner scanner = new Scanner(System.in);System.out.println("请输入您的姓名:");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;}
}

7.3 构建一个主循环

用户可以不断选择要进行的操作

while(true){}

7.4 显示用户对应的菜单

while(true){//这里会触发多态,根据实际指向来决定是谁的菜单int choice = user.menu();
}

7.5 根据序号,执行对应操作

//给user 提供一个对应的 “执行” 的方法,最终都是落到对应的 IOperation 对象上
user.work(choice,bookList);//回到 User 类里创建对应方法
public void work(int choice, BookList bookList){//这个操作,是通过输入的 choise 值选择数组中对应的那个操作//这里每个操作的下标要和菜单上的序号一一对应//这里还可以添加一个判断,判断输入的数字是否合法if(choice < 0 && choice > operations.length){System.out.println("输入的选项非法");return;}operations[choice].work(bookList);
}

当主逻辑写到这里,就可以进行测试了

测试顺利就可以进入最后的 操作实现

8、IOperation 操作实现

8.1 ExitOperation

package library.operation;import library.BookList;public class ExitOperation implements IOperation{@Overridepublic void work(BookList bookList) {//只需要结束整个程序System.out.println("Goodbye!");//这里的参数是程序的退出码,不重要System.exit(0);}
}

8.2 ListOperation

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);System.out.println("[" + i + "]" + book);}}
}

通过 for 循环对我们存储书的数组进行遍历,循环的次数来自父类的 size ,循环里分别指向图书列表每一个,最后进行打印,这里在打印时添加一个下标,方便之后进行利用下标进行删除

我们会看到打印出来的结果是一段哈希码,我们需要再写一个 toString 方法,回到 Book类中

@Override
public String toString() {return "[" + name + "," + author + "," + price + "," + type + "," + isBorrowed + "]";
}

这样就把我们的书籍列表打印出来了

8.3 AddOperation

让用户输入新的书籍,并添加到书籍列表中

package library.operation;import jdk.swing.interop.SwingInterOpUtils;
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,price,type);int size = bookList.getSize();bookList.setBooks(size,book);bookList.setSize(size + 1);System.out.println("新增图书完成");}
}

通过 书 的四个属性创建一本新的书,先获取 size 再通过 size 来找到 书 存放的位置,最后让 size+1 表示当前图书的有效位置

可以看到已经成功将新书存入书籍列表中了

8.4 DelOperation

        在写删除之前先来了解一个小知识,当我们进行删除文件时,总是能非常快速的完成,无论文件大小,删除都是一瞬间。因为在硬盘里,当你进行删除时,硬盘会将你所删除的这个文件在的位置声明这里没有东西,实际上你的文件还是存在,只是之后新的数据会覆盖在这个区域上。这也是文件误删后可以通过技术手段进行找回的原因

        在这写删除仍然使用这个概念,当我们删除图书时,只需要将有效图书个数-1就可以,书依然存在数组里但是不会显示出来。

        这里又牵出了一个问题,有效个数-1只会让最后一本图书不显示,当删除的书不是最末尾的书呢,所以这里可以将问题转换,如果要删除其中一本,只要让这本和最末尾的书进行交换即可

package library.operation;import library.BookList;import java.util.Scanner;public class DelOperation implements IOperation{@Overridepublic void work(BookList bookList) {Scanner scanner = new Scanner(System.in);System.out.println("输入要删除的图书序号");//创建变量 index 来记录要删除的图书的序号int index = scanner.nextInt();//判断一下序号是否在范围内if(index<0 || index>=bookList.getSize()){System.out.println("序号有误");return ;}//判断删除的序号是不是最后一本if(index == bookList.getSize() -1){//如果是最后一本,就把 Size-1 bookList.setSize(bookList.getSize() -1);}else {//如果不是最后一本,就要把最后一本复制到删除的序号位置//        修改图书(要修改的下标,要修改的图书      (最后一本书的下标))bookList.setBooks(index,bookList.getBook(bookList.getSize()-1));//最后也要让 Size-1bookList.setSize(bookList.getSize() -1);}System.out.println("删除成功");}
}

删除前:

进行删除:

删除后:

原来在最后的福尔摩斯探案集就来到原来高等数学的位置,这样就算删除成功了

8.5 BorrowOperation

借阅只需要修改单个属性即可

package library.operation;import library.Book;
import library.BookList;import java.util.Scanner;public class BorrowOperation implements IOperation{@Overridepublic void work(BookList bookList) {Scanner scanner = new Scanner(System.in);System.out.println("输入要借阅的图书序号");int index = scanner.nextInt();//这里将我们要借阅的图书实例化,才可以修改它的 BorrowBook book = bookList.getBook(index);//因为Borrwed属性是布尔值,所以不需要去写 == trueif(book.getBorrowed()){System.out.println("该书已被借阅");}else {//借阅成功后修改属性book.setBorrowed(true);System.out.println("借阅成功");}}
}

借阅过程:

借阅结果:

8.6  ReturnOperation

归还图书也差不多,只需要修改一些内容

package library.operation;import library.Book;
import library.BookList;import java.util.Scanner;public class ReturnOperation implements IOperation{@Overridepublic void work(BookList bookList) {Scanner scanner = new Scanner(System.in);System.out.println("输入要归还的图书序号");int index = scanner.nextInt();Book book = bookList.getBook(index);if(book.getBorrowed()){book.setBorrowed(false);System.out.println("归还成功");}else {System.out.println("该书未被借阅");}}
}

8.7 FindOperation

这里写简单一些,只通过书名来查找书的序号

package library.operation;import library.Book;
import library.BookList;import java.util.Scanner;public class FindOperation implements IOperation{@Overridepublic void work(BookList bookList) {//输入姓名Scanner scanner = new Scanner(System.in);String name = scanner.next();//对所有图书进行遍历for(int i = 0;i< bookList.getSize();i++){//对图书进行实例化Book book = bookList.getBook(i);//判断字符串是否相等需要用到equalsif(book.getName().equals(name)){//相等则打印书籍信息System.out.println(book);}}System.out.println("查找结束");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/486912.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Google BERT入门(3)Transformer的自注意力机制的理解(下)

文章目录 4.自注意力机制的理解步骤 4 4.自注意力机制的理解 步骤 4 我们计算了查询矩阵和键矩阵之间的点积&#xff0c;得到了分数&#xff0c;然后使用softmax函数对分数进行了归一化。现在&#xff0c;自注意力机制的最后一步是计算注意力矩阵Z。 注意力矩阵包含句子中每…

大舍传媒-关于海外媒体宣发的探讨

关于海外媒体宣发的探讨 一、海外媒体宣发的重要性 在当今全球化的时代&#xff0c;海外媒体宣发对于企业、组织和个人来说具有至关重要的意义。通过有效的海外媒体宣发&#xff0c;可以提升品牌知名度&#xff0c;拓展国际市场&#xff0c;增强影响力&#xff0c;吸引更多的潜…

城市基础设施数字化管理:打造安全、智能的城市生命线

随着数字化转型的深入&#xff0c;城市基础设施生命线的安全管理正面临前所未有的机遇与挑战。城市基础设施&#xff0c;包括交通、能源、供水、排水、通信等&#xff0c;是城市运行的“生命线”&#xff0c;其安全治理直接关系到城市的稳定与人民生活的安全。 数字化转型对城…

241207-通过Docker部署Wiki.JS并设置ElasticSearch进行中文搜索

A. 最终效果 B. 配置文件 version: "3" services:wiki:image: ghcr.io/requarks/wiki:2container_name: wikijsports:- "3000:3000"volumes:- /home/lgk/Projects/WikiJS/config:/configenvironment:- DB_TYPEpostgres- DB_HOSTdatabase- DB_PORT5432- DB…

ConcurrentLinkedQueue<>实现生产者-消费者问题理解和简易demo

1.ConcurrentLinkedQueue<> ConcurrentLinkedQueue 是 Java 中的一个线程安全的无界队列实现。它基于无锁&#xff08;lock-free&#xff09;的算法&#xff0c;采用了一个高效的、非阻塞的、可伸缩并发控制机制。这使得在高并发场景下能够实现较高的吞吐量。 无界性质…

LDR6500:音频双C支持,数字与模拟的完美结合

在当今数字化快速发展的时代&#xff0c;音频设备的兼容性和性能成为了用户关注的重点。LDR6500&#xff0c;作为乐得瑞科技精心研发的USB Power Delivery&#xff08;PD&#xff09;协议芯片&#xff0c;凭借其卓越的性能和广泛的应用兼容性&#xff0c;为音频设备领域带来了新…

面试技术点之安卓篇

一、基础 二、高级 三、组件 Android中SurfaceView和TextureView有什么区别&#xff1f; 参考 Android中SurfaceView和TextureView有什么区别&#xff1f; 四、三方框架 五、系统源码 六、性能优化

Mock神器:Easy-Mock 私有化部署及使用介绍

在现代前后端分离的开发模式中&#xff0c;后端接口的数据模拟是一个常见且必要的需求。尤其是在后端接口尚未开发完成时&#xff0c;前端开发需要依赖模拟数据进行开发与测试。Easy-Mock 是一个非常流行的开源工具&#xff08;虽然它已经停止更新好长时间了&#xff09;&#…

React v19稳定版发布12.5

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&#x1f495;&#x1f495;&#x1f495; 目…

如何在Ubuntu中利用repo和git地址下载获取imx6ull的BSP

01-设置git的用户名和邮箱 git config --global user.name "suwenhao" git config --global user.email "2487872782qq.com"这里不设置的话后面在第5步的repo配置中还是会要求输入&#xff0c;而且以后进行相关操作都要输入&#xff0c;不妨现在就进行配置…

高德地图3D地图SDK造成ANR问题记录

问题描述&#xff1a; 在新接手的项目中使用到了高德地图的3D的SDK,其依赖导入如下 api com.amap.api:3dmap:latest.integrationapi com.amap.api:search:9.7.0在使用过程中&#xff0c;用到了TileOverlay图层&#xff0c;使用过程中有一下两个问题&#xff1a; 1.在特定的AMAP…

【AI实战项目】基于OpenCV的“颜色识别项目”完整操作过程

OpenCV是一个广受欢迎且极为流行的计算机视觉库&#xff0c;它因其强大的功能、灵活性和开源特性而在开发者和研究者中备受青睐。 学习OpenCV主要就是学习里面的计算机视觉算法。要学习这些算法的原理&#xff0c;知道它们适用于哪些场景&#xff0c;然后通过Python编写代码来…

浅谈网络 | 应用层之云网络隔离GRE/VXLAN

目录 前言GRE 隧道技术VXLANGRE/VXLAN接入云平台 前言 之前提到&#xff0c;为云平台中的租户实现隔离时&#xff0c;常用的策略是基于 VLAN。然而&#xff0c;VLAN 只有 12 位&#xff0c;共支持 4096 个 ID&#xff0c;这在最初设计时看似足够&#xff0c;但随着云计算的快速…

Spark on Yarn安装配置,大数据技能竞赛(容器环境)

Spark on Yarn模式&#xff0c;即把Spark作为一个客户端&#xff0c;将作业提交给Yarn服务&#xff0c;由于在生产环境中&#xff0c;很多时候都要与Hadoop使用同一个集群&#xff0c;因此采用Yarn来管理资源调度&#xff0c;可以有效提高资源利用率。 环境说明&#xff1a; 服…

java+springboot+mysql在线文件管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的在线文件管理系统&#xff0c;系统包含管理员、使用员、监察员角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;使用员管理&#xff1b;监测员管理&#xff1b;留言管理&#xff08;回复&#xff09;&#xff1b…

SD Express 卡漏洞导致笔记本电脑和游戏机遭受内存攻击

Positive Technologies 最近发布的一份报告揭示了一个名为 DaMAgeCard 的新漏洞&#xff0c;攻击者可以利用该漏洞利用 SD Express 内存卡直接访问系统内存。 该漏洞利用了 SD Express 中引入的直接内存访问 (DMA) 功能来加速数据传输速度&#xff0c;但也为对支持该标准的设备…

基于单片机的智能灯光控制系统

摘要 现在的大部分的大学&#xff0c;都是采用了一种“绿色”的教学方式&#xff0c;再加上现在的大学生缺乏环保意识&#xff0c;所以在学校里很多的教室&#xff0c;在白天的时候灯都会打开&#xff0c;这是一种极大的浪费&#xff0c;而且随时都有可能看到&#xff0c;这是…

ros项目dual_arm_pick-place(urdf文件可视化查看)

前言 一直想写一些项目的讲解&#xff0c;今天&#xff08;2024.12.05&#xff09;可以说正式开始了。 dual_arm_pick-place项目&#xff0c;是关于两个机械臂协同传递物品。 正文 这次的话&#xff0c;给大家讲一下里面的urdf文件。 这篇文章主要来看一下项目中的urdf文件…

springSecurity权限控制

权限控制&#xff1a;不同的用户可以使用不同的功能。 我们不能在前端判断用户权限来控制显示哪些按钮&#xff0c;因为这样&#xff0c;有人会获取该功能对应的接口&#xff0c;就不需要通过前端&#xff0c;直接发送请求实现功能了。所以需要在后端进行权限判断。&#xff0…

【C++笔记】map和set的使用

前言 各位读者朋友们大家好&#xff01;上期我们讲完了二叉搜索树这一数据结构&#xff0c;这一期我们来讲STL中的map和set这两大容器。这两个容器的底层是红黑树&#xff0c;红黑树的底层是平衡二叉搜索树。 目录 前言一. 序列式容器和关联式容器二. set系列的使用2.1 set类…