[Java] 自己写图书馆管理系统(详细版)

目录

一、简介

二、需求

三、具体设计

一、大纲

二、分析过程

三、小结

1.整体流程

2.ListBookOrderByXXXCommand

3.匿名类对象语法知识点

4.类和对象(面向对象设计)

四、完整代码


一、简介


实现一个简单的能对图书馆的书籍进行简单管理的一个系统。所用到的知识有:类,抽象类,封装,继承,多态,接口。(基础知识的学习可看我博客的其他文章~)

二、需求


1.用户登录

2.管理员角色(增加书籍 、查阅书籍(根据书名排序、根据价格排序、根据借阅情况排序) 、删除书籍 、打印书籍列表

3.普通用户角色(查询书籍 、借阅书籍 、归还书籍

都在命令行上完成操作

三、具体设计


一、大纲

1.从持久化存储中(文件)加载书籍信息 -> 以顺序表的形式进行呈现

2.用户登录 -> User对象(多态体现)
3.进入一个循环中
        3.1打印用户角色对应的菜单,并且让用户选择

        3.2根据用户的选择,以Executable 对象来体现(多态),执行对应的操作命令(方法最终的执行是由对象类型决定的,对象不同,执行方法不同)
4.用户退出(Ctrl + D),打印退出信息

二、分析过程

1.输入过程需要处理很多事情:①打印提示信息②读取用户输入③用户有没有按 ctrl + D 退出,因此我们直接封装一个对象去处理输入问题。

Input input = new Input();

2.在用户登录中,我们需要一个用户管理的对象,由该对象完成用户登录的具体操作:①要求用户输入②判断用户角色。

 UserStorage userStorage = new UserStorage();
 User user = userStorage.login(input);

3.在打印用户菜单中,我们需要一个接口,可以返回给我们一个可以执行的命令,从输入中打印菜单并且进行用户选择。

IExecutable command = input.menuAndSelect();      //这是一个命令
command.excute(user,input);     //去执行

4.因为我们要写的类很多,所以根据他们不同的职责,进行分类,比如:新建一个输入包把输入的类(Input)放在里面。新建一个用户包,把用户的类(User、UserStorage)放在里面。新建一个命令包,把命令的接口放在里面。

 

5.写 login

①先让用户输入用户名 ② 根据用户名,角色是管理员还是普通用户 ③ 根据不同角色,创建不同用户,输入时,写成带有提示的输入(prompt)。

6.在Input 类中完成prompt。

7.我们提前定义好一些用户名,作为管理员。

8.完成IExecutable 接口,里面实现 excute 方法。 

9.完成menuAndSelect()方法,首先要显示菜单,角色不同,拥有的功能不同,因此需要用户信息,把User user 传入。同时menuAndSelect()方法中的showMenu();方法也要实现,首先需要得到这个角色支持哪些命令(以IExecutable[ ] 数组的方式来体现)

    public IExecutable menuAndSelect(User user) {
        showMenu(user); //角色不同,拥有的功能不同,因此需要用户信息
    }

    private void showMenu(User user) {
        //1.得到角色支持的命令
        IExecutable[] supportedCommands = user.getSupportedCommands();
        
        //2.遍历并打印每个命令的名称,显示操作菜单
        for(int i = 0;i < supportedCommands.length;i++){
            IExecutable command = supportedCommands[i];
            System.out.printf("    %2d. %s\n",command.getName());
        }
        
    }

10.想要增加几个命令,就多写几个 command 利用接口、抽象类 + 继承等实现了多态的效果,使得开发的过程变得简单。(分为管理员用户 和 普通用户)

11.具体的实现,添加书籍:1.让用户输入要添加的书籍 input.prompt()        2.使用用户输入信息,构造成书籍对象Book(name、author、type、price、borrowedBy)     

public class Book {
    public String name;
    public String author;
    public String type;
    public int price;
    public String borrowedBy;   // 如果没人借走,就是null
}

  3.把书籍对象添加到类似 BookStorage(书架)对象上。将书籍尾插到书架上

public class BookStorage {
    private Book[] array;
    private int size;

    public BookStorage(){
        array = new Book[20];
        size = 0;
    }

    //尾插
    public void add(Book book){
        //1.确保容量够用
        ensureCapacity();

        array[size++] = book;
    }

    private void ensureCapacity(){
        if(size < array.length){
            //说明至少还可以放一个元素,容量够用
            return;
        }
        //否则进行扩容
        array = Arrays.copyOf(array,array.length * 2);
    }
}

书架对象只有一个,书籍对象有很多个。所以两者之间的关系是容器与元素的关系。把书架抽象成关于书籍的顺序表。

12.实现所有的 command 内容,根据需要也可以添加 command 的内容

13.书籍的格式化:职责归属放到Book.toString()

比较:书籍默认按照名称比较(自然顺序),如果需要其他比较,则使用外部比较器

14.功能实现完成之后,先以管理员的身份运行程序,添加书籍,退出;再以普通用户身份运行程序,借阅书籍;发现普通用户中没有书籍 。如何解决?

借助可以在多进程中共享的存储,这个存储还具有持久化(进程退出后,数据仍然保存)。这个共享的存储就是硬盘:想办法把数据放到硬盘上,硬盘上的数据,被操作系统抽象成一个个文件,我们只需要把数据写到文件中即可

具体实现:1.程序启动时,从文件中(指定一个路径)读取所有的书籍信息,读到内存中(以BookStorage 对象中 Book 的形式体现)

2.凡是对BookStorage 做改动,我们都需要把数据,写一份到文件中(指定路径)

3.规定格式:思考一个Book对象在文件中长什么样?

        暂且规定:每行一本书,书的属性之间用一个特殊字符(@)分割。这个成立的前提是,书名,作者名,类型名,借阅人的字符中不能出现 \n 和 @,否则不知道怎么去解读了。字符集编码必须是UTF-8。

三、小结

1.整体流程

从持久化存储中(文件)加载书籍信息 -> 以顺序表的形式进行呈现

通过用户登录 -> 当前登录用户对象(管理员用户 or 普通用户)

循环{

        根据不同的角色用户,显示不同的操作菜单(靠多态机制  <-  抽象类、继承、引用指向等等这些语法知识点一起来实现)

        让用户选择具体的操作 ->  得到当前要指向的命令

        执行命令,根据命令不同,执行不同的操作(靠多态机制 <- 接口、继承、引用指向等等这些语法知识点一起来实现)

}

对于我们input 对象来说,由于在用户登录、用户选择命令、执行命令时都要用到input 对象,因此,①从性能角度来说,没必要每个地方都建立一个独立的input 对象 ②有时候在代码的不同位置,需要共享一些信息的时候。所以我们有一个公共的input 对象就够了,别人只负责去使用就好了。我们的Input 对象,全局只有一个;User 对象(当前登录用户),全局只有一个BookStorage 对象(图书管理系统的书架)全局只有一个。

2.ListBookOrderByXXXCommand

①模板设计模式:父类(抽象类)实现了 execute 方法:使用操作的模板       

        a.获取外部比较器对象   (留给子类们去实现)

        b.获取所有书籍信息

        c.根据比较依据排序

        d.展示列表

多态 为 模板设计模式 提供了底层服务(没有多态,就做不到 模板设计模式)

        抽象类、继承、方法的重写、引用的指向等语法基础,为实现多态,提供了底层服务

②深入应用了对象的比较 Comparable or Comparator

③代码风格       printBook的代码全部抽象到 Book.toString 中,从面向对象的角度来讲,职责封装更合理。这些代码语句,放到哪里都能执行,但是放到合适的类、合适的方法中,让程序员看起来,层次分明,层次划分的更清楚(封装概念的体现)

④属性对象逃逸(逃逸有风险)

3.匿名类对象语法知识点

public class ListBookOrderByBorrowedCommand extends AbsListBookCommand{
   private static class BorrowedComparator implements Comparator{

       @Override
       public int compare(Object o1, Object o2) {
           Book b1 = (Book) o1;
           Book b2 = (Book) o2;

           int br1 = b1.borrowedBy == null ? 0 : 1;
           int br2 = b2.borrowedBy == null ? 0 : 1;

           return br1 - br2;  //没被借走的比较小,在上面,被借走的在下面
       }
   }

   private final Comparator comparator = new BorrowedComparator();

BorrowedComparator类,这个类,只使用了一次,创建了一个comparator对象。理论上,再也不会用到这个类了。可以用匿名类对象的语法替换,好处:1.不用再花心思为类起名字了。2.从语法角度,保证了确实没有其他地方用到这个类了。3.代码可以短一点。

改进后:

public class ListBookOrderByBorrowedCommand extends AbsListBookCommand{
    private final Comparator comparator = new Comparator() {
       @Override
       public int compare(Object o1, Object o2) {
           Book b1 = (Book) o1;
           Book b2 = (Book) o2;

           int br1 = b1.borrowedBy == null ? 0 : 1;
           int br2 = b2.borrowedBy == null ? 0 : 1;

           return br1 - br2;  //没被借走的比较小,在上面,被借走的在下面
       }
   };

new 父类( ... ) { }; ①定义一个类(没有名字,所以称为匿名类),这个类继承(实现)了父类。②直接用这个类实例化一个对象出来。

4.类和对象(面向对象设计)

输入对象(Input)                          整个应用只需要一份

用户存储对象(UserStorage)       整个应用只需要一份

当前登录用户对象(User:AdminUser、CommonUser   也可以添加其他的对象)     整个应用只需要一份

书架管理对象(BookStorage)       整个应用只需要一份

书籍管理对象(Book)                    用到的时候创建

命令对象(实现了 IExecutable 的很多 XXXCommand 对象)           理论上:整个应用只需要一份,每个用户子类中独立一份 

四、完整代码


 详情请看

零七/图书馆管理系统 - Gitee.comhttps://gitee.com/hlingqi/library-management-system/tree/master/out/production/%E5%9B%BE%E4%B9%A6%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9FIDEA

  • 6
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值