目录
前言:
1、项目实现要求
2、设计思路流程
设计思路:
登录后菜单的实现效果:
3、代码实现(大体框架)
Main类
book包
Book类
BookList类
user包
User类
AdminUser(管理员)类
NormalUser(普通用户)类
4、业务逻辑(实现opera包中的类)
管理员的业务逻辑
显示图书(ShowOperation)
查找图书(FindOperation)
退出系统(ExitOperation)
增加图书(AddOperation)
删除图书(DelOperation)
普通用户的业务逻辑
借出图书(BrrowOperation)
归还图书(ReturnOperation)
5、最终实现效果
管理员:
普通用户:
前言:
- 这篇博客是在学习了一部分Java基础语法后的练习项目,通过这个练习对我们之前学过的数组、类和对象、抽象类和接口、继承、多态和封装等知识点进行巩固;也上我们初次了解一下面向对象编程的思想。
- 面向对象编程,所有的操作都是通过对象和动作的交互完成的。
1、项目实现要求
图书管理系统,面向管理员和普通用户使用,对管理员开放的功能有:增加图书、删除图书、查找图书、显示图书、退出系统;对普通用户开放的功能有:查找图书、借阅图书、归还图书、退出系统。
2、设计思路流程
设计思路:
- 根据上述图片将图书管理系统的对象可以抽取成为两类:用户和书
- 所以根据两类对象,分别创建user包和book包;分别在两个包当中创建相应的类。
- 用户类对象又可分为:管理员和普通用户;两类对象有存在共有属性,所以我们可以将他们共有的属性设置为一个User父类的抽象类。
- 书类对象又可分为:书和书架;书本身可以抽象为一个对象,书架用来对多本书进行管理,所以书架也可以抽象为一个对象,所以书和书架可以设置为两个类来实现,书架可以设置为一个数组。
- 当然对象设置完成之后,对象所要实现的功能我们可以再设置一个opera包,再opera包中设置一个接口IOperation,每个功能设置为一个类并且都实现接口IOperation。
登录后菜单的实现效果:
管理员身份:
普通用户:
3、代码实现(大体框架)
Main类
import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {
//发生向上转型 User作为返回值类型
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 );//返回普通用户对象
}
}
public static void main(String[] args) {
//准备数据
BookList booklist = new BookList();
//登录
User user = login();//将login方法中返回的用户身份用user接收
while (true){//用while来实现循环操作
int choice = user.menu();//这里的choice用来接收AdminUser和NormalUser中返回的操作;
user.doWork(choice, booklist);//这里的user代表的是AdminUser或者NormalUser
}
}
}
❗❗❗注意:在login方法中,返回值有两个,且是两种不同类型的对象,并且要传给User类型的user变量,所以不能设置为void,又因为返回的两个对象都是User的子类,所以用User作为返回值类型,并且在main方法中用User类型的user变量来接收,这里就发生了向上转型。
book包
Book类
package book;
public class Book {
private String name;//书名
private String author;//作者
private int price;//价格
private String type;//类型
private boolean isBorrowed;//是否被借出
//写一个构造方法,但是isBorrowed 属性不因该写在构造方法中,因为在添加一本新书的时候,默认都是未借出的
public Book(String name, String author, int price, String type) {
this.name = name;
this.author = author;
this.price = price;
this.type = type;
}
//这些属性都是以封装的形式出现的,所以都要提供公开的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;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
(isBorrowed == true?"已经被借出":"未被借出")+
'}';
}
}
BookList类
package book;
public class BookList {
private static final int DEFAULT_SIZE = 10;
private Book[] books = new Book[DEFAULT_SIZE ];
//private Book[] books = new Book[10];
private int usedSize;//记录当前books数组当中,有多少本书
//通过构造方法给books这个书架中放书,并通过usedSize来记录书本个数。
public BookList(){
books[0] = new Book("三国演义","罗贯中",89,"小说");
books[1] = new Book("西游记","吴承恩",78,"小说");
books[2] = new Book("红楼梦","曹雪芹",49,"小说");
this.usedSize = 3;
}
//因为books被private分装了,所以要提供一个get和set方法,
public Book getBook(int pos){
return this.books[pos];
//返回这个books数组中pos下标的元素
}
//这个setBook方法被用于增添图书的功能中
public void setBook(Book book){
books[usedSize] = book;//这里写死了,给下标为usedSize的地方添加书,
}
//这个setBook方法被用于删除图书的功能中
public void setBook(int pos,Book book){
books[pos] = book;//表示给数组下标为pos的地方。放一本书
}
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
}
user包
User类
package user;
import book.BookList;
import opera.IOperation;
public abstract class User {
protected String name;
protected IOperation[] ioperations;//定义一个数组,用来存放相应用户的操作
public User(String name) {
this.name = name;
}
public abstract int menu();//在User类中实现menu方法没有意义,所以定义成为一个抽象方法。
//doWork方法用来将AdminUser对象和NormalUSer对象中的choice选择的数组下标所对应的操作类调用起来
public void doWork(int choice ,BookList booklist){
this.ioperations[choice].work(booklist);
//调用ioperation数组的choice下标所对应的操作对象中的work方法
}
}
AdminUser(管理员)类
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的操作对象,要和下边的菜单对应起来
new AddOperation(),
new DelOperation(),
new ShowOperation(),
};
}
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("4.显示图书!");
System.out.println("0.退出系统!");
System.out.println("******************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();//这里的choice用来接收管理员用户在菜单中的选项
return choice ;//这里返回的choice 被Main类中的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[]{
new ExitOperation(),
new FindOperation(),
new BrrowOperation(),
new ReturnOperation(),
};
}
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.退出系统!");
System.out.println("******************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice ;
}
}
4、业务逻辑(实现opera包中的类)
管理员的业务逻辑
显示图书(ShowOperation)
package opera;
import book.Book;
import book.BookList;
public class ShowOperation implements IOperation{
@Override
public void work(BookList booklist) {
System.out.println("显示图书!");
int currentSize = booklist.getUsedSize();
//通过currentSize变量来记录BookList对象中传过来的usedSize,
//通过for循环将books数组中的所有元素遍历输出
for (int i = 0; i < currentSize; i++) {
//通过booklist调用BookList中的getBook方法,得到下标为i的books数组中的元素
Book book = booklist.getBook(i);
//输出这本书
System.out.println(book);
}
}
}
查找图书(FindOperation)
package opera;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class FindOperation implements IOperation {
@Override
public void work(BookList booklist) {
System.out.println("查找图书!");
System.out.println("请输入要查找的书名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
//通过currentSize变量来记录booklist引用调用getUsedSize传过来的usedSize
int currentSize = booklist.getUsedSize();
//通过for循环来遍历查找
for (int i = 0; i < currentSize; i++) {
//通过booklist调用BookList对象中的getBook方法,得到books数组下标为i元素
Book book = booklist.getBook(i);
//通过book引用来调用Book类中的getName方法,得到书名和查找的书名通过equals来比较。
if (book.getName().equals(name)) {
System.out.println("找到了这本书");
System.out.println(book);
//返回找到的这本书
return;
//这里直接return,我们假设没有重复的书名
}
}
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,在这里设置为0.
}
}
增加图书(AddOperation)
package opera;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class AddOperation implements IOperation {
@Override
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("输入类型:");
String type = scanner.nextLine();
System.out.println("输入价格:");
int price = scanner.nextInt();
//以上属性,可以构成书的对象
Book book = new Book(name,author,price,type);
//新增的这本书,是要放在books着这个数组中,所以不能存在相同的书,
// 所以要通过遍历来查找有没有相同的书,如果没有则加入到books数组中,如果有则不用加入
int currentSize = booklist.getUsedSize();
for (int i = 0; i < currentSize; i++) {
//通过booklist调用BookList中的getBook方法,得到下标为i的books数组中的元素
Book tmp = booklist.getBook(i);
if (tmp.getName().equals(name)) {
System.out.println("已经存在这本书了,不能再放入了!");
return;
}
}
booklist.setBook(book);
//修改usedSize
booklist.setUsedSize(currentSize+1);
//这里通过setusedSize方法,将currentSize+1传到BookList书架对象中,
//对usedSize经行修改。currentSize通过BookList的get方法得到usedSize的值,
//所以currentSize+1,就表示对usedSize进行加1
}
}
画图理解思路:
删除图书(DelOperation)
删除图书中的难点:
- 挪动数据
- 修改usedSize
- 将最后一位置空(防止内存泄漏)
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();
//设置index用来接收要删除的书籍的下标
int index = -1;
for (int i = 0; i < currentSize; i++) {
Book tmp = booklist.getBook(i);
if (tmp.getName().equals(name)){
index = i;
break;
}
}
//挪动数据,currentSize-1表示的是数组中存在元素的最后一位
for (int j = index; j < currentSize-1; j++) {
//这里的j < currentSize-1不能改为j < currentSize或j <= currentSize-1
//这样在挪动数据的时候会发生数组越界
Book book = booklist.getBook(j+1);
//通过BookList的引用调用getBook这个方法,得到数组j+1下标的元素内容
booklist.setBook(j,book );
//通过BookList的引用调用setBook方法,在Books这个数组指定的j下标的位置放一本书
}
//修改usedSize
booklist.setUsedSize(currentSize-1);
//因为删除的是对象,所以 把最后一个设置为null
booklist.setBook(currentSize-1,null);
System.out.println("删除成功!");
}
}
画图理解:
想要解决这个问题,在上述代码中通过修改usedSize,并且通过BookList的引用来调用setBook方法对最后一位赋一个空值。来解决删除最后一位的问题,usedSize-1,表示书架上的书被删除了一本。但是在 booklist.setBook(currentSize-1,null);这句代码中的意思是,在数组下标的最后一位,放null。
画图解释:
普通用户的业务逻辑
借出图书(BrrowOperation)
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 currentSize = booklist.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = booklist.getBook(i);
//这里将输入的书名与书架中的书名进行比较并且查看是否被借出,
//因为isBorrowed属性在设置的时候为Boolean类型,所以用false来判断
if(book.getName().equals(name)&&book.isBorrowed()==false){
book.setBorrowed(true);
System.out.println("借阅成功");
return;
}
}
}
}
归还图书(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 currentSize = booklist.getUsedSize();
for (int i = 0; i < currentSize; i++) {
Book book = booklist.getBook(i);
//这里将输入的书名与书架中的书名进行比较并且查看是否被借出,因为isBorrowed属性在设置的时候为Boolean类型,所以用true来判断
if(book.getName().equals(name)&&book.isBorrowed()==true){
book.setBorrowed(false);
System.out.println("归还成功");
return;
}
}
}
}