JavaSE:图书管理系统

1、引言

经过一个月的学习,我们掌握了数据类型、逻辑控制、数组、方法、类和对象、封装、继承、多态、抽象类、接口......我们已经掌握了Java的语法,在这里,我们来实现一个图书管理系统的小项目,将我们学到的知识全部用起来!以后学习了MySQL,我们还可以将这个小项目进行升级!

2、运行展示

首先,我们先来运行一下图书管理系统的代码,了解一下整体逻辑:

QQ2024528-205028-HD

以下几点值得注意:

1.管理员和普通用户所具有不同的操作权限

2.书架中原本就已经存储了三本书

3. 我们可以进行多种操作来管理或使用图书

OK,话不多说,我们进入正题~

3、图书管理系统

在项目中,我们有着多个对象:图书、书架、管理员、普通用户、删除图书操作、添加图书操作、展示图书操作、借阅图书操作、归还图书操作、排序图书操作........

为了更好的管理代码,同时使逻辑更加清晰明确,我们可以创建包来管理相关代码。

3.1 图书相关

 我们可以单独创建一个包,用来存放与图书有关的相关代码。

3.1.1 public class Book(图书类)

首先,图书管理系统,那必不可少的就是图书类,我们创建图书类并定义好相关属性,我这里有:书名、作者、价格、类型、状态(是否被借出)等等(自已来定义你需要的属性)......

需要注意的是,我们最好将这些属性使用private来封装起来,提供公开的get和set接口,提高书籍的安全性。

并且,我们创建带相关参数的构造方法,以后在实例化图书对象时完成初始化,isBorrowed可以不作为参数传入,因为boolean类型的成员变量的默认值为false,即默认为未借出。(因为我们创建这本图书的时候肯定还没有被借出)

我们可以先重写一下toString方法,后续会用到。

整体代码:

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;
    }

    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;
    }


    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", type='" + type + '\'' +
                (isBorrowed == true ? ", 该书被借出" : ", 该书未被借出") +
                '}';
    }
}

3.1.2 public class BookList(书架类)

在图书系统中,我们肯定需要有一个能够存放的图书的书架,通过这个书架来对图书完成一些增删查改的操作,我们再来定义一个BookList类。

在这个类中,我们定义一个数组,用来存放Book类的对象,即存放图书(使用了组合)。

还可以定义一个整形变量成员usedSize存放实际的图书数目。

别忘了将这些成员属性封装起来~

 

别忘了,图书系统中原本就有着三本书,那这三本书肯定是在构造对象时就完成了初始化,于是我们就在构造方法中生成这三本书(放入Book数组中),并将usedSize置为3 。

在后续对图书进行增删查改时肯定会涉及到具体的一本书,我们可以写一个公开接口来得到或更改某一下标的图书:

整体代码:

public class BookList {
    private Book[] books = new Book[100];//存放图书
    private int usedSize;//实际图书数目

    public BookList() {
        //书架中原本就有着三本书,在构造方法中完成初始化
        books[0] = new Book("三国演义","罗贯中",50,"小说");
        books[1] = new Book("朝花夕拾","鲁迅",25,"散文");
        books[2] = new Book("悲惨世界","雨果",30,"小说");
        this.usedSize = 3;
    }

    public Book[] getBooks() {//得到Book数组
        return books;
    }
    
    public void setBook(int pos,Book book) {//通过下标来设置某本书
        this.books[pos] = book;
    }
    public Book getBook(int pos) {//通过下标来得到某本书
        return this.books[pos];
    }

    public int getUsedSize() {//得到图书的实际数目
        return usedSize;
    }

    public void setUsedSize(int usedSize) {//设置图书的实际数目
        this.usedSize = usedSize;
    }
}

4.1 操作相关

我们再新创建一个包,来管理操作相关的代码

对于管理员和普通用户,他们分别有着不同的操作,而这些操作都是对书架上的图书进行的,我们可以写一个和操作相关的接口,在接口中定义一个抽象方法,不同的操作都需要通过实现这个接口来规范行为,使代码、逻辑更加清晰。

