java初级内容结课项目——图书管理系统

        在前面的十三课中,笔者已经介绍了有关java的各种语法及其细节。若要融会贯通,则还需大量的练习,而非单纯的依赖于笔记中的内容。毕竟“纸上得来终觉浅,绝知此事要躬行”。在java语法的最后一节内容,我将运用之前学到的所有内容,实现一个简单的图书管理系统,并力将整个项目的实现细节讲解到位,共同学习。话不多说,进入正题。

         首先,我会展示项目的最终实现效果:

一:管理员层面

 

 二:用户层面

 

实现一个图书馆里系统,要包含以下三大块内容:

1.书包,要有每本书的信息,同时还要把每本书存放起来。即对于书的细节和一本书的存放情况,分别进行实现。于是就有了我们的第一个包:

2. 操作包:图书管理系统,其核心就是对书籍进行存取管理,这里同时又涉及到操作者的身份。操作者身份不同,则可以进行的操作也有所差异。这里先抽象出一个操作包,用于存放可能进行的操作。

 3.正如2中所提到的,我们的第三个包,就是用于区分不同操作者的。

         结合我们之前的思考,最后整体的结构如下图所示:

        需要说明的是,在实际开发过程中,我们很难一次性想到所有需要实现的功能,通常会根据编写程序的进度及过程中出现的问题,不断改进、完善每个文件中的具体内容。但为使文章的思路更加流程,也为了减小书写的难度,我的行文思路是:在打好框架的基础上,尽量按照上图中从上到下的顺序,进行拆分讲解。

package book

package book;

public class Book {
    public String name;
    String author;
    double price;
    String type;
    boolean isBorrowed;

