当前位置: 首页 > news >正文

图书管理系统——Java实现

文章目录

  • Java实现图书管理系统
    • 问题分析
    • 框架搭建
    • 业务实现
    • 项目测试
    • 代码演示
      • Book
      • ioperation
      • User
      • Main(默认包)

Java实现图书管理系统

学习了前六篇的SE语法,我们现在要用它们实现一个简单的图书管理系统项目,深入了解各个知识点的应用场景。我们将整个过程分为四大部分:

  • 问题分析
  • 框架搭建
  • 业务实现
  • 项目测试

其中,框架搭建最为重要且难以理解,涉及类、接口等之间的复杂关系。


问题分析

我们期望实现一个不同身份操作界面不同的图书管理系统。

而要使用面向对象的思想实现该项目,第一步肯定是找对象

初步分析,我们的项目会包含以下对象:

  1. :书的属性
  2. 用户:用户又分为普通用户和管理员

单一的书对象太过分散不好维护,所以我们决定添加一个新类书架,书架中有若干的书对象,我们后期操作的对象就是书架。

(以下所有代码块的内容不一定是完成版,我们会在解决问题的过程中不断改进之前的代码)


【书、书架】

我们先实现书类

其中,我们用private修饰书类的成员变量,尽可能体现Java的封装性,同时添加getset方法;

图书系统少不了图书信息的打印,为了方便打印,我们选择重写toString方法,注意boolean类型的打印,它指示书的借阅情况,如果仅打印truefalse,不利于用户理解,所以我们做出一些改动如下代码中可见:

//Book.java
package Book;public class Book {private String name;//书名private String author;//作者private double price;//价格private String kind;//类型private boolean borrow;//借阅情况//构造方法public Book(String name, String author, double price, String kind) {this.name = name;this.author = author;this.price = price;this.kind = kind;}//get、set方法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 getKind() {return kind;}public void setKind(String kind) {this.kind = kind;}public boolean isBorrow() {return borrow;}public void setBorrow(boolean borrow) {this.borrow = borrow;}//重写toString@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", kind='" + kind + '\'' +" " + (borrow == true ? "已借阅" : "未借阅") +'}';}
}

接下来是书架

书架里有若干书,书架与书的关系是:A has B的关系,所以我们考虑到使用组合

仍然使用private修饰成员变量,并给出getset方法。

//BookList.java
package Book;public class BookList {private Book[] books = new Book[10];//组合private int size;//书的数量//构造方法初始化书架public BookList() {//初始给两本书this.books[0] = new Book("三国演义", "罗贯中", 23, "小说");this.books[1] = new Book("红楼梦", "曹雪芹", 23, "小说");this.size = 2;}public Book getBook(int pos) {return this.books[pos];}public void setBook(Book book) {this.books[this.size] = book;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public Book[] getBooks() {return this.books;}
}

【用户】

分析: 用户分为两种,管理员和普通用户,符合A is B的关系,即普通用户或管理员是用户,所以用户部分可以实现继承关系,将两种身份的共性进行抽取,简化代码。

用户类

实际上,我们并不会实例化一个用户的对象,因为用户要指名身份,所以我们考虑将User类设计成抽象类

并将其成员变量尽可能地封装。

