Javase.图书管理系统基本框架

news2024/11/24 20:04:25

图书管理系统基本框架

  • 1.核心类介绍
  • 2. book包详解
    • 2.1 Book 类
      • 2.1.2 代码展示
      • 2.1.2 代码解析
    • 2.2 BookList 类
      • 2.2.2 代码展示
      • 2.2.2 代码解析
    • 2.3Book类和BookList类的联系
  • 3. 用户角色与管理
    • 3.1 User 类
      • 3.1.1 代码展示
      • 3.1.2 代码解析
    • 3.2 adminUser 类
      • 3.2.1 代码展示
      • 3.2.2代码解析
    • 3.3 normalUser 类
      • 3.3.1 代码展示
      • 3.3.2 代码解析
    • 3.4三者之间的联系
  • 4. 操作类详解
    • 4.1 IOperation 接口
      • 4.1.1 代码展示
    • 4.1.2接口和各实现类之间的关系
    • 4.2 AddOperation 类
      • 4.2.1 代码展示
      • 4.2.2 代码解析
    • 4.3 BorrowOperation 类
      • 4.3.1 代码展示
      • 4.2.2 代码解析
    • 4.4 DelOperation 类
      • 4.4.1 代码展示
      • 4.2.2 代码解析
    • 4.5 ExitOperation 类
      • 4.5.1 代码展示
      • 4.2.2 代码解析
    • 4.6 FindOperation 类
      • 4.6.1 代码展示
      • 4.2.2 代码解析
    • 4.7 ReturnOperation 类
      • 4.7.1 代码展示
      • 4.2.2 代码解析
    • 4.8 ShowOperation 类
      • 4.8.1 代码展示
      • 4.2.2 代码解析
  • 5. 系统整合与实践
    • 5.1 类之间的交互与整合
    • 5.1.1 package book
    • 5.1.2 package ioperations
    • 5.1.2 package user
    • 5.2 类和类之间的整体联系
    • 5.3 功能拓展

1.核心类介绍

本项目的核心类包括BookUser(及其子类adminUser和normalUser)、以及多个操作类(AddOperation、BorrowOperation等)。Book类代表图书信息,User类及其子类处理用户身份与权限,而操作类则封装了图书管理的各项功能,共同支撑起整个系统的运作。

图片预览

在这里插入图片描述

2. book包详解

2.1 Book 类

2.1.2 代码展示

package book;

public class Book {
    private String name;//书名
    private String author;//作者
    private int price;//价格
    private String type;//书的类型
    private boolean isBorrowed;//书的状态(是否借出)

    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 +
                ((isBorrowed == true) ? "已借出" : "未借出") +
                '}';
    }
}

2.1.2 代码解析

这个Book类定义了书籍的基本属性和行为。

  1. 属性

    • name:书名
    • author:作者
    • price:价格
    • type:书的类型
    • isBorrowed:表示书是否被借出,是一个布尔值。
  2. 构造方法
    当创建一个新的Book对象时,需要传入书名、作者、价格和类型,这些值将被用来初始化对象的相应属性。

  3. Getter 和 Setter 方法
    对于每个属性,都有对应的获取(getter)和设置(setter)方法,允许外部代码读取或修改这些属性的值。

  4. toString 方法
    这个方法用于返回书籍信息的字符串表示。它拼接了书名、作者、价格和类型,并根据isBorrowed属性的值添加书籍的借出状态(“已借出"或"未借出”)。

逻辑关系分析:

  • Book类封装了书籍的基本信息。
  • 构造方法确保在创建书籍对象时,必须提供必要的信息(书名、作者、价格、类型)。
  • Getter 方法允许外部访问书籍的属性,但不允许直接修改。
  • Setter 方法允许外部修改书籍的属性,提供了对属性值的保护和控制。
  • toString 方法提供了一种标准化的方式来展示书籍的详细信息,包括其是否被借出的状态。

整体而言,这个类通过封装、数据隐藏和提供接口,实现了对书籍信息的有效管理和保护。

2.2 BookList 类

2.2.2 代码展示

package book;

public class BookList {
    //把书作为对象:
    private Book[] books = new Book[10];//书架
    private int usedSize;//书本的有效个数

    //书架
    public BookList() {
        this.books[0] = new Book("三国演义", "罗贯中", 10, "小说");
        this.books[1] = new Book("西游记", "吴承恩", 20, "小说");
        this.books[2] = new Book("红楼梦", "曹雪芹", 30, "小说");

        this.usedSize = 3;
    }

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

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

    public int getUsedSize() {
        return usedSize;
    }

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

2.2.2 代码解析

这个BookList类代表了一个书架,它管理一个包含书籍(Book对象)的数组。

  1. 属性

    • books:一个Book对象数组,代表书架上的书,最多可以容纳10本书。
    • usedSize:表示书架上当前已经放置的书籍数量。
  2. 构造方法
    在创建BookList对象时,构造方法会初始化书架,并在书架上放置三本初始的书籍,同时设置usedSize为3,表示书架上有3本书。

  3. Getter 和 Setter 方法

