[JAVA]一步接一步的一起开发-图书管理系统(非常仔细,你一定能看懂)[1W字+]

时间:2022-07-18 01:12:35

目录

1.想法

2.框架的搭构

2.1图书

2.1.1Book类

2.1.2BookList类

2.2用户

2.2.1User抽象类

2.2.2AdminUser类(管理者)

2.2.3NormalUser

2.3操作

操作接口

借阅操作

删除操作

查询操作

归还图书

展示图书

退出系统

2.4小结

3.主函数的编写

4.操作类的实现

增加图书的实现

借阅图书的实现

删除图书的实现

退出系统的实现

查找图书的实现

归还图书的实现

展示图书的实现

5.代码总览


整体代码在本文最底部

1.想法

首先,关于系统的开发,我们第一步的是搭构整体的框架,再分步实现各个具体的功能。

对于这个图书管理系统的开发,我想达到的目的大致为:

用户分为:1.普通用户

                 2.管理者

根据用户分类的不同,我们会有相不同的菜单展示。菜单上展示有编号的操作供选择,根据选择的编号调用相应的操作。

每一本书的属性分为:书名,作者,价格,类型,借阅状态。

创建一个数组作为书架,存放书。

[JAVA]一步接一步的一起开发-图书管理系统(非常仔细,你一定能看懂)[1W字+]

2.框架的搭构

创建三个包,分类好。因为我们从上面的导图中可以看出,此系统分为三个大类再相互调用链接。

[JAVA]一步接一步的一起开发-图书管理系统(非常仔细,你一定能看懂)[1W字+]

2.1图书

2.1.1Book类

对于图书,我们要先创建一个类,定义其属性。

package book;

public class Book {
    private String name;//书名
    private String author;//作者
    private int price;//价格,此处定义为整数,可以自行决定
    private String type;//类型
    private boolean isBorrow;//借阅状态
    //写出相应的构造方法,因为后续我们要添加书,需要有传参的操作
    //借阅状态在创建书的时候就不用放进去了,boolean默认值为false我们可以将其认定为‘未借阅’
    public Book(String name, String author, int price, String type){   
        this.name = name;
        this.author = author;
        this.price = price;
        this.type = type;
    }
    //因为成员属性都用private修饰符进行了封装,相应的创建出setter与getter

    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 isBorrow() {
        return isBorrow;
    }

    public void setBorrow(boolean borrow) {
        isBorrow = borrow;
    }
    
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", type='" + type + '\'' +
                (isBorrow ? ", 已借阅" : ", 未借阅") + isBorrow +
                '}';
    }
}

2.1.2BookList类

package book;

public class BookList {
    //我们之前创建了一个Book类型,代表一本书
    //此处我们就可以创建Book[]类型的数组,代表数组中每一个元素都为Book类型,
    //即每一个元素都能代表一本书
    private Book[] books = new Book[10];//引用名为books,暂定能存放为10本
    private int useSize;//创建一个引用存放书架上存放的图书数量
    //我们可以提前将图书放进去
    public BookList() {//BookList的构造方法,到时候创建BookList对象的时候会调用,生成三本书。
        books[0] = new Book("三国演义","罗贯中",19,"小说");
        books[1] = new Book("西游记","吴承恩",29,"小说");
        books[2] = new Book("水浒传","施耐庵",8,"小说");
        this.useSize = 3;
    }
    //Book[]和useSize的setter与getter
    //public Book[] getBooks() {
    //    return books;
    //}

    public Book getBooks(int pos) {
        return books[pos];
    }

    //public void setBooks(Book[] books) {
    //    this.books = books;
    //}

    public void setBooks(int pos,Book books) {
        this.books[pos] = books;
    }

    public int getUseSize() {
        return useSize;
    }

    public void setUseSize(int useSize) {
        this.useSize = useSize;
    }
}

2.2用户

对于用户,在屏幕前的人选择之前,我们是无法得知下一步要选择的类型是哪一个。这时候我们就可以运用上我们的抽象类。抽象类规定了每个用户下一定具有的成员,此外子类还可以根据作为不同的用户类型来构建新的专属的成员/成员方法。

