当前位置:   article > 正文

面向对象思想实现图书管理系统_面向对象程序设计—图书管理系统设计项目开发

面向对象程序设计—图书管理系统设计项目开发

ps:

此工程分为四个包,分别是input(用于输入输出和给出提示信息),command(定义行为),user(普通用户和管理员用户)和main(主函数)

  1. package 图书管理系统;
  2. import 图书管理系统.book.BookStorage;
  3. import 图书管理系统.command.IExecutable;
  4. import 图书管理系统.input.Input;
  5. import 图书管理系统.input.QuitException;
  6. import 图书管理系统.user.User;
  7. import 图书管理系统.user.UserStorage;
  8. public class Main {
  9. // 由于输入过程,需要处理一些杂事
  10. // 1) 打印提示信息
  11. // 2) 读取用户输入
  12. // 3) 用户有没有按 Ctrl + D 退出
  13. // 直接封装一个对象去处理输入的问题
  14. public static void main(String[] args) {
  15. // 0. 实例化一个负责处理输入的对象
  16. Input input = new Input();
  17. // 1. 我们的书架对象,在应用运行过程中,只需要一份
  18. // 2. 改从文件中加载数据
  19. BookStorage bookStorage = BookStorage.loadFromFile();
  20. try {
  21. // 1. 用户登录
  22. // 我们需要一个用户管理的对象,由该对象完成用户登录的具体操作
  23. // 1.1. 要求用户输入
  24. // 1.2. 判断用户角色 ...
  25. UserStorage userStorage = new UserStorage();
  26. User user = userStorage.login(input);
  27. // 2. 进入一个循环中
  28. while (true) {
  29. // 2.1 打印用户角色对应的菜单,并且让用户选择
  30. // execute : 执行
  31. // executable : 具备可以执行的能力
  32. // IExecutable : 计划用接口去表示
  33. // command: 命令
  34. IExecutable command = input.menuAndSelect(user);
  35. // 2.2 根据用户的选择,执行对应的操作命令
  36. command.execute(bookStorage, user, input);
  37. }
  38. } catch (QuitException exc) {
  39. // 用户要退出,我们什么都不做
  40. }
  41. // 3. 用户退出,打印退出信息
  42. System.out.println("欢迎下次使用");
  43. }
  44. }