    • getBook(int pos):根据位置获取书架上的某本书。
    • getBooks():获取整个书籍数组。
    • setBook(int pos, Book book):在指定位置放置一本书。
    • getUsedSize()setUsedSize(int usedSize):分别用于获取和设置书架上当前使用的空间(即书本的数量)。

逻辑关系分析:

  • BookList类模拟了一个书架,可以存放最多10本书。
  • 构造方法初始化了书架,并在其上放置了三本预定义的书籍。
  • 通过getter方法可以查看书架上的书籍信息,包括获取特定位置的书籍或整个书籍数组。
  • 通过setter方法可以在书架上放置或替换书籍。
  • usedSize属性跟踪书架上当前有多少本书,这有助于避免访问空位置或超出数组界限。

总的来说,这个类通过封装一个Book对象数组和相关的操作方法,提供了一个管理和访问书架上书籍的接口。

2.3Book类和BookList类的联系

  1. Book 类:

    • 描述了书的基本属性,如书名、作者、价格、类型和借阅状态。
    • 提供了构造函数用于初始化这些属性。
    • 提供了getter和setter方法来访问和修改这些属性。
    • 重写了toString方法,用于以字符串形式展示书的信息,特别是借阅状态被转换为了中文描述。
  2. BookList 类:

    • 表示一个书架,可以存放多本书。
    • 使用了一个Book类型的数组books来存储书,并设置了一个上限为10本书。
    • usedSize变量用于跟踪书架上实际存放的书的数量。
    • 构造函数中初始化了书架,放置了三本书,并设置了usedSize为3。
    • 提供了方法来获取和设置书架上特定位置的书,以及获取整个书架的书和usedSize的值。

逻辑关系:

  • Book类定义了书的属性和行为。
  • BookList类使用Book对象来构建一个书架,可以管理和操作书架上的书。
  • BookList的构造函数中,创建了三个Book对象并放置在书架上。

简而言之,Book类代表单本书,而BookList类代表一个可以存储多本书的书架,并提供了管理和访问这些书的方法。

3. 用户角色与管理

3.1 User 类

3.1.1 代码展示

package user;

import book.BookList;
import ioperations.IOperation;

public abstract class User {
    //用户通过接口数组和名字来操作图书系统的
    protected String name;
    IOperation[] iOperations;

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

    public abstract int menu();

    public void doIoperation(int choice, BookList bookList) {
        iOperations[choice].work(bookList);//真正操作图书系统
    }
}

3.1.2 代码解析

User是一个抽象类,它代表了一个使用图书系统的用户。以下是User类逻辑关系的简短分析:

  1. 属性

    • name:存储用户的名字。
    • iOperations:是一个IOperation接口类型的数组,用于存储用户可以执行的各种操作。
  2. 构造方法

    • 构造方法接受一个字符串参数,用于设置用户的名字。
  3. 抽象方法

    • menu():这是一个抽象方法,需要在User的子类中实现。这个方法预计会返回一个整数,可能代表用户选择的操作编号。
  4. 普通方法

    • doIoperation(int choice, BookList bookList):这个方法接受一个操作编号(choice)和一个BookList对象。根据操作编号,它会调用iOperations数组中相应位置的IOperation对象的work方法,对bookList执行具体的操作。这是用户与图书系统交互的桥梁,通过这个方法,用户可以执行添加、查找、归还或展示书籍等操作。

简而言之,User类定义了一个使用图书系统的用户的基本属性和行为。它使用了一个IOperation接口数组来代表用户可以执行的各种操作,并通过doIoperation方法来实际执行用户选择的操作。这个类是一个抽象类,意味着它不能直接实例化,而是需要具体的子类来实现menu方法,并可能提供额外的功能或属性。

3.2 adminUser 类

3.2.1 代码展示

package user;

import ioperations.*;

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() {
        System.out.println("欢迎" + this.name + "来到图书系统");
        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();
        return choice;
    }
}

3.2.2代码解析

AdminUser类是User类的子类,代表图书系统的管理员用户。以下是AdminUser类逻辑关系的简短分析:

  1. 继承关系

    • AdminUser继承了User类,这意味着它继承了User的所有属性和方法,并且可以添加或覆盖父类的方法以实现特定的管理员功能。
  2. 构造方法

    • 构造方法接收管理员的名字作为参数,并通过调用父类的构造方法来设置该名字。
    • 在构造方法中,初始化了iOperations数组,该数组包含了管理员可以执行的操作。这些操作包括退出、查找、添加、删除和显示图书。
  3. 覆盖的menu方法

    • menu方法被覆盖以提供管理员特定的菜单选项。
    • 方法首先输出欢迎信息和管理员菜单,然后提示用户输入操作选择。
    • 使用Scanner类从用户那里接收输入,表示用户选择的操作编号。
    • 返回用户选择的操作编号,这个编号将用于后续调用doIoperation方法来执行相应的操作。

简而言之,AdminUser类通过继承User类并覆盖其menu方法,为管理员用户提供了特定的功能和操作菜单。管理员可以执行查找、新增、删除和显示图书等操作,这些都是通过iOperations数组中存储的相应操作类来实现的。

3.3 normalUser 类

3.3.1 代码展示

package user;