//User.java
package User;
import Book.BookList;
import ioperation.IOperation;public abstract class User {public String name;//构造方法public User(String name) {this.name = name;}}

普通用户管理员的代码类似,我们一并实现:

//AdminUser.java
package User;
import ioperation.*;
import java.util.Scanner;public class AdminUser extends User {//构造方法先利用super初始化父类成员public AdminUser(String name) {super(name);}
}
//NormalUser.java
package User;
import ioperation.*;
import java.util.Scanner;public class NormalUser extends User {//构造方法先利用super初始化父类成员public NormalUser(String name) {super(name);}
}

到这里,我们实现了几个基本的类,后续也会一一完善,问题分析告一段落,我们直接进入框架搭建模块,这里是项目的难点。


框架搭建

我们先模拟一下项目执行过程:

程序启动 ——> 用户输入信息(登录) ——> 程序根据用户身份展示不同的操作页面 ——> 用户输入操作 ——> 程序执行 ——> … …

——> 程序终止

基于上面的模拟过程,我们开始一步一步搭建框架:


在已有实现类的基础上,我们先实现登录的逻辑,自定义方法名:login

这部分是我们框架的开始,是用户最先看到的画面,我们期望登陆方法能够:

  • 实现用户选择身份的交互
  • 返回可操作的对象:返回值有两种情况,而返回的对象的类共同继承了User类,所以我们选择将方法返回值设置成User类,这里即体现了向上转型
    public static User login() {System.out.println("请输入您的名字:");Scanner scanner = new Scanner(System.in);String name = scanner.nextLine();System.out.println("请输入您的身份:1. 管理员  2. 普通用户");int choice = scanner.nextInt();if(choice == 1) {return new AdminUser(name);}else {return new NormalUser(name);}}

我们拿到了用户身份,接下来我们要据此给出相应的菜单:

不同的身份,打印不同的菜单,符合多态的思想:

我们在父类中定义抽象方法menu,两个子类重写menu方法,然后用父类引用访问重写后的menu方法,即可实现多态:

关于menu方法,我们不只期望它可以打印菜单,我们期望它打印菜单的同时可以与用户交互,拿到用户的选择并返回等待进一步的操作。(菜单的打印自行发挥,菜单中的操作就是后面要实现的业务)

  1. 拓展父类User

    //User.java
    package User;
    import Book.BookList;
    import ioperation.IOperation;public abstract class User {public String name;public User(String name) {this.name = name;}//待重写的抽象方法public abstract int menu();
    }
    
  2. 子类AdminUserNormalUser重写menu方法

    //AdminUser.java
    package User;
    import ioperation.*;
    import java.util.Scanner;public class AdminUser extends User {public AdminUser(String name) {super(name);}@Overridepublic int menu() {System.out.println("欢迎" + this.name + "使用图书管理系统");System.out.println("********管理员菜单********");System.out.println("*************************");System.out.println("******* 1.添加图书 *******");System.out.println("******* 2.删除图书 *******");System.out.println("******* 3.查找图书 *******");System.out.println("******* 4.展示图书 *******");System.out.println("******* 0.退出系统 *******");System.out.println("*************************");Scanner scanner = new Scanner(System.in);System.out.println("请输入您的操作:");int choice = scanner.nextInt();if(choice < 0 || choice > 4) {return -1;}return choice;}
    }
    
    //NormalUser.java
    package User;
    import ioperation.*;
    import java.util.Scanner;public class NormalUser extends User {public NormalUser(String name) {super(name);}@Overridepublic int menu() {System.out.println("欢迎" + this.name + "使用图书管理系统");System.out.println("********普通用户菜单********");System.out.println("*************************");System.out.println("******* 1.查找图书 *******");System.out.println("******* 2.借阅图书 *******");System.out.println("******* 3.归还图书 *******");System.out.println("******* 0.退出系统 *******");System.out.println("*************************");Scanner scanner = new Scanner(System.in);System.out.println("请输入您的操作:");int choice = scanner.nextInt();if(choice < 0 || choice > 3) {return -1;}return choice;}
    }
    

此处暂停,我们梳理一下我们已经实现的逻辑:

体现在Main类中的main方法中:

//Main.java
import Book.BookList;
import User.*;
import java.util.Scanner;public class Main {//登录方法public static User login() {System.out.println("请输入您的名字:");Scanner scanner = new Scanner(System.in);String name = scanner.nextLine();System.out.println("请输入您的身份:1. 管理员  2. 普通用户");int choice = scanner.nextInt();if(choice == 1) {return new AdminUser(name);}else {return new NormalUser(name);}}//main方法public static void main(String[] args) {//创建书架BookList bookList = new BookList();//登录并确定用户类型返回User user = login();while (true) {//根据用户类型打印菜单并返回用户操作选择int choice = user.menu();if(choice < 0) {System.out.println("输入非法,请重新输入!");}else {//根据用户选择执行相关操作//......}}}
}

最后一部分逻辑,也是最难理解的一部分:根据用户选择调用指定操作

我们当然可以选择在Main类中一次性实现所有的操作方法并调用,但这样书写代码的缺陷是非逻辑代码大量集中,不方便维护,同时也没有利用Java的优点。

我们给出下面的解决方案:

  1. 创建一个接口,规范所有操作
  2. 创建若干操作类,实现规范接口

创建规范接口

//IOperation.java
package ioperation;
import Book.BookList;public interface IOperation {//工作方法void work(BookList bookList);
}

根据菜单创建若干的操作类(这里仅给出逻辑代码,具体的操作在 业务实现 模块实现)

//AddOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class AddOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("添加图书...");}
}//DelOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class DelOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("删除图书...");}
}//FindOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class FindOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("查找图书...");}
}//ShowOperation.java
package ioperation;
import Book.*;public class ShowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("展示图书...");}
}//BorrowOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class BorrowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("借阅图书...");}
}//ReturnOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class ReturnOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("归还图书...");}
}//ExitOperation.java
package ioperation;
import Book.BookList;public class ExitOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("退出系统...");}
}

仅实现以上代码并不能将用户(login方法返回值)、用户选择(menu方法返回值)、操作(上代码)联系起来

我们采取这样的解决方案:

  • 在父类User中添加成员变量,其类型是IOperation[]
  • 分别使子类AdminUserNormalUser的构造方法可以初始化父类的IOperation[]类型的成员,这样,我们在实例化子类对象时,就构建好了这样一个数组
  • 在父类User中创建操作方法,父类引用调用此方法,并在此方法中再调用指定操作类中的重写方法
  • 我们的项目的各种操作都是针对BookList(书架)的,所以我们的参数列表要大量出现BookList类对象

完善后的父类User

//User.java
package User;
import Book.BookList;
import ioperation.IOperation;public abstract class User {public String name;protected IOperation[] iOperations;//新添成员变量public abstract int menu();public User(String name) {this.name = name;}//新添操作方法public void doOperation(int choice, BookList bookList) {this.iOperations[choice].work(bookList);}
}

完善后的子类