book包:

  1. package 图书管理系统.book;
  2. import 图书管理系统.user.User;
  3. public class Book implements Comparable {
  4. public String name;
  5. public String author;
  6. public String type;
  7. public int price;
  8. public String borrowedBy;
  9. @Override
  10. public int compareTo(Object o) {
  11. Book b=(Book) o;
  12. return name.compareTo(b.name);// 自然顺序是以书名为顺序
  13. // 书名也是 String 类型,也得遵守对象的比较规则
  14. }
  15. @Override
  16. public String toString() {
  17. //强行用StringBuilder
  18. String.format("《%s》by %s,[%s],%d",name,author,type,price);
  19. StringBuilder sb=new StringBuilder();
  20. if (borrowedBy==null){
  21. sb.append("可借用!");
  22. }else {
  23. sb.append("被");
  24. sb.append(borrowedBy);
  25. sb.append("借走了");
  26. }
  27. return sb.toString();
  28. }
  29. public boolean isBorrowed(){
  30. return borrowedBy==null;
  31. }
  32. public boolean equalsByName(String name){
  33. return this.name.equals(name);// 1. 也是为了封装,看起是一行一个方法
  34. // 2. name 是 String 类型,判断相等性,也需要使用 equals 判断
  35. }
  36. public void borrowed(User user){
  37. borrowedBy=user.getUsername();
  38. }
  39. @Override
  40. public boolean equals(Object o) {
  41. if (this == o) return true;
  42. if (o == null || getClass() != o.getClass()) return false;
  43. Book book = (Book) o;
  44. return name.equals(book.name);
  45. }
  46. public boolean isBorrowedBy(User user){
  47. if (borrowedBy==null){
  48. return false;
  49. }
  50. return borrowedBy.equals(user.getUsername());
  51. }
  52. public void returned(User user){//换书操作
  53. borrowedBy=null;
  54. }
  55. }
  1. package 图书管理系统.book;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.io.PrintWriter;
  6. import java.lang.reflect.Array;
  7. import java.util.Arrays;
  8. import java.util.Scanner;
  9. public class BookStorage {
  10. private Book[] array;
  11. private int size;
  12. public BookStorage(){
  13. array=new Book[20];
  14. size=0;
  15. }
  16. // 要让静态方法能使用,也得使用静态属性
  17. private static final File file=new File("C:\\java data\\.metadata\\book-storage.txt");
  18. //直接使用类名调用的一定是静态方法
  19. public static BookStorage loadFromFile(){
  20. BookStorage bookStorage=new BookStorage();
  21. if (!file.exists()){
  22. return bookStorage; //说明第一次运行,创建一个空对象
  23. }
  24. //开始加载
  25. try {
  26. Scanner sc=new Scanner(file,"UTF-8");
  27. while (sc.hasNextLine()){
  28. String line=sc.nextLine();
  29. // split 按照指定字符串,进行切割
  30. String[] group=line.split("@");
  31. if (group.length!=5){
  32. throw new RuntimeException("文件格式不对");
  33. }
  34. String name=group[0];
  35. String author=group[1];
  36. String type=group[2];
  37. String priceStr=group[3];
  38. int price;
  39. try{
  40. price=Integer.parseInt(priceStr);
  41. }catch (NumberFormatException exc){
  42. throw new RuntimeException("价格不是数字");
  43. }
  44. String borrowedByStr=group[4];
  45. String borrowedBy;
  46. if (borrowedByStr.equals("null")){
  47. borrowedBy=null;// 把字符串 "null" 转成 null
  48. }else {
  49. borrowedBy=borrowedByStr;
  50. }
  51. Book book=new Book();
  52. book.name=name;
  53. book.author = author;
  54. book.type = type;
  55. book.price = price;
  56. book.borrowedBy = borrowedBy;
  57. bookStorage.add(book);
  58. }
  59. sc.close();
  60. return bookStorage;
  61. }catch (IOException e){
  62. throw new RuntimeException(e);
  63. }
  64. }
  65. public void add(Book book) {
  66. //尾插
  67. ensureCapacity();
  68. array[size++]=book;
  69. saveToFile();
  70. }
  71. public Book[] toArray(){
  72. //return array; // 直接返回可不可以? 语法上成立。不可以
  73. // 理论有 两条:
  74. // 1. 返回 array,它的长度是 array.length ,但我们真正的书籍只有 size 本
  75. // 应该是返回一个 长度是 size 的数组,而不是长度是 array.length 的数组
  76. // 2. 一旦把 array 返回出去之后(数组对象逃逸了)
  77. // 别人会怎么操作数组对象,我们完全无法控制
  78. // 所以可能打破顺序表的一致性问题。比如 Arrays.fill(array, null)
  79. // size > 0 但是 array 中全部是 null
  80. return Arrays.copyOf(array,size);
  81. // 实际上还是有风险的,因为只是浅拷贝
  82. // 如果使用者有意还是无意改了 Book 对象属性
  83. // 我们还是会收到影响的
  84. // 最好的办法是做深拷贝,但这里不做那么复杂了
  85. }
  86. private void ensureCapacity() {
  87. if (size<array.length){
  88. return;
  89. }
  90. array= Arrays.copyOf(array,array.length*2);
  91. }
  92. // TODO: 我们这里隐含一个假设,就是我们的书架中,不允许出现同名的书籍
  93. // TODO: 否则删除的时候操作有歧义
  94. // TODO: 这个判断,我们在 AddBookCommand 中是没有操作
  95. public Book searchByName(String name){
  96. for (int i=0;i<size;i++){
  97. Book book=array[i];
  98. if (book.equals(name)){
  99. return book;
  100. }
  101. }
  102. return null;
  103. }
  104. // 原则上,如果顺序表要保持原有顺序的情况下,删除某个元素(可能在中间)
  105. // 则时间复杂度必然是 O(n) 的
  106. // 我们这里需要保持顺序么?array 中的原始顺序其实在当前需求下不是那么重要!
  107. public void remove(Book name){
  108. for (int i=0;i<size;i++){
  109. Book item=new Book();
  110. if (item.equals(name)){
  111. array[i]=array[size-1];
  112. array[size-1]=null;
  113. size--;
  114. return;
  115. }
  116. }
  117. saveToFile();
  118. }
  119. // 普通方法,保存是当前 BookStorage 对象的内容
  120. public void saveToFile() {
  121. try{
  122. PrintWriter writer=new PrintWriter(file,"UTF-8");
  123. for (int i=0;i<size;i++){
  124. Book book=array[i];
  125. StringBuilder sb=new StringBuilder();
  126. sb.append(book.name);
  127. sb.append("@");
  128. sb.append(book.author);
  129. sb.append("@");
  130. sb.append(book.type);
  131. sb.append("@");
  132. sb.append(book.price);
  133. sb.append("@");
  134. sb.append(book.borrowedBy);
  135. writer.println(sb.toString());
  136. }
  137. writer.flush();
  138. writer.close();
  139. }catch (IOException exc){
  140. throw new RuntimeException(exc);
  141. }
  142. }
  143. }