import ioperations.*;

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

    @Override
    public int menu() {
        System.out.println("欢迎" + this.name + "来到图书系统");
        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();
        return choice;
    }
}

3.3.2 代码解析

NormalUser类是User类的另一个子类,代表图书系统的普通用户。以下是NormalUser类逻辑关系的简短分析:

  1. 继承关系

    • NormalUser继承了User类,因此它继承了父类的所有属性和方法,并可以根据需要覆盖或添加新的方法。
  2. 构造方法

    • 构造方法接受普通用户的名字作为参数,并通过调用父类的构造方法来初始化该名字。
    • 在构造方法中,还初始化了iOperations数组,这个数组包含了普通用户可以执行的操作。这些操作包括退出系统、查找图书、借阅图书和归还图书。
  3. 覆盖的menu方法

    • menu方法在NormalUser类中被覆盖,以提供普通用户特定的菜单选项。
    • 方法首先打印欢迎信息和普通用户菜单,然后提示用户输入他们的操作选择。
    • 使用Scanner类从控制台接收用户的输入,该输入代表用户想要执行的操作编号。
    • 返回用户选择的操作编号,此编号稍后将用于调用doIoperation方法,以执行用户选择的操作。

简而言之,NormalUser类通过继承User类并定制其menu方法,为普通用户提供了特定的操作菜单和功能。普通用户可以执行查找、借阅和归还图书等操作,这些操作是通过iOperations数组中相应位置的操作类来实现的。这个类与AdminUser类相似,但提供的操作和功能是根据普通用户的需求来定制的。

3.4三者之间的联系

父类User定义了用户的通用属性和行为,包括用户名字和一系列操作。它设置了一个框架,使得不同的用户类型可以执行不同的操作。

子类AdminUserNormalUser分别继承了User类,代表两种不同类型的用户:管理员和普通用户。这两个子类都拥有父类的属性和方法,但各自定制了可执行的操作集合iOperations和菜单选项menu()

AdminUser提供了管理员特有的功能,如添加、删除图书等,而NormalUser则提供了普通用户需要的功能,如借阅和归还图书。

通过这种继承关系,代码实现了用户角色的多态性,即不同类型的用户可以以不同的方式使用系统,但都基于相同的用户基础结构。

4. 操作类详解

4.1 IOperation 接口

4.1.1 代码展示

public interface IOperation {
    void work(BookList bookList);
}

4.1.2接口和各实现类之间的关系

IOperation 是一个接口,它定义了一个 work 方法,该方法接受一个 BookList 类型的参数。这个接口的作用是规定一种操作契约,即任何实现了 IOperation 接口的类都必须提供 work 方法的具体实现,并且这个方法需要能够对一个 BookList 对象执行某种操作。

现在,让我们来分析 IOperation 接口与 AddOperationBorrowOperationDelOperationExitOperationFindOperationReturnOperationShowOperation 等类之间的逻辑关系:

  1. IOperation 接口

    • 定义了操作的通用接口,即 work 方法。
    • 它是所有具体操作的抽象表示。
  2. 具体实现类(如 AddOperation)

    • 这些类是 IOperation 接口的具体实现。
    • 每个类都必须实现 work 方法,以定义该类对应的特定操作。
    • 例如,AddOperationwork 方法可能会实现向 BookList 中添加书籍的逻辑。

逻辑关系:

  • IOperation 是所有操作类的基类(接口),它定义了操作的通用方法。
  • AddOperationBorrowOperationDelOperationExitOperationFindOperationReturnOperationShowOperation 等类是 IOperation 的具体实现,每个类都负责实现一种特定的图书管理操作。
  • 这些实现类通过覆盖(实现)work 方法,提供了对 BookList 对象执行特定操作的具体逻辑。

这种设计允许系统以一种统一和灵活的方式处理不同的图书管理操作,因为所有的操作都遵循相同的接口规范。同时,这种结构也便于扩展和维护,因为可以轻松地添加新的操作类,只要它们实现了 IOperation 接口。

4.2 AddOperation 类

4.2.1 代码展示

package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class AddOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.print("添加书籍:");

        //1. 判满
        int currentSize = bookList.getUsedSize();
        if (currentSize == bookList.getBooks().length) {
            System.out.println("书架满了 不能放了.....");
            return;
        }


        //2. 构建对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入书名:");
        String name = scanner.nextLine();

        System.out.println("请输入作者:");
        String author = scanner.nextLine();

        System.out.println("请输入书的类型:");
        String type = scanner.nextLine();

        System.out.println("请输入价格:");
        int price = scanner.nextInt();


        Book newBook = new Book(name, author, price, type);

        //3. 判断书架有没有这本书
        for (int i = 0; i < currentSize; i++) {
            Book book = bookList.getBook(i);
            if (book.getName().equals(name)) {
                System.out.println("有这本书不能插入!");
                return;
            }
        }

        //4.插入这本书
        bookList.setBook(currentSize, newBook);

        bookList.setUsedSize(currentSize + 1);

        System.out.println("新增图书成功!!!");

    }
}

4.2.2 代码解析

