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

图书管理系统

一、图书管理系统菜单
🍓管理员菜单

1.查找图书

2.新增图书

3.删除图书

4.显示图书

0.退出系统

---------------------------------------------------------------------------------------------------------------------------------

🌼用户菜单

1.查找图书

2.借阅图书

3.归还图书

0.退出系统

二、实现基本框架
先建立一个新的文件,命名为TestBook,在文件内建立两个包,分别命名为user(用户)、book(图书)。

 先写book相关的代码。于是,我们先在book包中新建一个java类,名为:Book。

显示图书时,我们希望它能显示出所有图书的名称、作者、价格、类型和图书目前是否借出。

  private String name;//书名
    private String author;//作者
    private int price;//价格
    private String type;//类型
    private boolean isBorrowed;//是否被借出,初始值是false,在构造方法中不用写
 右击鼠标,选择Generate,选择Getter and Setter 选项,点击shift,点最后一个,就能全选:

自动生成:

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

再写它们的构造方法:

当我们新增一本图书时,它默认就是未被借出的,所以不用构造方法。

快捷键:alt+insert。按ctrl,可以多选,直接生成下面代码块:

 
    public Book(String name, String author, int price, String type) {//构造方法
        this.name = name;
        this.author = author;
        this.price = price;
        this.type = type;
    }
 我们再右键选择Generate,选择ToString,全选,点OK,自动生成:

  @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", type='" + type + '\'' +
                ", isBorrowed=" + isBorrowed +
                '}';
    }
此时,在book包中新建一个类:BookList(书架):

在这个书架中,我们希望能在里面固定的位置放书,并且能知道放了几本书:

    private  Book[] books=new  Book[10];//这个书架可以放十本书
    private int usedSize;//记录下当前book数组中有几本书
然后依旧是右键Generate ,getter and setter,自动生成:

 当前界面:

我们还记得在C语言中,我们用到的 define,用define语句来定义一个常量,同理,我们这边也可以定义一个能放多少本书的常量:

  private static final int DEFAULT_SIZE=10;
  private  Book[] books=new  Book[DEFAULT_SIZE];
我们这边就是先按思路慢慢写,慢慢补充。在后面,我会放完整的代码。

book包已经告一段落了,现在来写user包。

我们在user包中新建三个类:AdminUser(管理员)、NormalUser(用户)、User。

NormalUser、AdminUser,这也就是我们图书管理系统面对的两个对象了,管理员和用户,他们具有一些相同的属性。我们就可以写一个User类,让两个类去继承,来省一些代码了。

🥗我们先写User类叭~

package user;
 
public class User {
    protected String name;//名字.这边的protect代表的是名字的权限。如果是private,它只能在同一个包的同一类使用。就不能让AdminUser类继承了。
    //写public的话,权限太大了,不是很好。
    public User(String name) {//构造方法
        this.name = name;
    }
}
所以在AdminUser类中:

package user;
 
public class AdminUser extends User{
    public AdminUser(String name) {
        super(name);
    }
}
可以直接用快捷键,alt+insert,直接生成构造方法。

同理,NormalUser类中:

package user;
 
public class NormalUser extends User{
    public NormalUser(String name) {
        super(name);
    }
}
 
我们书的属性和用户属性的包和类已经写了大概。我们现在回归到我前面列的功能上:

 然后,我们就会发现我们想要实现的功能和操作基本上是针对图书的。所以,这边,我们可以选择直接在图书book包中写方法,也可以选择另外再创建一个包。

我这边是新建了一个包,命名为:opera,再创建一个接口命名为IOPeration。

创建接口:点oper,右击,点击java Class:

 然后页面为:

 创建接口:

package opera;
 
import book.BookList;
 
public interface IOPeration {//创建接口
    void work(BookList bookList);//抽象方法
    //功能主要是针对图书的,也就是针对书架。
}
 我们在opera(实现功能的包)中,创建两个类,AddOperation、FindOperation,这两个类。

我们会发现这两个类的实现也都要依靠BookList(书架)来实现。所以,在这两个类中,实现接口:

FindOperation类中:

package opera;
 
import book.BookList;
public class FindOperation implements IOPeration{//继承
    @Override
    public void work(BookList bookList) {//重写IOPeration类中的work方法
        System.out.println("查找图书!");
    }
}
AddOperation类中:

package opera;
 
import book.BookList;
 
public class AddOperation implements IOPeration {
    public void work(BookList bookList){
        System.out.println("新增图书!");
    }
}
 同理,新建类DelOperation(删除图书):

package opera;
 
import book.BookList;
 
public class DelOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("删除图书!");
    }
}
 新建一个类:ShowOperation(显示图书):

package opera;
 
import book.BookList;
 
public class ShowOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("打印所有图书!");
    }
}
 再新建一个类:ExitOperation(退出系统):

package opera;
 
import book.BookList;
 
public class ExitOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统!");
    }
}
新建一个BrrowOperation类(借阅图书):

package opera;
 
import book.BookList;
 
public class BrrowOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅图书!");
    }
}
 再新建一个类:ReturnOperation(借阅图书):

package opera;
 
import book.BookList;
 
public class ReturnOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("归还图书!");
    }
}


接着,我们来细化我们的类。

🍅我们还没有给user添加菜单。

我们先给管理员添加菜单:

    public void menu(){
        System.out.println("____________________________________");
        System.out.println("1.查找图书");
        System.out.println("2.新增图书");
        System.out.println("3.删除图书");
        System.out.println("4.显示图书");
        System.out.println("0.退出系统");
    }
再给用户添加菜单:

public void manu(){
    System.out.println("_________________");
    System.out.println("hello,"+name+"~");
    System.out.println("1.查找图书!");
    System.out.println("2.借阅图书!");
    System.out.println("3.归还图书!");
    System.out.println("0.退出系统!");
}
现在,我们写main方法。在src下新建一个类:Main:

import user.AdminUser;
import user.NormalUser;
import user.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->管理员 0->普通用户");
            int choice =scanner.nextInt();
            if(choice==1){
                //说明是管理员
                //由于有返回值,所以我们的方法返回值就不能写void了。但是我们也无法确定返回值是什么,可能是管理员,可能是用户。所以,用向上转型,写User.
                return new AdminUser(name);//返回实例化一个管理员对象
            }else {
                return new NormalUser(name);//返回实例化一个用户对象
            }
        }
    public static void main(String[] args) {
  User user=login();//执行上面的login方法
        user.menu();//实现打印菜单
    }
}

执行login方法时,我们是还不知道new的对象是管理员还是用户的。所以,在打印菜单时,我们也不能直接使用我们在AdminUser类和NormalUser类中写的menu()方法。

✨🎉所以在写user.menu();这个语句时,不行!

所以,我们想到了重写。

我们把User类改成抽象类,在抽象类中写一个menu的抽象方法。

package user;
public abstract class User {//抽象类
    protected String name;//名字.这边的protect代表的是名字的权限。如果是private,它只能在同一个包的同一类使用。就不能让AdminUser类继承了。写public的话
    //权限太大了,不是很好。
    public User(String name) {//构造方法
        this.name = name;
    }
    public abstract void menu();//抽象方法,打印菜单
}
那么, 在AdminUser类和NormalUser类中,也应该有相应的改动,把里面的menu()写成重写的形式。

这也仅仅是实现了打印菜单:

 这个过程还是有一些弯弯绕绕的。我们可以通过调试,来捋清我们的思路:

调试的话:

 然后,编译器就会带我们一步步地看它是怎么执行的。

接着,我们继续完善我们的代码。光打印一个菜单,不执行我们想要的功能,可不行。

所以,我们在我们的menu菜单中,需要输入我们的功能选择:

   Scanner scanner=new Scanner(System.in);
        int choice=scanner.nextInt();
        return choice;
输入功能选择,我们就要通过这个选择就实现:

首先,我们要根据对象(管理员或用户),选择引用哪一个菜单方法:

NormalUser类中:

 public NormalUser(String name) {
        super(name);
        this.ioPerations=new IOPeration[]{//引用,这边用super也可以,因为这里没有同名的,不需要做区分。用this最好
                new FindOperation(),
                new BrrowOperation(),
                new ReturnOperation(),
                new ExitOperation()//以动态方式申请内存。拿到变量后,我们就给他们分配内存
        };
 AdminUser类中:

  public AdminUser(String name) {
        super(name);
        this.ioPerations=new IOPeration[]{
                new ExitOperation(),
                new FindOperation(),
                new AddOperation(),
                new DelOperation(),
                new ShowOperation()
        };
    }
 当我们在构造方法中,写了这些,也就为它们分配了内存。当main类中login()方法下,new一个对象时,就会执行相应的构造方法,在这里就是开辟内存:

 在User类中:

我们加上这样一段代码:

 public void doWork(int choice, BookList bookList){//通过选择的操作,去选择执行数组下的哪个操作
        this.ioPerations[choice].work(bookList);
    }
this.ioPerations[choice]其实就是new了一个对象。后面的.work(bookList)是调用图书中对应的work方法。

由此一来,我们就可以根据我们一步步的选择,调用book包中对应的work方法。

为了让代码在输入0的时候退出系统,我们用while语句(在Main方法中修改):

   while (true){
            int choice=user.menu();//实现打印菜单
            user.doWork(choice,bookList);
        }
 

这下子基本框架就构造好了。

先看一下测试结果:

 三、实现业务
3.1 打印所有图书
 我们先在BookList类,也就是书架中先添加图书:

public BookList(){//构造方法
        books[0]=new Book("《三国演义》","罗贯中",40,"小说");
        books[1]=new Book("《西游记》","吴承恩",60,"小说");
        books[2]=new Book("《红楼梦》","曹雪芹",45,"小说");
        this.usedSize=3;
    }
   //通过这个方法,实现ShowOperation中的通过下标打印数组元素
    public Book getBook(int pos){
        return this.books[pos];
    }
然后,我们实现打印所有图书这个业务 。

🍍在ShowOperation类中,添加打印所有图书的程序,利用for循环。

 在ShowOperation类中:

package opera;
 
import book.BookList;
 
public class ShowOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("显示图书!");
        int currentSize= bookList.getUsedSize();
        for (int i=0;i<currentSize;i++){
            System.out.println(bookList.getBook(i));
        }
    }
}
实现的结果:

 我们会发现一些小瑕疵,比如这边输出的false。我们想把它改成已借出,未借出。

这时,我们要用到三目运算符。条件?符合输出:不符合输出

在book类中修改:

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


 3.2 退出系统
退出系统很简单,只需要加上👇语句即可。0代表正常退出。

System.exit(0);
 实现结果:

 3.3 查找图书
查找图书是跟刚才打印图书差不多的思路。通过for循环,利用equal()进行比对,输出图书信息。

在FindOperation类中补充代码:

public class FindOperation implements IOPeration{//继承
    @Override
    public void work(BookList bookList) {//重写IOPeration类中的work方法
        System.out.println("查找图书!");
        System.out.println("请输入要查找的图书名字");
        Scanner scanner=new Scanner(System.in);
       String name=scanner.nextLine();
       int currentSize= bookList.getUsedSize();
       for (int i=0;i<currentSize;i++){
           Book book=bookList.getBook(i);
           if(book.getName().equals(name)){//判断查找图书名字是否相同
               System.out.println("查到了:");
               System.out.println(book);//输出图书信息
           }else {
               System.out.println("没有这本书");
           }
       }
    }
 
}

 3.4 增加图书
