目录
目录
▪退出系统 - ExitOperation (exit:v,退出)
▪添加书籍 - AddOperation (add:v,添加)
▪借阅书籍 - BorrowOperation (borrow:v,借阅)
▪展示书籍 - DisOperation (display:v,展示,陈列)
▪归还书籍 - ReturnOperation (return:v,返回)
▪查找书籍 - FindOperation (find:v,找出)
▪删除书籍 - DelOperation (delete:v,删除)
欢迎各位在评论区提问或指出问题,请多多赐教 ——海鱼🐟
▮设定对象的类
首先,图书管理系统最基本的东西就是书,“书”这个类是整个系统的基础,所以我们先创造出“书”。接着,有了书以后,要有一个放书的容器,我们需要创建一个“书架”,用这个类来装书。最后,有书有书架后,就要有人来使用它们,我们要创建一个“用户”来使用它们,根据用户的身份不同,我们给予用户不同的操作权限,即“普通人”与“管理员”的权限不同。
java是面向对象的语言。在进行编程前,要先给项目中的对象设计好类。图书管理系统所设计的类如上。注意:用户是普通人和管理员的父类。
▮类设计
▪ Book - 书类
对于一本书,它有着“书名,作者,种类,价格,等属性”。当我们拿起一本书阅读时,总是会先去看看书的封面,此时书的封面上写着书名,书通过这种方法告诉了“用户”,它的名字是什么?所以,现实中我们都知道,要了解书名是什么,就要去看书的封面。但在java里,“书”通过getName这个公开的方法来告诉我们书名是什么,所以,“用户”想要知道了解书名,只能通过getName()来了解,想要修改书名,只能通过setName()来修改。
书的其他属性同上。
•代码演示
public class Book { private String name; //书名 private String author; //作者 private int price; //价格 private String type; //种类 private boolean isBorrowing; //借阅状态 //构造方法 public Book(String name, String author, int price, String type) { this.name = name; this.author = author; this.price = price; this.type = type; } //toString输出成员属性 @Override public String toString() { return "Book{" + "name='" + name + '\'' + ", author='" + author + '\'' + ", price=" + price + ", type='" + type + '\'' + ", Borrow='"+ (isBorrowing ?"已被借阅" :"未被借阅") + '\'' + //IDEA的快捷方式不会自动生成此条,需要自行添加 '}'; } }
这里省略了get,set成员属性的方法,记得自己生成,因为成员属性都是private所修饰,进行了封装,不添加的话没法操作成员属性。
toString()进行了修改,不是全靠自动生成。里面还使用了三木操作符“ …?… :… ”操作,代码中有标注。
▪ Bookcase - 书架
对于一个书架,它首先要有“容量”,即书架上能放几本书?然后,我们要在书架里掏出框框,作为放书的地方,即“Book[ ] booklist”。最后,把书放到书架后,我们还要知道,书架上放有几本书,即“书本个数”
有了书架后,我们要放书或换书,即setBooks;我们还要通过书架的索引来取书,即getBooks()。我们每次操作书籍后,我们要知道书架上还有几本书,即getUsednumber();我们还有可能改变书本个数,即setUsednumber()。
•代码演示
public class Bookcase { private static final int BOOKCASE_SIZE = 10; //书架容量,用final修饰,不可修改 private Book[] booklist = new Book[BOOKCASE_SIZE]; //书单 private int usednumber; //使用书架的书本数量,即书架上有几本书 //默认构造方法 public Bookcase() { //书架上的的默认放置的书本 booklist[0] = new Book("三国演义", "罗贯中", 19, "小说"); booklist[1] = new Book("西游记", "吴承恩", 28, "小说"); booklist[2] = new Book("红楼梦", "曹雪芹", 39, "小说"); this.usednumber = 3; } //功能:根据下标来找到书籍 public Book getBooks(int pos) { //参数:下标 return booklist[pos]; //返回:下标对应的Book } //功能:更换下标处的书籍 public void setBooks(int pos, Book book) { //参数:下标,新的Book对象 booklist[pos] = book; } //功能:得到书架上书本的个数 public int getUsednumber() { return usednumber; } //功能:修改书架上书本的个数 public void setUsednumber(int usednumber) { this.usednumber = usednumber; } }
这里提上一句。很多时候,我很难设计好对象所要进行的行为。当我不知道该写什么方法的时候,我都会选择去写后面的代码,写着写着就会发现,欸,这里需要的方法我没有写,然后跑回来补上所需的方法。就这样,我一直来来回回的写着,最后写出了我的项目。
写完后在回头优化一下自己的代码,删减和调整一下,就完成了一个非常不错的项目。
所以说,大家都不要害怕写项目,不知道怎么写代码的时候,就先去写后面的代码。一直写下去,通过后面的代码来提醒你,你要写什么样的代码。
▪ User - 用户(父类)
对于一个用户,我们要知道它的“名字”和“身份”。同时要能获取用户的名字,即getName()。有了用户后,要根据他们的身份赋予他们不同的行为,这里用的是接口数组“Ioperation[] ioperation”来记录他们的行为。
用户的身份不需要作为属性,因为要用“向上转型”来绑定子类,绑定不同的子类,就代表着不同的身份。•代码演示
public class User { private String name; //用户名 //构造方法,非默认 public User(String name){ this.name = name; } //这是一个接口数组,装的是用户能进行的行为 public Ioperation[] ioperation; //这个方法会被子类所重写,用于打印菜单,得到选项 public int menu (){ //menu:n,菜单 return 0; } //输出用户名 public String gteName(){ return this.name; } }
operation是一个接口数组用来装入各种行为,至于要装入什么行为,由子类来定。而且子类要进行的行为都要通过它来调用,所以它用“ public ”来修饰,没有封装。
menu()这个方法后文会讲,现在不管。
• AdminiUser - 管理员
管理员的权限是固定的,能进行的行为也是固定的。所以在构造方法里就给“管理员”赋予行为,因为构造方法只调用一次。
•代码演示
public class AdminiUser extends User{ //构造方法,非默认 public AdminiUser(String name){ super(name); //调用父类构造方法 operation = new Ioperation[]{ //创建了一个数组,里面装着各种对象 new ExitOperation(), //实现“退出系统”方法的类 new AddOperation(), //实现“增加书籍” new DelOperation(), //实现“删除书籍” new DisOperation(), //实现“展示书籍” }; } }
这个对象所要进行的行为没有写进这个类中,而是使用“接口”来连接对象要进行的行为。至于这些行为怎么实现,后文慢慢介绍。
▪ NomalUser - 普通人
普通人的权限是固定的,能进行的行为也是固定的。所以在构造方法里就给“普通人”赋予行为,因为构造方法只调用一次。
•代码演示
public class NomalUser extends User{ //继承了父类User //构造方法,非默认 public NomalUser(String name){ super(name); //调用父类构造方法 super.operation = new Ioperation[]{ new ExitOperation(), //实现“退出系统” new BorrowOperation(),//实现“借阅书籍” new ReturnOperation(),//实现“归还书籍” new FindOperation(), //实现“查找书籍” }; } }
这个对象所要进行的行为没有写进这个类中,而是使用“接口”来连接对象要进行的行为。至于这些行为怎么实现,后文慢慢介绍。
▮接口和行为类
▪接口 - Iopreration
接口里的抽象方法代表着一类行为,别的类通过实现接口,重写接口的抽象方法来与接口相绑定。当接口这个USB插到左边的某个类时,通过使用这个USB就能调用,被插入的类里的,重写了接口抽象方法的,用户所需要的行为方法。
被插入:Ioperation operation = new 被插入类();•接口代码展示
public interface Ioperation { //operation:n. 操作 //功能:这是一个抽象方法,它的功能由七大类来重写实现 void work(Bookcase bookcase); // 参数:Bookcase的一个实例对象,无返回 }
接口左边有七个类,这七个类都实现了接口Ioperation,里面都只有一个重写方法,每个重写的方法的参数和返回值类型是一样的,与接口的抽象方法一致。唯独不同的就只有方法的功能。
▪退出系统 - ExitOperation (exit:v,退出)
public class ExitOperation implements Ioperation{ //这个类实现了接口 @Override //重写的标志 public void work(Bookcase bookcase) { System.out.println("退出系统"); System.exit(0); //调用了System类中的exit方法,传入0表示程序正常结束 } }
用类System的exit()方法来退出程序,给exit传入“0”表示程序正常退出。
▪添加书籍 - AddOperation (add:v,添加)
public class AddOperation implements Ioperation{ //这个类实现了接口 @Override public void work(Bookcase bookcase){ //传入一个Bookcase的对象 System.out.println("-----添加书籍-----"); //输入添加书籍的信息 Scanner sc = new Scanner(System.in); System.out.println("请输入书籍名称"); String name = sc.nextLine(); System.out.println("请输入书籍作者"); String author = sc.nextLine(); System.out.println("请输入书籍类型"); String type = sc.nextLine(); System.out.println("请输入书籍价格"); int price = sc.nextInt(); //这里是整形,上面的都是字符串 //调用对象bookcase的方法得到书架上书籍的数量 int usednumber = bookcase.getUsednumber(); //调用对象bookcase的setBooks方法,new了一个新的书籍放进书架 bookcase.setBooks(usednumber,new Book(name,author,price,type)); //因为数组下标是从0开始的,所以usednumber作为索引时,正好指向一个空位 //添加了一本书籍后,书架上书籍的数量加1 bookcase.setUsednumber(usednumber+1); System.out.println("添加成功"); } }
此方法传入一个类型为Bookcase的对象:bookcase。首先,创建几个变量来接受输入的书籍属性;然后,取得bookcase的“书籍数量”作为下标索引,因为数组下标是从0开始的,所以书籍数量作为下标,正好指向书架上的空位;接着,new一个新的Book对象,用前面输入的变量来初始化后,传给方法bookcase.setBooks()来添加书籍;最后,用bookcase.setUendnumber()方法给“书籍数量”加1。
▪借阅书籍 - BorrowOperation (borrow:v,借阅)
public class BorrowOperation implements Ioperation{ //这个类实现了接口 @Override public void work(Bookcase bookcase) { //传入了一个类型为Bookcase的对象 System.out.println("-----借阅书籍-----"); //输入借阅书籍的名称 Scanner sc = new Scanner(System.in); System.out.println("请输入借阅书籍名称"); String name = sc.nextLine(); //调用对象bookcase的方法得到书架上书籍的数量,作为遍历结束的条件 int usednumber = bookcase.getUsednumber(); //遍历书架里所有的书籍 for(int i=0; i<usednumber; i++){ //在书架中寻找与借阅书籍名称相同的书籍 if(name.equals(bookcase.getBooks(i).getName())){ //name.equals(str): 调用了字符串name的实例方法,来比较name是否与str同名 //bookcase.getBooks(i): 找到下标i对应的Book对象 //.getName(): 得到此Book对象的"书名"属性,这是一个字符串属性,即str System.out.println("借阅成功"); //把这本书的属性改为“已借阅” Book book = bookcase.getBooks(i); book.setBorrowing(true); System.out.println(book); //若找到此书,则直接结束这个方法,不执行下方"未查到此书"的打印 return; } } System.out.println("未查到此书"); } }
此方法传入一个类型为Bookcase的对象:bookcase。首先,用一个变量“name”来接收借阅书名;然后,遍历bookcase的booklist(书单)[];接着,用字符串变量name的equals()来一一比对,bookcase.booklist[]里,书籍的书名;最后,找到同名书籍后,用setBorrowing()把此书的借阅状态改成“已借阅”
▪展示书籍 - DisOperation (display:v,展示,陈列)
public class DisOperation implements Ioperation{ //这个类实现了接口 @Override public void work(Bookcase bookcase) { System.out.println("-----展示书籍-----"); //调用对象bookcase的方法得到书架上书籍的数量,作为遍历结束的条件 int usednumber = bookcase.getUsednumber(); for(int i=0; i<usednumber; i++){ //使用println(对象)来打印对象的所有属性, System.out.println(bookcase.getBooks(i)); //bookcase.getBooks(i): 找到下标i对应的Book对象 //println(对象)等同于调用对象的toString()方法,所以对象内部要重写toString } //书架书籍为空的情况 if(usednumber == 0){ System.out.println("图书馆书籍为空"); return; } } }
此方法传入一个类型为Bookcase的对象:bookcase。首先,遍历bookcase的booklist(书单)数组;然后,bookcase.getBooks(i)取得类Book的对象;最后,用println(Book对象)调用toString()来打印对象。
▪归还书籍 - ReturnOperation (return:v,返回)
public class ReturnOperation implements Ioperation{ //这个类实现了接口 @Override public void work(Bookcase bookcase) { System.out.println("-----归还书籍-----"); //输入归还书籍的名称 Scanner sc = new Scanner(System.in); System.out.println("请输入归还书籍名称"); String name = sc.nextLine(); //调用对象bookcase的方法得到书架上书籍的数量,作为遍历结束的条件 int usednumber = bookcase.getUsednumber(); for(int i=0; i<usednumber; i++){ //在书架中寻找与借阅书籍名称相同的书籍 if(name.equals(bookcase.getBooks(i).getName())){ //name.equals(str): 调用了字符串name的实例方法,来比较name是否与str同名 //bookcase.getBooks(i): 找到下标i对应的Book对象 //.getName(): 得到此Book对象的"书名"属性,这是一个字符串属性,即str System.out.println("归还成功"); //把这本书的属性改为“未借阅” Book book = bookcase.getBooks(i); book.setBorrowing(false); System.out.println(book); //若找到此书,则直接结束这个方法,不执行下方"图书馆未收藏此书"的打印 return; } } System.out.println("图书馆未收藏此书"); } }
此方法传入一个类型为Bookcase的对象:bookcase。首先,用一个变量“name”来接收归还书名;然后,遍历bookcase的booklist(书单)[];接着,用字符串变量name的equals()来一一比对,bookcase.booklist[]里,书籍的书名;最后,找到同名书籍后,用setBorrowing()把此书的借阅状态改成“未借阅”。
▪查找书籍 - FindOperation (find:v,找出)
public class FindOperation implements Ioperation{ //这个类实现了接口 @Override public void work(Bookcase bookcase) { System.out.println("-----查找书籍-----"); //输入查找书籍的名称 Scanner sc = new Scanner(System.in); System.out.println("请输入查找书籍名称"); String name = sc.nextLine(); //调用对象bookcase的方法得到书架上书籍的数量,作为遍历结束的条件 int usednumber = bookcase.getUsednumber(); if(usednumber == 0){ System.out.println("图书馆书籍为空"); return; } for(int i=0; i<usednumber; i++){ //在书架中寻找与借阅书籍名称相同的书籍 if(name.equals(bookcase.getBooks(i).getName())){ //name.equals(str): 调用了字符串name的实例方法,来比较name是否与str同名 //bookcase.getBooks(i): 找到下标i对应的Book对象 //.getName(): 得到此Book对象的"书名"属性,这是一个字符串属性,即str System.out.println("查找成功"); //使用println(对象)来打印对象的所有属性, System.out.println(bookcase.getBooks(i)); //bookcase.getBooks(i): 找到下标i对应的Book对象 //println(对象)等同于调用对象的toString()方法,所以对象内部要重写toString //若找到此书,则直接结束这个方法,不执行下方"未查到此书"的打印 return; } } System.out.println("未查到此书"); } }
此方法传入一个类型为Bookcase的对象:bookcase。首先,用一个变量“name”来接收查找书名;然后,遍历bookcase的booklist(书单)[];接着,用字符串变量name的equals()来一一比对,bookcase.booklist[]里,书籍的书名;最后,找到同名书籍后,用bookcase.getBooks(i)取得类Book的对象,用println(Book对象)调用toString()来打印对象。
▪删除书籍 - DelOperation (delete:v,删除)
public class DelOperation implements Ioperation{ //这个类实现了接口 public void work(Bookcase bookcase){ System.out.println("-----删除书籍-----"); //输入删除书籍的名称 Scanner sc = new Scanner(System.in); System.out.println("请输入删除书籍名称"); String name = sc.nextLine(); //调用对象bookcase的方法得到书架上书籍的数量,作为遍历结束的条件 int usednumber = bookcase.getUsednumber(); if(usednumber == 0){ System.out.println("图书馆书籍为空"); return; } for(int i=0; i<usednumber; i++){ //在书架中寻找与借阅书籍名称相同的书籍 if(name.equals(bookcase.getBooks(i).getName())){ //name.equals(str): 调用了字符串name的实例方法,来比较name是否与str同名 //bookcase.getBooks(i): 找到下标i对应的Book对象 //.getName(): 得到此Book对象的"书名"属性,这是一个字符串属性,即str System.out.println("删除成功"); for(;i<usednumber;i++){ //用下标i+1的书籍来覆盖下标为i的书籍,既实现了对书籍的删除,又补上了删除后的空缺部分 bookcase.setBooks(i,bookcase.getBooks(i+1)); } //因为i后面的书籍都被前移,最后的一本书籍会多余一本,要被清空 bookcase.setBooks(usednumber,null); //书籍数量-1 bookcase.setUsednumber(usednumber -= 1); } } } }
此方法传入一个类型为Bookcase的对象:bookcase。首先,用一个变量“name”来接收删除书名;然后,遍历bookcase的booklist(书单)[];再然后,用字符串变量name的equals()来一一比对,bookcase.booklist[]里,书籍的书名;接着,找到同名书籍后,用一个循环来将此书后方的书籍前移,前移的结果就是覆盖了此书起到删除作用,但booklist[]的最后一本书多出一本,即AXBCD -> ABCDD(BCD前移,覆盖了X,多余了D);最后,清除多余的D,再给“书籍数量”减1。
▮主函数main来启动项目
▪Main类
public class Main { //功能:根据选项的不同,返回子类管理员或普通人 public static User chose (){ //输入User的name属性 System.out.println("请输入你的名字"); Scanner sc = new Scanner(System.in); String name = sc.nextLine(); //选择身份 System.out.println("请输入你的身份:1.管理员 2.普通人员"); int i = sc.nextInt(); //返回子类:管理员 if(i == 1){ return new AdminiUser(name); //new了一个对象 //返回子类:普通人 }else if(i == 2){ return new NomalUser(name); } return null; } //mian()函数 public static void main(String[] args) { //创建一个书架对象 Bookcase Bookcase = new Bookcase(); //创建一个父类User来接收子类,实现向上转型 User user = chose(); int chose = 0; //循环执行程序 while(true){ //nume()是一个被子类所重写的方法,这里实现了动态绑定,执行的是子类的menu方法 //chose是一个整数,来接收你的选择 chose = user.menu(); //根据你的选择来执行对应的行为 user.operation[chose].work(Bookcase);//chose作为下标,与对应的选项想呼应 } } }
main()函数放在Main这个类中。首先,在main函数里定义了一个方法chose(),它是来让用户选择他的身份,并根据用户的选择来创建子类“管理员”或“普通人”对象,并把创建的子类作为chose()的返回值。
然后,main创建了一个Bookcase的对象:bookcase,他就是一个默认构造了三本书的书架。接着,main定义了一个User类型的引用类型:user,并执行上面的chose()来得到对象;最后,main通过while循环,一直打印循环菜单和执行选项对应的功能。
▪管理员的菜单
public class AdminiUser extends User{ //打印菜单,返回选项 public int menu(){ System.out.println('\n'); Scanner sc = new Scanner(System.in); System.out.println("管理员:"+super.gteName()+",欢迎进入图书管理系统"); System.out.println("0.退出系统"); System.out.println("1.添加书籍"); System.out.println("2.删减书籍"); System.out.println("3.展示书籍"); System.out.println("请选择你的操作:"); return sc.nextInt(); } //构造方法,非默认 public AdminiUser(String name){ super(name); operation = new Ioperation[]{ //菜单的选项与方法的下标所对应 new ExitOperation(), new AddOperation(), new DelOperation(), new DisOperation(), }; } }
菜单menu()方法会打印菜单,并且返回用户选择的选项值,由main中的chose变量接收。
▪普通人菜单
public class NomalUser extends User{ //打印菜单,返回选项 public int menu(){ System.out.println('\n'); //打印双'\n' Scanner sc = new Scanner(System.in); System.out.println("普通人员:"+super.gteName()+",欢迎进入图书管理系统"); System.out.println("0.退出系统"); System.out.println("1.借阅书籍"); System.out.println("2.归还书籍"); System.out.println("3.查找书籍"); System.out.println("请选择你的操作:"); return sc.nextInt(); } //构造方法,非默认 public NomalUser(String name){ super(name); super.operation = new Ioperation[]{ new ExitOperation(), //菜单的选项与方法的下标所对应 new BorrowOperation(), new ReturnOperation(), new FindOperation(), }; } }
菜单menu()方法会打印菜单,并且返回用户选择的选项值,由main中的chose变量接收。