//AdminUser.java
package User;
import ioperation.*;
import java.util.Scanner;public class AdminUser extends User {public AdminUser(String name) {super(name);//根据管理员菜单进行初始化this.iOperations = new IOperation[]{new ExitOperation(),new AddOperation(),new DelOperation(),new FindOperation(),new ShowOperation(),};}@Overridepublic int menu() {System.out.println("欢迎" + this.name + "使用图书管理系统");System.out.println("********管理员菜单********");System.out.println("*************************");System.out.println("******* 1.添加图书 *******");System.out.println("******* 2.删除图书 *******");System.out.println("******* 3.查找图书 *******");System.out.println("******* 4.展示图书 *******");System.out.println("******* 0.退出系统 *******");System.out.println("*************************");Scanner scanner = new Scanner(System.in);System.out.println("请输入您的操作:");int choice = scanner.nextInt();if(choice < 0 || choice > 4) {return -1;}return choice;}
}
//NormalUser.java
package User;
import ioperation.*;
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()};}@Overridepublic int menu() {System.out.println("欢迎" + this.name + "使用图书管理系统");System.out.println("********普通用户菜单********");System.out.println("*************************");System.out.println("******* 1.查找图书 *******");System.out.println("******* 2.借阅图书 *******");System.out.println("******* 3.归还图书 *******");System.out.println("******* 0.退出系统 *******");System.out.println("*************************");Scanner scanner = new Scanner(System.in);System.out.println("请输入您的操作:");int choice = scanner.nextInt();if(choice < 0 || choice > 3) {return -1;}return choice;}
}

框架最后一步:完善main方法:

//Main.java
import Book.BookList;
import User.*;
import java.util.Scanner;public class Main {public static User login() {System.out.println("请输入您的名字:");Scanner scanner = new Scanner(System.in);String name = scanner.nextLine();System.out.println("请输入您的身份:1. 管理员  2. 普通用户");int choice = scanner.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();if(choice < 0) {System.out.println("输入非法,请重新输入!");}else {//根据用户选择执行相关操作user.doOperation(choice, bookList);}}}
}

业务实现

完成了框架搭建,业务实现就简单多了,业务实现仅需要将实现操作接口的操作类的重写方法完善即可。

【添加图书】

判断书架是否满 ——> 判断新书是否重复 ——> 添加

//AddOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class AddOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("添加图书...");//判断书架是否已满int size = bookList.getSize();if(size == 10) {System.out.println("书架满了...");return;}Book[] books = bookList.getBooks();Scanner scanner = new Scanner(System.in);//判断新书是否重复System.out.println("请输入书名;");String name = scanner.nextLine();for (int i = 0; i < size; i++) {if(name.equals(books[i].getName())) {System.out.println("已存在这本书!");return;}}System.out.println("请输入作者:");String author = scanner.nextLine();System.out.println("请输入价格:");int price = scanner.nextInt();//这里要注意,要读走回车,否则类型kind接受的是回车//或者让用户先输入类型,也可以解决这一问题String tmp = scanner.nextLine();System.out.println("请输入类型:");String kind = scanner.nextLine();Book book = new Book(name, author, price, kind);bookList.setBook(book);bookList.setSize(size + 1);}
}

【删除图书】

判断书架是否为空 ——> 寻找指定图书 ——> 根据寻找结果进行相关操作

//DelOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class DelOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("删除图书...");//判断书架是否为空int size = bookList.getSize();if(size == 0) {System.out.println("书架为空!");return;}//输入信息Scanner scanner = new Scanner(System.in);System.out.println("请输入您要删除的书名:");String name = scanner.nextLine();//删除Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {books[i] = null;for (int j = i; j < size - 1; j++) {books[j] = books[j + 1];}bookList.setSize(size - 1);System.out.println("删除成功!");return;}}System.out.println("没有查询到指定的书!");}
}

【查找图书】

输入信息 ——> 查找 ——> 成功则打印

//FindOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class FindOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("查找图书...");int size = bookList.getSize();Scanner scanner = new Scanner(System.in);System.out.println("请输入您要查询的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {System.out.println("查找成功,信息如下:");System.out.println(books[i].toString());return;}}System.out.println("没有查询到指定的书!");}
}

【展示图书】

判断书架是否为空 ——> 展示图书

//ShowOperation.java
package ioperation;
import Book.*;public class ShowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("展示图书...");int size = bookList.getSize();if(size == 0) {System.out.println("书架为空!");return;}Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {System.out.println(books[i].toString());}}
}

【借阅图书】

输入信息 ——> 查找图书 ——> 借阅成功或失败(借阅成功,将Book对象的borrow成员设置成true即可)

//BorrowOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class BorrowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("借阅图书...");int size = bookList.getSize();Scanner scanner = new Scanner(System.in);System.out.println("请输入您要借阅的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {if(!books[i].isBorrow()) {System.out.println("借阅成功!");books[i].setBorrow(true);return;}else {System.out.println("该书已被借阅!");return;}}}System.out.println("没有查询到指定的书!");}
}

【归还图书】

输入信息 ——> 检查借阅情况 ——> 归还或打印其他信息(归还成功,将Book对象的borrow成员设置成false即可)

//ReturnOperation.java
package ioperation;
import Book.*;
import java.util.Scanner;public class ReturnOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("归还图书...");int size = bookList.getSize();Scanner scanner = new Scanner(System.in);System.out.println("请输入您要归还的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {if(!books[i].isBorrow()) {System.out.println("这本书还没有被借阅呢,无法归还,请检查是否输入错误!");return;}else {System.out.println("归还成功!");books[i].setBorrow(false);return;}}}System.out.println("没有查询到指定的书!");}
}

【退出系统】

//ExitOperation.java
package ioperation;
import Book.BookList;public class ExitOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("退出系统...");System.exit(0);}
}

项目测试

【登录测试】

在这里插入图片描述
在这里插入图片描述


【操作演示(部分)】

