🎉🎉🎉点进来你就是我的人了
博主主页: 🙈🙈🙈戳一戳,欢迎大佬指点!欢迎志同道合的朋友一起加油喔🤺🤺🤺
目录
实现的一个基本效果
1.管理员的系统
2.用户的系统
3.大体框架
一、实现的一个大致思路
- 既然我们要实现一个图书管理系统,首先我们要有书架(BookList)和书(Book)的详细信息对吧,所以创建Book类记录每本书的基本信息,然后创建BookList类,在BookList(书架)这个类里面定义Book类型的数组,用于存放每本书,再定义一个变量usedSize用来记录的存放书籍的数组里面一共有几本书!
-
图书管理系统会涉及到两类人,管理员和用户,而系统面对不同的使用者又会提供不同的功能,所以一共会提供7个功能,也就是要写7个功能类.
-
然后我们发现,这7个功能类如果每个功能实现的方法名都不统一的情况,那么调用起来是不是会特别麻烦呢,因此我们定义一个统一的接口,这些功能类需要遵守接口的规范去实现,在这里,细心的小伙伴肯定会发现这些功能都是围绕着书架去操作(像这些添加,删除,查找,显示等操作是不是都围绕书架里面的存放的书去操作呀),因此我们在定义这个方法的同时可以传一个书架的实例化对象过去,后面可以用在实现这些功能的时候就可以利用传过来的书架对象去调用书单里面的成员方法和成员变量了.
-
然后我们再看看操作这个系统的两类使用者,一个是管理员,一个是普通用户,由于用户和管理员操作图书管理系统的功能不同,因此提供给他们的菜单也不同,同时他们都有姓名等一些公共的属性,所以这里我们可以定义一个User父类,让AdminUser和 NormalUser去继承这个类。
- 注意到这里的菜单不一样,可以分别再AdminUser和NormalUser里面都定义一个menu方法,但是这样不灵活,所以我们可以在User类里面定义一个抽象方法,然后让另外两个类重写这个抽象方法,以后还可以方便进行多态(动态绑定),更加灵活,注意到方法是abstract修饰的抽象方法,User类也要改为abstract修饰的抽象类。
- 注意用户在看见菜单(menu)以后,肯定要输入一个数字去操作菜单里面的功能,所以需要返回一个数字代表你所使用的功能,这里可以把menu方法定义为返回值为int型的方法
- 最后我们在最外面新建一个Main类,里面写main方法,在main方法之前我们写一个login方法(登录的方法),用来读入用户的名称以及他的用户类型,如果是管理员,返回一个AdminUser对象,如果是普通用户,返回一个NormalUser对象,这里注意把login()方法的返回值设置为User类才可以成功返回对象,然后执行main方法中User user = login()(这里父类引用指向了子类对象,发生了多态中的向上转型),接收login()方法返回的对象;然后user.menu()(这里父类调用了子类重写的方法,注意父类引用指向的是哪个对象,调用的就是哪个对象重写的方法),也就是用接收的对象调出菜单.
- 还有在User的内部我们定义了一个成员变量,也就是操作接口的数组,用于存放不同的实现类
然后在调用AdminUser或NormalUser的时候,会按顺序初始化这些实现操作功能的类,这里相当于IOperation接口发生了向上转型
最后关键的一步,我们现在的user根据long()方法的返回值已经完成了动态绑定,相当于已经知道了使用该系统的人是管理员还是普通用户,接下来要做的就是根据返回的choice的值来调用相应的实现操作功能的类里面的work方法,就能完成我们对该图书系统做出的指令。
二、代码演示及详解
1.book包
1.1 Book类的实现
我们这里书籍的属性有书名、作者、价格、类型以及是否被借出,我们结合封装性,将属性设置为private权限,并提供相应的get方法和set方法,空参构造器,以及一个不包含是否被借出的构造器(布尔值的默认类型就是false,可以不进行初始化)并需要提供对应的toString()方法的重写(具体重写情况看展示效果),代码实现如下:
public class Book {
private String name; //书名
private String author; //作者
private double price; //书的价格
private String type; //书的类型
private boolean isBorrowed; //默认false 表示书没有借出,所以不用初始化
//构造方法
public Book() {
}
public Book(String name, String author, double 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 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 + '\'' +
// ", isBorrowed=" + isBorrowed +
(isBorrowed ==true? " 已经借出" : " 未借出")+ //三目运算符判断书当前的状态
'}';
}
}
1.2 BookList类的实现(书架)
Book类的每个实例化对象都是一本书,而在进行增删查操作时往往需要对Book类的每个对象进行操作,为了方便操作我们将Book类的对象保存在Booklist类的Book类型的books数组中,在打开系统的时候先让它有几本书存在,我们使用构造方法在创建几个Book类的对象同时将它们存放在books数组中,为了方便管理,我们需要设置一个书的数量的成员变量并且仅对本类可见,所以我们是使用private关键字对其进行修饰,并且为其设置get和set方法.
注意:这里对外公开了getBook和setBook方法,是为了我们后面在实现类的功能(例如增删查改)的时候,可以直接通过当前类的对象调用这个方法去访问书架上面的书,以及设置书的位置.
public class BookList {
private Book[] books =new Book[10]; // 声明了一个可以存放10本书的数组
private int usedSize; //默认存放了0本书
//无参构造方法,用于初始化
public BookList(){
books[0] =new Book("三国演义","罗贯中",88,"小说");
books[1] =new Book("红楼梦","曹雪芹",108,"小说");
books[2] =new Book("西游记","吴承恩",95,"小说");
usedSize =3; //表示现在书单里面存了三本书
}
//对应的get/set方法
public Book getBook(int pos) { //取到pos位置的那本书
return this.books[pos];
}
public Book setBook(int pos,Book book) { //将pos位置上的书置为book
return this.books[pos] =book;
}
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
}
2.operation包
2.1 IOperation接口
IOperation接口是所有功能类的公共规范,它应该具有抽象方法work,这个方法的操作对象应该是BooList类的对象,所有的实现类必须按这个方法的标准去重写这个方法.
import book.BookList;
import java.util.*;
public interface IOperation {
public abstract void work(BookList bookList); //接口中有一个工作的抽象方法,传了一个书单的对象过去
}
2.2 AddOperation实现类
添加图书的细节:这里注意只要把书添加到usedSize位置上即可,因为数组的下标是从0开始遍历的,最后不要忘了添加成功后总的书籍本数要加1.
import book.Book;
import book.BookList;
import java.util.*;
public class AddOperation implements IOperation{
@Override
public void work(BookList bookList) {
Scanner scanner =new Scanner(System.in);
System.out.println("新增图书");
//增加的图书只要放到当前数组的usedSize位置就可以添加成功
System.out.println("请输入图书的名字:");
String name = scanner.nextLine();
System.out.println("请输入图书的作者:");
String author = scanner.nextLine();
System.out.println("请输入图书的价格:");
double price = scanner.nextDouble();
System.out.println("请输入图书的类型:");
String type = scanner.next();
Book book =new Book(name,author,price,type);
int usedSize = bookList.getUsedSize();
bookList.setBook(usedSize,book);
bookList.setUsedSize(usedSize+1);
System.out.println("图书添加成功");
}
}
2.3 DelOperation实现类
删除图书的细节: 每个地址存放了一本书,假设删除的是第二本书,我们可以拿后面的书覆盖前面的书,这样就可以删除掉指定位置的书,虽然最后一个位置的书并没有被覆盖(也是就说现在最后这本书同时被两个引用指向了),但是我们要知道,在删除完一本书之后,总的书籍本数也就少了1本,因此通过下标打印全部书籍的时候,不会访问到最后一本书,但是为了防止内存泄漏,我们还是给最后一个位置指向的对象置为null.
import book.Book;
import book.BookList;
import java.util.*;
public class DelOperation implements IOperation{
@Override
public void work(BookList bookList) {
Scanner scanner =new Scanner(System.in);
System.out.println("删除图书");
System.out.println("请输入要删除的图书的名称");
String name = scanner.next();
int n = bookList.getUsedSize();
for (int i = 0; i < n; i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)){
for (int j = i; j < n-1; j++) {
bookList.setBook(j,bookList.getBook(j+1));
}
bookList.setUsedSize(n-1);
bookList.setBook(n-1,null);
System.out.println("图书删除成功");
return; //如果找到了,就直接return出去
}
}
System.out.println("抱歉,没有找到你需要删除的书!");
}
}
2.4 FindOperation实现类
import book.Book;
import book.BookList;
import java.util.*;
public class FindOperation implements IOperation{
@Override
public void work(BookList bookList) {
Scanner scanner =new Scanner(System.in);
System.out.println("查找图书");
System.out.println("请输入图书的名称");
String name = scanner.next();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)){
System.out.println("找到该图书!");
System.out.println(book);
return; //如果找到了,就直接return出去
}
}
System.out.println("没有找到该图书!");
}
}
2.5 ShowOperation实现类
import book.BookList;
import java.util.*;
public class ShowOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("显示所有图书");
for (int i = 0; i < bookList.getUsedSize(); i++) {
System.out.println(bookList.getBook(i));
}
}
}
2.6 BorrowOperation实现类
import book.Book;
import book.BookList;
import java.util.*;
public class BorrowOperation implements IOperation{
@Override
public void work(BookList bookList) {
Scanner scanner =new Scanner(System.in);
System.out.println("借阅图书");
System.out.println("请输入图书的名称");
String name = scanner.next();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name) ){
if(!book.isBorrowed()){ //如果找到该书切该书没有被借,那就借阅成功
book.setBorrowed(true);
System.out.println("图书借阅成功");
}else{
System.out.println("该图书已被借阅");
}
return; //如果找到了,就直接return出去
}
}
System.out.println("该图书不存在!"); //走到这里说明这本书不存在
}
}
2.7 ReturnOperation实现类
import book.Book;
import book.BookList;
import java.util.*;
public class ReturnOperation implements IOperation{
@Override
public void work(BookList bookList) {
Scanner scanner = new Scanner(System.in);
System.out.println("归还图书");
System.out.println("请输入需要归还图书的名称");
String name = scanner.next();
for (int i = 0; i < bookList.getUsedSize(); i++) {
Book book = bookList.getBook(i);
if(book.getName().equals(name)){
if(book.isBorrowed()){
book.setBorrowed(false);
System.out.println("图书归还成功");//如果找到该书,且该书已被借阅,那就归还成功
}else{
System.out.println("该书未被借阅");
}
return; //如果找到了,就直接return出去
}
}
System.out.println("该图书不存在!"); //走到这里说明这本书不存在
}
}
2.8 ExitOperation实现类
import book.BookList;
import java.util.*;
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
System.exit(0); //退出系统
}
}
3.user包
3.1 User父类
对于普通用户和管理员层面我们都有使用者的名字,并且都有各自的功能选择界面以及根据用户的选择进行相应的工作的方法,所以:
User类应该具有以下属性:
1.String类型的name;
2.保存功能类的iOperations接口类型的数组;
3.抽象方法menu(菜单)方法;
4.根据用户选择对booklist对象进行操作的doWork方法;
import book.BookList;
import operation.IOperation;
public abstract class User {
protected String name; //使用者的姓名
IOperation[] iOperations; //定义了一个接口数组,用于存放接口的实现类对象;
//构造方法
public User(String name) {
this.name = name;
}
//定义一个菜单的抽象方法
public abstract int menu();
public void doWork(int choice, BookList bookList){
iOperations[choice].work(bookList); //用接口数组里面的第choice个对象去调用实现类中工作的方法,同时把书单这个对象传过去
}
}
3.2 AndminUser子类(管理员)
import operation.*;
import java.util.*;
public class AndminUser extends User{
public AndminUser(String name) {
super(name);
this.iOperations =new IOperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new ShowOperation()
};
}
@Override
public int menu() {
System.out.println("==========================================");
System.out.println("尊贵的管理员-"+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("==========================================");
System.out.println("请输入操作:");
Scanner scanner =new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
3.3 NormalUser子类(普通用户)
import operation.*;
import java.util.*;
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
this.iOperations =new IOperation[]{
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
@Override
public int menu() {
System.out.println("==========================================");
System.out.println("尊贵的用户-"+this.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.Mian(测试类)
import book.BookList;
import user.AndminUser;
import user.NormalUser;
import user.User;
import java.util.*;
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();
if(choice ==1){
return new AndminUser(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.doWork(choice,bookList); //多态的形式调用doWork这个方法,同时把返回值和书单这个对象传过去
}
}
}
看到这里,有没有发现所有的知识点都串联起来了呢
三.根据图书管理系统浅总结一下面向对象的三大特征
封装:
封装就是尽可能地隐藏内部的执行细节,只 保留一些对外接口使之与外部发生联系。系统的其他部分只有通过包裹在数据外面的被授权的操作来与这个抽象数据类型交流与交互。用户不需要知道对象内部方法的实现细节,但可以根据对象提供的外部接口(对象名和参数)访问该对象。好处:(1)不需要让用户对让人头疼的细节和逻辑和代码编写而费心,只需要使用一些对外接口即可。(2)方便程序开发者通过控制访问权限可以将可以将不想让客户端程序员看到的信息隐藏起来。
继承:
一个类继承另一个类,主动继承的类为子类,被继承的类为父类。子类与父类的关系并不是日常生活中的父子关系,子类与父类而是一种特殊化与一般化的关系,是is-a的关系,子类是父类更加详细的分类。如 class Person 继承于 Animal,就可以理解为Person is a Animal.注意设计继承的时候.继承后子类自动拥有了父类的属性和方法,子类可以写自己特有的属性和方法,目的是实现功能的扩展,当然子类也可以复写父类的方法即方法的重写。比如说Animal有一个普通的吃方法,因为Person类,即人的吃方法和其他动物的吃方法是不一样的,人的吃方法讲究色香味俱全,所以Person类就可以重写父类的吃方法。好处:实现代码的复用性,可以减少程序员对代码的编写。
多态:
相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在程序编译时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的实现类上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
低耦合,高扩展力在此图书系统中已经发挥的淋漓尽致了吧 !