Java 图书管理系统

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

经过了一段时间的学习,总算拉了一坨大的(X
本篇文章简单写了点关于图书管理系统的实现
想的跟写的有点区别,有可能上下文衔接做的不太好,也不知道当时写的时候怎么想的,写的风格有可能会变化,请谅解(擦汗
本文代码是一小块一小块,分段来讲的
如有错误,请多指正!


图书管理系统

在敲代码之前,咱先看一下图书馆管理系统,大概是什么东西:
在这里插入图片描述
在这里插入图片描述

如图所示,咱最先要做的,就是写一个小小的菜单
在这个菜单中我们可以选择我们的身份


1.开始菜单

嗯,这块还是很简单的,用 Scanner 来接收输入值,用 “sout” 进行输出打印
然后选择哪个用户 咱就实例化哪个用户,乱输入就重试(

    public static User login() {
        Scanner in = new Scanner(System.in);
        Time time = new Time();
        System.out.println("请输入您的姓名:");
        String name = in.nextLine();
        System.out.println("尊敬的 " + name + " " + time.getTime() + "好");
        System.out.println("请选择您的身份:1.管理员 2.普通用户");
        
        while (true) {
            String choice = in.nextLine();
            if (choice.equals("1")) {
                return new AdminUser();
            } else if (choice.equals("2")) {
                return new NolmalUser();
            } else {
                System.out.println("非法输入,请重试!");
            }
        }
    }

这里的 time 是我自己为了好看正的一个 获取时间段并返回问候语的,后面会写


2.用户

由于我们需要有两个用户去进行操作,我们要分开写两个写~
但是这两个之间一定是会有重复的地方吗,所以咱可以利用继承

可以先写一个父类用户,用来给其他两个用户继承并重写

public class User{
	public abstract int menu();
}

由于两个用户 都得打印菜单
在两个用户类里重复写两遍菜单 会导致代码冗余(其实就是更麻烦了)

我们可以在父类使用抽象,子类去实现他

这块返回值使用的是 int类 的原因是因为,我们要通过 在这个菜单中 选择的数字(也就是 1,2,3,4,0…)来操作对应的方法(比如 增删查改)


2.1.管理员用户

咱现在创建两个用户类,一个管理员,一个普通用户
让它们继承父类User,并实现父类的menu()方法
这样就少了一点重复的代码(挠头


2.1.1.菜单
public int menu() {
        Scanner in = 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.println("请输入你的操作:");
}

在这里插入图片描述


2.1.2.选择操作

简单来写 可以直接用

	Scanner in = new Scanner(System.in);
	int choice = in.nextInt();
	if(choice >=0 && choice <=4){
		return choice;	
	}else{
		System.out.println("输入错误!");
	}

但是,这么写的话有个问题
就是,我万一输入的不是数字(int)的话,就报错啦
在这里插入图片描述
在这里插入图片描述
所以我们要换一种方法写咯

	while (true) {
		String choice = in.nextLine();
		switch (choice){
			case "0":
			case "1":
			case "2":
			case "3":
			case "4":
				return Integer.parseInt(choice);
			default:
				System.out.println("非法输入,请重试!");
		}
	}

由于我学术不精,没学会啥高级的方法,只能用这种笨办法了(甚至这个Integer.parseInt也是我上网搜的(可以参考下菜鸟教程 Java parseInt() 方法

这里就是我把输入的数字当成字符接收,然后switch如果不是这几个 “数字” 就是非法输入(这里咱就不怕输入字符导致nextInt报错了

然后重点来了,返回值这块,简单来说就是给字符转换成数字返回,也就是 int
那么我们User那边的public abstract int menu();就能接收到 然后进行其他操作咯

还有一件事! 这里之所以用while(true)是为了让这一整个 选择操作 可以重复运行,总不能输入一次错误 就又得从头 输入用户名-选择身份-选择操作 吧(太麻烦了


2.2.普通用户

大部分和管理员用户的代码差不多~


2.2.1.菜单
public class NolmalUser extends User {
	public int menu() {
        Scanner in = 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.println("请输入你的操作:");
    	}
	}

在这里插入图片描述


2.2.2.选择操作
	while (true) {
		String choice = in.nextLine();
		switch (choice){
			case "0":
			case "1":
			case "2":
			case "3":
				return Integer.parseInt(choice);
			default:
				System.out.println("非法输入,请重试!");
		}
	}

用户暂时先写到这里咯,剩下的要结合后面的来讲,咱接下来写 “书库”


3.书库

图书管理系统,肯定是得有书吧?那么,一本本的书又该存在哪里呢?当然是书库咯!
咱先来讲 这个 “书” 该如何实现


3.1.书

  1. 咱直接创一个类,就叫… “Book” 吧
  2. 书是不是得有 书名、作者、价格、类型等等 这种东西吧?(由于我们写的是图书管理系统,会出现借出/归还之类的情况,所以要加一个 “借出状态” 这种东西
  3. 构造方法也要写上,因为咱要实例化一堆书
  4. 基本的get set 也要带上,咱一定会用上的,因为 增删之类的操作 一定会涉及到 对书内容的修改(这里只用写能用上的,要不然一堆代码都用不上 浪费了
  5. 我们还有可能会对 书 进行打印输出(比如显示所有图书),所以咱还得重写一个 toStirng(直接用自动生成就可以,我这边为了好看,改成了中文
public class Book { //类

	String name;    //书名	
    String author;  //作者   
    float price;    //价格    
    String type;    //类型
    boolean isLend; //是否借出
   	
    public Book(String name, String author, float price, String type) {
    	this.name = name;
    	this.author = author;
   		this.price = price;
  		this.type = type;
    }
    
    public String getName() {
        return name;
    }

	public boolean isLend() {
    	return isLend;
    }
    public void setLend(boolean lend) {
    	isLend = lend;
    }
    
    @Override
    public String toString() {
        return "Book{" +
                "书名='" + name + '\'' +
                ", 作者='" + author + '\'' +
                ", 价格=" + price +
                ", 类型='" + type + '\'' +
                ", 是否借出='" + (isLend ? "是" : "否") + '\'' +
                '}';
    }
}

这样下来,一个 书的类 就差不多完事儿了,后续有什么新的添加进去就好~


3.2.库

现在我们要想一下,怎么样才能把一堆 类 存储在一起?
咱可以使用类数组,数组就是我们的"库"

  1. 先创建一个书库类 咱就叫它为 BookLIst
  2. 要把类存在数组里 所以要建一个 类数组
  3. 书库里默认放四本书(放四大名著吧,别的也可以
  4. 后续进行操作咱得知道书库里有几本书可以供我们操作,所以要弄一个变量来记录库中书量
  5. get set 安排上,后面要用到。简单来说想知道书库里某一本书里面是什么,肯定是得先拿出来看看吧(getBooks),然后还得放回去吧(setBooks
  6. 最后就是,我们需要一个判断用书库是否为满的方法,方便后面判断
public class BookList {
    Book[] books = new Book[10];
    private int useSize;

    public BookList() {
        books[0] = new Book("水浒传", "施耐庵", 59.9f, "小说");
        books[1] = new Book("三国演义", "罗贯中", 69.9f, "小说");
        books[2] = new Book("西游记", "吴承恩", 79.9f, "小说");
        books[3] = new Book("红楼梦", "曹雪芹", 89.9f, "小说");
        this.useSize = 4;
    }

	//获取/设置 书
    public Book getBooks(int i) {
        return books[i];
    }
    public void setBooks(int i, Book book) {
        books[i] = book;
    }

	//获取/设置 使用量
    public int getUseSize() {
        return useSize;
    }
    public void setUseSize(int useSize) {
        this.useSize = useSize;
    }
    
    //判断是否为满
    public boolean isFull(){
        return useSize == 10;
    }
}

4.各种方法

咱在上面已经把书库写好了,咱现在就要去实现,在用户菜单中的各种方法咯
在这里插入图片描述
如图,有几个重复的方法,我们可以复用,所以我们只需要写:
查找、新增、删除、显示、借阅、归还、退出
7个方法就ok啦~

不同的对象 需要同样的功能 这种情况 我们应该用什么呢?
当然是接口咯(目前就学到这个了

public interface IOperations {
    public abstract void work(BookList bookList);
}

这里就是 创建了一个接口,里面有个 抽象方法work()
接口 就是抽象方法的集合Java 接口 | 菜鸟教程


4.1.查找

竟然要进行查找,难免需要一个查找的目标,咱这边就用 书名 来进行查找啦
咱跟上面一样,先弄清楚我们需要什么,需要怎么做:

  1. 最重要的就是 我们写的方法 都是在 实现IOperations接口(还有接口里的抽象方法),所以我们要用到implements关键字!
  2. 我们要输入书名,所以需要Scanner
  3. 然后就是在书库里进行查找,我们这里就直接用暴力查找,遍历了(其他的有点麻烦
  4. 查找后只有两种结果,找到了/没找到

整个流程简单来说就是:先拿到书-看书名-确认是否是我要找的书

public class Find implements IOperations {
    @Override
    public void work(BookList bookList) {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入要查找的书名:");
        String name = in.nextLine();
        for (int i = 0; i < bookList.getUseSize(); i++) { 
        //使用getUseSize()知道目前书库里有几本书,避免超过数组(书库)大小导致内存!
            Book book = bookList.getBooks(i);
            //从书库中获取当前 i 位置的 书
            if(book.getName().equals(name)){
            //如果从书里获取的名字 和 我要查找的书名一致 就是找到了,反之没找到
                System.out.println("找到了:");
                System.out.println(book);
                return;
            }
        }
        System.out.println("没找到");
    }
}

前两步都很轻松吧,关键在于第三步,我们要如何查找
跟上面说的一样要用 书名
这时候我们在之前 书库 类里定义的getBooks方法、书 类里定义的getName方法派上用场了,知道了书名,咱就可以在遍历的过程中进行对比啦,
书名 是字符串,判断字符串之间内容是否相同 我们可以使用equals()

这样下来查找部分就没有问题咯~


4.2.新增

书库里不能只有四本书吧,所以我们要往里面添加新书

  1. 判断我的书库 是否有足够的空间 去存储
  2. 我得知道我要添加的新书的 各种属性(书名、作者、价格、类型)
  3. 在空位添加一本书
public class Add implements IOperations {
	@Override
    public void work(BookList bookList) {
        if(bookList.isFull()){
            System.out.println("书库满了,不能新增!");
            return;
        }
        Scanner in = new Scanner(System.in);
        System.out.println("请输入书名:");
        String name = in.nextLine();
        System.out.println("请输入作者:");
        String author = in.nextLine();
        System.out.println("请输入价格:");
        float price = in.nextFloat();
        in.nextLine();	//这里nextFloat()它不会把回车也过消耗掉,所以需要我们手动消耗一下,要不然程序就卡住了
        System.out.println("请输入类型:");
        String type = in.nextLine();
        Book book = new Book(name, author, price, type);	//用构造方法创建一本新书
        bookList.setBooks(bookList.getUseSize(), book);		//放到指定位置(如图
        bookList.setUseSize(bookList.getUseSize() + 1);		//然后因为添加了一本新书,useSize也要跟着+1
        System.out.println("新增图书成功!");
    }
}

在这里插入图片描述

这段没有什么太复杂的咯


4.3.删除

  1. 要删除什么书?(遍历查找
  2. 怎么删?
public class Del implements IOperations {
    @Override
    public void work(BookList bookList) {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入要删除的书名:");
        String name = in.nextLine();
        for (int i = 0; i < bookList.getUseSize(); i++) {
            Book book = bookList.getBooks(i);
            if (book.getName().equals(name)) {
                for (int j = i; j < bookList.getUseSize() - 1; j++) {	//如图
                    bookList.setBooks(j, bookList.getBooks(j + 1));
                }
                bookList.setUseSize(bookList.getUseSize() - 1);
                System.out.println("删除成功");
                return;
            }
        }
        System.out.println("查无此书,请重试!");
    }
}

在这里插入图片描述

如果在for循环里直接使用i < getSize的话会出现图里这种情况,也就是内存泄漏

在这里插入图片描述
所有过程如图,咱就是进行了一个简单的,复制粘贴(覆盖)+ 删除


4.4.显示

显示的话咱直接上代码!

public class Show implements IOperations {
    @Override
    public void work(BookList bookList) {
        for (int i = 0; i < bookList.getUseSize(); i++) {
            Book book = bookList.getBooks(i);
            System.out.println(book);
        }
    }
}

把每个书拿过来 直接sout就可以了,因为我们在写Book类的时候就早已把toString重写过~
在这里插入图片描述


4.5.借阅,归还

借阅/归还其实就是 给借出状态更改一下的事儿
直接调用之前在Book类里定义的setLend方法就好了

借阅:

public class Lend implements IOperations {
    @Override
    public void work(BookList bookList) {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入要借阅的书名:");
        String name = in.nextLine();
        for (int i = 0; i < bookList.getUseSize(); i++) {
            Book book = bookList.getBooks(i);
            if ((book.getName().equals(name))) {
                if (book.isLend()) {
                    System.out.println("借阅失败,已被借阅!");
                } else {
                    System.out.println("成功借阅!");
                    book.setLend(true);
                }
                return;
            }
        }
    }
}

归还:

public class Return implements IOperations {
    @Override
    public void work(BookList bookList) {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入要归还的书名:");
        String name  = in.nextLine();
        for(int i =0;i< bookList.getUseSize();i++){
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)){
                if(book.isLend()){
                    book.setLend(false);
                    System.out.println("成功归还!");
                }else {
                    System.out.println("归还失败,未被借出!");
                }
            }
            return;
        }
    }
}

看代码就知道 两个方法,本质上没有太大区别,主要是 为了分开这两个功能,重复写了很多代码(暂时没找到解决方法,知识有限)


4.6.退出

啊哈!最喜欢的环节!
嘎嘎简单

public class Exit implements IOperations {
    @Override
    public void work(BookList bookList) {
        System.out.println("正在退出...");
        System.exit(0);
    }
}

直接一个exit中断程序就可以啦!!!


4.7.获取时间段

这个方法从网上搜索出来的,我还没学(挠头
出处:java判断时间为上午,中午,下午,晚上,凌晨

public class Time {
    Date date = new Date();
    SimpleDateFormat df = new SimpleDateFormat("HH");
    String str = df.format(date);
    int a = Integer.parseInt(str);

    public String getTime() {

        if (a >= 0 && a <= 6) {
            return "凌晨";
        }
        if (a > 6 && a <= 12) {
            return "上午";
        }
        if (a == 13) {
            return "中午";
        }
        if (a > 13 && a <= 18) {
            return "下午";
        }
        if (a > 18 && a <= 24) {
            return "晚上";
        }
        return str;
    }
}

5.结合(用户+方法)

写了这么多方法,咱总算可以结合起来了(抹泪
咱这么多方法,其实只是在实现一个接口,也就是IOperations接口
那咱怎么用 1,2,3,4,0…去指定执行呢?
跟书库差不多,咱可以把 接口 弄成一个 数组
用下标的方式访问 各种实现接口的方法

User:

public abstract class User {
    IOperations[] iOperations;	//接口数组

    public abstract int menu();	//抽象方法 menu 两个用户重写各自的菜单

    public void doIOperations(int choice, BookList bookList) {
        this.iOperations[choice].work(bookList);
        //谁用 谁就调用 [位置] 的 work方法(在书库里执行)
    }
}

AdminUser:

public class AdminUser extends User {
    public AdminUser() {
        this.iOperations = new IOperations[]{
                new Exit(),
                new Find(),
                new Add(),
                new Del(),
                new Show()
        };
    }
    ...//其他代码
}

这里就是管理员这里的 接口数组里 有这些 实现方法,由于数组下标是从 0 开始
我们第一位 就放 退出
然后就是 查找,增添,删除,查看
在这里插入图片描述
通过new关键字就可以实例化(差不多跟激活一样)这些方法
这里其实就是,只要实例化了,这个用户,他就会顺便实例化跟他对应的方法

NolmalUser:

public class NolmalUser extends User {
    public NolmalUser() {
        this.iOperations = new IOperations[]{
                new Exit(),
                new Find(),
                new Lend(),
                new Return(),
        };
    }
    ...//其他代码
}

普通用户这边其实也差不多的


6.main

最关键的地方来咯,也是最麻烦的地方(
咱在上面所有的就是为了现在这个
在上面结合中 我们有一个 执行操作的方法doIOperations
如图所示,咱得靠上面所有代码结合过来看这四行代码(悲

    public static void main(String[] args) {
        BookList bookList = new BookList();
        User user = login();
        while (true) {
            user.doIOperations(user.menu(), bookList);
        }
    }
}
  1. 这里我们先实例化了一个书库
  2. 调用login()方法选择用户(管理/普通)并实例化对象
  3. 实例化对象同时,实例化了对应用户的this.iOperations[]中的方法对象
  4. 实例化完成后,在打印出来的 选择操作菜单 中进行选择,并以int返回给menu(),也就是

user.doIOperations(user.menu(), bookList)

中的user.menu()

  1. 这下就可以把书库传入并直接调用user.doIOperations(user.menu(), bookList)进行各种操作了
    在这里插入图片描述
    再解释一下这里的图,这是我们在结合过程中写的一段用来操作书库的方法
    它的原理就是和图里写的一样:
this.iOperations[ choice ].work( bookList)
管理员用户/普通用户方法第几个方法中的实现/执行对谁执行(书库)

总结

写的我汗流浃背,实习期间只有晚上有时间,写了三个晚上(挠头
希望能对大家有点小帮助吧,有些地方含糊不清,表达不出来(求饶
欲知后事如何,请听下回分解…

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值