在这里插入图片描述

其他操作均可正常运行,大家下来可以自己实现一下。


代码演示

演示代码分布在多个包中:

  1. Book:包含书、书架对象
  2. ioperation:包含操作接口以及实现操作接口的类
  3. User:包含用户(父类)、管理员、普通用户类
  4. Main(默认包):代码总逻辑,使用上三部分代码

在这里插入图片描述

Book

//Book.java
package Book;public class Book {private String name;private String author;private double price;private String kind;private boolean borrow;public Book(String name, String author, double price, String kind) {this.name = name;this.author = author;this.price = price;this.kind = kind;}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 getKind() {return kind;}public void setKind(String kind) {this.kind = kind;}public boolean isBorrow() {return borrow;}public void setBorrow(boolean borrow) {this.borrow = borrow;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", kind='" + kind + '\'' +" " + (borrow == true ? "已借阅" : "未借阅") +'}';}
}//BookList.java
package Book;public class BookList {private Book[] books = new Book[10];private int size;public BookList() {//初始给两本书this.books[0] = new Book("三国演义", "罗贯中", 23, "小说");this.books[1] = new Book("红楼梦", "曹雪芹", 23, "小说");this.size = 2;}public Book getBook(int pos) {return this.books[pos];}public void setBook(Book book) {this.books[this.size] = book;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public Book[] getBooks() {return this.books;}
}

ioperation

//IOperation.java
package ioperation;import Book.BookList;public interface IOperation {void work(BookList bookList);
}//AddOperation.java
package ioperation;import Book.Book;
import Book.BookList;import java.util.Scanner;public class AddOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("添加图书...");int size = bookList.getSize();if(size == 10) {System.out.println("书架满了...");return;}Book[] books = bookList.getBooks();Scanner scanner = new Scanner(System.in);System.out.println("请输入书名;");String name = scanner.nextLine();for (int i = 0; i < size; i++) {if(name.equals(books[i].getName())) {System.out.println("已存在这本书!");return;}}System.out.println("请输入作者:");String author = scanner.nextLine();System.out.println("请输入价格:");int price = scanner.nextInt();//读走回车String tmp = scanner.nextLine();System.out.println("请输入类型:");String kind = scanner.nextLine();Book book = new Book(name, author, price, kind);bookList.setBook(book);bookList.setSize(size + 1);}
}//DelOperation.java
package ioperation;import Book.Book;
import Book.BookList;import java.util.Scanner;public class DelOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("删除图书...");int size = bookList.getSize();if(size == 0) {System.out.println("书架为空!");return;}Scanner scanner = new Scanner(System.in);System.out.println("请输入您要删除的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {books[i] = null;for (int j = i; j < size - 1; j++) {books[j] = books[j + 1];}bookList.setSize(size - 1);System.out.println("删除成功!");return;}}System.out.println("没有查询到指定的书!");}
}//FindOperation.java
package ioperation;import Book.*;import java.util.Scanner;public class FindOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("查找图书...");int size = bookList.getSize();Scanner scanner = new Scanner(System.in);System.out.println("请输入您要查询的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {System.out.println("查找成功,信息如下:");System.out.println(books[i].toString());return;}}System.out.println("没有查询到指定的书!");}
}//ShowOperation.java
package ioperation;import Book.BookList;
import Book.Book;public class ShowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("展示图书...");int size = bookList.getSize();if(size == 0) {System.out.println("书架为空!");return;}Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {System.out.println(books[i].toString());}}
}//BorrowOperation.java
package ioperation;import Book.Book;
import Book.BookList;import java.util.Scanner;public class BorrowOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("借阅图书...");int size = bookList.getSize();Scanner scanner = new Scanner(System.in);System.out.println("请输入您要借阅的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {if(!books[i].isBorrow()) {System.out.println("借阅成功!");books[i].setBorrow(true);return;}else {System.out.println("该书已被借阅!");return;}}}System.out.println("没有查询到指定的书!");}
}//ReturnOperation.java
package ioperation;import Book.Book;
import Book.BookList;import java.util.Scanner;public class ReturnOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("归还图书...");int size = bookList.getSize();Scanner scanner = new Scanner(System.in);System.out.println("请输入您要归还的书名:");String name = scanner.nextLine();Book[] books = bookList.getBooks();for (int i = 0; i < size; i++) {if(books[i].getName().equals(name)) {if(!books[i].isBorrow()) {System.out.println("这本书还没有被借阅呢,无法归还,请检查是否输入错误!");return;}else {System.out.println("归还成功!");books[i].setBorrow(false);return;}}}System.out.println("没有查询到指定的书!");}
}//ExitOperation.java
package ioperation;import Book.BookList;public class ExitOperation implements IOperation {@Overridepublic void work(BookList bookList) {System.out.println("退出系统...");System.exit(0);}
}

User