我们要先输入新增图书信息,new一个对象,判断这本图书是否已经存在,如果不存在,则存入书架中。

AddOperation类:

package opera;
 
import book.Book;
import book.BookList;
 
import java.util.Scanner;
 
public class AddOperation implements IOPeration {
    public void work(BookList bookList){
        System.out.println("新增图书!");
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入新增图书名字:");
        String name= scanner.nextLine();
        System.out.println("请输入新增图书作者:");
        String author=scanner.nextLine();
        System.out.println("请输入价格");
       int price=scanner.nextInt();
        Scanner scanner2=new Scanner(System.in);
        System.out.println("请输入小说类型:");
        String type=scanner2.nextLine();
        Book book=new Book(name,author,price,type);
        int currentSize= bookList.getUsedSize();
        for (int i=0;i<currentSize;i++){
            Book temp=bookList.getBook(i);
            if(temp.getName().equals(name)){//判断查找图书名字是否相同
                System.out.println("已经有这本书了");
                return;
            }
        }
     bookList.setBooks(book);
        System.out.println("新增图书成功!");
        //修改图书数量
        bookList.setUsedSize(currentSize+1);
    }
}

 bookList.setBooks(book);这个语句,我们需要在书架那个类加上setBooks()方法:

  public void setBooks(Book book){
        this.books[usedSize]=book;
    }
 🍓注意!!!
在增加图书的时候,我遇到了困难。

我在价格的地方,设置的是int类型。 int price=scanner.nextInt();这个语句执行完,它就不会执行后面的输入语句了。这是我疏忽的一个点。

有三种解决方案。

1.像我上面的代码一样,多写一个  Scanner scanner2=new Scanner(System.in); 这是改动最小的方法了。

2.就是把图书的价格和类型的顺序调换一下,就是要几个文件都改一小下,其实也很快。这样子int price=scanner.nextInt();,最后输这个输入命令的话,就能保证输入命令全部执行

3.这个方法也比较简单,就是把图书的价格类型改成String,那样子,就没有影响了。

3.5 删除图书 
🍆删除图书,我们要注意,不仅仅是把那本书删除就好了,还需要把后面的书往前挪。

DelOperation类:

   public void work(BookList bookList) {
        System.out.println("删除图书!");
        System.out.println("请输入要删除图书的名称");
        Scanner scanner=new Scanner(System.in);
        String name=scanner.nextLine();
        int currentSize= bookList.getUsedSize();
        int index=-1;
        for (int i=0;i<currentSize;i++){
            Book temp=bookList.getBook(i);
            if(temp.getName().equals(name)){//判断查找图书名字是否相同
                index=i;
                break;
            }
        }
        //删除图书,把后面的图书往前面挪
        for (int j=index;j<currentSize-1;j++){
            Book book=bookList.getBook(j+1);//拿到j下标后面的书
            bookList.setBooks(j,book);//放到j下标的位置
        }
        bookList.setUsedSize(currentSize-1);//修改size值
        bookList.setBooks(currentSize-1,null);//因为删除的是对象,所以把地址置为null,就没有人引用了
    }

BookList类:

  public void setBooks(int pos,Book book){
        this.books[pos]=book;
    }
我们可以注意到在BookList新添加的这个方法跟刚才在写增加图书时放置图书的方法相似。不过,我们可以注意到,增加图书,就是在最后面放一本书,就好了。而这里,是把后面的书一本本往前挪一个书位。

3.6 借阅图书
思路:判断图书是否在书库中存在,判断图书是否已经被借出。满足条件,执行

temp.setBorrowed(true);
3.7 归还图书 
思路:判断图书是否在书库中存在,判断书是否已被借出。

满足条件:

temp.setBorrowed(false);
总代码


Book:

package book;
 
public class Book {
    private String name;//书名
    private String author;//作者
    private int price;//价格
    private String type;//类型
    private boolean isBorrowed;//是否被借出,初始值是false,在构造方法中不用写
 
    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;
    }
 
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", type='" + type + '\'' +
                ", isBorrowed=" +(isBorrowed==true?"    已借出":"    未借出") +
                '}';
    }
 
    public void setBorrowed(boolean borrowed) {
        isBorrowed = borrowed;
    }
}

 BookList

package book;
//书架
public class BookList {
    private static final int DEFAULT_SIZE=10;
    private  Book[] books=new  Book[DEFAULT_SIZE];//这个书架可以放十本书
    public BookList(){//构造方法
        books[0]=new Book("《三国演义》","罗贯中",40,"小说");
        books[1]=new Book("《西游记》","吴承恩",60,"小说");
        books[2]=new Book("《红楼梦》","曹雪芹",45,"小说");
        this.usedSize=3;
    }
    //通过这个方法,实现ShowOperation中的通过下标打印数组元素
    public Book getBook(int pos){
        return this.books[pos];
    }
    public void setBooks(Book book){
        this.books[usedSize]=book;
    }
    public void setBooks(int pos,Book book){
        this.books[pos]=book;
    }
    private int usedSize;//记录下当前book数组中有几本书
    public int getUsedSize() {
        return usedSize;
    }
    public void setUsedSize(int usedSize) {
        this.usedSize = usedSize;
    }
}

AddOperation

package opera;
 
import book.Book;
import book.BookList;
 
import java.util.Scanner;
 
