图书管理小练习

发布于:2023-01-20 ⋅ 阅读:(12) ⋅ 点赞:(0) ⋅ 评论:(0)

图书管理小练习

前言: 本文 将 结合 类和对象, 封装 继承 ,多态, 抽象类, 以及 接口 来完成 一个图书 管理小练习 。

1.构建框架

我们 要明白一个道理 , 不管 干什么 都需要 一个大致的 框架 或 大致的 目标 ,如 人生一样, 不能 想到啥 做啥 ,而是 有一定的 规划 我们 才能 按照 这个规划 走下去,而不是 走到下 想到哪 。

正如 此 我们 想要完成 一个 图书 管理 小练习, 那么 我们 是不是 可以想到 书 , 书架 , 以及 我们的 管理 员 最后 还有我们的 用户 这几个 对象 ,

这里我们就 创建 了 两个 包 ,存放 在 BookExercise 这 包中 、

在这里插入图片描述

1.1Book 底下的 图书 类 和 书架类


下面 就 在 Book 包中 创建 我们 的 书 , 和 书架。

在这里插入图片描述

这里 我们 的 Book 是 书 里面的 属性 是 我们 书的 相关 属性 ,如 : 作者 , 书的 价钱 , 书 的 类型(如 : 小说 , 教材 等) , 这本书 是否 被 借出,

下面 就来 创建我们的 书 : 为了 体现我们的 封装 , 我们的 字段 都使用 private 修饰 ,提供 特有 的 get 和 set 方法, 这里 就可以 通过我们的 构造 方法 来 为这些 字段 赋值 , 但 是否借出 ,可以 不通过 构造 方法 赋值 , 默认 这本 书 是 没有被 借出的。

注意: 别 想 憨憨 一样 自己 手敲 ,之前 介绍 过 编译器 通过 快捷 键生成 set 和 get 方法 , 以及 构造 方法 ,最后 还可以 重写 我们 的 toString 方法(打印我们 书 的 信息 )。
在这里插入图片描述