//User.java
package User;import Book.BookList;
import ioperation.IOperation;public abstract class User {public String name;protected IOperation[] iOperations;public abstract int menu();public User(String name) {this.name = name;}public void doOperation(int choice, BookList bookList) {this.iOperations[choice].work(bookList);}
}//AdminUser.java
package User;import ioperation.*;import java.util.Scanner;public class AdminUser extends User {public AdminUser(String name) {super(name);this.iOperations = new IOperation[]{new ExitOperation(),new AddOperation(),new DelOperation(),new FindOperation(),new ShowOperation(),};}@Overridepublic int menu() {System.out.println("欢迎" + this.name + "使用图书管理系统");System.out.println("********管理员菜单********");System.out.println("*************************");System.out.println("******* 1.添加图书 *******");System.out.println("******* 2.删除图书 *******");System.out.println("******* 3.查找图书 *******");System.out.println("******* 4.展示图书 *******");System.out.println("******* 0.退出系统 *******");System.out.println("*************************");Scanner scanner = new Scanner(System.in);System.out.println("请输入您的操作:");int choice = scanner.nextInt();if(choice < 0 || choice > 4) {return -1;}return choice;}
}//NormalUser.java
package User;import ioperation.*;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()};}@Overridepublic int menu() {System.out.println("欢迎" + this.name + "使用图书管理系统");System.out.println("********普通用户菜单********");System.out.println("*************************");System.out.println("******* 1.查找图书 *******");System.out.println("******* 2.借阅图书 *******");System.out.println("******* 3.归还图书 *******");System.out.println("******* 0.退出系统 *******");System.out.println("*************************");Scanner scanner = new Scanner(System.in);System.out.println("请输入您的操作:");int choice = scanner.nextInt();if(choice < 0 || choice > 3) {return -1;}return choice;}
}

Main(默认包)