这个AddOperation类实现了IOperation接口,并提供了work方法用于向BookList中添加新的书籍。以下是该方法的逻辑关系分析:

  1. 检查书架是否已满

    • 首先,获取书架当前的使用大小(currentSize)和书架的总容量。
    • 如果书架已满(currentSize等于书架总容量),则输出提示信息并结束方法。
  2. 构建新书籍对象

    • 使用Scanner类从用户那里获取新书籍的信息(书名、作者、类型和价格)。
    • 利用这些信息创建一个新的Book对象。
  3. 检查书籍是否已存在

    • 遍历书架上的所有书籍。
    • 如果找到与新书籍同名的书籍,则输出提示信息并结束方法。
  4. 添加新书籍到书架

    • 将新创建的Book对象添加到书架的下一个可用位置(即currentSize所指示的位置)。
    • 更新书架的使用大小(usedSize),将其增加1。
    • 输出成功添加新书籍的信息。

简而言之,这个类的work方法实现了向书架中添加新书籍的功能,同时确保了书架不会超出容量,并且避免了重复添加相同的书籍。

4.3 BorrowOperation 类

4.3.1 代码展示

package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class BorrowOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅书籍:");

        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入你借阅的书名:");
        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)) {
                if (book.isBorrowed()) {
                    System.out.println("这本书已经被借出了!");
                    return;
                }
                book.setBorrowed(true);
                System.out.println("借阅成功!");
                return;
            }
        }
        System.out.println("没有你要借阅的这本书....");
    }
}

4.2.2 代码解析

这个BorrowOperation类实现了IOperation接口,并提供了work方法用于处理书籍借阅的逻辑。以下是该方法逻辑关系的简短分析:

  1. 提示用户并接收输入

    • 输出提示信息,告知用户正在进行借阅操作。
    • 使用Scanner类接收用户输入的要借阅的书名。
  2. 遍历书架上的书籍

    • 获取书架当前的使用大小(currentSize)。
    • 遍历书架上的每一本书,检查书名是否与用户输入的书名匹配。
  3. 检查书籍状态并执行借阅

    • 如果找到匹配的书名,首先检查该书是否已经被借出。
    • 如果书已经被借出,则输出提示信息并结束方法。
    • 如果书未被借出,将其借阅状态设置为已借出,输出借阅成功的提示信息,并结束方法。
  4. 处理未找到书籍的情况

    • 如果遍历完书架上的所有书籍都没有找到匹配的书名,则输出提示信息表示没有用户要借阅的这本书。

简而言之,这个类的work方法实现了书籍借阅的功能,通过用户输入的书名来查找并尝试借阅书籍,同时确保了同一本书不会被重复借出,并在未找到书籍或书籍已被借出时给出相应的提示。

4.4 DelOperation 类

4.4.1 代码展示

package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 姚东名
 * Date: 2024-06-22
 * Time: 9:56
 */
public class DelOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("删除书籍:");

        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入你删除的书名:");
        String name = scanner.nextLine();
        int currentSize = bookList.getUsedSize();

        int pos = -1;
        //找到这本书
        int i = 0;
        for (; i < currentSize; i++) {
            Book book = bookList.getBook(i);
            if (book.getName().equals(name)) {
                pos = i;
                break;
            }
        }

        if (i == currentSize) {
            System.out.println("没有你要删除的书!");
            return;
        }

        //这里开始删除
        for (int j = pos; j < currentSize - 1; j++) {
            //bookList[j] = bookList[j+1];
            Book book = bookList.getBook(j + 1);

            bookList.setBook(j, book);
        }

        bookList.setBook(currentSize - 1, null);

        bookList.setUsedSize(currentSize - 1);
        System.out.println("删除成功!!!!");
    }
}

4.2.2 代码解析

这个DelOperation类实现了IOperation接口,并提供了work方法用于从BookList中删除指定的书籍。以下是该方法逻辑关系的简短分析:

  1. 提示用户并接收输入

    • 输出提示信息,告知用户正在进行删除书籍操作。
    • 使用Scanner类接收用户输入的要删除的书名。
  2. 查找要删除的书籍

    • 遍历书架上的书籍,查找与用户输入书名相匹配的书籍,并记录其位置pos
    • 如果未找到匹配的书籍,则输出提示信息并结束方法。
  3. 执行删除操作

    • 如果找到了要删除的书籍,从该书的位置开始,将后面的每一本书向前移动一个位置,覆盖掉要删除的书籍。
    • 将书架的最后一个位置设置为null,因为已经有一本书被“移除”了。
    • 更新书架的使用大小(usedSize),将其减少1。
    • 输出删除成功的提示信息。

简而言之,这个类的work方法实现了从书架中删除指定书籍的功能,通过用户输入的书名来查找并删除书籍,同时在未找到书籍时给出相应的提示。删除操作是通过将后面的书籍向前移动来覆盖要删除的书籍,并更新书架的使用大小。

4.5 ExitOperation 类

4.5.1 代码展示

package ioperations;

import book.BookList;


public class ExitOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统:");
        System.exit(0);
    }
}

4.2.2 代码解析

