我们学习JAVA之后,对面向对象会有朦朦胧胧的感觉,总感觉那么近又那么远,那么清晰又那么模糊,这里我带来一个图书小练习,里面整合了大部分面向对象相关的思想,希望能帮到你
注意:这里只是为了让我们理解面向对象,逻辑不妥当,可以自行修改
目录
1.运行展示
这里给了两种身份,我们可以用两种身份登陆,从而获取不同的操作权限,在操作的内部给一个目录,然后依次实现里面的相关逻辑就好,我们的重点是面向对象的框架搭建
2.代码讲解
这里是我建的相关包,可以参考
2.1书类【包含封装】
既然是图书系统,所以肯定首先有书籍类
package Book;
public class Book {
private String name; // 图书名
private String author; // 图书作者
private float price; // 图书价格
private String type; // 图书类型
private boolean isBorrowed; // 借出状态
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 float getPrice() {
return price;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setPrice(float price) {
this.price = price;
}
public boolean getBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean isBorrowed) {
this.isBorrowed = isBorrowed;
}
public Book(String name, String author, int price, String type) {
this.name = name;
this.author = author;
this.price = price;
this.type = type;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price + " " +
(!isBorrowed ? "未借出" : "已借出")
;
}
}
在这个类中,我们只需要提供对应的get,set方法和构造方法,还有toString方法即可,主要用来操作图书,这里体现了我们面向对象的封装,都是基础性的东西,没啥能提的点
2.2书架类【包含封装】
既然是图书管理系统,那么肯定会有一个书架来将图书进行整合操作的,那我们就建一个BookList类,在这里面书写对应的代码
package Book;
public class BookList {
private Book[] books = new Book[10];
private int usedSize;
public BookList(){
books[0] = new Book("三国演义"," 罗贯中 ", 19 , "小说");
books[1]= new Book("红楼梦"," 曹雪芹 ", 39 , "小说");
books[2] = new Book("西游记"," 吴承恩", 29 , "小说");
usedSize = 3;
}
/*
寻找pos位置的书
*/
public Book getBook(int pos){
return books[pos];
}
/*
设置pos位置的书
*/
public void setBook(int pos,Book book){
books[pos] = book;
}
/*
获取当前书本的个数
*/
public int getUsedSize(){
return usedSize;
}
/*
修改当前书的个数
*/
public void setUsedSize(int size){
usedSize = size;
}
}
这里既然是书架,我们就可以创建一个数组,来存储书籍,其次,我们需要知道总共有几本书,所以设置一个usedSize来记录图书的个数,并且提供set和get操作的方法,然后我们在前三个数组中提前存3本书,然后也提供对应的get和set方法,这里要注意get和set方法中的pos都是books数组的下标
2.3操作接口(IOperation)【包含接口,多态】
在这里,我们对需要进行的操作实现一个接口,然后定义一个work方法,这样我们就可以在不同的操作类中调用work方法,来实现多态了
package operation;
import Book.BookList;
public interface IOperation {
void work(BookList bookList);
}
我们只要在操作类中实现这个接口,就可以调用同一个方法,然后得到不同的结果了,体现了多态的思想
2.4新增图书
这部分就是简单的逻辑操作直接看代码
import Book.BookList;
import java.util.Scanner;
public class AddOperation implements IOperation{
public void work(BookList bookList){
Scanner sc = new Scanner(System.in);
System.out.println("新增图书");
System.out.println("请输入图书的名字");
String name = sc.nextLine();
System.out.println("请输入图书的作者");
String author = sc.nextLine();
System.out.println("请输入图书的价格");
int price = sc.nextInt();
System.out.println("请输入图书的类型");
String type = sc.nextLine();
Book book = new Book(name,author,price,type);
int currentSize = bookList.getUsedSize();
bookList.setBook(currentSize,book);
bookList.setUsedSize(currentSize+1);
System.out.println("新增完成");
}
}
2.5借出操作
这里的借出操作,我们只需要进行寻找对应的操作,然后再对isBorrow进行修改就可以了
import Book.BookList;
import java.util.Scanner;
public class BorrowOperation implements IOperation{
public void work(BookList bookList){
Scanner sc = new Scanner(System.in);
System.out.println("借阅图书");
System.out.println("请输入你需要借阅的图书");
String name = sc.nextLine();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)){
book.setBorrowed(true);
System.out.println("借阅成功");
}
}
System.out.println("没找到这本书");
}
}
2.6删除操作【包含封装】
删除操作只需要我们把图书后面的图书往前进行覆盖,然后对书架长度进行修改即可
package operation;
import Book.Book;
import Book.BookList;
import java.util.Scanner;
public class DelOperation implements IOperation {
public void work(BookList bookList) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入需要删除的书名");
String key = sc.nextLine();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if (book.getName().equals(key)) {
for (int j = i; j < bookList.getUsedSize() -1; j++) {
bookList.setBook(j,bookList.getBook(j+1)) ;
}
bookList.setUsedSize(bookList.getUsedSize()-1);
System.out.println("删除成功");
return;
}
}
System.out.println("未找到这本书");
}
}
注意:这里的覆盖操作必须用setBook和getBook来进行操作,因为我们的Book是被我们用privet进行修饰的,所以我们是不能直接进行操作的,所以要主get和set方法,包括我们的书架长度,依然是用get和set方法来操作的,又体现了我们的封装性。
2.7显示图书
就是遍历打印
package operation;
import Book.Book;
import Book.BookList;
public class DisplayOperation implements IOperation{
public void work(BookList bookList){
System.out.println("显示图书");
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
System.out.println(book);
}
}
}
这里其实也体现了多态,因为我们Book的toString被重写了,所以我们打印的时候就发生了动态绑定,调用的是我们重写的toString方法
2.8退出系统
这个涉及到内存的清理,我们这里暂时不讲,所以暂时用简单的代码进行叙述即可
package operation;
import Book.BookList;
public class ExitOperation implements IOperation{
public void work(BookList bookList){
System.out.println("退出系统");
}
}
2.9查找图书
这个其实我们在删除图书中已经使用过了,同样的逻辑
package operation;
import Book.Book;
import Book.BookList;
import java.util.Scanner;
public class FindOperation implements IOperation{
public void work(BookList bookList){
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.getBook(i);
if(book.getName().equals(name)){
System.out.println("找到了");
System.out.println(book);
return;
}
}
System.out.println("没有这本书");
}
}
2.10归还图书
这里我们只需要把对应的图书isBorrow更改为未借出即可
package operation;
import Book.Book;
import Book.BookList;
import java.util.Scanner;
public class ReturnOperation implements IOperation{
public void work(BookList bookList){
Scanner sc = new Scanner(System.in);
System.out.println("归还图书");
System.out.println("请输入你需要归还的图书");
String name = sc.nextLine();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)){
book.setBorrowed(false);
System.out.println("归还成功");
}
}
System.out.println("没找到这本书");
}
}
2.11不同用户的操作【包含继承】
2.11.1使用者类(父类)
这里我们因为不同的用户进行操作,但是都是人,都有个名字,所以我们书写一个父类用来继承
package User;
import Book.BookList;
import operation.IOperation;
public abstract class User {
protected String name;
protected IOperation[] iOperations;
public User(String name){
this.name = name;
}
public abstract int menu();
public void doOperation(int choice, BookList bookList){
this.iOperations[choice].work(bookList);
}
}
这里我们定义了一个IOperation(接口)类型的数组,但是我们并没有给他初始化,这个是为了我们在对于不同的操作者身份进行访问的时候,可以根据对应的选择操作调用到不同的操作类方法中去,这也是整个代码的较为核心的部分
然后我们给不同用户看到的目录是不同的,所以我们让这个menu方法被定义为抽象类,让我们在子类中对齐进行重写操作,这里的返回值类型是int,可以用来接收用户的选择
doOperation我们在main方法中讲,这里讲的话不好讲
2.11.2管理员类(子类)
这里我们因为有不同的用户,所以定义了不同身份的类,继承使用者类,然后对我们选择的身份进行对应的操作
package User;
import operation.*;
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 DisplayOperation()
};
}
public int menu(){
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);
return sc.nextInt();
}
}
这里我们有个重点:对从父类继承过来的iOperation进行初始化,分配内存操作,这里我用一个图,可以更好的理解
这里相当于我们iOperation数组中存了五个对象(可以认为是地址),然后由于他们都实现了IOperation接口,所以都发生了向上转型,为我们后面的调用奠定了基础
2.11.3用户身份(子类)
这里和上面的基本一致,只是我们的menu打印不同的东西和上面的对象使用对应的操作即可
package User;
import operation.*;
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()
};
}
public int menu() {
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);
return sc.nextInt();
}
}
2.12main函数整合(重点)
这里到我们的最重要的地方,整合先看代码
import Book.BookList;
import User.*;
import java.util.Scanner;
public class Main {
public static User login() {
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的姓名");
String name = sc.nextLine();
System.out.println("请选择你的身份 1.管理员 0.普通用户");
int choice = sc.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();
while (true) {
int choice = user.menu();
user.doOperation(choice, bookList);
if (choice == 0) {
break;
}
}
}
}
首先可以看到有一个Login方法,这个是登入操作,我们返回值用父类的类型User来进行接收,这里就发生了向上转型
其次我们看main函数里面,首先执行Login,选择登入的身份,然后用while进行循环操作,用chioce接收menu的返回值,如果是0,则结束循环
最后,我们可以看到我们用user调用了doOperation方法,这里我们因为发生了动态绑定,所以我们的user调用就和我们选择的身份进行调用时一个效果,也体现了多态,
然后我们分析doOperation方法
首先是参数,因为要对书架进行对应的操作,所以我们把书架和我们刚刚目录中选择的choice作为形参传进去,在看doOperation方法
我们首先用this也就是上面的user,对他的iOperation数组中的第chioce个元素进行操作,进行这个元素(也就是上面new的对象)我们可以实现里面的操作,我们都知道所有的操作类中,都有一个work方法,所以我们可以调用其中得到work方法,从而完成我们选择的操作
3.总结
这个小练习融合了几乎所有面向对象思想
对上面代码整合到编译器即可运行,如有不妥当得到地方,还请大佬指点