//Main.java
import Book.BookList;
import User.*;import java.util.Scanner;public class Main {public static User login() {System.out.println("请输入您的名字:");Scanner scanner = new Scanner(System.in);String name = scanner.nextLine();System.out.println("请输入您的身份:1. 管理员  2. 普通用户");int choice = scanner.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();if(choice < 0) {System.out.println("输入非法,请重新输入!");}else {//根据用户选择执行相关操作user.doOperation(choice, bookList);}}}
}

当前实现的项目没有保存数据的能力,我们后面会使用数据库做到这一点。

这个项目的意义在于提高我们的编码能力、熟悉前面学习的SE语法的应用场景、同时增加学习的趣味性
希望我们大家多多练习,早日成才!

相关文章:

图书管理系统——Java实现

文章目录 Java实现图书管理系统问题分析框架搭建业务实现项目测试代码演示BookioperationUserMain&#xff08;默认包&#xff09; Java实现图书管理系统 学习了前六篇的SE语法&#xff0c;我们现在要用它们实现一个简单的图书管理系统项目&#xff0c;深入了解各个知识点的应…...

Capto 标准版【简体中文+Mac 】

Capto 是一套易于使用的屏幕捕捉、视频录制和视频编辑 Capto-capto安装包-安装包https://souurl.cn/DPhBmP 屏幕录制和教程视频制作 记录整个屏幕或选择的任何特定区域。在创建内容丰富的教程视频时选择显示或隐藏光标。无论您做什么&#xff0c;都可以确保获得高质量的视频。…...

连锁收银系统的五大功能 会员营销是核心

连锁企业的收银系统是其经营管理的关键工具之一&#xff0c;具备多种功能可以帮助企业提高效率、优化服务并实现会员营销。以下是连锁收银系统的五大功能&#xff0c;其中会员营销作为核心功能将在最后详细讨论。 首先&#xff0c;收银系统应具备高效的销售管理功能。这包括商品…...

射频功率限幅器简略

在功率输入保护方面&#xff0c;限幅器是最好用的器件之一&#xff0c;可以保护后级电路不受超限功率的损害&#xff0c;限幅器其实像TVS功能一样&#xff0c;让超过阈值的功率释放到接地上&#xff0c;来达到限制幅度的目的&#xff0c;目前限幅器的限幅幅度大多都大于15dBm,很…...

[备忘] Reboot Linux in python

1.可行的Reboot方法 1.1 修改/etc/sudoers 假定当前用户是mimi&#xff0c;增补这一行&#xff1a; mimi ALL(ALL) NOPASSWD: ALL 这是为了免输指令。 sudoers文件尽量在覆盖前把它的权限改回去&#xff1a; 原始权限 mimidebian-vm:~/test_app$ ls -l /tmp/sudoers -r--r-…...

windows打开工程文件是顺序读写吗

在 Windows 操作系统中&#xff0c;打开和读写工程文件的过程可以是顺序读写&#xff0c;也可以是随机读写&#xff0c;具体取决于使用的软件和文件的性质。以下是一些详细解释&#xff1a; 顺序读写 顺序读写&#xff08;sequential access&#xff09;是指按文件中数据的顺…...

【Python】解决Python报错:AttributeError: ‘generator‘ object has no attribute ‘xxx‘

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…...

【1800】【5.22-5.24】

E1. String Coloring (easy version) E2. String Coloring (hard version) 【细节参考了题解】 题意&#xff1a;序列拆分为最少的若干条不降序列。 思路&#xff1a;简单版可以 n 2 n^2 n2 dp。定义 b o o l d p ( i , j ) bool ~dp(i, j) bool dp(i,j) 表示是否存在方案…...

统计各个商品今年销售额与去年销售额的增长率及排名变化

文章目录 测试数据需求说明需求实现分步解析 测试数据 -- 创建商品表 DROP TABLE IF EXISTS products; CREATE TABLE products (product_id INT,product_name STRING );INSERT INTO products VALUES (1, Product A), (2, Product B), (3, Product C), (4, Product D), (5, Pro…...

华为校招机试 - 矿车运输成本(20240522)

题目描述 露天矿采矿作业的特点是规模大,矿石和废料的移动量达到百万吨,运输成本开销较大,需要寻求一种最优的运输路径节省成本。 已知矿场可以划分成 N * M 的网格图,每个网格存在地形的差异,因此通过不同网格时,成本开销存在差异。 网格有以下 5 种类型: 标志为 S …...

【C++奇技淫巧】CRTP(奇特重现模板模式)

CRTP&#xff08;Curiously Recurring Template Pattern&#xff0c;奇特重现模版模式&#xff09;,是一种在C中使用模板来实现的设计模式&#xff0c;主要用于实现编译时多态性&#xff08;静态多态&#xff09;。这种模式通过类模板和模板继承机制来实现&#xff0c;使得派生…...

web学习笔记(六十一)

目录 如何使用公共组件来编写页面 如何使用公共组件来编写页面 1.导入公共组件nav.vue import Catenav from "/components/nav.vue"; 2.在页面插入子组件 如果使用了setup语法糖此时就可以直接在页面插入 <Catenav ></Catenav>标签&#xff0c; …...

Nginx在Docker中的应用:容器化部署与扩展

在当今的云计算和微服务时代&#xff0c;Docker容器技术因其轻量级、可移植性和可扩展性而受到广泛关注。Nginx&#xff0c;作为一个高性能的HTTP和反向代理服务器&#xff0c;也在Docker中找到了其广泛的应用场景。本文将探讨Nginx在Docker中的容器化部署和扩展策略&#xff0…...

vscode编译和调试wsl环境的c语言程序

直接f5会报错&#xff0c;提示你改一下json文件 launch.json { “version”: “0.2.0”, “configurations”: [ { “name”: “(gdb) Launch”, “type”: “cppdbg”, “request”: “launch”, “program”: “ w o r k s p a c e F o l d e r / a . o u t " , " …...

(CPU/GPU)粒子继承贴图颜色发射

GetRandomInfo节点(复制贴进scratch pad Scripts) Begin Object Class/Script/NiagaraEditor.NiagaraClipboardContent Name"NiagaraClipboardContent_22" ExportPath/Script/NiagaraEditor.NiagaraClipboardContent"/Engine/Transient.NiagaraClipboardConten…...

【C#】 一个窗体能够显示、最小化、最大化、关闭时分别触发方法

在C#的WPF应用程序中&#xff0c;窗体&#xff08;即继承自System.Windows.Window的类&#xff09;能够通过处理以下事件来响应显示、最小化、最大化和关闭操作&#xff1a; 1.显示&#xff1a; 窗体显示时没有直接对应的事件&#xff0c;但你可以通过覆盖OnLoaded方法或订阅…...

pgsql基本操作

查看已经存在的数据库 postgres# \lList of databasesName | Owner | Encoding | Collate | Ctype | Access privileges ----------------------------------------------------------------------postgres | postgres | UTF8 | C | C | runoobdb …...

3d渲染的常用概念和技术,渲染100邀请码1a12

之前我们介绍了3D渲染的基本原理和流程&#xff0c;这次说下几个常用概念和技术。 3D渲染中涉及到很多专业的概念和技术&#xff0c;它们决定了渲染质量和效果&#xff0c;常用的有以下几个。1、光线追踪 光线追踪是一些专业渲染器&#xff08;如V-Ray和Corona等&#xff09;…...

热敏电阻的设计

热敏电阻(NTC)的作用&#xff1a;抑制开机时的浪涌电流。防止开机瞬间产生的浪涌电流损坏后面的元件。 取值依据:根据对开机的脉冲电流&#xff08;浪涌电流&#xff09;小于多少A&#xff1f; 由,这个U是指最大输入电压&#xff0c;I为要求的浪涌电流。 NTC是负温度系数的热…...

macOS上编译android的ffmpeg及ffmpeg.c

1 前言 前段时间介绍过使用xcode和qt creator编译调试ffmepg.c&#xff0c;运行平台是在macOS上&#xff0c;本文拟介绍下android平台如何用NDK编译链编译ffmepg库并使用。 macOS上使用qt creator编译调试ffmpeg.c macOS上将ffmpeg.c编译成Framework 大体思路&#xff1a; 其…...

RxSwift - 实现一个MVVM架构的TableView

文章目录 RxSwift - 实现一个MVVM架构的TableView前沿MVVM架构的Tableview目录结构1、模型&#xff08;Model&#xff09;2、视图模型&#xff08;ViewModel&#xff09;3、视图&#xff08;View&#xff09; 界面效果 RxSwift - 实现一个MVVM架构的TableView 前沿 MVVM架构在…...

在 CentOS 7 上安装并配置 Redis 允许远程连接的详细教程

第一部分&#xff1a;安装 Redis Redis 是一款高性能的键值存储系统&#xff0c;广泛应用于缓存、消息队列及数据库场景。下面是如何在 CentOS 7 系统上安装 Redis 的步骤。 步骤1&#xff1a;安装 EPEL 仓库 EPEL (Extra Packages for Enterprise Linux) 提供了许多 CentOS 默…...

越来越多企业选择开源批发订货系统

在当今竞争激烈的市场环境中&#xff0c;越来越多的企业选择开源批发订货系统来提高运营效率、降低成本并实现业务的数字化转型。以下是开源批发订货系统的四大优势及其重要功能&#xff1a; 首先&#xff0c;开源批发订货系统具有高度的灵活性和定制性。由于其源代码开放&…...

KT6368A双模蓝牙芯片上电到正常发送AT指令或指令复位需要多久

一、简介 KT6368A芯片上电到正常发送AT指令&#xff0c;或者开启蓝牙广播被搜索到&#xff0c;或者指令复位需要多久等等系列问题总结 详细描述 其实这些问题归结到一起&#xff0c;就还是一个问题&#xff0c;芯片上电需要多久的时间 在另外一份文档里面&#xff0c;是有描…...

代码随想录算法训练营第38天 | 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

代码随想录算法训练营第38天 | 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯 理论基础自己看到题目的第一想法看完代码随想录之后的想法 链接: 509. 斐波那契数 链接: 70. 爬楼梯 链接: 746. 使用最小花费爬楼梯 理论基础 五部曲&#xff1a; 1.确定dp数组&#xf…...

变现实谈,我要的不是灵光一现,而是真实的实现!——感悟篇

变现要的是行动不是想法 正文时代奇点奇迹 点题以己及人 正文 每当我看到了一个有趣的事情 我会在脑中构思一些想法 会贴合我当下的想要做的事情 比如 在我写下这篇文章之前 我看到了 二战期间的诞生的一个奇迹 可口可乐 我就思考 咦 原来可口可乐居然是在这么个时间点成长…...

Matlab操作Excel筛选指定数据的对应数据

Matlab中在表格中寻找指定汉字&#xff0c;并返回其所在行数&#xff0c; 将该行数的另一列提取出来。 目录 一、前言 二、直接在命令行输出 三、保存筛选数据excel 一、前言 源数据excel&#xff1a; 指定汉子&#xff1a;买&#xff0c;得到下面数据&#xff1a; 二、直接…...

对于C++STL及其时间复杂度的总结

由于本次在山东CCPC邀请赛中&#xff0c;对于堆的时间复杂度记忆不清晰&#xff0c;导致第4题没有做出来&#xff0c;与铜牌失之交臂&#xff0c;故觉应整理STL的时间复杂度。 本文仅整理有用&#xff08;竞赛&#xff09;的stl及其用法&#xff0c;并且不阐述过于基础的内容。…...

Docker搭建FRP内网穿透服务器

使用Docker搭建一个frp内网穿透 在现代网络环境中&#xff0c;由于防火墙和NAT等原因&#xff0c;内网设备无法直接被外网访问。FRP (Fast Reverse Proxy) 是一款非常流行的内网穿透工具&#xff0c;它能够帮助我们将内网服务暴露给外网。本文将介绍如何在Linux服务器上使用Do…...

【NumPy】掌握NumPy的divide函数:执行高效的数组除法操作

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…...

您的虚拟机未能继续运行,原因是遇到一个可纠正的错误。请保留挂起状态并纠正错误,或放弃挂起状态。

镜像&#xff1a;应急响应靶机 错误信息 此虚拟机的处理器所支持的功能不同于保存虑拟机状态的虚拟机的处理器所支持的功能。 从文件"E:\XXX.vmss"还原 CPU 状态时出错。 您的虚拟机未能继续运行&#xff0c;原因是遇到一个可纠正的错误。请保留挂起状态并纠正错误…...

FPGA DMA IP核使用指南

摘要 本文旨在介绍FPGA中DMA(Direct Memory Access)IP核的使用,包括其基本框架、测试代码编写以及仿真波形的分析。DMA是一种允许外围设备直接与内存进行数据交换的技术,无需CPU的介入,从而提高了数据传输的效率。 1. 引言 在现代FPGA设计中,DMA IP核因其…...

【博客20】缤果Matlab串口调试助手V1.0(中级篇)

超级好用的Matlab串口调试助手 开发工具: MATLAB 2024a中文版 (编程语言matlab) -> Matlab APP Designer 目录 前言 一、软件概要&#xff1a; 二、软件界面&#xff1a; 1.App演示 ​ ​---- ◇♣♡♠ ---- 2.其他扩展App展示 ​编辑 三、获取 >> 源码以及G…...

南京威雅学校:2024年度大戏《Tinkerbell(小叮当)》震撼落幕

三天连演三场 两小时十六幕高潮迭起的舞台故事 一百五十余名师生台前幕后全统筹 逾千名观众现场观演 四个城市五大平台同步直播 南京威雅2024年度大戏 《Tinkerbell&#xff08;小叮当&#xff09;》震撼落幕 它以商演级别的舞台设计 宏大而精密的舞台调度 直击心灵的…...

Kotlin 函数

文章目录 函数的定义函数的返回值参数默认值 & 调用时参数指定函数作用域Lambda 表达式匿名函数内联函数扩展函数中缀函数递归函数 & 尾递归函数 函数的定义 函数可以理解成一个小小的加工厂&#xff0c;给入特定的原材料&#xff0c;它就会给出特定的产品。 fun [接…...

动态路由协议实验——RIP

动态路由协议实验——RIP 什么是RIP ​ RIP(Routing Information Protocol,路由信息协议&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;是一种动态路由选择协议&#xff0c;用于自治系统&#xff08;AS&#xff09;内的路由信息的传递。RIP协议基于…...

数据结构 | 二叉树(基本概念、性质、遍历、C代码实现)

1.树的基本概念 树是一种 非线性 的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#xff0c;称为根…...

很多Oracle中的SQL语句在EF中写不出来

很多复杂的Oracle SQL语句在Entity Framework&#xff08;EF&#xff09;中很难直接表达出来。虽然EF提供了一种方便的方式来使用C#代码查询和操作数据库&#xff0c;但它在处理某些复杂的SQL特性和优化时可能会有局限性。 以下是一些在EF中可能难以直接实现的Oracle SQL功能和…...

浏览器打开PHP文件弹出下载而不是运行代码

说明 使用phpstudy&#xff0c;极少会出现这种情况。 这里主要是帮助大家理解&#xff0c;为什么上传的木马不运行。 问题原因 首先需要理解&#xff0c;访问PHP文件弹出下载&#xff0c;说明服务端的容器&#xff08;比如Apache或者Nginx&#xff09;把文件当成了一个普通二…...

安卓自定义UI组件开发流程

安卓自定义ui组件开发流程 开发安卓自定义UI组件的流程大致可以分为以下几个步骤&#xff1a; 确定需求和设计&#xff1a; 确定需要自定义的UI组件的功能和外观。设计组件的交互逻辑和视觉效果。 创建自定义组件类&#xff1a; 创建一个新的Java类&#xff0c;继承自View、V…...

【LINUX】LINUX基础(目录结构、基本权限、基本命令)

文章目录 LINUX的目录结构LINUX的基本权限LINUX基本命令 LINUX的目录结构 /&#xff1a;表示根目录bin&#xff1a;存放二进制可执行文件(命令ls、cat、mkdir等)boot&#xff1a;存放系统引导文件dev&#xff1a;存放设备文件etc&#xff1a;存放系统配置文件home&#xff1a;…...

Aigtek功率放大器的主要性能要求有哪些

功率放大器是电子系统中的重要组件&#xff0c;用于将低功率信号放大到高功率水平。功率放大器的性能直接影响到信号的放大质量和系统的整体性能。下面西安安泰将介绍功率放大器的主要性能要求。 增益&#xff1a;功率放大器应当具有足够的增益&#xff0c;即将输入信号的幅度放…...

2024.5.29晚训参考代码

因为本套题没有BFS例题&#xff0c;所以我先把BFS模板放着 #include<bits/stdc.h> using namespace std; int n,m;//n*m的棋盘 int dis[402][402]; bool vis[402][402]; int X[]{-2,-2,-1,-1,1,1,2,2};//偏移量的表 int Y[]{-1,1,-2,2,-2,2,-1,1};//定义一个数组&…...

【计算机网络】——概述(图文并茂)

概述 一.信息时代的计算机网络二.互联网概述1.网络&#xff0c;互连网&#xff0c;互联网&#xff08;因特网&#xff09;1.网络2.互连网3.互联网&#xff08;因特网&#xff09; 2.互联网简介1.互联网发展的三个阶段2.互联网服务提供者&#xff08;ISP&#xff09;3.互联网的组…...

C语言多个源程序编译的CMakeList文件编写/源程序生成动态库

1.编译多个源程序时CMakeLists文件编写 1.若源程序目录结构如下&#xff1a; main.cpp中include“LCD_2inch4.h”头文件&#xff0c;而LCD_2inch4.h中include其它源程序&#xff0c;则CmakeLists.txt文件可为如下&#xff1a; # 设置项目名称 cmake_minimum_required(VERSI…...

C# list集合

一、list集合基本使用 1.添加元素 ① 单个元素添加 List<int> list new List<int>();for (int i 0; i < 3; i){list.Add(i);}//输出&#xff1a;0,1,2 ②初始化时添加元素 List<int> list2 new List<int> { 1, 2, 3 };//输出&#xff1a;0,1…...

****三次握手和四次挥手

一、三次握手 1.简要描述TCP三次握手的过程 第一次握手&#xff0c;客户端发送SYN包到服务器&#xff1b; 第二次握手&#xff0c;服务器收到SYN包&#xff0c;回复一个SYNACK包&#xff1b; 第三次握手&#xff0c;客户端收到服务器的SYNACK包后&#xff0c;回复一个ACK包…...

开发语言Java+前端框架Vue+后端框架SpringBoot开发的ADR药物不良反应监测系统源码 系统有哪些优势?

开发语言Java前端框架Vue后端框架SpringBoot开发的ADR药物不良反应监测系统源码 系统有哪些优势&#xff1f; ADR药物不良反应监测系统具有多个显著的优势&#xff0c;这些优势主要体现在以下几个方面&#xff1a; 一、提高监测效率与准确性&#xff1a; 通过自动化的数据收集…...

问题排查|记录一次基于mymuduo库开发的服务器错误排查(段错误--Segmentation fault (core dumped))

问题记录&#xff1a; 在刚完成mymuduo库之后&#xff0c;写了一个简单的测试服务器&#xff0c; 但是在服务器运行后直接报错&#xff1a; cherryhcss-ecs-4995:~/mymuduo/example$ ./testserver Segmentation fault (core dumped)出现多错误这通常意味着程序试图访问其内存空…...

Mysql常用操作DQL数据库、表操作:

DQL是指MySQL数据库中的数据查询语言&#xff08;Data Query Language&#xff09;。它是用来从数据库中检索所需数据的语言。DQL允许用户通过指定查询条件和筛选条件来检索数据库中的数据&#xff0c;并以所需的方式来显示结果。DQL语句可以用于从单个表中查询数据&#xff0c…...