这个ExitOperation类实现了IOperation接口,并提供了work方法用于退出系统。其逻辑关系非常简单:

  1. 输出提示信息:首先,输出一条信息提示用户系统正在退出。

  2. 退出程序:然后,调用System.exit(0)方法立即终止Java虚拟机,从而结束整个程序。这里的0是退出状态码,表示程序正常退出。

简而言之,这个类的work方法实现了退出系统的功能,通过调用System.exit(0)来结束程序运行。

4.6 FindOperation 类

4.6.1 代码展示

package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class FindOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("查找书籍:");

        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入你的书名:");
        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("没有你要找的这本书....");
    }
}

4.2.2 代码解析

这个FindOperation类实现了IOperation接口,并提供了work方法用于在BookList中查找指定的书籍。以下是该方法逻辑关系的简短分析:

  1. 提示用户并接收输入

    • 输出提示信息,告知用户正在进行书籍查找操作。
    • 使用Scanner类接收用户输入的要查找的书名。
  2. 遍历书架上的书籍

    • 获取书架当前的使用大小(currentSize)。
    • 遍历书架上的每一本书,检查书名是否与用户输入的书名匹配。
  3. 查找并输出结果

    • 如果找到匹配的书名,输出找到的书籍信息,并结束方法。
    • 如果遍历完所有书籍都没有找到匹配的书名,则输出提示信息表示没有用户要查找的这本书。

简而言之,这个类的work方法实现了书籍查找的功能,通过用户输入的书名来在书架中查找书籍,找到则输出书籍信息,未找到则给出相应的提示。

4.7 ReturnOperation 类

4.7.1 代码展示

package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class ReturnOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("归还书籍:");
        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入你归还的书名:");
        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)) {
                if (book.isBorrowed()) {
                    book.setBorrowed(false);
                    System.out.println("归还成功!");
                    return;
                }
            }
        }
        System.out.println("没有你要归还的图书!!!");
    }
}

4.2.2 代码解析

这个ReturnOperation类实现了IOperation接口,并提供了work方法用于处理书籍归还的逻辑。以下是该方法逻辑关系的简短分析:

  1. 提示用户并接收输入

    • 输出提示信息,告知用户正在进行书籍归还操作。
    • 使用Scanner类接收用户输入的要归还的书名。
  2. 遍历书架上的书籍

    • 获取书架当前的使用大小(currentSize)。
    • 遍历书架上的每一本书,检查书名是否与用户输入的书名匹配。
  3. 检查书籍状态并执行归还

    • 如果找到匹配的书名,首先检查该书是否处于被借出状态。
    • 如果书已经被借出,则将其借阅状态设置为未借出,输出归还成功的提示信息,并结束方法。
  4. 处理未找到书籍或书籍未被借出的情况

    • 如果遍历完书架上的所有书籍都没有找到匹配的书名,或者书籍本身就未被借出,则输出提示信息表示没有用户要归还的图书。

简而言之,这个类的work方法实现了书籍归还的功能,通过用户输入的书名来查找并尝试归还书籍,同时确保了只有被借出的书籍才能被归还,并在未找到书籍或书籍未被借出时给出相应的提示。

4.8 ShowOperation 类

4.8.1 代码展示

package ioperations;

import book.Book;
import book.BookList;


public class ShowOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("展示书籍:");
        int currentSize = bookList.getUsedSize();//3
        for (int i = 0; i < currentSize; i++) {
            Book book = bookList.getBook(i);
            System.out.println(book);
            //Book book1 = bookList[i];
        }
    }
}

4.2.2 代码解析

这个ShowOperation类实现了IOperation接口,并提供了work方法用于展示书架上的所有书籍。以下是该方法逻辑关系的简短分析:

  1. 输出提示信息:首先,输出一条信息提示用户接下来将展示书籍。

  2. 获取书架使用大小:通过调用bookList.getUsedSize()方法来获取书架上当前书籍的数量。

  3. 遍历并展示书籍:使用一个for循环遍历书架上的每一本书。在每次循环中,通过bookList.getBook(i)方法获取指定索引位置的书籍对象,并将其信息打印到控制台。

简而言之,这个类的work方法实现了展示书架上所有书籍的功能,通过遍历书架并逐一打印每本书的信息来完成这一操作。

5. 系统整合与实践

5.1 类之间的交互与整合

5.1.1 package book

//book.java
package book;


public class Book {
    private String name;//书名
    private String author;//作者
    private int price;//价格
    private String type;//书的类型
    private boolean isBorrowed;//书的状态(是否借出)

    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 +
                ((isBorrowed == true) ? "已借出" : "未借出") +
                '}';
    }
}
//BookList.java
package book;


public class BookList {
    //把书作为对象:
    private Book[] books = new Book[10];//书架
    private int usedSize;//书本的有效个数

    //书架
    public BookList() {
        this.books[0] = new Book("三国演义", "罗贯中", 10, "小说");
        this.books[1] = new Book("西游记", "吴承恩", 20, "小说");
        this.books[2] = new Book("红楼梦", "曹雪芹", 30, "小说");

        this.usedSize = 3;
    }

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

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