input包:

  1. package 图书管理系统.input;
  2. import 图书管理系统.command.IExecutable;
  3. import 图书管理系统.user.User;
  4. import java.util.Scanner;
  5. public class Input {
  6. Scanner scanner=new Scanner(System.in);
  7. public String prompt(String prompt){
  8. System.out.println(prompt+":");
  9. System.out.print(">");
  10. if (!scanner.hasNextLine()){//说明用户按下了ctrl+D,想要退出
  11. throw new QuitException();//通过异常向外部通知
  12. }
  13. return scanner.nextLine();
  14. }
  15. public IExecutable menuAndSelect(User user){
  16. IExecutable[] supportedCommands = user.getSupportedCommands();
  17. while (true){
  18. showMenu(supportedCommands);
  19. // 角色不同,理论上拥有的功能不同
  20. // 需要当前用户信息
  21. String selectStr=prompt("请选择您要进行的操作");
  22. try {
  23. int select=Integer.parseInt(selectStr);
  24. if (select>=1&select<=supportedCommands.length){
  25. return supportedCommands[select-1];
  26. }
  27. System.out.println("请输入正确的序号!");
  28. }catch (NumberFormatException exc){
  29. System.out.println("请输入正确的数字");
  30. }
  31. }
  32. }
  33. private void showMenu(IExecutable[] supportedCommands) {
  34. // 2. 遍历并打印每个命令的名称,显示操作菜单
  35. System.out.println("----------------");
  36. for (int i=0;i<supportedCommands.length;i++){
  37. IExecutable command=supportedCommands[i];
  38. System.out.printf(" %2d. %s\n", i + 1, command.getName());
  39. }
  40. System.out.println("----------------");
  41. }
  42. }
  1. package 图书管理系统.input;
  2. public class QuitException extends RuntimeException{
  3. }

user包:

  1. package 图书管理系统.user;
  2. import 图书管理系统.command.IExecutable;
  3. public abstract class User {
  4. private String username;
  5. public User(String name){
  6. this.username=name;
  7. }
  8. public String getUsername(){
  9. return username;
  10. }
  11. // 所以也完全不知道支持哪些命令
  12. // 应该定义成抽象方法,供子类去实现
  13. public abstract IExecutable[] getSupportedCommands();
  14. }
  1. package 图书管理系统.user;
  2. import 图书管理系统.command.*;
  3. public class AdminUser extends User {
  4. public AdminUser(String name) {
  5. super(name);
  6. }
  7. @Override
  8. public IExecutable[] getSupportedCommands() {
  9. return new IExecutable[] {
  10. // 管理员支持 添加书籍命令
  11. new AddBookCommand(),
  12. // 管理员支持 删除书籍命令
  13. new RemoveBookCommand(),
  14. // 管理员支持 根据书名列出书籍命令
  15. new ListBookOrderByNameCommand(),
  16. // 管理员支持 根据价格列出书籍命令
  17. new ListBookOrderByPriceCommand(),
  18. // 管理员支持 根据借阅情况列出书籍命令
  19. new ListBookOrderByBorrowedCommand()
  20. };
  21. }
  22. }
  1. package 图书管理系统.user;
  2. import 图书管理系统.command.*;
  3. public class CommandUser extends User {
  4. public CommandUser(String name) {
  5. super(name);
  6. }
  7. @Override
  8. public IExecutable[] getSupportedCommands() {
  9. return new IExecutable[] {
  10. new ListBookOrderByNameCommand(),
  11. new ListBookOrderByPriceCommand(),
  12. new ListBookOrderByBorrowedCommand(),
  13. new BorrowBookCommand(),
  14. new ReturnBookCommand()
  15. };
  16. }
  17. }
  1. package 图书管理系统.user;
  2. import 图书管理系统.input.Input;
  3. public class UserStorage {
  4. // 提前定义一些用户名,作为管理员
  5. private static final String[] ADMIN_USERNAMES={
  6. "文佳怡",
  7. "耿超扬"
  8. };
  9. private boolean isAdmin(String name){
  10. for (String admin:ADMIN_USERNAMES){
  11. if (admin.equals(name)){
  12. return true;
  13. }
  14. }
  15. return false;
  16. }
  17. public User login(Input input){
  18. // 1. 先让用户输入用户名
  19. //prompt:提示符
  20. String username=input.prompt("请输入用户名");
  21. // 2. 根据用户名,角色是管理员还是普通的用户
  22. // 3. 根据不同的角色,创建不同的用户
  23. // admin: 管理员
  24. if (isAdmin(username)){
  25. return new AdminUser(username);
  26. }else {
  27. return new CommandUser(username);
  28. }
  29. }
  30. }

