整合 多态+数据结构(顺序表)+类+封装+接口+继承的面向对象编程的一个实用案例之:图书馆管理
重要逻辑
-
找对象
- 书有名字、作者、类型、价格、是都被借阅的状态。可以作为一类对象
- 用户可以有姓名等,可以成为一个对象,在此处,用户又可细化为两类(管理员和普通用户),他们都可以独成一类
- 对图书的增删查改这些行为可以作为对象,作为一类
-
创建对象
- 书有了,整合这些数据的数据结构在此处选择较为简单的顺序表作为手段。后续学完数据库,可以将数据放在数据库中。
- 为了面向对象编程,我们将行为各成一派,所有派别都实现一个接口(所有派的掌门人),这里既可以认为是实现接口,也可以理解成继承关系,为后续动态绑定做铺垫。
- 针对用户方面,我们希望的是:一个用户选择身份后,其背后的逻辑(比如对应身份的菜单(用一个数组实现))已经初始化完成,再让用户进行下一步选择时,已经可以进入功能(方法)的使用了。
-
使用对象 前述对象的交互,完成逻辑表达。
第一步:我们可以先针对书,建立一个包,该包下建立书类和顺序表,之前都是写在一个包里,现在是写在一个包下的两个类中,这也是真正的习惯之一。(注意事项已经写在代码注释行)💛
package book;
public class Book {
private String name;
private String author;
private String type;
private int price;
private boolean isBorrowed;
public Book(String name, String author, String type, int price) {
this.name = name;
this.author = author;
this.type = type;
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", type='" + type + '\'' +
", price=" + price +
(isBorrowed==true?" 已被借出 ":" 未被借出 ")+
'}';
}
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 String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
}
对BookList来说
package book;
import java.util.Arrays;
public class BookList {
private Book[] books=new Book[10];
private int usedSize;
public BookList() {
books[0]=new Book("三国演义","罗贯中","小说",17);
books[1]=new Book("水浒传","施耐庵","小说",44);
books[2]=new Book("西游记","吴承恩","小说",35);
this.usedSize=3;
}
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
public Book getPos(int pos){
if(pos<0||pos>this.usedSize){
System.out.println("下标不合法");
return null;
}
return books[pos];
}
public boolean isFull(){
return this.usedSize==this.books.length;
}
public void setPos(int pos,Book book){
if(isFull()){
this.books= Arrays.copyOf(this.books,2*this.books.length);
}
if(pos<0||pos>this.usedSize){
System.out.println("下标不合法");
return;
}
for (int i = this.usedSize-1; i >=pos ; i++) {
this.books[i+1]=this.books[i];
}
this.books[pos]=book;
this.usedSize++;
}
}
第二步:针对用户:??
目前用户的抽象我们只能想到只要是用户都用名字,那就先写出来,继承关系也打好。
第三步:针对我们的Main函数:其逻辑
-
先建立书的顺序表 -
让用户登录,这里很重要,逻辑是:让用户选择好身份后,我们的编译器已经生成对应其身份的菜单了!并且呢,不管用户选哪个身份,我们都用User去接受,使其发生向上转型,为什么让它向上转型?因为要实现多态!哪里多态?我们可以用父类引用打印不同子类的菜单!哦!所以这里User和其子类中都要写menu(),并使其构成重写,不过打印出来的菜单只是给我们看的,其实在打印之前,也就是让用户选择身份的时候,再说白了,就是通过子类实例化对象的时候,这个对应菜单的数组就已经建立好了。 -
让用户根据其身份选择功能,也就是说我们给用户一个menu,他们能看到一些功能,他们做出选择后(其实就是返回值),我们的编译器就能拿到对应的方法进行下一步的执行。 针对Main:
import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {
public static User login(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入姓名:");
String name=scanner.nextLine();
System.out.println("========请选择访问身份:1:管理员 0:普通用户========");
int choice=scanner.nextInt();
while(true){
if(choice==1){
return new AdminUser(name);
}else if(choice==0){
return new NormalUser(name);
}else{
System.out.println("输入错误,请重新输入:");
}
}
}
public static void main(String[] args) {
BookList bookList=new BookList();
User user=login();
while(true){
int choice=user.menu();
user.doWork(choice,bookList);
}
}
}
当然我们的main函数编到子类用户实例化的时候要去对子类用户和用户做思考:
-
子类和父类都要menu(),并且多态式打印 -
子类用户实例化的时候,要产生对应的菜单(数组),反正两类子类用户都有对应的数组,那再在父类用户User中添一个字段(操作的那个引用),这个引用也将在子类构造方法中先于子类自身构造时先被初始化,到这用户这块基本都齐全了。先思考到这。然后代码给你们看看: User:
package user;
import book.BookList;
import operation.IOperation;
public abstract class User {
protected String name;
protected IOperation[] iOperations;
public abstract int menu();
public void doWork(int choice, BookList bookList){
iOperations[choice].work(bookList);
}
}
AdminUser:
package user;
import operation.*;
import java.util.Scanner;
public class AdminUser extends User{
public AdminUser(String name){
this.name=name;
this.iOperations=new IOperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new DisplayOperation()
};
}
public int menu(){
System.out.println("========管理员菜单========");
System.out.println("Hello "+this.name+" 欢迎来到图书小练习");
System.out.println("0:退出系统");
System.out.println("1:查找图书");
System.out.println("2:新增图书");
System.out.println("3:删除图书");
System.out.println("4:打印图书");
System.out.println("请输入你的选择:");
Scanner scanner=new Scanner(System.in);
int choice =scanner.nextInt();
return choice;
}
}
NormalUser:
package user;
import operation.*;
import java.util.Scanner;
public class NormalUser extends User{
public NormalUser(String name){
this.name=name;
this.iOperations=new IOperation[]{
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
public int menu(){
System.out.println("========普通用户菜单========");
System.out.println("Hello "+this.name+" 欢迎来到图书小练习");
System.out.println("0:退出系统");
System.out.println("1:查找图书");
System.out.println("2:借阅图书");
System.out.println("3:归还图书");
System.out.println("请输入你的选择:");
Scanner scanner=new Scanner(System.in);
int choice =scanner.nextInt();
return choice;
}
}
第三步:Main函数已经完成了2/3了,🌮
这里还是想通过父类引用实现多态的调用方法,那就继续在User和子类用户里新添一个方法(要构成重写):doWork()
这个方法,要能根据选择拿到数组的元素,这个数组元素你们发现了没有,每个元素都是接口,那之前说了所有的方法都实现了这个接口,就相当于继承,
这里通过IO接口又一次实现多态!
上代码:IOperation:
package operation;
import book.BookList;
public interface IOperation {
void work(BookList bookList);
}
功能函数:
如AddOperation:
package operation;
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("请输入书的类型:");
String type=scanner.nextLine();
System.out.println("请输入书的价格:");
int price=scanner.nextInt();
Book book=new Book(name,author,type,price);
int curSize=bookList.getUsedSize();
bookList.setPos(curSize,book);
bookList.setUsedSize(curSize+1);
System.out.println("填加图书成功");
System.out.println("===========================");
}
}
其余的留给读者去实现。下篇博客给大家揭晓本人的答案(当然不一定最好)?
|