    public int getUsedSize() {
        return usedSize;
    }

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

5.1.2 package ioperations

接口

//IOperation.java
package ioperations;

import book.BookList;


public interface IOperation {
    void work(BookList bookList);
}

基于接口实现的类

//AddOperation.java
package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class AddOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.print("添加书籍:");

        //1. 判满
        int currentSize = bookList.getUsedSize();
        if (currentSize == bookList.getBooks().length) {
            System.out.println("书架满了 不能放了.....");
            return;
        }


        //2. 构建对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入书名:");
        String name = scanner.nextLine();

        System.out.println("请输入作者:");
        String author = scanner.nextLine();

        System.out.println("请输入书的类型:");
        String type = scanner.nextLine();

        System.out.println("请输入价格:");
        int price = scanner.nextInt();


        Book newBook = new Book(name, author, price, type);

        //3. 判断书架有没有这本书
        for (int i = 0; i < currentSize; i++) {
            Book book = bookList.getBook(i);
            if (book.getName().equals(name)) {
                System.out.println("有这本书不能插入!");
                return;
            }
        }

        //4.插入这本书
        bookList.setBook(currentSize, newBook);

        bookList.setUsedSize(currentSize + 1);

        System.out.println("新增图书成功!!!");

    }
}
//BorrowOperation.java
package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class BorrowOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅书籍:");

        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入你借阅的书名:");
        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)) {
                if (book.isBorrowed()) {
                    System.out.println("这本书已经被借出了!");
                    return;
                }
                book.setBorrowed(true);
                System.out.println("借阅成功!");
                return;
            }
        }
        System.out.println("没有你要借阅的这本书....");
    }
}
//DelOperation.java
package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class DelOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("删除书籍:");

        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入你删除的书名:");
        String name = scanner.nextLine();
        int currentSize = bookList.getUsedSize();

        int pos = -1;
        //找到这本书
        int i = 0;
        for (; i < currentSize; i++) {
            Book book = bookList.getBook(i);
            if (book.getName().equals(name)) {
                pos = i;
                break;
            }
        }

        if (i == currentSize) {
            System.out.println("没有你要删除的书!");
            return;
        }

        //这里开始删除
        for (int j = pos; j < currentSize - 1; j++) {
            //bookList[j] = bookList[j+1];
            Book book = bookList.getBook(j + 1);

            bookList.setBook(j, book);
        }

        bookList.setBook(currentSize - 1, null);

        bookList.setUsedSize(currentSize - 1);
        System.out.println("删除成功!!!!");
    }
}
//ExitOperation.java
package ioperations;

import book.BookList;


public class ExitOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统:");
        System.exit(0);
    }
}
//FindOperation.java
package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class FindOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("查找书籍:");

        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入你的书名:");
        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("没有你要找的这本书....");
    }
}
//ReturnOperation.java
package ioperations;

import book.Book;
import book.BookList;

import java.util.Scanner;


public class ReturnOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("归还书籍:");
        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入你归还的书名:");
        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)) {
                if (book.isBorrowed()) {
                    book.setBorrowed(false);
                    System.out.println("归还成功!");
                    return;
                }
            }
        }
        System.out.println("没有你要归还的图书!!!");
    }
}
//ShowOperation.java
package ioperations;

import book.Book;
import book.BookList;


public class ShowOperation implements IOperation {
    @Override
    public void work(BookList bookList) {
        System.out.println("展示书籍:");
        int currentSize = bookList.getUsedSize();//3
        for (int i = 0; i < currentSize; i++) {
            Book book = bookList.getBook(i);
            System.out.println(book);
            //Book book1 = bookList[i];
        }
    }
}

5.1.2 package user

父类

//User.java
package user;

import book.BookList;
import ioperations.IOperation;


public abstract class User {
    //用户通过接口数组和名字来操作图书系统的
    protected String name;
    IOperation[] iOperations;

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

    public abstract int menu();

    public void doIoperation(int choice, BookList bookList) {
        iOperations[choice].work(bookList);//真正操作图书系统
    }
}

基于父类的子类

//AdminUser.java
package user;

import ioperations.*;

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() {
        System.out.println("欢迎" + this.name + "来到图书系统");
        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();
        return choice;
    }
}
//NormalUser.java
package user;

import ioperations.*;

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

    @Override
    public int menu() {
        System.out.println("欢迎" + this.name + "来到图书系统");
        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();
        return choice;
    }
}

5.2 类和类之间的整体联系

  1. 基础结构:系统的基础是User类,它定义了用户的通用属性和行为,包括用户名和一系列操作。这个类为不同类型的用户提供了一个统一的框架。

  2. 用户角色:系统通过继承User类来定义两种不同类型的用户角色——AdminUser(管理员用户)和NormalUser(普通用户)。这两种用户角色都继承了父类的基本属性和方法,但根据各自的需求定制了特定的功能和操作。

  3. 操作集合:每个用户角色都有一个操作集合(iOperations数组),其中包含了该角色可以执行的操作。这些操作通常封装在实现了某个接口(如IOperation)的对象中,允许系统以统一的方式调用不同的操作。

  4. 菜单系统:每个用户角色都有一个定制的菜单系统(通过menu()方法实现),用于向用户展示可用的操作选项,并接收用户的选择。这个菜单系统根据用户的角色(管理员或普通用户)提供不同的选项。

  5. 操作执行:当用户通过菜单选择一个操作后,系统会根据用户的选择调用相应的操作(通过doIoperation()方法)。这个调用是基于操作集合中的接口对象,实现了多态性,使得系统可以灵活地处理不同类型的操作。

  6. 扩展性:通过接口和继承的使用,系统具有良好的扩展性。如果需要添加新的用户角色或操作,只需创建新的类或实现新的接口,而无需对现有代码进行大量修改。

