文章目录
实现效果介绍
此小练习的实现效果如下:它将面对
管理员
和普通用户
两种用户来提供服务,并且各自的服务并不相同。下面让我们一起来实现代码吧
实现思路
一般写项目,每个独立的功能都会写成一个类,而有关联的功能,都会将多个类存放在一个包中,此项目我们将用 3 个包来体现我们的效果
1. book包
- 我们这个是图书系统小练习,必不可缺的就是Book类了 —> 用来定义一本书
- 既然是图书系统,那么必然不可能仅仅只有一本书,我们还需要一个书架,来存储书籍 BookList 类
2. user包
- 因为我们有两种用户可以使用这个图书系统,而且每种用户都有自己的特性,所以也需要定义成类
- 有 User类(后面两个类的共同特征抽取出来的,User类可以是一个抽象类),adminUser类,normalUser类
3. opertion包
这个包底下就是我们的基本操作了……
4. Main类
上面的类就已经实现了我们需要的功能了,Main类就是来整合这些操作功能的,在Main类中,我们需要根据登陆的账户类型不同,来显示不同的菜单供其使用图书系统.
具体代码实现
book包
Book类
这个Book类主要是存放一本书的具体信息,这个信息包括书名,作者,价格,类型,是否被借出。并且为了安全起见,我们需要吧这些信息全部都用private来修饰,然后对外提供一些公开的接口供外面的使用(这就体现了面向对象中的
封装
)
public class Book {
private String name; // 书名
private String author; // 作者
private double price; // 价格
private String type; // 类型
private boolean isBorrowed; // 是否借出
public Book(String name, String author, double 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 double getPrice() {
return price;
}
public void setPrice(double 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 + '\'' +
((this.isBorrowed == true)?"已借出":"未借出") +
'}';
}
}
BookList类
BookList类,这就相当于一个书架,用来存放书籍的,而且在其构造方法中,我们默认就放了三本书,在其里面也提供了对 usedSize 和 books 两个变量的公开操作方法
public class BookList {
public int getBookLength() {
return bookLength;
}
private int bookLength = 10;
private Book[] books = new Book[bookLength]; // 数组用来存放书的,最多放10本书
private int usedSize; // 数组中已存几本书
/**
* 默认书架上有三本书
*/
public BookList() {
books[0] = new Book("三国演义","罗贯中",56.7,"小说");
books[1] = new Book("西游记","吴承恩",66.6,"小说");
books[2] = new Book("红楼梦","曹雪芹",54.3,"小说");
this.usedSize = 3;
}
/**
* 获取已存几本书
* @return
*/
public int getUsedSize() {
return usedSize;
}
/**
* 增加/删除时,修改usedSize
* @param usedSize
*/
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
// 因为借书,新增,删除等操作,都是针对Book[] 书架来的,其实可以在这里实现,但为了低耦合,使用接口
/**
* 获取pos位置的书
* @param pos
* @return
*/
public Book getPos(int pos) {
if(pos < 0 && pos == bookLength) {
throw new IndexNotValidException("pos不合法");
}
return books[pos];
}
/**
* 给数组pos位置放一本书
* @param pos
* @param book
*/
public void setBooks(int pos,Book book) {
if(pos < 0 && pos == bookLength) {
throw new IndexNotValidException("pos不合法");
}
books[pos] = book;
}
}
operation包
在这个包里,我们用到了 接口,因为所有的操作中,都只有一个 work方法,而且参数也都一样,我们就可以将其抽象成一个接口,然后后面实现功能的时候,我们直接实现这个接口的内容即可
AddOperation
public class AddOperation implements IOPeration{
public void work(BookList bookList) {
int currentSize = bookList.getUsedSize();
if(currentSize == bookList.getBookLength()) {
throw new IndexNotValidException("书架已满");
}
Scanner sc = new Scanner(System.in);
System.out.println("请输入图书的名字:");
String name = sc.nextLine();
System.out.println("请输入图书的作者");
String author = sc.nextLine();
System.out.println("请输入图书的价格");
Double price = sc.nextDouble();
System.out.println("请输入图书的类型");
String type = sc.nextLine();
Book book = new Book(name,author,price,type);
bookList.setBooks(currentSize,book);
bookList.setUsedSize(currentSize+1);
System.out.println("新增成功");
}
}
BorrowOperation
public class BorrowOperation implements IOPeration {
public void work(BookList bookList) {
System.out.println("借阅图书");
Scanner sc = new Scanner(System.in);
System.out.println("请输入借阅图书的名字:");
String name = sc.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if(book.getName().equals(name)) {
book.setBorrowed(true);
System.out.println("借阅成功");
return;
}
}
System.out.println("此书已被借阅或这没有这本书");
}
}
DeleteOperation
public class DeleteOperation implements IOPeration {
public void work(BookList bookList) {
System.out.println("删除图书");
Scanner sc = new Scanner(System.in);
System.out.println("请输入删除图书的名字:");
String name = sc.nextLine();
int index = 0;
int currentSize = bookList.getUsedSize();
int i = 0;
for (; i < currentSize; i++) {
Book book = bookList.getPos(i);
if(book.getName().equals(name)) {
index = i;
break;
}
}
// 1. 没有找到 2.找到了
if(i == currentSize) {
System.out.println("没有你要删除的图书");
return;
}
// 开始删除
for (int j = index; j < currentSize - 1; j++) {
Book book = bookList.getPos(j+1);
bookList.setBooks(j,book);
}
bookList.setBooks(currentSize-1,null);
bookList.setUsedSize(currentSize-1);
System.out.println("删除成功");
}
}
DisplayOperation
public class DisplayOperation implements IOPeration {
public void work(BookList bookList) {
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
System.out.println(book);
}
}
}
ExitOperation
public class ExitOperation implements IOPeration {
// 退出前可能需要销毁书架上的所有书
public void work(BookList bookList) {
System.out.println("退出系统");
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
bookList.setBooks(i,null);
}
System.exit(0);
}
}
FindOperation
public class FindOperation implements IOPeration {
public void work(BookList bookList) {
System.out.println("查找图书");
Scanner sc = new Scanner(System.in);
System.out.println("请输入图书的名字:");
String name = sc.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if(book.getName().equals(name)) {
System.out.println("找到这本书,信息如下:");
System.out.println(book);
return;
}
}
System.out.println("没有找到");
}
}
ReturnOperation
public class FindOperation implements IOPeration {
public void work(BookList bookList) {
System.out.println("查找图书");
Scanner sc = new Scanner(System.in);
System.out.println("请输入图书的名字:");
String name = sc.nextLine();
int currentSize = bookList.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = bookList.getPos(i);
if(book.getName().equals(name)) {
System.out.println("找到这本书,信息如下:");
System.out.println(book);
return;
}
}
System.out.println("没有找到");
}
}
User包
User类
这里定义了一个 IOPeration的数组(也就是operation中的接口创建的数组),一个很巧妙的用法:因为AdminUser 和 NormalUser 中的菜单并不相同,但是它们都实现了IOPeration接口,因此我们可以通过IOPeration数组来分别存储我们需要进行的操作
abstract public class User {
// 防止其他包底下也要继承User,所以用protected
protected String name;
public IOPeration[] ioPerations;
public User(String name) {
this.name = name;
}
public abstract int menu();
public void doOperation(int choice, BookList bookList) {
ioPerations[choice].work(bookList);
NormalUser 与 AdminUser
在实例化用户之前,我们就在不同的类中创建了 IOPeration数组,并填入当前类所需要的对象了,然后根据我们的选择,返回了下标,然后在User类中的doOperation方法直接在数组中取出对应下标的对象,然后调用 work方法,来实现功能
public class NormaUser extends User {
public NormaUser(String name) {
super(name);
this.ioPerations = new IOPeration[] {
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation(),
};
}
@Override
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 sc = new Scanner(System.in);
int choice = sc.nextInt();
return choice;
}
}
public class AdminUser extends User {
public AdminUser(String name) {
super(name);
this.ioPerations = new IOPeration[] {
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DeleteOperation(),
new DisplayOperation(),
};
}
@Override
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 sc = new Scanner(System.in);
int choice = sc.nextInt();
return choice;
}
}
Main方法
我们可以看到Main方法是相当简洁的,里面只有一个 login方法,而login方法的返回值是User,这样我们就可以发生
向上转型
,从而实现多态
public class Main {
public static User login() {
System.out.println("请输入姓名:");
Scanner sc = new Scanner(System.in);
String name = sc.nextLine();
System.out.println("请输入你的身份:1)管理员 0)普通用户");
int choice = sc.nextInt();
if(choice == 1) {
return new AdminUser(name);
} else {
return new NormaUser(name);
}
}
public static void main(String[] args) {
BookList bookList = new BookList();
User user = login(); // user到底引用那个对象,由login的返回值确定
while(true) {
int choice = user.menu();
// 根据下行代码来看,要不要doOperation方法都可,但是存在的话,代码更加的解耦合
// user.ioPerations[choice].work(bookList);
user.doOperation(choice,bookList);
}
}
}
总结
框架的搭起:Book类 -> BookList类 -> operation包(先不要实现功能,框架起来后,功能实现就容易了) -> AdminUser+NormalUser类 + Main类
其中最难的地方当属:IOPeration数组了,只要这个地方理解了,相信整个项目对你来说,难度就不大了
这个图书管理系统,更主要的是我们要理解 框架如何一步步搭起来的,不要看这个项目小,它可是涵盖了许多 Java基础知识(数组,封装,继承,多态,抽象类,接口,异常……),刚开始写的时候,不要想
一口吃成胖子
,不可能一开始就会想到所有的功能,一步一步来。
对于Java基础语法不是很熟悉的话,可以看看博主的另一篇文章:Java类和对象