    public Book(String name, String author, double 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 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 isBorrowed() {
        return isBorrowed;
    }

    public void setBorrowed(boolean borrowed) {
        isBorrowed = borrowed;
    }

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

        这个类非常简单,就是一个书类,包含了书名、作者、价格、类型、在借状态这5个private成员,并提供Getter And Setter方法实现访问;提供了一个带四个参数的构造方法,最后重写toString方法。唯一需要注意的是,我们并没有将status参数放在构造方法中进行初始化,因为当你添加一本书时,默认是未借出的,即status=false,而这正是status这个变量的默认值,无需进行手动传参的设置。

package book;

//BookList是书架,Book是书,实例化一书架booklist,实例化书book,booklist数组中上放的是book元素
public class BookList {
    private Book books[]=new Book[10];
    private int usedSize;

    public BookList(){
        books[0]=new Book("三国演义","罗贯中",25.8,"名著");
        books[1]=new Book("百年孤独","马尔克斯",54.5,"文学");
        books[2]=new Book("卡片笔记写作法","阿伦斯",23.3,"工具");
        usedSize = 3;
    }

    public int getUsedSize() {
        return usedSize;
    }

    public void setUsedSize(int usedSize) {
        this.usedSize = usedSize;
    }

    //获取某个下标的书
    public Book getPos(int pos){
        return books[pos];
    }

    //给数组的pos位置放一本书

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

        如你所见,这是一个书架类。一开头我们就定义了一个book[]数组,用于存放书的信息,当然数组中每个成员都是Book类型的。通过构造方法,我先将三本书放入了“书架”。

        usedSize用于显示当前书架中书的数目,我当然会为它提供Getter And Setter方法,以方便的获取和修改usedSize的值,及时更新数据。

        如果你有一定的预见性,可能会想到我们需要做这样的事件,就是在书架的任意位置存放一本书,所以我们提供了setBooks方法,其参数为pos位置和一本书对象book。

IOPeration


import book.BookList;

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

        这是一项独特的设计,既然我们要实现多个对书架的操作,我们索性实现一个操作接口,再让所有的操作实现这个接口,并重写其中的work()方法。参数自然是整个书架bookList。

 对于每个操作的具体实现,我会在后文进行讲解。

User

package users;
import book.BookList;
import operation.IOPeration;
public abstract class User {
    protected String name;

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

    public IOPeration[] ioPerations;//一个接口数组

    public abstract int menu();

    //如何得知调用哪个方法?
    public void doOperation(int choice, BookList booklist){
        ioPerations[choice].work(booklist);
        //数组的某个下标是对象,可以调用对象的work()方法。
    }
}

        首先,User中的方法无需具体实现,所以我们会将其设置为abstract抽象类,其中的方法也定义为抽象方法。管理员和用户拥有共同的属性姓名,定义为name并使用构造方法进行初始化(具体到子类自然要重写父类的构造方法)。

        我们先来看看最后实现出来的功能菜单:

        我们期望的是从键盘上输入各个操作所对应的数字,就可以调用相对应的方法。那么如何知道调用哪个方法呢?这就要使用到接口数组,将所有的操作放在一个接口数组ioPerations中,每个操作自然会对应数组的下标,通过下标就可以找到这个操作类,再调用这个类下的work()方法。

         如果对这里不理解,不妨回忆一下我们在第十一课——抽象类与接口一文中所讲过的这个例子:(理解的朋友可以直接跳过)

AdminUser

package users;

import book.BookList;

import operation.*;

import java.util.Scanner;

public class AdminUser extends User{

    //重写父类构造方法
    public AdminUser(String name) {
        super(name);


        this.ioPerations = new IOPeration[]{
                new ExitOperation(),
                new FindOperation(),
                new AddOperation(),
                new DelOperation(),
                new DisplayOperation()
        };
    }

    //重写父类抽象方法
    @Override
    public int menu() {
        System.out.println("===========管理员菜单==========");
        System.out.println("您好 "+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("请输入你的操作:");
        Scanner sc = new Scanner(System.in);
        int choice = sc.nextInt();
        return choice;
    }
}

         这是对于管理者的具体实现。首先,重写父类构造方法;第二步,创建接口数组,放入管理员可以进行的操作;最后,重写父类中的抽象方法menu()。需要注意是,数组的下标与操作要相互对应,所以我们将ExitOperation()放在数组的第一个位置,确保输入0时正常退出系统。

NormalUser

package users;


import operation.*;

import java.util.Scanner;

public class NormalUser extends User {


    public NormalUser(String name) {
        super(name);
        this.ioPerations = new IOPeration[]{
                 new ExitOperation(),
                 new FindOperation(),
                 new BorrowOperation(),
                 new ReturnOperation()
        };
    }
    @Override
    public int menu() {
        System.out.println("===========用户菜单==========");
        System.out.println("您好 "+this.name+" 欢迎来到世界联合图书馆");
        System.out.println("1.查找图书");
        System.out.println("2.借阅图书");
        System.out.println("3.归还图书");
        System.out.println("0.退出系统");
        System.out.println("请输入你的操作:");
        Scanner sc = new Scanner(System.in);
        int choice = sc.nextInt();
        return choice;
    }
}

        这是对于普通用户的具体实现。与管理员的唯一不同之处在于接口数组,因为它他们会进行不同的操作。

Main

import book.BookList;
import users.AdminUser;
import users.NormalUser;
import users.User;

import java.util.Scanner;

public class Main {
    public static User login(){
        System.out.println("请输入您的姓名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();
        System.out.println("请输入你的身份:1->管理员  0->用户");
        int choice =sc.nextInt();
        if(choice == 1){
            return new AdminUser(name);
        }else{
            return new NormalUser(name);
        }
    }

    public static void main(String[] args) {
        BookList bookList = new BookList();
        User user = login();
        while(true)
        {
            int choice = user.menu();
            user.doOperation(choice,bookList);

        }
    }

}

        在主函数的实现中,我们需要考虑一个非常重要的问题,就是如何得知当前正在使用该系统的人是管理员还是普通用户呢?所以我们设置登陆选项,根据使用者的输入确定其身份,不同的身份,会打印不同的菜单,也会实现不同的操作。父类引用引用子类对象,在这里用到了“继承”的知识,根据返回值的不同,当前用户的身份也可以得到确认了。

        根据我们的思考,在main函数中实例化出书架bookList和用户User对象即可。为实现多次输入,我们操作的具体实现放在while(true)循环中,并通过退出系统的类实现循环终止。

        至此,我们整体的实现逻辑已经言明。接下来,我会展示每一个操作的代码,需要注意的是,所有的操作都实现了IOPeration接口,并重写其中的work()方法。

AddOperation(新增图书)

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class AddOperation implements IOPeration{
    public void work(BookList bookList){
        System.out.println("新增图书!");
        int currentSize = bookList.getUsedSize();
        System.out.println("请输入你要添加的图书的信息:");
        Scanner sc = new Scanner(System.in) ;
        System.out.println("请输入书名");
        String name = sc.nextLine();
        System.out.println("请输入作者");
        String author = sc.nextLine();
        System.out.println("请输入类型");
        String type = sc.nextLine();
        System.out.println("请输入价格");
        double price = sc.nextDouble();
        Book book = new Book(name,author,price,type);
        bookList.setBooks(currentSize,book);
        bookList.setUsedSize(currentSize+1);
        System.out.println("添加成功!");
    }
}

         首先输入你要新增书目的所有信息,然后将这些信息作为参数实例化book,基于预见性,我们已经在BookList类中实现了在某个位置插入一本书的函数setBooks(),直接调用即可,最后别忘记通过setUsedSize()方法将书的数目+1。

BorrowOperation(借阅图书)

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class BorrowOperation implements IOPeration{
    public void work(BookList bookList){
        System.out.println("借阅图书!");
        System.out.println("请输入你要借阅的图书的名字:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i <currentSize ; i++) {
            Book book = bookList.getPos(i);
            if(book.getName().equals(name)&&book.isBorrowed()==false){
                System.out.println("借阅成功");
                book.setBorrowed(true);
               bookList.setUsedSize(--currentSize);
                return;
            }else if(book.getName().equals(name)&&book.isBorrowed()==true){
                System.out.println("该书已被借出");
                return;
            }else{
                System.out.println("该书不存在!");
                return;
            }
        }
    }

   Scanner sc = new Scanner(System.in);
}

        对于借书,我们的思路是输入书名,然后遍历书架数组,进行书名匹配。如果循环结束任未匹配成功,那么说明“该书不存在”;如果书名匹配成功并且借阅状态为“已借出”,那么说明该书存在但已经被借出,无法借阅;当且仅当书名匹配成功并且借阅状态为“未借出”时,才能进行借书。而借阅成功,需要将其借阅状态改为“已借出”,并将书目数减1。也有人认为此时应该直接将这本书的信息删去,不应该是只改变在借状态,这与每个人对项目的理解不同,你当然可以根据自己的想法进行业务拓展或改进。

 DelOperation(删除图书)

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class DelOperation implements IOPeration{
    public void work(BookList bookList) {
        System.out.println("删除图书!");
        System.out.println("请输入你要删除的书名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i < currentSize; i++) {
            Book book = bookList.getPos(i);
            if (book.getName().equals(name)) {
                for (int j = i; j < currentSize; j++) {
                    book = bookList.getPos(j + 1);
                    bookList.setBooks(j, book);
                }
                System.out.println("删除成功!");
                bookList.setUsedSize(--currentSize);
                return;
            }
        }
         System.out.println("该书不存在!");


    }

}

        如果要删除一本书,首先输入欲删除书的书名,然后遍历书架数组,进行书名匹配。如果匹配失败,那么自然无法进行删除;匹配成功时,可以进行删除。与在整型数组中删除元素的思路类似,删除书架数组任意位置的元素同样采用覆盖的方式。从你要删除的那本书开始进行循环,依次让后一本书覆盖前一本书(即设置前一本书的内容为后一本书,同样用到setBooks()函数)。删除成功之后,将书目数减1。

DisplayOperationy(展示图书)

package operation;

import book.Book;
import book.BookList;

public class DisplayOperation implements IOPeration{
    public void work(BookList bookList){
        System.out.println("显示图书!");
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i <currentSize ; i++) {
            Book book = bookList.getPos(i);
            System.out.println(book);
        }
    }

}

        显示图书,就是打印每一本书的信息。直接循环遍历书架数组,调用toString()方法打印每本书的信息即可。

ExitOperation(退出系统)

package operation;

import book.BookList;

public class ExitOperation implements IOPeration{
    public void work(BookList bookList){
        System.out.println("退出系统!");
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i <currentSize ; i++) {
            bookList.setBooks(i,null);
        }
        System.exit(0);
    }
}

        退出系统。当我们退出系统时,自然需要将书架中的内容情况,即循环遍历书架数组,将每一个位置上的元素置为NULL。System.exit(0)可以终止当前程序的运行,退出系统。

FindOperation(查找图书)

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class FindOperation implements IOPeration{
    public void work(BookList bookList){
        System.out.println("查找图书!");
        System.out.println("请输入你要查找的书名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i <currentSize ; i++) {
            Book book = bookList.getPos(i);
            if(book.getName().equals(name)){
                System.out.println("找到了,信息如下:");
                System.out.println(book);
                return;
            }
        }
        System.out.println("该书不存在!");
    }
}

        查找图书。输入你要查找的书名,并在书架数组中进行遍历匹配,如果匹配成功,说明该书存在,直接打印这本书的信息即可;如果匹配失败,则返回“该书不存在”。

ReturnOperation(归还图书)

package operation;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class ReturnOperation implements IOPeration{
    public void work(BookList bookList){
        System.out.println("归还图书!");
        System.out.println("请输入你要归还的图书的名字:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();
        int currentSize = bookList.getUsedSize();
        for (int i = 0; i <currentSize ; i++) {
            Book book = bookList.getPos(i);
            if(book.getName().equals(name)&&book.isBorrowed()==true){
                System.out.println("归还成功");
                book.setBorrowed(false);
                bookList.setUsedSize(++currentSize);
                return;
            }else if(book.getName().equals(name)&&book.isBorrowed()==false){
                System.out.println("该书不属于在借图书!");
                return;
            }
        }
        System.out.println("非本馆图书!");
    }

}

        归还图书。先输入你要归还的图书的书名,然后在书架数组中进行遍历匹配。一种情况是没有匹配成功,那说明这不是本馆的图书,直接打印“非本馆图书!”;在匹配成功的情况下,如果该书的借阅状态为“已借出”,那么可以进行归还,将其借阅状态设置为“未借出”,并将usedSize加1即可。如果你已经理解了这波操作,这也是为什么在借出图书时,我仅仅修改了图书的借阅状态,而没有直接将图书信息全部删除的原因。


        至此,整个图书管理系统已经实现完毕,并且笔者也已经在文章开头进行过效果的演示。

        这篇博客落幕,java基础语法的内容也已更新完毕了。虽然读者很少,我仍坚信这些文章的价值,也不会去怀疑书写这些文章的意义。即使无人问津,我们还是要去写;即使没有外界的正反馈,我们依然要遵从自己内心的声音,依然要相信坚持的力量。与诸君共勉!


        本课内容结束!

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值