目录
1、分析图书系统设计到的各种类和类的属性
2、编写代码
【1】Book类
【2】BookList 类
【3】具体操作分析
【4】用户分类
【5】开始整合(最难)
先给大家展示一下完成后图书系统的样子
接下来,主要讲解代码编写的思路,完整代码点击文字获取 图书管理小练习
1、分析图书系统设计到的各种类和类的属性
写代码之前,我们先要大致抽象出来一些该有的类和类的属性。
在具体写代码的时候还会有一些部分添加
1)首先 图书系统 肯定要有 书,而我们要想准确描述一本书,我们就要创建一个书类(Book)
包含属性
- 书名 name
- 作者 author
- 价格 price
- 类型 type
- 是否被借出 isBorrowed
2)有了书之后,就要有书架(用来存储书籍)。所以我们还要创建一个书架类 (BookList)
包含属性
- Book[] (存储书籍,可以要用数组来存储)
3)用户分类,我们的图书操作系统分为 【普通用户】和【管理员】,所以我们要创建 AdminUser类(管理员) 和 NormalUser 类(普通用户)
注意:不同的用户,打印的菜单不同,这里先提醒一下大家
4)各种操作类,我们还要创建一些来对书架进行操作(简称 操作类)。主要的操作如下
- 查找图书(FindOperation 类)
- 新增图书(AddOperation 类)
- 删除图书(DelOperation 类)
- 显示图书(DisplayOperation 类)
- 归还图书(ReturnOperation 类)
- 借阅图书(BorrowOperation 类)
- 退出书架(ExitOperation 类)
以上我们就基本把这个图书操作系统各个部分分析完了,而为了方便我们管理,我们还要对这些类进行分门别类。
也就是说,我们在编写代码时,把不同的类放在不同包下,用包来对这些类进行封装
2、编写代码
【1】Book类
我们首先来写 Book 类,把图书的各种特性创建成员变量,这些成员变量用 private 修饰
private String name;//书名
private String author;//作者
private int price;//价格
private String type;//类型
private boolean isBorrowed;//是否被借出
用 private 修饰体现封装
同时因为这些成员变量是被 private 修饰,在类外不能获取,所以我们要写一系列 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 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;}
然后,构造 Book 实例时,为了方便给成员变量赋值,所以我们也可以写一个构造方法。为了方便显示 书 的内容,我们还要写一个 toString 方法
public Book(String name, String author, int price, String type) {
this.name = name;
this.author = author;
this.price = price;
this.type = type;
}
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
((isBorrowed == true) ? "已经借出":"未借出")+
'}';
}
构造方法里面没有给 isBorrowed 赋值,是因为 isBorrowed 是 bollean 类型的变量,创建的初始值为 false,方便我们后续的操作。所以不用再给 isBorrowed 赋值
到这里 Book 类算是完成啦,接下来就是 BookList 类。
【2】BookList 类
单独的书的类型创建好了,现在就来创建一个 BookList 类用来存储书籍。
这个 BookList 就相当于 书架
我这里用数组来存储多本书,创建一个 Book数组 类型的成员变量,存储容量大小为10
private Book[] books = new Book[10];
存储书籍也能用 ArrayList、LinkList等....这里为了方便理解,我用了数组
存储 书 的书架有了,那我们如何知道这个书架里面有多少本书呢?
为了解决这个问题,再来创建一个成员变量来记录我们存储图书的数量
private int usedSize;//实时记录,当前books这个数组当中有多少本书
在书架中,我们可能要取书、存书等操作。而这些操作其实就是对 BookList 类中数组进行的操作,所以我们要在类中写一些方法来完成这些操作供外界使用。
- 通过下标获取书
- 在某位置下放书
- 获取 书架 中书的个数
- 修改 书架 中书的个数
/**
* @param pos pos一定是合法的
* @return
*/
public Book getBook(int pos){
return books[pos];
}
/**
* @param pos 此时pos一定是合法的
* @param book 是你要放的书
*/
public void setBooks(int pos,Book book){
books[pos] = book;
}
/**
* 实时获取当前书的个数
* @return
*/
public int getUsedSize(){return usedSize;}
/**
* 实时的修改当前书架上的书的个数
*/
public void setUsedSize(int size){
usedSize = size;
}
为了方便我们后面的操作,当我们构造 BookList 对象时,先生成三本书
public BookList(){
books[0] = new Book("三国演义","罗贯中",19,"小说");
books[1] = new Book("西游记","吴承恩",19,"小说");
books[2] = new Book("红楼明","曹雪芹",19,"小说");
usedSize = 3;
}
【3】具体操作分析
这里我把把这些操作方法类全部都放到一个 operation 包下面!
因为这些 “方法” 都是对 BookList进行操作,那我们是不是可以创建一个接口,来统一标准的规范
0)IOperation 接口
public interface IOperation {
void work(BookList bookList);
}
接下来,我们让具体的操作来实现这个接口
例如:添加图书 AddOperation 类
public class AddOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("添加图书");
}
}
这里先不着急实现具体的业务逻辑,我们先把逻辑整理好
其他的操作也是类似,这里就不在赘述了
借阅图书 BorrowOperation
删除图书 DelOperation
展示图书 DisplayOperation
查找图书 FindOperation
归还图书 ReturnOperation
退出 ExitOperation
【4】用户分类
我们的用户分为两种,一种是管理员,另一种是普通用户。
虽然他们的操作不同,但是都是属于用户这一类,所以我们可以写一个父类 User,在父类中 定义属性和方法,然后让子类继承。这样子类就不必重复写哪些操作
0)父类 User
public class User {
protected String name;//用户名
public User(String name){
this.name = name;
}
public abstract int menu();//打印菜单
//因为管理员和普通用户的菜单内容不一样,所以在父类中 menu 方法我们可以直接写为抽象方法
}
1)子类 AdminUuser 和 NormalUser
我们让子类 AdminUuser 和 NormalUser 继承 父类 User,这样我们就不用重复定义 name这个属性。
继承父类后,我们要提供一个构造方法来显示的帮助父类构造!!!
注意:不同用户菜单不同!
public class AdminUser extends User{
public AdminUser(String name) {
super(name);
}
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书小练习");
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;
}
}
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
}
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书小练习");
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);
int choice = scanner.nextInt();
return choice;
}
}
这里用户逻辑也基本实现啦,现在我们开始整合这些类
【5】开始整合(最难)
这里我们新创建一个类 Main(这个类不在上面任何包内),创建一个 main方法。接下来我们将在该方法中整合所以部分。
第一步:我们首先要准备我们的图书
BookList bookList = new BookList(); //准备图书
这里我们不用一本书一本的创建放到 bookList 中,因为在 BookList 实例化时就准备好了三本书
第二步:开始登陆
这里我创建一个 login 方法,然后在 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){
return new AdminUser(name);
}else {
return new NormalUser(name);
}
}
为什么 login 方法的返回值是 User?因为 AdminUser 类 和 NormalUser 类都是 User 的子类,不管我们选择哪个角色进行实例化,User 都能接收 【向上转型】
在 main 方法中,同样用 User接收
//登陆-> user 这个引用 引用那个对象
User user = login();
第三步:调用菜单,把具体操作跟菜单结合
因为上面我们一下选择 user 的实例化对象是管理员还是普通用户,所以我们直接调用menu 方法显示出来的菜单内容也是不一样的。
所以我们要在 AdminUser 类 和 NormalUser 类分别定义 menu方法
AdminUser 类中 menu() 方法
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书小练习");
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 类中 menu() 方法
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书小练习");
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);
int choice = scanner.nextInt();
return choice;
}
到这里还没结束,我们回到 Main类中,我们选择的用户类型是用 父类 User 接收的,
所以我们需要 user对象来调用 menu()。
此时编译器就会报错,原因就是 User 类中没有定义 menu,所以我们还要在 User 类中写一下menu() 方法
public abstract int menu();
父类中的 menu方法不需要具体实现,定义为抽象类就行。
此时我们在用 user调用就不会出错了,menu() 方法会动态绑定!!!
【我们选的哪个就会打印哪个的菜单】
然后我们创建一个变量来接收用户的选择
int choice = user.menu();//动态绑定
我们来看不同用户的菜单,在管理员菜单中 ‘2’ 是新增图书,而在普通用户菜单菜单中 ‘2’ 是借阅图书。
现在问题来了,我们如何才能知道用户想要执行那个 ‘2’ 操作呢?
我们是不是可以让 AdminUuser 对象和 NormalUser 对象中分别存储好各种要执行的操作就可以了。
现在我们重新回到 User类中,添加一个成员
protected IOperation[] iOperations;//此时并没有初始化和分配大小
然后分别在 AdminUuser 和 NormalUser 各自的抽象方法中各自初始化具体的内容
最后,在父类 User 中再定义一个具体调用哪个操作的方法
public void doOperation(int choice, BookList bookList){
this.iOperations[choice].work(bookList);
}
这样我们就能根据用户选择来决定实现那种方法啦
通过 choice 作为下标,来找到具体的执行类并执行类中的方法
为什么 doOperation 方法分别定义在 AdminUuser 和 NormalUser 中?
因为如果定义在 AdminUuser 和 NormalUser 中,在整合时 use 对象就无法调用 doOperation 方法。