接口代码:

public interface IOperation {
    void work(BookList bookList);
}

共有以下操作:

我们先来定义这些操作,先搭好整体框架后再来完成具体的操作的代码。

5.1 用户相关

同样,我们创建新包来管理用户相关的代码。

5.1.1 public class User(父类)

我们知道,用户分为管理员用户和普通用户,我们定义一个User类来抽取出他们的共性,作为他们的父类。

因为选择身份后会打印相关身份的菜单(各自菜单不同):

我们可以在父类User中定义一个不需要具体实现的菜单方法(子类中进行重写),就也是说可以将User定义为抽象类:

在子类中可以重写这个方法,各自实现各自的菜单。

菜单打印后,不同身份的用户会选择相关操作,不同用户的操作也是不相同的,我们该如何去处理呢?

因为在上文处理操作相关时,不同的操作都实现了一个IOperation接口,于是,我们可以在父类User中定义一个IOperation数组来存放相关操作(不初始化,也不给出元素数量),在各自子类用户中完成初始化。

5.1.2 public class NormalUser 、public class AdminUser(子类)

在两个子类中,我们写带参构造方法帮助父类完成初始化,并各自完成对IOperation数组的赋值,并且,重写各自的菜单方法。

AdminUser中代码:

//管理员用户
public class AdminUser extends User{
    public AdminUser(String name) {
        //帮助父类完成初始化
        super(name);

        //在iOperations数组中按照下标存放对应操作
        iOperations = new IOperation[] {
                new ExitOperation(),//退出系统
                new FindOperation(),//查找图书
                new ShowOperation(),//展示图书
                new DeleteOperation(),//删除图书
                new AddOperation(),//添加图书
                new SortByPrice(),//排序图书(通过价格)
                new SortByName(),//排序图书(通过书名)
        };
    }


    @Override
    //打印菜单(重写方法)
    public int menu() {
        System.out.println("========图书管理系统========");
        System.out.println("====1.查找图书 2.展示图书====");
        System.out.println("====3.删除图书 4.添加图书====");
        System.out.println("====5.排序图书 0.退出系统====");
        System.out.print("请输入您的操作:");
        Scanner scanner = new Scanner(System.in);
        int choice = scanner.nextInt();
        return choice;
    }
}

NormalUser中代码:

//普通用户
public class NormalUser extends User{
    public NormalUser(String name) {
        //帮助父类完成初始化
        super(name);

        在iOperations数组中按照下标存放对应操作
        iOperations = new IOperation[] {
                new ExitOperation(),//退出系统
                new FindOperation(),//查找图书
                new BorrowOperation(),//借阅图书
                new ReturnOperation()//归还图书
        };
    }
    @Override
    //打印菜单(重写方法)
    public int menu() {
        System.out.println("========图书管理系统========");
        System.out.println("====1.查找图书 2.借阅图书====");
        System.out.println("====3.归还图书 0.退出系统====");
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入您的操作:");
        int choice = scanner.nextInt();
        return choice;
    }
}

6.1 登录相关

(我们在默认包中创建Test类,在main方法中整合整个体系)

在运行图书系统时,还需要有登录界面:

我们在这里完成登录界面代码的处理,

我们可以单独抽象出一个方法来完成登录相关,需要注意的是,在选择身份后,我们都需要根据这个身份来完成后续的流程操作,这个方法可以以不同身份的对象为返回值,使用父类对象user来接收(向上转型),这样就可以处理返回值类的对象不统一的问题。

其中的代码很简单,相信大家都可以完成。

7.1 操作的处理

不同用户可执行的操作是不一样的,虽然不同用户已经在IOperation数组中初始化好了对于操作,可是,该如何去调用这些操作呢?

我们想到,IOperation数组是在父类中定义的,虽然不同用户初始化的数组不同,可是作为他们的父类,user是都可以访问这个数组的,那我们就可以在父类中写一个方法来完成对数组成员的访问,完成相关的操作。