public class AddOperation implements IOPeration {
    public void work(BookList bookList){
        System.out.println("新增图书!");
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入新增图书名字:");
        String name= scanner.nextLine();
        System.out.println("请输入新增图书作者:");
        String author=scanner.nextLine();
        System.out.println("请输入价格");
       int price=scanner.nextInt();
        Scanner scanner2=new Scanner(System.in);
        System.out.println("请输入小说类型:");
        String type=scanner2.nextLine();
        Book book=new Book(name,author,price,type);
        int currentSize= bookList.getUsedSize();
        for (int i=0;i<currentSize;i++){
            Book temp=bookList.getBook(i);
            if(temp.getName().equals(name)){//判断查找图书名字是否相同
                System.out.println("已经有这本书了");
                return;
            }
        }
     bookList.setBooks(book);
        System.out.println("新增图书成功!");
        //修改图书数量
        bookList.setUsedSize(currentSize+1);
    }
}

BorrwOperation:

package opera;
 
import book.Book;
import book.BookList;
 
import java.util.Scanner;
 
public class BrrowOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅图书!");
        System.out.println("请输入要借阅的图书名字:");
        Scanner scanner=new Scanner(System.in);
        String name=scanner.nextLine();
        int curentSize= bookList.getUsedSize();
        int x=1;
        for(int i=0;i<curentSize;i++){
            Book temp=bookList.getBook(i);
            if((temp.getName().equals(name))&&!temp.isBorrowed()){
               {
 
                    temp.setBorrowed(true);
                    x=0;
                   System.out.println("借阅成功!");
                   return;
                }
            }
        }
        if(x==1){
            System.out.println("没有该图书");
        }
    }
}

DelOperation:

package opera;
 
import book.Book;
import book.BookList;
 
import java.util.Scanner;
 
public class DelOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("删除图书!");
        System.out.println("请输入要删除图书的名称");
        Scanner scanner=new Scanner(System.in);
        String name=scanner.nextLine();
        int currentSize= bookList.getUsedSize();
        int index=-1;
        int z=0;
        for (int i=0;i<currentSize;i++){
            Book temp=bookList.getBook(i);
            if(temp.getName().equals(name)){//判断查找图书名字是否相同
                index=i;
                z=1;
                break;
            }
        }
        if(z==0){
            System.out.println("没有这本书!");
            return;
        }
        //删除图书,把后面的图书往前面挪
        for (int j=index;j<currentSize-1;j++){
            Book book=bookList.getBook(j+1);//拿到j下标后面的书
            bookList.setBooks(j,book);//放到j下标的位置
        }
        bookList.setUsedSize(currentSize-1);//修改size值
        bookList.setBooks(currentSize-1,null);//因为删除的是对象,所以把地址置为null,就没有人引用了
        System.out.println("删除成功!");
    }
 
}

ExitOperation:

package opera;
 
import book.BookList;
 
public class ExitOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统!");
        System.exit(0);//退出系统。0代表正常退出
    }
}
 FindOperation:

package opera;
 
import book.Book;
import book.BookList;
 
import java.util.Scanner;
 
public class FindOperation implements IOPeration{//继承
    @Override
    public void work(BookList bookList) {//重写IOPeration类中的work方法
        System.out.println("查找图书!");
        System.out.println("请输入要查找的图书名字");
        Scanner scanner=new Scanner(System.in);
       String name=scanner.nextLine();
       int currentSize= bookList.getUsedSize();
       for (int i=0;i<currentSize;i++){
           Book book=bookList.getBook(i);
           if(book.getName().equals(name)){//判断查找图书名字是否相同
               System.out.println("查到了:");
               System.out.println(book);//输出图书信息
               return;
           }
       }
        System.out.println("没有这本书!");
    }
 
}

IOPeration: 

package opera;
 
import book.BookList;
 
public interface IOPeration {//创建接口
    void work(BookList bookList);//抽象方法
    //功能主要是针对图书的,也就是针对书架。
}
 ReturnOperation:

package opera;
 
import book.Book;
import book.BookList;
 
import java.util.Scanner;
 
public class ReturnOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("归还图书!");
        System.out.println("请输入要归还的图书名字:");
        Scanner scanner=new Scanner(System.in);
        String name=scanner.nextLine();
        int curentSize= bookList.getUsedSize();
        for(int i=0;i<curentSize;i++){
            Book temp=bookList.getBook(i);
            if((temp.getName().equals(name))&&temp.isBorrowed()){
                {
                    temp.setBorrowed(false);
                    System.out.println("归还成功!");
                    return;
                }
            }
        }
    }
    }

ShowOperation:

package opera;
 
import book.BookList;
 
public class ShowOperation implements IOPeration{
    @Override
    public void work(BookList bookList) {
        System.out.println("显示图书!");
        int currentSize= bookList.getUsedSize();
        for (int i=0;i<currentSize;i++){
            System.out.println(bookList.getBook(i));
        }
    }
}
Main

import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.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->管理员 0->普通用户");
        int choice = scanner.nextInt();
        if (choice == 1) {
            //说明是管理员
            //由于有返回值,所以我们的方法返回值就不能写void了。但是我们也无法确定返回值是什么,可能是管理员,可能是用户。所以,用向上转型,写User.
            return new AdminUser(name);//返回实例化一个管理员对象
        } else {
            return new NormalUser(name);//返回实例化一个用户对象
        }
    }
 
    public static void main(String[] args) {
        User user = login();//执行上面的login方法
        BookList bookList = new BookList();
        while (true) {
            int choice = user.menu();//实现打印菜单
            user.doWork(choice, bookList);
        }
    }
}

测试的话,运行Main:

user代码

AdminUer

package user;
 
import opera.*;
 
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 ShowOperation()
        };
    }
    @Override
    public int menu() {//因为返回值choice是int类型的
        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);
        int choice=scanner.nextInt();
        return choice;
    }
 
}

NormalUser

package user;
 
import opera.*;
 
import java.util.Scanner;
 