所以第一步

2.2.1User抽象类

package user;

public abstract class User {
    protected String name;//用户名
    //构造方法
    public User(String name) {
        this.name = name;
    }
    //打印菜单
    public abstract int menu();
}

2.2.2AdminUser类(管理者)

package user;

import java.util.Scanner;

public class AdminUser extends User{
    //构造方法,要先构造父类的
    public AdminUser(String name) {
        super(name);
    }
    //每一个用户类型都要有不同的菜单
    //管理者菜单为:
    public int menu() {
        System.out.println("管理员菜单!");
        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("****************************");
        System.out.println("请输入你的操作:");
        Scanner scanner = new Scanner(System.in);
        int choice = scanner.nextInt();//获取所选择的功能编号
        return choice;//返回功能编号
    }
}

2.2.3NormalUser

package user;

import java.util.Scanner;

public class NormalUser extends User{
    //构造方法
    public NormalUser(String name) {
        super(name);
    }
    //普通用户的菜单
    public int menu() {
        System.out.println("普通用户的菜单!");
        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("****************************");
        System.out.println("请输入你的操作:");
        Scanner scanner = new Scanner(System.in);
        int choice = scanner.nextInt();
        return choice;
    }
}

2.3操作

对于操作,我们可以创建一个接口来规范方法。因为我们不知道具体调用的是哪一个方法,通过接口来达到类似于继承的状态。

因为所有操作都是对书架上的书进行操作,所以参数上均为书架

此环节只是搭构框架,所以方法均没有实现,再后文中会逐一实现。

操作接口

package operation;

import book.BookList;

public class AddOperation implements IOperation {
    @Override
    public void work(BookList bookList) {//重写接口的方法
        System.out.println("新增图书");
    }
}

借阅操作

package operation;

import book.BookList;

public class BorrowOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅图书");
    }
}

删除操作

package operation;

import book.BookList;

public class DelOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("删除图书");
    }
}

查询操作

package operation;

import book.BookList;

public class FindOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("查询图书");
    }
}

归还图书

package operation;

import book.BookList;

public class ReturnOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("归还图书");
    }
}

展示图书

package operation;

import book.BookList;

public class ShowOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("展示图书");
    }
}

退出系统

package operation;

import book.BookList;

public class ExitOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统");
    }
}

2.4小结

到了此处,我们已经把框架搭构完毕了,剩下的就是靠方法将他们联系起来构成一个整体

[JAVA]一步接一步的一起开发-图书管理系统(非常仔细,你一定能看懂)[1W字+]

3.主函数的编写

因为我们还不知道要怎么将这一堆类链接起来,所以我们可以先试着写主函数。从头开始走一遍,查缺补漏。

第一步,我们创建的用户的登录方法,根据选择的不同可以创建不同的用户类型对象并接收。

import user.AdminUser;
import user.NormalUser;
import user.User;

import java.util.Scanner;

public class Test {
    public static User login(){
        //输入姓名
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您的姓名:");
        String name = scanner.nextLine();//读取姓名
        System.out.println("请选择您的用户类型  1 -> ‘管理者’ 0 -> ‘普通用户’:");
        int choice = scanner.nextInt();//接收用户类型
        //得到了用户类型,就可以根据用户所选的编号创建用户对象
        if(choice == 1){//如果选择1,创建管理者对象
            return new AdminUser(name);
        }else{//如果选择0,创建普通用户对象
            return new NormalUser(name);
        }
        //在类中创建了一个对象,请问我们怎么得知创建的是普通用户还是管理者呢??
        //这时候我们就需要把这个方法的返回值设为‘User’,再将新建出的对象返回接收就好了
    }
    public static void main(String[] args) {
        //第一步,要做的是用户登录,输入信息,选择用户类型
        //我们可以创建一个类名为login来实现
        User user = login();//创建一个引用来接收新创建的对象,并发生了向上转型,子类对象给父类引用
    }
}

第二步,人有了,书还没呢。所以我们在主函数中new一个书架对象