综上所述,这个图书系统通过面向对象的设计原则(如继承、多态和接口)构建了一个灵活且可扩展的逻辑结构,能够支持不同类型的用户执行各自特定的操作。

5.3 功能拓展

  1. 增加用户认证与权限管理:目前系统虽然通过不同的用户类(AdminUser和NormalUser)区分了用户角色,但可以进一步增加用户认证机制,如用户名和密码登录,以及更细粒度的权限管理,确保用户只能访问其权限范围内的功能。

  2. 引入数据库支持:为了提升系统的数据持久化和检索能力,可以集成数据库来存储图书信息、用户信息和借阅记录等。这将使得数据管理更加高效和可靠。

  3. 优化用户界面:当前的菜单系统是基于控制台的简单文本输出,可以考虑开发一个图形用户界面(GUI)或网页界面,提升用户体验和交互性。

  4. 增加图书推荐功能:通过分析用户的借阅历史和偏好,可以为用户提供个性化的图书推荐,增强用户粘性和满意度。

  5. 实现图书预约与续借功能:为了满足用户更多的需求,可以增加图书预约和续借功能,使得用户能够更加方便地管理自己的借阅行为。

  6. 集成在线支付系统:如果图书系统涉及费用(如逾期罚款、图书购买等),可以集成在线支付系统,为用户提供便捷的支付方式。

  7. 提供API接口:为了与其他系统进行集成,可以提供API接口,允许第三方开发者或系统调用图书系统的功能,如查询图书信息、进行借阅操作等。

总结:通过增加用户认证与权限管理、引入数据库支持、优化用户界面、增加图书推荐功能、实现图书预约与续借功能、集成在线支付系统以及提供API接口等改进措施,可以进一步提升图书系统的安全性、可用性、用户体验和扩展性。这些改善将有助于图书系统更好地服务于用户,满足用户多样化的需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1852819.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学生选课管理系统(JAVA课设)PS:有前端界面

1.课设要求描述 实现系统的所有功能&#xff0c;包括但不限于&#xff1a; 学生信息管理&#xff08;增加、删除、修改、查询&#xff09;课程信息管理选课操作成绩管理 2.制作思路及基础讲解 此项目主要是用于完成大二下半学期的JAVA大作业&#xff0c;也可当作课设&…

Ubuntu:解决github出现 Permission denied (publickey)的问题

因为使用的Ubuntu 长久没有使用&#xff0c;使用下载的时候突然报错&#xff0c;使用ssh key这种方式进行clone &#xff0c;pull github上面的项目&#xff0c;使用 git clone或者git pull origin master出现permission denied (publickey)&#xff0c;原因是因为ssh key过期失…

leetcode 二分查找·系统掌握 x的平方根

题目&#xff1a; 题解 这题可以使用~01~泛型查找在0~x/2的范围内查找答案。 int mySqrt(int x) {long l0,rx,mid;while(l<r){mid(lr1)>>1;if(mid*mid>x)rmid-1;else lmid;}//因为一定有答案所以不用判定是否查找失败return l;}

计算机系统基础实训六-ShellLab实验

实验目的与要求 1、让学生更加理解进程控制的概念和具体操作方法&#xff1b; 2、让学生更加理解信号的概念和具体使用方法&#xff1b; 3、让学生更加理解Unix shell程序的原理和实现方法&#xff1b; 实验原理与内容 shell是一种交互式的命令行解释器&#xff0c;能代表…

从关键新闻和最新技术看AI行业发展(2024.6.3-6.16第二十五期) |【WeThinkIn老实人报】

写在前面 【WeThinkIn老实人报】旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的优化建议&#xff0c;一起交流学习&#x1f4aa; 欢迎大家关注Rocky的公众号&…

Node.js 系列之 Express 框架入门实战教程

目录 1 Node.js是什么2 Express初体验3 Express 路由3.1 什么是路由3.2 路由的使用3.3 获取路由参数 4 常见响应设置4.1 express 响应方法4.2 原生响应方法 5 express 中间件5.1 中间件作用5.2 中间件类型5.3 全局中间件5.4 路由中间件 6 获取请求体数据7 路由模块化 1 Node.js…

51单片机学习记录(二)————外部中断

文章目录 前言一、中断1.中断的定义 二、51中断1.中断源2.中断的配置3.中断允许控制寄存器4.中断触发方式51中断有两种触发方式&#xff1a; 三、外部中断1.外部中断引脚2.外部中断配置&#xff08;以外部中断0为例&#xff09; 总结 前言 一个学习嵌入式的小白~ 有错误评论区…