Bookpublic class Book {

    private  String name; // 书名
    private  String author; // 作者
    private int price; // 价格
    private String type; // 类型
    private boolean isBorrowed;// 是否借出
    // 这个 可以不用 写进 toString, new 一个 isBorrowed 默认没有借出

    给定 普通成员变量。 封装起来 给定 特有 的get 和 set 方法

   // 构造方法


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

最后 你会 发现 你就 随便 一点 , 就 完成了 50 - 60 行 代码 。下面继续

图书 的 基本 信息 有了 ,那么我们 就需要 创建我们 存放 图书 的 书架 了 。

第一步 :创建 一个 BookList 类 , 当作我们的 书架 (这里我们 采用 顺序表 )

在这里插入图片描述


第二步 : 创建 一个 对象 数组 (里面 是 对象 的 地址) , 用来 存放 我们 的 图书 ,

在这里插入图片描述


同样为了 体现 封装 性 我们 通过 关键字 private 将 这个 数组 封装起来 后面 通过 我们的 get 和 set 方法 来 获取 和 设置 这个 数组 即可 。


有了 数组 , 我们 是不是 要想 , 如果 计算 这个 数组 中 存放 的 图书 数量 呀 , 这里 我们就可以 创建 一个 size 变量 ,添加 一本书 ,就 让 size++ , 删 出 一本书 就 让 size-- ,同样 我们 也将这个 变量被 private 修饰 。

在这里插入图片描述

这里 就 完成 我们 书架 的 一大半了, 为了 好看 我们现在 书架 中 存放 3 本书 (既然 是 图书 馆 ,咋可能没有 书 呢?), 这里 我们 有两种 方法 存放 这 三本书 , 一 通过 方法 , 二 通过 构造 方法 。

方法 一: 通过 方法

在这里插入图片描述

方法 二 : 通过 构造 方法 (注意 size 需要 赋值 ,这里 就说明 书架中 已有 3 本书 )。

在这里插入图片描述


想一想 这两种 方法 哪一种 好 呢 ?

我觉得 第二种 好点 , 你想 ,我们 创建 对象时 , 就是 通过 构造方法 来 创建, 这时 构造方法, 就 将 三本书 放进 了 书架 , 而 第一种 ,我们 创建 对象 后,还需要 对象 取调用 func方法 , 多了 一步, 所以 第二种 好点 。


附上代码: BookList 类

public class BookList {
    // 书架  存放 书的 类 。

   private  Book[] books = new Book[10];
   private int size = 0;

   // 通过 getPos 获取当前 pos 位置的 书
   public Book getPos(int pos) {
      return books[pos];
   }

   // 设置 pos 位置 放一本书
   public void setBook(int pos,Book book) {
      this.books[pos] = book;
   }

   public int getSize() {
      return size;
   }

   public void setSize(int size) {
      this.size = size;
   }
//   public void func(){
//      books[0] = new Book("三国演义","罗贯中",17,"小说");
//      books[1] = new Book("西游记","吴承恩",47,"小说");
//      books[2] = new Book("水浒传","施耐庵",37,"小说");
//
//      this.size = 3;
//   }

   public BookList() {
      books[0] = new Book("三国演义","罗贯中",17,"小说");
      books[1] = new Book("西游记","吴承恩",47,"小说");
      books[2] = new Book("水浒传","施耐庵",37,"小说");
      this.size = 3;
   }
}

书 和 书架 我们 完成了 , 那么 就来 看看我们的 User包底下 的 管理员 和 用户 是如何写的 。

1.2 User 底下的 管理员类 和 用户类


场景构造 : 想一想我们 的 管理员 和 用户 ,分别 在 图书 馆 中 有 的 权限 ,

管理员: 添加图书 , 删除 图书, 查找 图书 ,显示 全部图书。 最后 还有 一个 退出系统(用来 退出 整个 程序 )

用户: 查找 图书 , 借阅 图书 , 归还 图书 ,退出系统。

此时 我们 就 将 我们 管理员 和 用户 的 所有 权限 给 列举出来 (这些 权限 也就是 我们 后面需要实现的 功能) ,还有 其他的功能 可以 自行 补充 ,


这里我们 就来 实现 一下我们 的 管理员 类 , 和 用户 类 。

在这里插入图片描述


这 里 我们 需要 创建 三个 类 , 一个 管理员 , 一个 普通 用户 ,还有 一个 共同的 父类 存放 我们 的字段 如: 姓名 。

另外 通过 这 个 父类 我们 还可以 实现 (向上转化 , 动态绑定 ,多态)等 操作。

这里 我们 就需要 一个 目录 将上面这些 功能 全部 罗列 出来 让 管理员 或 用户 进行 选着 。

在这里插入图片描述


这里我们 就 将 父类 User 中的 menu 写成我们的 抽象方法 , 那么 User 就 是我们的 抽象类 (这 就 将我们学习的 抽象类 给 用到了)
在这里插入图片描述

有了 普通 用户 , 和 管理员 ,那么我们 需要 如何调用 呢 ?

下面 就来 演示 一下:
在这里插入图片描述


下面 就 根据 选着 来 调用 相应 的 类 , (1. 管理员 or 0 . 普通用户)

在这里插入图片描述

这里 就 可以 得到 我们 需要的 对象。 那么 这里 我们 需要那 什么作为返回值 呢 ?

想一想 ,提示向上转型 。

这里 我们 能否想到 之前 讲到 过的 向上 转型 , 这是 第三种 方法 ,通过 返回值 实现 向上转型 ,完成 了 我们的 父类 引用 引用 了 子类对象 。

在这里插入图片描述

在这里插入图片描述

这里 就完成了 我们 对 这两个类 的 引用 。

这里我们 只 实现 了 我们 的 目录 , 下面就来 实现我们的 方法 。

1.3 管理员 and 用户 对应 方法串联


这些 方法 我们 可以 在 BookList 中 实现 , 但 我们 毕竟 是 要将 之前 学习 的 知识 串起来, 那么我们 就通过 接口, 和 类 来 实现 我们的 方法,

这里 就创建 第三个 包 :operation 用来 存放 我们 实现 的 方法(如 : 新增 图书 , 删除 图书 等 )。

在这里插入图片描述

这里 我们 就 将 全部 方法 的 类创建 出来了 ,可以 看到 还有 一个 接口 , 这个 接口 非常 关键 后面 你就能 明白了 。

在这里插入图片描述

补: Add: 增加 图书 , Boorow : 借阅图书 , DelOperation : 删除 图书 , DisplayOperation : 打印图书 或 显示 图书

ExitOperation : 退出系统 FindOpeation : 查找 图书 ReturnOperation : 归还 图书 。

有了上面 的 方法 我们就来 实现 一下 。

但有 一点我们需要 注意 , 这里 我们 需要 让每个 类实现我们的 接口Ioperation 然后 实现接口 中 的 抽象 方法 work 在重写的 work 中 实现我们的 方法 逻辑 , 如添加元素,删除 元素 。 为啥 呢 ?

这个 我们想 通过接口 是不是 可以完成 向上 转向 ,然后 通过 一个 work 方法 调用 这些 类 的work 方法 (这里 就 发生 了 动态绑定 和 多态)。 就 不需要 左一个方法 ,右一个 方法 ,方便我们的 调用 。

在这里插入图片描述

这里 我们 先 完成 这些 方法 , 方法 的 实现 的 逻辑下面在完成 ,先 将 这些 东西 串起来。

此时 我们 就来 想 如何 才能 调用 到 相对 的 方法 ,如 : 管理员 调用 管理员 所用有的 权限 ,普通用户 调用 所有 的权限 。

我们 知道 对象 数组, 数组 中存放 的是 我们 对象的 地址,通过 下标 来访问 对应 的 对象 ,那么 能不能 让 接口 成为 一个 数组 ,然后 存放 管理员 ,和 普通用户相对 的 方法 呢?

这里就来 尝试 一下 。

注意:我们 管理员 类 和 普通 用户类 都拥有 这个 对象 数组, 这就算 一个共性 ,我们就可以定义到 父类 User 中 ,然后 在考虑其他 。

在这里插入图片描述


这个数组 我们 就定义 好 了, 接下来 就需要考虑, 这个数组 的 內部 所含的 对象 了 。


如:

管理员: 添加图书 , 删除 图书, 查找 图书 ,显示 全部图书。 最后 还有 一个 退出系统(用来 退出 整个 程序 )

这里 , 添加图书算一个 对象, 那么 我们就通过 new 类名创建 一个对象放入 这个 数组 当中,其他类似。

在这里插入图片描述

这样是不是 就通过 我们的 构造方法, 将 这些 方法全部 存放到我们的 ioperation 数组当中 , 这里 我们 的方法 需要 对着我们目录提供的 顺序 哦。

注意:我们一次 只能 选着 管理员 或 普通成员 ,所以 这个 ioperation 数组 只会 初始化一次。

那么同理 用户 也是 这样的

用户: 查找 图书 , 借阅 图书 , 归还 图书 ,退出系统。

在这里插入图片描述


下面 就来使用 一下,

在这里插入图片描述

可以看到我们就成功 的调用了 方法,但还是 有很大的 问题 。

第一: 我们 的目录 只能看 ,难以 选择选择相对 的 方法 。

那么 我们 能不能 优化 现在的 代码呢?

其实 非常简单,我们 只需要在目录 方法 里 面 添加 输入 语句 即可。
在这里插入图片描述

下面 就来 使用 一下 :

在这里插入图片描述

这里还有一些东西没有完成 ,下面我们 先来实现 一下我们 的 方法 。 在回头来看一下 。

2.管理员 and 用户 方法 实现

注意 : 我们 之前 的work 方法 中 没有写 参数 , 并非是 不要参数, 你想一想, 我们 是不是需要 对书架进行 操作,添加 图书 ,删除 图书 等 , 那么是不是 需要 添加 一个 BookList 类型的参数 呢 ???

2.1Add - 添加 图书


在 添加 图书 的需要 注意 一个 小细节 : 如果 我们 先 输入 数字 在输入 字符串 这里 就会出现 问题,(这个问题 在逻辑 控制那篇文章 特意 讲过)

如: 这里我们输入 一个 20 就会直接 退出程序 而我们的 str 什么 都没 赋值,

在这里插入图片描述


此时 我们 通过 调式能知道 这里 str会拿到上一行 输入 数字的换行符 空 , 所以我们 什么输出不了 ,也无法 赋值, 这里 的 解决方式就可 在 写一个 sc.nextLine()将 这个 换行符 吸收 。

在这里插入图片描述

在这里插入图片描述

附上代码:

public class Add implements Ioperation {
    @Override
    public void work(BookList bookList) {
        // 添加 图书 。
        System.out.println("新增 图书 ");
        System.out.println("新增 图书 的 名字");
        String name = sc.nextLine();
        System.out.println("新增 图书的 作者");
        String author = sc.nextLine();

        System.out.println("新增 图书的 价格");
        double price = sc.nextDouble();
        // 吸收 赋值price 的 换行符
        sc.nextLine();
        System.out.println("新增 图书的 类型");
        String type = sc.nextLine();
        Book book = new Book(name, author, price, type);
        // 判断是否 需要 扩容。
        bookList.func();
        // 拿到 当前 size 的 大小。
        int size = bookList.getSize();
        // 因为我们 的数组  封装起来了 ,提供 了 特有的 方法 让他添加 图书 ,这里就 通过这个方法
        //完成我们的 图书 的添加 
        bookList.setBooks(size, book);
        // 此操作为更新 图书 
        bookList.setSize(size + 1);
        System.out.println("新增图书成功");
    }
}

2.2 Borrow - 借阅图书

我们 的 借阅图书 , 非常简单 只需要 , for循环 在 书架 中 找 通过 equals 对象 比较 如果 相同 返回 true , 找到 了 我们 就 将 isBorrowed 设为 true 即可 true表示 这本书 已被借出

public class Borrow implements Ioperation {
    @Override
    public void work(BookList bookList) {
        // 借阅 图书 。
        // 1.判断 该图书是否 存在 ,或 是否 被 借出 。
        System.out.println("借阅 图书 区 ");
        System.out.println("输入 想要 借阅 图书 的 名字");
        String name = sc.nextLine();
        int size = bookList.getSize();
        for (int i = 0; i < size; i++) {
            // 通过  我们 设计  方法 拿到 当前 i 位置 的 图书 ,
            Book book = bookList.getBooks(i);
            if (book.getName().equals(name)) {
                // 此时 说明找到了 我们需要的 书 。
                if (book.getisBorrowed()) {
                    System.out.println("该图书 已被借出  ");
                } else {
                    book.setBorrowed(true);
                    System.out.println("借阅成功");
                    System.out.println(book);
                }

            }
        }
        System.out.println("本 图书 馆没有 此 书");

    }
}

2.3 DelOperation - 删除 图书

在这里插入图片描述

那么 删除 我们的 图书 不也一样吗 ,现在 数组中 找到 要删除 图书的 下标 ,然后 不就 更 上面 一样 了 ,直接 覆盖 就好 。

public class DelOperation implements Ioperation {
    @Override
    public void work(BookList bookList) {
        // 删除图书。
        System.out.println("删除 图书 ");
        System.out.println("输入 要删除 的 图书 名字");
        String name = sc.nextLine();

        // 顺序表 删除  挪位子。
        int index = 0;
        int size = bookList.getSize();
        int i = 0;
        for (i = 0; i < size; i++) {
            // 通过 getBooks 拿到我们的 i 位置的 下标
            Book book = bookList.getBooks(i);
            if (book.getName().equals(name)) {
                // 这里 不考虑 重复 的 书 ,只删除 第一本。
                index = i;
                //拿到 下标我们就 直接 退出 循环 即可
                break;
            }
        }
        // 如果  i 大于我们 的 图书 的 数量 ,那么 就说明 没有找到我们的 图书 
        if (i >= size) {
            System.out.println("没有你要删除的 图书");
            return;
        }

        for (int j = index; j < size - 1; j++) {
            // 拿到 j + 1 本 书
            Book book = bookList.getBooks(j + 1);
            bookList.setBooks(j, book);
        }
        // 将 最后 一本 书 置为 空, 要不 会 出现 内存 泄露
        bookList.setBooks(size - 1, null);
        bookList.setSize(size - 1);
        System.out.println("删除 成功");

    }
}

2.4 DisplayOperation - 显示 图书

public class DisplayOperation implements Ioperation {

    public void work(BookList bookList) {
        // 打印 图书  / 显示 图书

        System.out.println("显示 全部 图书");
        int size = bookList.getSize();
        for (int i = 0; i < size; i++) {
            Book book = bookList.getBooks(i);
            System.out.println(book);
        }
    }
}

2.5 ExitOperation - 退出 系统

public class ExitOperation implements Ioperation{
    @Override
    public void work(BookList bookList) {
        System.out.println("退出 程序");
        // 这里 exit(0) 表示正常 退出 系统
        System.exit(0);
    }
}

2.6 FindOperation - 查找图书

public class FindOperation implements Ioperation {

    @Override
    public void work(BookList bookList) {
        // 查找 图书

        System.out.println("查找 图书 区 ");
        System.out.println("输入 要查找 的 图书 ");
        String name = sc.nextLine();
        int size = bookList.getSize();
        for (int i = 0; i < size; i++) {
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)){
                System.out.println("找到此书,信息如下");
                System.out.println(book);
                return;
            }
        }
        System.out.println("未 查找到 此 书");
    }
}