至此,父类的代码才完成了:

public abstract class User {
    protected String name;

    protected IOperation[] iOperations;

    public User(String name) {
        this.name = name;
    }

    public abstract int menu();

    public void doOperation(int choice, BookList bookList) {
        if(choice == 5) {
            System.out.println();
            int sortType = -1;
            System.out.println("请选择您想要的排序方式:1->按价格排序  2->按书名排序");
            Scanner scanner = new Scanner(System.in);

            do {
                sortType = scanner.nextInt();
                if(sortType != 1 && sortType != 2) {
                    System.out.println("输入错误,请重写输入!");
                }
                if(sortType == 2) {
                    this.iOperations[choice + 1].work(bookList);
                    return;
                }
            }while (sortType != 1 && sortType != 2);

        }
        this.iOperations[choice].work(bookList);
    }

}

8.1 操作代码的完成

整体的框架已经搭好了,我们现在来完成操作代码的实现。

8.1.1 增添图书

增加图书的实质就是在Book数组尾添加一个Book对象,这个Book对象就是我们新增添的图书,虽然数组被封装了,但是我们提供了公开的接口可以对数组进行操作,相信这对于大家来说是不难的。(别忘了增加UsedSize的值)

public class AddOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println();
        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("请输入您所要添加图书的价格:");
        int price = scanner.nextInt();
        scanner.nextLine();
        System.out.println("请输入您所要添加图书的类型:");
        String type = scanner.nextLine();
        Book book = new Book(name, author, price, type);
        int currentSize = bookList.getUsedSize();
        bookList.setBook(currentSize,book);
        bookList.setUsedSize(currentSize + 1);
        System.out.println("成功添加该图书!!!");
        System.out.println();
    }
}

8.1.2 借阅图书

我们需要查找到要借阅的那本书,再将那本书的状态修改为true(因为该变量为布尔类型,false为未借出,true为借出)就可以了。(当然,借阅该书的前提为这本书存在并且未被借出,别的细节大家都可以自己来添加)

public class BorrowOperation implements IOperation{

    @Override
    public void work(BookList bookList) {
        System.out.println();
        System.out.println("=====借阅图书=====");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要借阅图书的书名:");
        String name = scanner.nextLine();
        for (int i = 0; i < bookList.getUsedSize(); i++) {
            Book book = bookList.getBook(i);
            if(book.getName().equals(name)) {
                if (book.isBorrowed() == true) {
                    System.out.println("很抱歉,该图书已被借阅!!!");
                    System.out.println();
                    return;
                }
                book.setBorrowed(true);
                System.out.println("借阅图书成功!!!");
                System.out.println();
                return;
            }
        }
        System.out.println("没有查找到该图书!!!");
        System.out.println();
    }
}

8.1.3 删除图书

同样,我们需要先找到那本书,接着这本书将后面的书往前移动,覆盖掉这本书就可以了,最后要将末尾的引用置空,防止末尾引用仍有指向的数据。(别忘了减少UsedSize的值)

public class DeleteOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println();
        System.out.println("=====删除图书=====");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要删除图书的书名:");
        String name = scanner.nextLine();
        int currentSize = bookList.getUsedSize();
        if(currentSize == 0) {
            System.out.println("本图书管理系统中未存储任何图书,无法进行删除操作!!!");
            System.out.println();
            return;
        }
        for (int i = 0; i < bookList.getUsedSize(); i++) {
            Book book = bookList.getBook(i);
            if (book.getName().equals(name)) {
                for (int j = i; j < currentSize - 1; j++) {
                    Book book1 = bookList.getBook(j + 1);
                    bookList.setBook(j, book1);
                }
                bookList.setBook(currentSize - 1,null);
                bookList.setUsedSize(currentSize - 1);
                System.out.println("成功删除该图书!!!");
                System.out.println();
                return;
            }
        }
        System.out.println("没有查找到该图书!!!");
        System.out.println();
    }
}

8.1.4 退出系统

