文章目录

  • 图书管理系统
  • 1.前言
  • 2.项目剖析
  • 3.总结
  • 4.致谢


图书管理系统

1.前言

为了解决广大用户喜欢在网上看书的问题,本人写了一套图书管理系统,来帮助大家在网络上看书,但是这套系统并不完善,目前还只是一个小程序,等本人的知识积累到一定程度,就可以把这个图书管理系统,写成网页的形式来供大家使用了。

大家先看下面这两个图,来了解一下整个系统功能的使用:

下面这是管理员的权限:

JAVA如何做系统 怎么用java做一个管理系统_开发语言

下面这是普通用户的权限:

JAVA如何做系统 怎么用java做一个管理系统_System_02

大家看完这两个图之后,我们具体分析一下,整个项目是怎么实现的。

2.项目剖析

整个项目可以拆分成两个对象,哪两个对象呢?一个就是用户,一个图书,说白了就是对用户的权限加以限制,不同权限的用户,对图书的操作是不同的,比如说管理员他可能就需要,添加,删除一些图书,而普通用户只需要去选择要不要借阅这些图书来看看。下面就是我具体实现的步骤了:

  1. 那我们第一步其实定义一些实体,来把用户还有图书这些东西给抽象出来,Java是面向对象的,你得把对象给我弄出来是吧!那我们的代码就可以这么写:
    创建一个User对象:
//代码就是想到什么,写什么,现在觉得user就只需要个名字,我就写了个名字放在这里
public class User {
    protected String name;  

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

创建一个Book对象:

/**
 * 创建一个图书对象,图书应该有书名,作者,价格,类型以及有没有被借出这些属性吧!
 * 你看我都写成了private,证明我不想直接让别人访问,我得给一些接口吧!得让别人访问
 * 到阿!然后就给了个构造方法,还有get和set方法,还有重写toString方法。
 */
public class Book {
    private String name; //书名
    private String author; //作者
    private int price; // 价格
    private String type; //类型
    private boolean isBorrowed; // 是否被借出

    public Book() {
    }

    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=" + (isBorrowed ? "借出" : "未借出") +
                '}';
    }
}
  1. 既然两个实体都被我们建立出来了,那我们就应该得细分一下了,分什么呢?用户有哪些用户呢?管理员算一个吧!普通用户也算一个吧!那就有两个用户了,那我们是不是也得把这两个用户给建立出来,他们既然都属于用户这一块,我刚好是不是可以直接用到继承的知识,让这两个用户继承我的User,就没有必要再定义name属性了,直接用我父类的就好了。
    创建一个AdminUser对象:
/**
 * 创建了一个AdminUser来继承User,是不是就可以复用User里面的属性了
 */
public class AdminUser extends User {

    //子类创建了构造方法,是不是先要帮父类进行初始化阿!
    public AdminUser(String name) {
        super(name);
    }
}

创建一个NormalUser对象:

/**
 * 创建了一个NormalUser来继承User,是不是也可以复用User里面的属性了
 */
public class NormalUser extends User {

    //子类创建了构造方法,是不是先要帮父类进行初始化阿!
    public NormalUser(String name) {
        super(name);
    }
}
  1. 书这个对象已经建立出来了,但是仔细思考,我创建好了一本书,是不是没有地方放呀!那没有地方怎么办?创建一个书架对象,专门用来存放书这个对象,那说到存放,第一个是不是想到就是数组阿!
    创建一个BookList对象:
import java.util.Arrays;

public class BookList {

    //数组的默认大小
    private static final int DEFAULT_SIZE = 10;
    //创建一个book类型的数组,数组默认大小是10
    private Book[] books = new Book[DEFAULT_SIZE];
    //数组用了几个元素
    private int usedSize;

    //在构造方法里,默认初始化了三本书,也就是说程序一执行,就会有三本书在里面
    public BookList() {
        books[0] = new Book("三国演义", "罗贯中", 19, "历史");
        books[1] = new Book("水浒传", "施耐庵", 21, "历史");
        books[2] = new Book("红楼梦", "曹雪芹", 31, "历史");
        //把usedSize改为3
        this.usedSize = 3;
    }


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

    public void setBooks(Book book) {
        books[usedSize] = book;
    }

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


    public int getUsedSize() {
        return usedSize;
    }

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

    public static int getDefaultSize() {
        return DEFAULT_SIZE;
    }