2.7 ReturnOperation - 归还图书

public class ReturnOperation implements Ioperation{
    @Override
    public void work(BookList bookList) {
        // 归还 图书 ,
        System.out.println("归还 图书 区");
        System.out.println("请输入你要归还图书的名字");
        String name = sc.nextLine();
        int size = bookList.getSize();
        for(int i = 0;i<size;i++){
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)){
                // 将原本 借出 图书 的 true 置为  false
                book.setBorrowed(false);
                System.out.println("归还成功 !!!");
                System.out.println(book);
                return;
            }
        }
        System.out.println("此 书 不是 本 图书 馆 ,归还 失败");
    }
}

上面 我们 的功能 就完成了,这里我们只是 简单的完成 ,还有很多情况 没有考虑, 如: 删除的 书 有很多本此时就 只能删除一本, 如扩容 等


最后 我们 就来 完成最后 的 步骤 。

在这里插入图片描述

一开始 我们 是 这样 完成我们 的 方法调用 ,这 里 我们 就可以 简化 成 一个 User 类 中 的 一个 方法 即可 , 方便 还 易懂。

这样就完成了 我们 的 图书 管理小练习。

在这里插入图片描述

最后我们 将我们 的 操作 换成 循环 就能 使用多个方法 。

在这里插入图片描述

但 最后我们 还有 一个 细节 每 弄 就是 图书 是否被 借出 , 这里 就可以 使用 三目运算符 ,来判断 如果 isBorrowerd 为 true 就说明 被 借出 , 为false 就 说明 没被 借出 。

在这里插入图片描述

这里 图书 管理 小练习 就 完成了 。

下文预告: String类的 常见 方法使用、


网站公告

欢迎关注微信公众号

今日签到

点亮在社区的每一天
签到