我们直接调用系统提供的exit方法就可以完成退出。

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

8.1.5 查找图书

输入想要查找图书的名称,循环遍历Book数组,找到后打印这本书的信息就可以了。(我们已经在Book类中重写了toString方法)

public class FindOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println();
        System.out.println("=====查找图书=====");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要查找图书的书名:");
        String name = scanner.nextLine();
        for (int i = 0; i < bookList.getUsedSize(); i++) {
            Book book = bookList.getBook(i);
            if (book.getName().equals(name)) {
                System.out.println("成功查找到该图书!!!");
                System.out.println(book);
                System.out.println();
                return;
                }
            }
        System.out.println("没有查找到该图书!!!");
        System.out.println();
    }
}

8.1.6 归还图书

与借阅图书相同,遍历找到那本书后,将状态修改为false即可。

public class ReturnOperation implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println();
        System.out.println("=====归还图书=====");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要归还图书的书名:");
        String name = scanner.nextLine();
        for (int i = 0; i < bookList.getUsedSize(); i++) {
            Book book = bookList.getBook(i);
            if(book.getName().equals(name)) {
                if (book.isBorrowed() == false) {
                    System.out.println("该图书还未被借阅!!!");
                    System.out.println();
                    return;
                }
                book.setBorrowed(false);
                System.out.println("归还图书成功!!!");
                System.out.println();
                return;
            }
        }
        System.out.println("没有查找到该图书!!!");
        System.out.println();
    }
}

8.1.7 展示图书

我们只需要在遍历数组时,打印出当前图书的信息即可。

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

8.1.8 排序图书

在完成排序图书时,由于我实现了两种不同的排序方式(通过书名和书的价格),所以利用了比较器进行排序,这样可以使比较方式更加灵活。

public class NameComparator implements Comparator<Book> {//用书名来比较
    @Override
    public int compare(Book o1, Book o2) {
        return o1.getName().compareTo(o2.getName());
    }
}
public class PriceComparator implements Comparator<Book> {//用价格来比较
    @Override
    public int compare(Book o1, Book o2) {
        return o1.getPrice() - o2.getPrice();
    }
}

以书名排序代码:

public class SortByName implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println();
        NameComparator nameComparator = new NameComparator();
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i < currentSize - 1; i++) {
            boolean flg = false;
            for (int j = 0; j < currentSize - 1 - i; j++) {
                Book book1 = bookList.getBook(j);
                Book book2 = bookList.getBook(j + 1);
                if (nameComparator.compare(book1,book2) > 0) {
                    bookList.setBook(j,book2);
                    bookList.setBook(j + 1,book1);
                    flg = true;
                }
            }
            if(flg == false) {
                break;
            }
        }
        System.out.println("所有图书已按书名排序成功!!!");
        System.out.println();
    }
}

以价格排序代码:

public class SortByPrice implements IOperation{
    @Override
    public void work(BookList bookList) {
        System.out.println();
        PriceComparator priceComparator = new PriceComparator();
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i < currentSize - 1; i++) {
            boolean flg = false;
            for (int j = 0; j < currentSize - 1 - i; j++) {
                Book book1 = bookList.getBook(j);
                Book book2 = bookList.getBook(j + 1);
                if(priceComparator.compare(book1,book2) > 0) {
                    bookList.setBook(j,book2);
                    bookList.setBook(j+1,book1);
                    flg = true;
                }
            }
            if(flg == false) {
                break;
            }
        }
        System.out.println("所有图书已按价格排序成功!!!");
        System.out.println();
    }

 4、总结

到这里,图书管理系统就已经完成了,其实就是将我们SE语法部分的知识串了一遍,如果大家掌握的好的话,完成这个应该是没有难度的。

完整的代码在博主的码云上哦:小丁爱养花/JavaSE - Gitee.com

最后,我想对大家以及自己说几句话:

静下心来,才能越走越远,才会越来越强。

不求一步登天,相信一切都会水到渠成。

及时当勉励,岁月不待人~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值