comand:

  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import 图书管理系统.book.BookStorage;
  4. import 图书管理系统.input.Input;
  5. import 图书管理系统.user.User;
  6. import java.lang.reflect.Array;
  7. import java.util.Arrays;
  8. import java.util.Comparator;
  9. // 由于 AbsListBookCommand 是 抽象类,允许出现抽象方法
  10. public abstract class AbsListBookCommand implements IExecutable {
  11. protected abstract Comparator getComparator();
  12. @Override
  13. public void execute(BookStorage bookStorage, User user, Input input) {
  14. Comparator comparator=getComparator();
  15. Book[] books=bookStorage.toArray();
  16. if (comparator==null){
  17. Arrays.sort(books);
  18. }else {
  19. Arrays.sort(books,comparator);
  20. }
  21. for (Book book:books){
  22. System.out.println(book);
  23. }
  24. }
  25. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import 图书管理系统.book.BookStorage;
  4. import 图书管理系统.input.Input;
  5. import 图书管理系统.user.User;
  6. public class AddBookCommand implements IExecutable {
  7. @Override
  8. public String getName() {
  9. return "添加书籍";
  10. }
  11. @Override
  12. public void execute(BookStorage bookStorage, User user, Input input) {
  13. System.out.println("开始添加书籍,首先读取书籍信息:");
  14. String name = input.prompt("请输入书籍名称");
  15. String author = input.prompt("请输入书籍作者");
  16. String type = input.prompt("请输入书籍类型");
  17. int price;
  18. while (true) {
  19. try {
  20. String priceStr = input.prompt("请输入书籍价格(必须是数字)");
  21. price = Integer.parseInt(priceStr);
  22. break;
  23. } catch (NumberFormatException exc) {
  24. System.out.println("价格格式错误");
  25. }
  26. }
  27. // 刚加架的书肯定没被借阅
  28. Book book = new Book();
  29. book.name = name;
  30. book.author = author;
  31. book.type = type;
  32. book.price = price;
  33. book.borrowedBy = null;
  34. System.out.println("将书籍添加到 书架上");
  35. bookStorage.add(book);
  36. System.out.println(user.getUsername() + " 完成了 添加书籍的操作: " + name);
  37. }
  38. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import 图书管理系统.book.BookStorage;
  4. import 图书管理系统.input.Input;
  5. import 图书管理系统.user.User;
  6. public class BorrowBookCommand implements IExecutable {
  7. @Override
  8. public void execute(BookStorage bookStorage, User user, Input input) {
  9. // 通过书名,完成借阅
  10. System.out.println("开始借阅书籍,首先读取书籍信息:");
  11. String name = input.prompt("请输入书籍名称");
  12. Book book = bookStorage.searchByName(name);
  13. if (book == null) {
  14. // 没有找到
  15. System.out.println("没有这本书 " + name + ",无法借阅");
  16. return;
  17. }
  18. if (book.isBorrowed()) {
  19. System.out.println("书籍已经被 " + book.borrowedBy + " 借走,暂时不允许借阅");
  20. return;
  21. }
  22. // 由于 book 返回的引用,指向的书籍对象,和 BookStorage 中保存的 Book 对象是同一个对象
  23. // 通过 book 引用修改,也会让 BookStorage 中生效
  24. book.borrowed(user);
  25. bookStorage.saveToFile();
  26. System.out.println(user.getUsername() + " 完成了 借阅书籍的操作: " + name);
  27. }
  28. @Override
  29. public String getName() {
  30. return "借阅书籍";
  31. }
  32. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.BookStorage;
  3. import 图书管理系统.input.Input;
  4. import 图书管理系统.user.User;
  5. public interface IExecutable {
  6. void execute(BookStorage bookStorage, User user, Input input);
  7. String getName();
  8. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import java.util.Comparator;
  4. public class ListBookOrderByBorrowedCommand extends AbsListBookCommand {
  5. private final Comparator comparator = new Comparator() {
  6. @Override
  7. public int compare(Object o1, Object o2) {
  8. Book b1 = (Book) o1;
  9. Book b2 = (Book) o2;
  10. int br1 = b1.borrowedBy == null ? 0 : 1;
  11. int br2 = b2.borrowedBy == null ? 0 : 1;
  12. return br1 - br2; // 未借走的书籍比较“小”
  13. }
  14. };
  15. @Override
  16. public String getName() {
  17. return "根据借阅情况排序,列出书籍";
  18. }
  19. @Override
  20. protected Comparator getComparator() {
  21. return comparator;
  22. }
  23. }
  1. package 图书管理系统.command;
  2. import java.util.Comparator;
  3. public class ListBookOrderByNameCommand extends AbsListBookCommand {
  4. @Override
  5. public String getName() {
  6. return "根据书名排序,列出书籍";
  7. }
  8. @Override
  9. protected Comparator getComparator() {
  10. return null;
  11. }
  12. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import java.util.Comparator;
  4. public class ListBookOrderByPriceCommand extends AbsListBookCommand {
  5. private static class PriceComparator implements Comparator {
  6. @Override
  7. public int compare(Object o1, Object o2) {
  8. Book b1 = (Book) o1;
  9. Book b2 = (Book) o2;
  10. return b1.price - b2.price;
  11. }
  12. }
  13. private final Comparator comparator = new PriceComparator();
  14. @Override
  15. protected Comparator getComparator() {
  16. return comparator;
  17. }
  18. @Override
  19. public String getName() {
  20. return "根据价格排序,列出书籍";
  21. }
  22. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import 图书管理系统.book.BookStorage;
  4. import 图书管理系统.input.Input;
  5. import 图书管理系统.user.User;
  6. public class RemoveBookCommand implements IExecutable {
  7. @Override
  8. public String getName() {
  9. return "删除书籍";
  10. }
  11. @Override
  12. public void execute(BookStorage bookStorage, User user, Input input) {
  13. // 只支持按照名称删除
  14. System.out.println("开始删除书籍,首先读取要删除的书籍信息:");
  15. String name = input.prompt("请输入书籍名称");
  16. // 增加一些业务逻辑:如果书籍已经借走,则不允许删除
  17. Book book = bookStorage.searchByName(name);
  18. if (book == null) {
  19. // 没有找到
  20. System.out.println("没有这本书 " + name + ",无法删除");
  21. return;
  22. }
  23. // 看起来 book.isBorrowed() 和 book.borrowedBy != null 是逻辑等价的
  24. // 应该用 book.isBorrowed() 比 后边更好,为什么?
  25. // 从职责划分的角度(封装)
  26. // 提到了方法的重用挺好,但这里的原因不是这个
  27. if (book.isBorrowed()) {
  28. System.out.println("书籍已经被 " + book.borrowedBy + " 借走,暂时不允许删除");
  29. return;
  30. }
  31. bookStorage.remove(book);
  32. System.out.println(user.getUsername() + " 完成了 删除书籍的操作: " + name);
  33. }
  34. }
  1. package 图书管理系统.command;
  2. import 图书管理系统.book.Book;
  3. import 图书管理系统.book.BookStorage;
  4. import 图书管理系统.input.Input;
  5. import 图书管理系统.user.User;
  6. public class ReturnBookCommand implements IExecutable {
  7. @Override
  8. public void execute(BookStorage bookStorage, User user, Input input) {
  9. // 通过书名,完成归还
  10. System.out.println("开始借阅书籍,首先读取书籍信息:");
  11. String name = input.prompt("请输入书籍名称");
  12. Book book = bookStorage.searchByName(name);
  13. if (book == null) {
  14. // 没有找到
  15. System.out.println("没有这本书 " + name + ",无法归还");
  16. return;
  17. }
  18. if (!book.isBorrowed()) {
  19. System.out.println("书籍没有被借走,不需要归还");
  20. return;
  21. }
  22. if (!book.isBorrowedBy(user)) {
  23. System.out.println("书籍不是被 " + user.getUsername() + " 借走的,无法归还");
  24. return;
  25. }
  26. book.returned(user);
  27. bookStorage.saveToFile();
  28. System.out.println(user.getUsername() + " 完成了 归还书籍的操作: " + name);
  29. }
  30. @Override
  31. public String getName() {
  32. return "归还书籍";
  33. }
  34. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/512301
推荐阅读
  

闽ICP备14008679号