    //如果数组内容满了,还想插入,那就得扩容了,借助copyOf这个方法,就可以进行扩容
    public void dilatation() {
        this.books =  Arrays.copyOf(books, 2 * DEFAULT_SIZE);
    }
}
  1. 到这里实体的部分我们都建立完了,剩下的就是每个用户对书的操作是不一样的,也就是说我们得把那些操作也得给实现实现吧!那我们对书的操作有哪些呢?有添加图书,借阅图书,删除图书,查找图书,归还图书,显示所有图书以及退出系统,一共七个操作,我想的是,如果我定义一个接口,到时候方法的调用者,他传哪个参数,我就调用哪个方法,这样我就实现了接口的统一,并且能实现你传入什么参数,我就调用什么功能,也就是说我要定义一个接口,让这些功能去实现我的接口,最后就能展现出,你传的参数不一样,我就能给你展示出不同的功能。
    定义一个IOpreationBook接口:
//里面就一个方法,到时候大家都得实现我这个方法,我就可以用多态的知识,来调用不同的方法
public interface IOpreationBook {
    void work(BookList bookList);
}

定义一个AddBookOpreation类:

//添加一本图书
//实现IOpreationBook接口,并且重写work方法
public class AddBookOpreation implements IOpreationBook {

    @Override
    public void work(BookList bookList) {

        //如果数组满了,就进行扩容
        if (bookList.getUsedSize() == BookList.getDefaultSize()) {
            bookList.dilatation();
        }

        Scanner scan = new Scanner(System.in);
        System.out.println("添加图书");
        System.out.println("请输入书名:");
        String name = scan.nextLine();
        System.out.println("请输入作者:");
        String author = scan.nextLine();
        System.out.println("请输入类型:");
        String type = scan.nextLine();
        System.out.println("请输入价格:");
        int price = scan.nextInt();
        //如果数组里面已经有这本输入了,这不允许插入
        if (findBook(bookList, name) != null) {
            System.out.println("不允许重复插入");
            return;
        }
        Book book = new Book(name, author, price, type);
        bookList.setBooks(book);
        //插入成功不要忘记将usedSize+1
        bookList.setUsedSize(bookList.getUsedSize() + 1);
        System.out.println("添加成功");
    }
}

定义一个BorrowBookOpreation类:

//借阅一本图书
//实现IOpreationBook接口,并且重写work方法
public class BorrowBookOpreation implements IOpreationBook {

    @Override
    public void work(BookList bookList) {
        System.out.println("借阅图书");
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入要借阅图书的名字:");
        String name = scan.nextLine();
        //借书的前提是要有这本书,所以要去数组里找一找,看看有没有这本书
        Book book = findBook(bookList, name);
        if (book == null) {
            System.out.println("找不到这本书");
            return;
        }
		
        //找到这本书之后呢?看看有没有被借出去,没有被借出去,就可以借走了,否则借阅失败
        if (book.isBorrowed() == false) {
            book.setBorrowed(true);
            System.out.println("借阅成功");
        } else {
            System.out.println("借阅失败");
        }
    }
}

定义一个DelBookOpreation类:

//删除一本图书
//实现IOpreationBook接口,并且重写work方法
public class DelBookOpreation implements IOpreationBook {
   
    @Override
    public void work(BookList bookList) {
        Scanner scan = new Scanner(System.in);
        System.out.println("删除一本图书");
        System.out.println("请输入图书的名字:");
        String name = scan.nextLine();
        //删除图书,得先看看有没有这本书,没有则结束方法,有则返回下标的位置
        int pos = findBook(name, bookList);
        if (pos == -1) {
            System.out.println("找不到这本书");
            return;
        }
        //确定下标的位置了,那就让后面的书覆盖掉前面的书,就可以实现删除了
        int currentLen = bookList.getUsedSize();
        for (int i = pos; i < currentLen - 1; i++) {
            Book book = bookList.getBook(i + 1);
            bookList.setBooks(book, i);
        }
        /**
         * 这里为什么要置为null呢?我们仔细分析的话,后面的书虽然把前面的书覆盖了,但是
         * 后面那本书还存在着,引用还是指向着他,所以我们最好的方法就是把他置为null,
         * 这样就不会指向他了。
         */
        bookList.setBooks(null, currentLen - 1);
        //删完之后,别忘记让usedSize-1
        bookList.setUsedSize(currentLen - 1);
        System.out.println("删除成功");
    }
}

定义一个FindBookOpreation类:

//查找一本图书
//实现IOpreationBook接口,并且重写work方法
public class FindBookOpreation implements IOpreationBook {