public class NormalUser extends User{
    public NormalUser(String name) {
        super(name);
        this.ioPerations=new IOPeration[]{//引用,这边用super也可以,因为这里没有同名的,不需要做区分。用this最好
                new ExitOperation(),
                new FindOperation(),
                new BrrowOperation(),
                new ReturnOperation()
                //以动态方式申请内存。拿到变量后,我们就给他们分配内存
        };
    }
 
    @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.退出系统!");
        Scanner scanner=new Scanner(System.in);
        int choice=scanner.nextInt();
        return choice;
    }

User

package user;
 
import book.BookList;
import opera.IOPeration;
 
public abstract class User {//抽象类
    protected String name;//名字.这边的protect代表的是名字的权限。如果是private,它只能在同一个包的同一类使用。就不能让AdminUser类继承了。写public的话
    //权限太大了,不是很好。
    protected IOPeration[] ioPerations;
    public User(String name) {//构造方法
        this.name = name;
    }
    public abstract int menu();//抽象方法,打印菜单,因为有了choice返回值int类型,所以void改成int
    public void doWork(int choice, BookList bookList){//通过选择的操作,去选择执行数组下的哪个操作
        this.ioPerations[choice].work(bookList);
    }
}

相关文章:

图书管理系统

一、图书管理系统菜单 &#x1f353;管理员菜单 1.查找图书 2.新增图书 3.删除图书 4.显示图书 0.退出系统 --------------------------------------------------------------------------------------------------------------------------------- &#x1f33c;用户菜…...

图解HTTP(2、简单的 HTTP 协议)

HTTP 协议用于客户端和服务器端之间的通信 请求访问文本或图像等资源的一端称为客户端&#xff0c;而提供资源响应的一端称为服务器端。 通过请求和响应的交换达成通信 请求必定由客户端发出&#xff0c;而服务器端回复响应报文 请求报文是由请求方法、请求 URI、协议版本、…...

小鹅知识付费系统登录,网课怎么推广与宣传?有啥获客方法?

现在很多教育机构都开始做网络课程&#xff0c;同行之间的竞争也愈发激烈&#xff0c;机构的网课想要盈利就需要对课程进行宣传推广&#xff0c;网课要怎么推广和宣传呢&#xff1f; 在线课程要想推广获客方法有几种&#xff0c;不同推广方法获客效果也是不同的&#xff0c;只有…...

韩顺平0基础学Java——第5天

p72——p86 今天同学跟我说别学java&#xff0c;真的吗&#xff1f;唉&#xff0c;先把这视频干完吧。 逻辑运算符练习 x6&#xff0c;y6 x6&#xff0c;y5 x11&#xff0c;y6 x11&#xff0c;y5 z48 错了&a…...

单片机为什么能直接烧录程序?

在设计芯片的时候&#xff0c;关于烧录的环节是一个不得不考虑的问题。首先排除掉&#xff0c;由外部硬件直接操控FLASH的方案&#xff0c;这个方案有很多缺点。 1、每个IC使用的FLASH型号各不相同&#xff0c;每种型号的FLASH的烧录命令和流程都有差别&#xff0c;这会导致烧…...

【Linux】25. 网络基础(一)