【ARM】PK51如何将BL51链接器切换成LX51链接器

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决客户在使用PK51进行项目研发的时候&#xff0c;想要使用LX51链接器进行使用。 2、 问题场景 客户在使用51芯片进行开发的时候&#xff0c;发现工程中使用的是BL51链接器&#xff0c;而不是LX51链接器&#xff…

【非常实验】如何在移动设备上运行 Docker?

本章就从在 DevOps 中最基本但也是最强大的工具 Docker 开始。最近,我在尝试更多Termux的可能性,于是就想着试试Docker适不适合arm架构。 我用的是天玑9000芯片,而不是高通,所以显示不出来 Qualcomm。所以我决定从在手机上运行 docker 开始,但这可能吗?让我们一起来看看吧…

Node.js实现短链接(ShortLink):shortid、epxress让URL更简单

文章目录 一、短链接介绍二、插件介绍1、epxress2、shortid 三、实现方案1、安装依赖&#xff1a;2、实现原理 四、示例代码五、测试生产短链接 一、短链接介绍 短链接是指仅包含一个网址的链接形式&#xff0c;通俗一些就是将一个很长很复杂的的网址变成一个简短易记的链接。…

基于CSDN的Markdown文本编辑器的博客界面优化 | HTML | 文本标签 | 图像标签 | 个人主页引导

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的内容是如何在CSDN的Markdown编辑器中实现上图的效果&#xff0c;如果觉得能帮助到你的话就点击个人主页点点关注吧❗ 文章目录 1.前言2.基础知识3.字…

游戏工厂:AI(AIGC/ChatGPT)与流程式游戏开发

游戏工厂&#xff1a;AI&#xff08;AIGC/ChatGPT&#xff09;与流程式游戏开发 码客 卢益贵 ygluu 关键词&#xff1a;AI&#xff08;AIGC、ChatGPT、文心一言&#xff09;、流程式管理、好莱坞电影流程、电影工厂、游戏工厂、游戏开发流程、游戏架构、模块化开发 一、前言…

ArcGIS批量投影转换的妙用(地理坐标系转换为平面坐标系)

​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 这次文章我们来介绍一下&#xff0c;如何巧妙用要素数据集来实现要素的批量投影。不需要ArcGIS的模型构建器与解决。 例如&#xff0c;有多个要素要将CGCS_2000地理坐标系投…

单机、集群和分布式

目录 1.概述 2.单机服务器 单机版的服务器的性能&#xff0c;设计上的瓶颈&#xff1f; 3.集群 解决瓶颈1&#xff1a; 没有解决瓶颈2&#xff1a; 没有解决瓶颈3&#xff1a; 集群的优点&#xff1f; 集群的缺点&#xff1f; 4.分布式 分布式的优点&#xff1f; 分…

1970-2022年中国碳排放1KM栅格数据

【数据简介】 数据名称&#xff1a;1970-2022年中国碳排放栅格数据&#xff08;1KM) 区域范围&#xff1a;全国 数据格式&#xff1a;tif文件 数据大小:800M 数据来源&#xff1a;欧盟委员会全球大气排放数据库&#xff08;EDGAR) 部分数据预览&#xff1a; 原文链接http…

君子小人的格局、境界

子曰&#xff1a;君子怀德&#xff0c;小人怀土&#xff1b;君子怀刑&#xff0c;小人怀惠。 直译&#xff1a;君子怀念道德&#xff0c;小人怀念乡土&#xff1b;君子关心法度&#xff0c;小人关心恩惠。 这里的君子与小人只是体现格局、境界的不同&#xff1b; 君子怀的是德…

算法基础精选题单 动态规划(dp)(递推+线性dp)(个人题解)

前言&#xff1a; 一些简单的dp问题。 正文&#xff1a; 题单&#xff1a;237题】算法基础精选题单_ACM竞赛_ACM/CSP/ICPC/CCPC/比赛经验/题解/资讯_牛客竞赛OJ_牛客网 (nowcoder.com) 递推&#xff1a; NC235911 走楼梯&#xff1a; #include<bits/stdc.h> using na…

JAVA期末复习题1

目录 Java 填空题整理及解析 1. 说出Java的特点&#xff1a; 2. Java的运行机制是先编译再解释运行。 3. 请按照以下分类补全对应的数据类型&#xff1a; 4. 在有限次数循环时&#xff0c;一般选择for循环结构&#xff1b;未知循环次数时&#xff0c;可以选择while循环结构…

一文读懂LLM API应用开发基础(万字长文)

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者&#xff0c;上一篇文章中我们详细介绍了LLM开发的基本概念&#xff0c;包括LLM的模型、特点能力以及应用&#xff1b;&#x1f632; 在本文中作者将通过&#xff1a…

用VPS部署聊天机器人有哪些优势?

VPS足以帮助您将人工智能 (AI) 的功能无缝融入聊天机器人并增强客户支持。聊天机器人已迅速成为改善用户体验的首选解决方案&#xff0c;因为它们全天候在线且可编程回答各种问题。 聊天机器人在客户支持方面的作用不容置疑。但所有出色的解决方案都需要出色的网络托管。 VPS…