    @Override
    public void work(BookList bookList) {
        System.out.println("查找一本书");
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入图书的名字:");
        String name = scan.nextLine();
        int currentLen = bookList.getUsedSize();
        /**
         * 这里就是给数组遍历了,名字一样则返回,不一样就接着循环下去,如果循环都走完了,还没有
         * 找到的话,就说明没有这本书。
         */
        for (int i = 0; i < currentLen; i++) {
            /**
             * 这里别看写的很长,其实就是获取数组里面的一个对象,然后通过对象获取他的名字
             * 然后进行比较就完了
             */
            if (bookList.getBook(i).getName().equals(name)) {
                System.out.println(bookList.getBook(i));
                return;
            }
        }
        System.out.println("找不到这本书");
    }
}

定义一个ReturnBookOpreation类:

//归还一本图书
//实现IOpreationBook接口,并且重写work方法
public class ReturnBookOpreation implements IOpreationBook {
    
    @Override
    public void work(BookList bookList) {
        System.out.println("归还图书");
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入图书的名字:");
        String name = scan.nextLine();
        //归还图书也是要先判断有没有这本书
        Book book = findBook(bookList, name);
        if (book == null) {
            System.out.println("找不到这本书");
            return;
        }
		
        //有这本书再判断是否已经被借走了,被借走了再归还就没毛病
        if (book.isBorrowed() == true) {
            book.setBorrowed(false);
            System.out.println("归还成功");
        } else {
            System.out.println("归还失败");
        }
    }
}

定义一个ShowBookOpreation类:

//展示所有图书
//实现IOpreationBook接口,并且重写work方法
public class ShowBookOpreation implements IOpreationBook {
    
    @Override
    public void work(BookList bookList) {
        System.out.println("显示所有图书");
        int currentLen = bookList.getUsedSize();
		//这里一个for循环就能显示出所有图书
        for (int i = 0; i < currentLen; i++) {
            System.out.println(bookList.getBook(i));
        }
    }
}

定义一个ExitBookOpreation类:

//退出系统
//实现IOpreationBook接口,并且重写work方法
public class ExitBookOpreation implements IOpreationBook {
    
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统成功");
        /**
         * 在java里面,正常退出的结束码是0,所以我们只要调用exit这个方法,并赋值一个0,
         * 就可以退出这个程序
         */
        System.exit(0);
    }
}
  1. 到这里对书的操作我们就已经全部实现好了,现在就剩下一个问题了,不同权限的用户,该怎么调用不同的方法呢?我想到的方法是对User这个对象,添加一些东西,添加什么呢?添加一个接口数组,再添加一个对接口数组做操作的方法,为什么要这样设计呢?首先我加了个接口数组,那我的子类一定也继承了这个接口数组,那我就可以在子类为父类初始化的时候,往这个接口数组存放东西,比如说管理员有查找图书,添加图书的这几个功能,我就可以在初始化的时候,为这个数组添加对应功能的实例,然后再通过对接口数组操作的方法,去调用我想用的那几个功能就可以了,说的很抽象,我们具体看看代码就明白了。
    为User对象添加属性和方法:
public class User {
    protected String name;
    //添加了一个接口数组
    protected IOpreationBook[] iOpreationBook;

    public User(String name) {
        this.name = name;
    }
	
    //添加了一个对接口数组操作的方法
    public void doWork(int choice, BookList bookList) {
        //里面调用了接口数组里的对象里面的方法
        this.iOpreationBook[choice].work(bookList);
    }
}

让AdminUser这个对象为父类的属性进行初始化:

public class AdminUser extends User {

    public AdminUser(String name) {
        //初始化了父类的name属性
        super(name);
        //初始化了父类里的接口数组,给这个数组里面添加对应的操作
        /**
         * 看到这里,有些同学就会问,为什么你可以这么赋值呢?你们忘记这些操作都实现了
         * IOpreationBook这个接口了吗?那这个接口数组不就是IOpreationBook这个类型吗?
         * 那把我这些操作放进去,不就刚好构成多态,然后发生向上转型吗?不就可以通过父类
         * 来调用我子类重写的方法吗?所以大家还是要把知识点记牢阿!
         */
        this.iOpreationBook = new IOpreationBook[]{
                new ExitBookOpreation(),
                new FindBookOpreation(),
                new AddBookOpreation(),
                new DelBookOpreation(),
                new ShowBookOpreation()
        };
    }
}

让NormalUser这个对象为父类的属性进行初始化:

public class NormalUser extends User {

    public NormalUser(String name) {
        //初始化了父类的name属性
        super(name);
        //初始化了父类里的接口数组,给这个数组里面添加对应的操作
        this.iOpreationBook = new IOpreationBook[]{
                new ExitBookOpreation(),
                new FindBookOpreation(),
                new BorrowBookOpreation(),
                new ReturnBookOpreation()
        };
    }
}
  1. 看到这里,我们已经把整体的构架搭建完了,写到这里的时候,发现少了点什么,好像没有写菜单阿!那我们把User改为抽象类,然后添加一个抽象方法叫做menu(),然后让子类去重写这个方法,菜单不就出来了吗?
    把User变为抽象类,并添加一个抽象方法
//我把User改为抽象类,因为这样才能添加抽象方法,我的子类才能重写我的抽象方法
public abstract class User {
    protected String name;
    protected IOpreationBook[] iOpreationBook;

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

    //添加抽象方法
    //为什么这个菜单还有返回值呢?我得知道用户输入了点什么呀!我才好去调用对应的方法呀!
    public abstract int menu();

    public void doWork(int choice, BookList bookList) {
        this.iOpreationBook[choice].work(bookList);
    }
}

让AdminUser去实现父类的抽象方法:

public class AdminUser extends User {

    public AdminUser(String name) {
        super(name);
        this.iOpreationBook = new IOpreationBook[]{
                new ExitBookOpreation(),
                new FindBookOpreation(),
                new AddBookOpreation(),
                new DelBookOpreation(),
                new ShowBookOpreation()
        };
    }

    //实现抽象方法,定义自己的菜单
    @Override
    public int menu() {
        System.out.println("*****************************");
        System.out.println("hello " + 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 scan = new Scanner(System.in);
        int choice = scan.nextInt();
        return choice;
    }
}

让NormalUser去实现父类的抽象方法:

public class NormalUser extends User {

    public NormalUser(String name) {
        super(name);
        this.iOpreationBook = new IOpreationBook[]{
                new ExitBookOpreation(),
                new FindBookOpreation(),
                new BorrowBookOpreation(),
                new ReturnBookOpreation()
        };
    }

    //实现抽象方法,定义自己的菜单
    @Override
    public int menu() {
        System.out.println("*****************************");
        System.out.println("hello " + name + "欢迎来到图书小练习!");
        System.out.println("1.查找图书");
        System.out.println("2.借阅图书");
        System.out.println("3.归还图书");
        System.out.println("0.退出系统");
        System.out.println("*****************************");
        System.out.println("请输入你的操作:");
        Scanner scan = new Scanner(System.in);
        int choice = scan.nextInt();
        return choice;
    }
}
  1. 到这里我们整体项目就写完了,剩下就是运行我们刚刚写的方法了。
public class Main {

    //写一个登录方法,来获取当前用户是哪个身份
    public static User Login() {
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入你的姓名:");
        String name = scan.nextLine();
        System.out.println("请输入你的身份:1-》管理员,0-》普通用户");
        int choice = scan.nextInt();

        if (choice == 1) {
            return new AdminUser(name);
        } else {
            return new NormalUser(name);
        }
    }

    public static void main(String[] args) {
        //知道是哪个身份之后,调用那个用户对应的方法
        User user = Login();
        BookList bookList = new BookList();
        while (true) {
            /**
             * 通过用户调用menu方法,就能知道用户输入了那个数字,然后去调用对应数字的那个方法
             * 有人说用户乱输入怎么办?没关系阿!我这个是死循环,你不输入0,这个程序就结束不了
             * 你乱输入,找不到对应方法,写的好一点的,就提示你输入错误,让你重新输入,写的不好
             * 的,程序就直接报错了,所以呢?不要乱输入哈!
             */
            int choice = user.menu();
            user.doWork(choice, bookList);
        }
    }
}
  1. 一起看看整体的效果吧!

3.总结

当项目写出来的那一刻,挺开心的,虽然这个项目很小,也有很多不足的地方,但是这些都是我们学习的动力,就是在不断受挫,再不断爬起来,那个时候你会发现,你比昨天的自己更棒了。说说这个项目,这个项目用了哪些语法呢?用了变量+各种数据类型+if+for+数组+方法+继承+封装+多态+抽象类+接口,就是把前面所学的知识,进行了个整合,自己把这个系统写完了,对你的帮助,你的理解真的很大,也希望各位同学能继续坚持下去,继续在编程的这条路越走越远。