网络基础(一) 计算机网络背景 网络发展 独立模式: 计算机之间相互独立; 网络互联: 多台计算机连接在一起, 完成数据共享; 其实本质上一台计算机内部也是一个小型网络结构(如果我们将计算机内部某个硬件不存放在电脑中&#xff0c;而是拉根长长的线进行连接。这其实也就是网…...

项目经理【人】任务

系列文章目录 【引论一】项目管理的意义 【引论二】项目管理的逻辑 【环境】概述 【环境】原则 【环境】任务 【环境】绩效 【人】概述 【人】原则 【人】任务 一、定义团队的基本规则&塔克曼阶梯理论 1.1 定义团队的基本规则 1.2 塔克曼阶梯理论 二、项目经理管理风格 …...

Linux学习(嵌入式硬件知识)

GPU和CPU GPU&#xff08;Graphics Processing Unit&#xff0c;图形处理单元&#xff09;和 CPU&#xff08;Central Processing Unit&#xff0c;中央处理单元&#xff09;是计算机中两种不同的处理器。它们在功能、设计和用途上有所不同。 CPU&#xff08;中央处理单元&…...

英语学习笔记4——Is this your ...?

Is this your …? 词汇 Vocabulary suit /sut/ n. 西装&#xff0c;正装 suit 的配套&#xff1a; shirt n. 衬衫tie n. 领带&#xff0c;领结belt n. 腰带trousers n. 裤子shoes n. 鞋子 school /skuːl/ n. 学校 所有学校 搭配&#xff1a;middle school 初中    hig…...

Hive Bucketed Tables 分桶表

Hive Bucketed Tables 分桶表 1.分桶表概念 2.分桶规则 3.语法 4.分桶表的创建 5.分桶表的好处...

【拆位法 决策包容性 位运算】2871. 将数组分割成最多数目的子数组

本文涉及知识点 拆位法 贪心 位运算 决策包容性 位运算、状态压缩、子集状态压缩汇总 LeetCode2871. 将数组分割成最多数目的子数组 给你一个只包含 非负 整数的数组 nums 。 我们定义满足 l < r 的子数组 nums[l…r] 的分数为 nums[l] AND nums[l 1] AND … AND nums[r…...

Java 线程池 ( Thread Pool )的简单介绍

想象一下&#xff0c;你正指挥着一支超级英雄团队&#xff0c;面对蜂拥而至的敌人&#xff08;任务&#xff09;&#xff0c;不是每次都召唤新英雄&#xff08;创建线程&#xff09;&#xff0c;而是精心调配现有成员&#xff0c;高效应对。这就是Java线程池的魔力&#xff0c;…...

鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位

时间概念太重要了&#xff0c;在鸿蒙内核又是如何管理和使用时间的呢? 时间管理以系统时钟 g_sysClock 为基础&#xff0c;给应用程序提供所有和时间有关的服务。 用户以秒、毫秒为单位计时.操作系统以Tick为单位计时&#xff0c;这个认识很重要. 每秒的tick大小很大程度上决…...

安装numpy遇到的问题

安装numpy的时候提示无法安装如下&#xff1a; (venv) E:\works\AI\venv\Scripts>pip install numpy pandas matplotlib jupyter -i https://pypi.douban.com/simple Looking in indexes: https://pypi.douban.com/simple WARNING: Retrying (Retry(total4, connectNone, r…...

页面嵌套,界面套娃,除了用iframe,还有其他方式吗?

UIOTOS可以了解下&#xff0c;uiotos.net&#xff0c;通过连线来代替脚本逻辑开发&#xff0c;复杂的交互界面&#xff0c;通过页面嵌套轻松解决&#xff0c;是个很新颖的思路&#xff0c;前端零代码&#xff01; 蓝图连线尤其是独创的页面嵌套和属性继承技术&#xff0c;好家…...

上传文件至linux服务器失败

目录 前言异常排查使用df -h命令查看磁盘使用情况使用du -h --max-depth1命令查找占用空间最大的文件夹 原因解决补充&#xff1a;删除文件后&#xff0c;磁盘空间无法得到释放 前言 使用XFTP工具上传文件至CentOS服务器失败 异常 排查 使用df -h命令查看磁盘使用情况 发现磁盘…...

渗透 如何防御ARP欺骗,LLMNR-MDNS-NBNS等协议的作用

一. 如何防御ARP欺骗&#xff1f; 1.使用双向IP/MAC绑定&#xff1b; 2.使用静态ARP缓存表&#xff1b; 3.使用ARP服务器&#xff0c;通过服务器来查找ARP转换表来响应其他机器的广播&#xff1b; 4.使用ARP欺骗防护软件&#xff1b; 5.在网关设备上部署防ARP欺骗攻击功能…...

【C++ 所有STL容器简介】

【C 所有STL容器简介】 1. vector2. list3. deque4. set / multiset5. map / multimap6. unordered_set / unordered_multiset7. unordered_map / unordered_multimap8. stack9. queue10. priority_queue C 标准模板库&#xff08;STL&#xff09;提供了一系列常用的容器&#…...

Django调用SECRET_KEY对数据进行加密

对数据进行加密 在Django中进行加密可以直接调用django配置文件中的SECRET_KEY , 同时还需要导入itsdangerous模块中的TimedJSONWebSignatureSerializer进行加密 1. 实现加密方法 , 生成用户加密链接 # 生成用户加密链接 def generate_verify_email_url(user):# 调研加密方法…...

芸众商城电商专业版400+插件源码+搭建教程

介绍&#xff1a; 芸众商城社交电商系统SAAS平台前端基于vue开发&#xff0c;后端基于研发积分商城系统源码 php&#xff0c;本文安装芸众商城全插件&#xff08;400多个&#xff09;商业版平台源码&#xff0c;可同时支持多端口部署运行&#xff1b;使用宝塔面板一键部署的形…...

【机器学习与实现】线性回归示例——波士顿房价分析

目录 一、创建Pandas对象并查看数据的基本情况二、使用皮尔逊相关系数分析特征之间的相关性三、可视化不同特征与因变量MEDV&#xff08;房价中值&#xff09;间的相关性四、划分训练集和测试集并进行回归分析 一、创建Pandas对象并查看数据的基本情况 boston.csv数据集下载&a…...

Redis核心数据结构——跳表(生成数据到文件和从文件中读取数据、模块合并、)

生成文件和从文件中读取数据。 需求如下&#xff1a; 你的任务是实现 SkipList 类中的数据持久化成员函数和数据加载成员函数。 持久化数据成员函数签名&#xff1a;void dump_file(); 该成员函数负责将存储引擎内的数据持久化到文件中。数据的持久化格式是将每个键值对写入文…...

微信小程序下载文件详解

在微信小程序中&#xff0c;下载文件通常涉及使用 wx.downloadFile API。这个 API 可以将网络资源下载到本地临时文件路径&#xff0c;然后你可以使用 wx.saveFile 将临时文件保存到本地持久存储位置。下面是一个下载文件的详细过程&#xff1a; 使用 wx.downloadFile 下载文件…...

2024 概率论和数理统计/专业考试/本科考研/论文/重点公式考点汇总

## 列表http://www.deepnlp.org/equation/category/statistics ## 均匀分布http://www.deepnlp.org/equation/uniform-distribution ## t-分布http://www.deepnlp.org/equation/student-t-distribution ## 伯努利分布http://www.deepnlp.org/equation/bernoulli-distributio…...

四川易点慧电子商务抖音小店:潜力无限的新零售风口

在当今数字化浪潮中&#xff0c;电子商务已经成为推动经济发展的重要引擎。四川易点慧电子商务有限公司凭借其敏锐的市场洞察力和创新精神&#xff0c;成功在抖音小店这一新兴平台上开辟出一片新天地。本文将探讨四川易点慧电子商务抖音小店的潜力及其在新零售领域的影响力。 一…...

Seal^_^【送书活动第3期】——《Hadoop大数据分析技术》

Seal^_^【送书活动第3期】——《Hadoop大数据分析技术》 一、参与方式二、作者荐语三、图书简介四、本期推荐图书4.1 前 言4.2 本书内容4.3 本书目的4.4 本书适合的读者4.5 配套源码、PPT课件等资源下载 五、目 录六、&#x1f6d2; 链接直达 Hadoop框架入门书&#xff0c;可当…...

win10下,svn上传.so文件失败

问题&#xff1a;win10下使用TortoiseSVN&#xff0c;svn上传.so文件失败 解决&#xff1a;右键&#xff0c;选择Settings&#xff0c;Global ignore pattern中删除*.so&#xff0c;保存即可。...

ubuntu20安装colmap

系统环境 ubuntu20 &#xff0c;cuda11.8 &#xff0c;也安装了anaconda。因为根据colmap的官方文档说的&#xff0c;如果根据apt-get安装的话&#xff0c;默认是非cuda版本的&#xff0c;而我觉得既然都安装了cuda11.8了&#xff0c;自然也要安装cuda版本的colmap。 安装步骤…...

kubeflow简单记录

kubeflow 13.7k star 1、Training Operator 包括PytorchJob和XGboostJob&#xff0c;支持部署pytorch的分布式训练 2、KFServing快捷的部署推理服务 3、Jupyter Notebook 基于Web的交互式工具 4、Katib做超参数优化 5、Pipeline 基于Argo Workflow提供机器学习流程的创建、编排…...

ARM的工作模式

ARM处理器设计有七种工作模式&#xff0c;这些模式允许处理器在不同的情境下以不同的权限级别执行任务&#xff0c;下面是这七大工作模式的概述&#xff1a; 用户模式&#xff08;User&#xff0c;USR&#xff09;&#xff1a; 这是非特权模式&#xff0c;大多数应用程序在此…...

为家庭公网IP配置DDNS域名

文章目录 域名配置域名更新frp配置修改 在成功完成frp改造Windows笔记本实现家庭版免费内网穿透之后&#xff0c;某天我突然发现内网穿透失效了&#xff0c;一番排查之后原来是路由器对应的公网IP更换了。果然我分到的并不是固定的公网IP&#xff0c;而是会定期变化的。为了免受…...

QT-TCP通信

网上的资料太过于书面化&#xff0c;所以看起来有的让人云里雾里&#xff0c;看不懂C-tcpsockt和S-tcpsocket的关系 所以我稍微画了一下草图帮助大家理解两个套接字之间的关系。字迹有的飘逸勉强看看 下面是代码 服务端&#xff1a; MainWindow::MainWindow(QWidget *parent) …...

SparkSQL优化

SparkSQL优化 优化说明 缓存数据到内存 Spark SQL可以通过调用spark.sqlContext.cacheTable("tableName") 或者dataFrame.cache()&#xff0c;将表用一种柱状格式&#xff08; an inmemory columnar format&#xff09;缓存至内存中。然后Spark SQL在执行查询任务…...

STM32——基础篇

技术笔记&#xff01; 一、初识STM32 1.1 ARM内核系列 A 系列&#xff1a;Application缩写。高性能应用&#xff0c;比如&#xff1a;手机、电脑、电视等。 R 系列&#xff1a;Real-time缩写。实时性强&#xff0c;汽车电子、军工、无线基带等。 M 系列&#xff1a;Microcont…...

【从零开始学架构 架构基础】架构设计的本质、历史背景和目的

本文是《从零开始学架构》的第一篇学习笔记&#xff0c;主要理解架构的设计的本质定义、历史背景以及目的。 架构设计的本质 分别从三组概念的区别来理解架构设计。 系统与子系统 什么是系统&#xff0c;系统泛指由一群有关联的个体组成&#xff0c;根据某种规则运作&#…...

Learning C# Programming with Unity 3D

作者&#xff1a;Alex Okita 源码地址&#xff1a;GitHub - badkangaroo/UnityProjects: A repo for all of the projects found in the book. 全书 686 页。...

北京车展现场体验商汤DriveAGI自动驾驶大模型展现认知驱动新境界

在2024年北京国际汽车展的舞台上&#xff0c;众多国产车型纷纷亮相&#xff0c;各自展示着独特的魅力。其中&#xff0c;小米SUV7以其精美的外观设计和宽敞的车内空间&#xff0c;吸引了无数目光&#xff0c;成为本届车展上当之无愧的明星。然而&#xff0c;车辆的魅力并不仅限…...

企业终端安全管理软件有哪些?终端安全管理软件哪个好?

终端安全的重要性大家众所周知&#xff0c;关系到生死存亡的东西。 各类终端安全管理软件应运而生&#xff0c;为企业提供全方位、多层次的终端防护。 有哪些企业终端安全管理软件&#xff1f; 一、主流企业终端安全管理软件 1. 域智盾 域智盾是一款专为企业打造的全面终端…...

Linux内核--设备驱动(七)媒体驱动框架整理--HDMI框架(2)

目录 一、引言 二、drm框架 ------>2.1、画布( FrameBuffer ) ------>2.2、绘图现场(CRTC) ------>2.3、输出转换器(Encoder ) ------>2.4、连接器 (Connector ) ------>2.5、显示面(Planner) 三、VOP部分详解 ------>3.1、dts ------>3.2、v…...

3.3 Gateway之自定义过滤器

1.Gateway过滤器种类 过滤器种类描述GatewayFilter路由过滤器&#xff0c;作用于任意指定的路由。默认不生效&#xff0c;要配置到路由后生效GlobalFilter全局过滤器&#xff0c;作用范围是所有路由。声明后自定生效 2.Gateway过滤器参数 参数描述ServerWebExchangeGateway内…...

Skywalking数据持久化与自定义链路追踪

学习本篇文章之前首先要了解一下Sky walking的基础知识 分布式链路追踪工具Skywalking详解 一&#xff0c;Sky walking数据持久化 Sky walking提供了es&#xff0c;MySQL等数据持久化方案&#xff0c;默认使用h2基于内存的数据库&#xff0c;重启之后数据即会丢失。 在实际工…...

设计模式之模板模式TemplatePattern(五)

一、模板模式介绍 模板方法模式&#xff08;Template Method Pattern&#xff09;&#xff0c;又叫模板模式&#xff08;Template Pattern&#xff09;&#xff0c; 在一个抽象类公开定义了执行它的方法的模板。它的子类可以更需要重写方法实现&#xff0c;但可以成为典型类中…...

划重点!PMP报考条件、报考步骤、考试内容、适合人群

参加PMP认证的好处&#xff0c;可以从几个方面来认识&#xff1a; 一、参加PMP认证与考试的过程&#xff0c;同时是一个系统学习和巩固项目管理知识的过程 二、参加PMP认证&#xff0c;您可以获得由PMI颁发的PMP证书 而拥有PMP认证表示你已经成为一个项目管理方面的专业人员…...

Java | Leetcode Java题解之第74题搜索二维矩阵

题目&#xff1a; 题解&#xff1a; class Solution {public boolean searchMatrix(int[][] matrix, int target) {int m matrix.length, n matrix[0].length;int low 0, high m * n - 1;while (low < high) {int mid (high - low) / 2 low;int x matrix[mid / n][m…...

C#高级编程笔记-泛型

本章的主要内容如下&#xff1a; ● 泛型概述 ● 创建泛型类 ● 泛型类的特性 ● 泛型接口 ● 泛型结构 ● 泛型方法 目录 1.1 泛型概述 1.1.1 性能 1.1.2 类型安全 1.1.3 二进制代码的重用 1.1.4 代码的扩展 1.1.5 命名…...

(超简单)SpringBoot中简单用工厂模式来实现

简单讲述业务需求 业务需要根据不同的类型返回不同的用户列表&#xff0c;比如按角色查询用户列表、按机构查询用户列表&#xff0c;用户信息需要从数据库中查询&#xff0c;因为不同的类型查询的逻辑不相同&#xff0c;因此简单用工厂模式来设计一下&#xff1b; 首先新建一个…...

java中的条件、循环和scanner类

if else ; 单行逻辑大括号可以省略&#xff1b;但是不建议省略&#xff1b; public static void main(String[] args) {boolean bool1 (Math.random() * 1000) % 2 > 1;System.out.println((Math.random() * 1000) % 2 "-" bool1);if(bool1) {System.out.prin…...

【Qt QML】Frame组件

Frame&#xff08;框架&#xff09;包含在&#xff1a; import QtQuick.Controls继承自Pane控件。用于在可视框架内布局一组逻辑控件。简单来说就是用来包裹和突出显示其他可视元素。Frame不提供自己的布局&#xff0c;但需要自己对元素位置进行设置和定位&#xff0c;例如通过…...

Web API之DOM

DOM 一.认识DOM二.获取元素三.事件基础四.操作元素(1).改变元素内容(2).修改元素属性(str、herf、id、alt、title&#xff09;(3).修改表单属性(4).修改样式属性操作(5).小结 五.一些思想(1).排他思想(2).自定义属性的操作 六.节点操作1.认识2.节点层级关系3.创建和添加、删除、…...

windows驱动开发-内核编程技术汇总(六)

在驱动程序中使用文件 内核模式组件通过其对象名称引用文件&#xff0c;该对象名称是连接到文件的完整路径的 \DosDevices 。 在 Microsoft Windows 2000 及更高版本的操作系统上&#xff0c; \?? 等效于 \DosDevices。例如&#xff0c;C:\WINDOWS\example.txt 文件的对象名…...

原创|手把手教你构建评分卡模型

作者&#xff1a;胡赟豪‍‍‍‍ 本文约2800字&#xff0c;建议阅读5分钟 本文介绍了构建评分卡模型。‍‍‍ 一、背景 在各种机器学习、深度学习模型快速发展的当下&#xff0c;评分卡模型作为一种可解释机器学习模型&#xff0c;仍然在金融、营销等领域被广泛使用。这一模型通…...

zip压缩unzip解压缩、gzip和gunzip解压缩、tar压缩和解压缩

一、tar压缩和解压缩 tar [选项] 打包文件名 源文件或目录 选项含义-c创建新的归档文件-x从归档文件中提取文件-v显示详细信息-f指定归档文件的名称-z通过gzip进行压缩或解压缩-j通过bzip2进行压缩或解压缩-J通过xz进行压缩或解压缩-p保留原始文件的权限和属性–excludePATTE…...

冲!哪怕公域拓展流量超卷,数字化转型营销也勇往直前!

在这个数字时代&#xff0c;公域拓展流量的竞争已经激烈到令人咋舌的程度&#xff01;然而&#xff0c;开利网络蚓链数字化转型营销解决方案经过上千家客户实践告诉我们&#xff0c;即使面对如此残酷的局面&#xff0c;我们也必须勇敢地去面对&#xff0c;利用想得到的合规合法…...

PPT为何无法复制粘贴?附解决办法!

PPT文件里的内容无法复制&#xff0c;或者复制后无法粘贴&#xff0c;这是怎么回事呢&#xff1f; 这种情况&#xff0c;一般是因为PPT被设置了保护&#xff0c;设置了以“只读方式”打开&#xff0c;就无法进行复制粘贴了。PPT的“只读方式”不同&#xff0c;解决方法也不同&…...

C++之lambda【匿名函数】

1、语法 语法结构&#xff1a; [捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {// 函数处理 }注意&#xff1a; 一般情况下&#xff0c;编译器可以自动推断出lambda表达式的返回类型&#xff0c;所以我们可以不指定返回类型。 但是如果函数体内有多个return语…...

Python函数之旅专栏(导航)

Python内置函数(参考版本:3.11.8)AELRabs( )enumerate( )len( )range( )aiter( )eval( )list( )repr( )all( )exec( )locals( )reversed( )anext( )round( )any( ) ascii( )FM  filter( )map( )S float( )max( )set( )Bformat( )memoryview( )setattr( )bin( )frozenset( )…...