在主函数中加上此语句即可。

BookList bookList = new BookList();//新建书架对象,并已经存放了三本书

第三步,我们选择好了用户类型,就该打印不同类型的菜单了。

//第三步,创建菜单
        while(true){
            int choice = user.menu();//向上转型,发生动态绑定,产生多态。
                        //虽是通过父类调用方法,得到的是相应子类对象的方法
                        //获取用户选择的操作编号
            
        }

第四步,根据所选编号调用相应的操作

我们该怎么根据标号选择相应的方法呢??我们可以创建一个IOperation[]类型的数组,数组中存放的下标对应菜单中的操作编号。

因为我们的操作方法都为IOperation接口的实现方法,所以使用IOperation类型来存放没有问题(其之间的关系可以看成”类继承“)。

既然用户和菜单之间区分了类型,我们存放操作的数组肯定也要根据菜单的不同来区分一二。通过这种想法我们可以在AdminUser类和NormalUser类所继承的抽象类User中,定义一个IOperation[]类型的成员属性。

再分别在两个子类中的构造方法中,创建存放不同操作的数组。

User抽象类,变更为:

package user;

import operation.IOperation;

public abstract class User {
    protected String name;//用户名

    //变更:增加
    protected IOperation[] iOperations;//定义一个IOperation[]类型,但还没有分配空间
    
    //构造方法
    public User(String name) {
        this.name = name;
    }
    //打印菜单
    public abstract int menu();

}

抽象类多了一个成员属性,相应的在子类的构造方法也要改变

AdminUser的构造方法变更为:

public AdminUser(String name) {
        super(name);
        this.iOperations = new IOperation[]{//实例化不同的对象,有了对象才能调用相应的方法
                new ExitOperation(),
                new FindOperation(),
                new AddOperation(),
                new DelOperation(),
                new ShowOperation()
        };
    }

NormalUser的构造方法变更为:

public NormalUser(String name) {
        super(name);
        this.iOperations = new IOperation[]{//分别实例化不同的操作方法
                new ExitOperation(),
                new FindOperation(),
                new BorrowOperation(),
                new ReturnOperation()
        };
    }

此时,我们已经创建了对应的对象,但还没使用方法来调用他。但我们并不知道用户的类型以及要使用的方法是什么,所以我们可以在抽象类User中创建doOperation方法来调用。

User抽象类新增:

public void doOperation(int choice ,BookList bookList){
        this.iOperations[choice].work(bookList);//调用iOperation[]下标为choice的方法,
                                                //每一个元素为IOperation类型,都有接口重写的work方法
                                                //这就是接口规范的意义了
    }
}

在主函数调用方法

    public static void main(String[] args) {
        BookList bookList = new BookList();//新建书架对象,并已经存放了三本书
        //第一步,要做的是用户登录,输入信息,选择用户类型
        //我们可以创建一个类名为login来实现
        User user = login();//创建一个引用来接收新创建的对象,并发生了向上转型,子类对象给父类引用
        //第三步,创建菜单
        while(true){
            int choice = user.menu();//向上转型,发生动态绑定,产生多态。虽是通过父类调用方法,得到的是相应子类对象的方法
                                     //获取用户选择的操作编号
            user.doOperation(choice,bookList);//根据choice调用对应操作方法
        }
    }

目前大致的框架以及构建起来了,剩下的操作逐一实现就可以了。

4.操作类的实现

bookList的getter和setter有所改变,记得回到上面看看噢。

增加图书的实现

思路:创建一个新的Book对象,再存放到bookList中

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class AddOperation implements IOperation {
    @Override
    public void work(BookList bookList) {//重写接口的方法
        System.out.println("新增图书");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入图书的名字:");
        String name = scanner.nextLine();
        System.out.println("请输入图书的作者:");
        String author = scanner.nextLine();
        System.out.println("请输入图书的类型:");
        String type = scanner.nextLine();
        System.out.println("请输入图书的价格:");
        int price = scanner.nextInt();
        //创建新图书对象
        Book book = new Book(name,author,price,type);
        //查看图书馆目前的存放数量,再放到末尾
        int curSize = bookList.getUseSize();
        bookList.setBooks(curSize,book);//存放到末尾
        bookList.setUseSize(curSize+1);//数量+1
        System.out.println("新增完毕");
    }
}

借阅图书的实现

思路:先获取所要借阅的图书的书名,再根据书名遍历bookList,查看借阅状态,如果为false将相应书的借阅状态改为true。如果没有图书或状态为true(即已被借阅)则返回相应语句提醒且对数组不进行操作。

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class BorrowOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅图书");
        System.out.println("请输入要借阅的图书书名");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        int curSize = bookList.getUseSize();
        for(int i = 0;i < curSize; i++){
            Book book = bookList.getBooks(i);//创建一个暂时的Book类型引用存放在数组中的元素
            if(book.getName().equals(name)){//比较书名
                if(book.getBorrow()){//如果进入则证明已经被借阅
                    System.out.println("此书已被借阅");
                    return;
                }else{
                    book.setBorrow(true);
                    System.out.println("借阅成功");
                    return;
                }
            }
        }
        System.out.println("馆内无此书");//循环结束了 则证明没有此书
        return;
    }
}

删除图书的实现

思路:我们一般在数组中达成删除,就是将后面的元素移位到要删除的数组的下标位置上进行覆盖,达到删除的效果。所以我们先获取要删除的书名,遍历,找到相应的下标位置,将下标往后的元素全部向前移动一位,再将原本的数组最后一位置空,且图书数量-1。找不到则返回相应语句

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class DelOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("删除图书");
        System.out.println("请输入要删除的书名");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        //遍历找书
        int curSize = bookList.getUseSize();
        int index = 0;
        int i = 0;
        for(i = 0; i < curSize; i++){
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)){
                System.out.println("已找到相应图书,正在进行删除");
                index = i;//获取下标
                break;
            }
        }
        //判断循环结束的原因
        if(i == curSize){//如果已经将图书全部遍历一遍
            System.out.println("没有要删除的图书");
            return;
        }
        for(int j = index; i < curSize - 1; j++){//最后一位不用移动,后面之间置空
            Book book = bookList.getBooks(i+1);//得到下标i+1的图书
            bookList.setBooks(i,book);//把i+1放到i进行覆盖
        }
        bookList.setBooks(curSize,null);//最后一位置空,因为我们已经整体往前移动了一位
        bookList.setUseSize(curSize-1);//总数-1
        return;
    }
}

退出系统的实现

直接退出就行,也可以在主函数进行break跳出while循环再retur结束

package operation;

import book.BookList;

public class ExitOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统");
        System.exit(0);
    }
}

查找图书的实现

思路:根据书名,遍历

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class FindOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("查询图书");
        System.out.println("请输入书名");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        int curSize = bookList.getUseSize();//获取长度
        for(int i = 0; i < curSize; i++){
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)){
                //找到了,打印,使用book的toString
                System.out.println("已找到,如下:");
                System.out.println(book.toString());
                return;
            }
        }
        System.out.println("没有此书");
    }
}

归还图书的实现

思路:和借阅的想法差不多,只要查看其状态再更改就好了。

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class ReturnOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("归还图书");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入书名");
        String name = scanner.nextLine();
        int curSize = bookList.getUseSize();
        for(int i = 0; i < curSize; i++){
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)){
                if(book.getBorrow()){
                    //进入if证明为true,即已被借阅
                    book.setBorrow(false);
                    System.out.println("归还成功");
                }else{
                    System.out.println("此书不用归还");
                }
            }
        }
        System.out.println("没有要归还的书");
        return;
    }
}

展示图书的实现

思路:遍历再打印即可

package operation;

import book.Book;
import book.BookList;

public class ShowOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("展示图书");
        int curSize = bookList.getUseSize();
        for(int i = 0; i < curSize; i++){
            Book book = bookList.getBooks(i);
            System.out.println(book);
        }
        return;
    }
}

5.代码总览

图书管理系统 · 28b2ad4 · Pigee1228/JAVA记录 - Gitee.com