用 Java 模拟一个图书馆。包括创建图书、创建读者、借书、还书、列出所有图书、 列出所有读者、列出已借出的图书、列出过期未还的图书等功能。每个读者最多只能借 3 本书,每个书最多只能借 3 个星期,超过就算过期。
下面是一个命令行下的实现。这个例子的主要目的是向初学者展示内部类的好处。 Command 及其子类都是 LibrarySimulator 的内部类。它们可以无阻碍的访问 LibrarySimulator 的成员。使用内部类,而不是大量的 if-else,让程序更容易扩展。
01.import java.io.BufferedReader; 02.import java.io.IOException; 03.import java.io.InputStreamReader; 04.import java.text.SimpleDateFormat; 05.import java.util.*; 06. 07./** 08. * 一个图书馆的课程设计。主要功能: 09. * 1. 创建图书 10. * 2. 创建读者 11. * 3. 借书 12. * 4. 还书 13. * 5. 列出所有书 14. * 6. 列出已借书 15. * 7. 列出超过日期未还的书 16. */ 17.public class LibrarySimulator { 18. 19. // 主菜单 20. private static final String MAIN_MENU = "1. 列出所有的书\n" + 21. "2. 列出已借出的书\n" + 22. "3. 列出过期未还的书\n" + 23. "4. 列出所有读者\n" + 24. "5. 创建图书\n" + 25. "6. 创建读者\n" + 26. "7. 借书\n" + 27. "8. 还书\n" + 28. "9. 退出\n" + 29. "请输入序号:"; 30. 31. // 选择图书类型的菜单。在借书和添加图书的时候都会用到 32. private static final String TYPE_MENU; 33. 34. // 表示一个数字的正则表达式 35. private static final String DIGIT_CHOICE_PATTERN = "^\\d$"; 36. 37. // 表示非空字符串 38. private static final String NOT_EMPTY_PATTERN = "\\S.*"; 39. 40. // 日期格式 41. static final String DATE_PATTERN = "yyyy/MM/dd"; 42. 43. // 验证用户输入日期的正则表达式 44. static final String DATE_FORMAT_PATTERN = "^\\d{4}/\\d{2}/\\d{2}$"; 45. 46. // 预定义的图书类型 47. static HashMap<String, String> TYPES = new LinkedHashMap<String, String>(); 48. 49. static { 50. TYPES.put("1", "科学类"); 51. TYPES.put("2", "文学类"); // 新的类别可以继续在后面添加 52. TYPE_MENU = createTypeMenu(); 53. } 54. 55. // 生成选择类别的菜单 56. private static String createTypeMenu() { 57. String str = ""; 58. for (String index : TYPES.keySet()) { 59. str += index + ". " + TYPES.get(index) + "\n"; 60. } 61. return str + "请选择书的类型:"; 62. } 63. 64. 65. private HashMap<Integer, Command> commands = new HashMap<Integer, Command>(); 66. 67. private ArrayList<Book> books = new ArrayList<Book>(); 68. 69. private ArrayList<Reader> readers = new ArrayList<Reader>(); 70. 71. // 程序入口。这里创建一个 LibrarySimulator 用于模拟界面。 72. public static void main(String[] args) { 73. new LibrarySimulator().start(); 74. } 75. 76. /** 77. * 构造函数 78. */ 79. public LibrarySimulator() { 80. commands.put(1, new Command1()); 81. commands.put(2, new Command2()); 82. commands.put(3, new Command3()); 83. commands.put(4, new Command4()); 84. commands.put(5, new Command5()); 85. commands.put(6, new Command6()); 86. commands.put(7, new Command7()); 87. commands.put(8, new Command8()); 88. } 89. 90. /** 91. * 这里接受用户输入,执行操作,然后再等待用户输入,这样不停的循环。 92. */ 93. private void start() { 94. String index = prompt(MAIN_MENU, DIGIT_CHOICE_PATTERN); 95. 96. while (!index.equals("9")) { 97. executeCommand(index); 98. index = prompt(MAIN_MENU, DIGIT_CHOICE_PATTERN); 99. } 100. } 101. 102. // 根据序号执行命令 103. private void executeCommand(String index) { 104. Command command = commands.get(Integer.parseInt(index)); 105. if (command != null) { 106. String result = command.execute(); 107. System.out.println(result + "\n"); 108. } 109. } 110. 111. // 打印一条提示信息,然后读取并返回用户输入 112. private String prompt(String message, String pattern) { 113. System.out.print(message); 114. if (pattern == null) { 115. return readInput(); 116. } else { 117. String result = ""; 118. while (!result.matches(pattern)) { 119. result = readInput(); 120. } 121. return result; 122. } 123. } 124. 125. // 读取用户输入 126. private String readInput() { 127. try { 128. BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 129. return reader.readLine(); 130. } catch (IOException e) { 131. e.printStackTrace(); 132. return ""; 133. } 134. } 135. 136. // 根据名字查找读者。找不到则返回 null。 137. private Reader getReaderByName(String readerName) { 138. for (Reader reader : readers) { 139. if (reader.getName().equals(readerName)) { 140. return reader; 141. } 142. } 143. return null; 144. } 145. 146. // 根据名字查找图书。找不到则返回 null。 147. private Book getBookByName(String bookName) { 148. for (Book book : books) { 149. if (book.getName().equals(bookName)) { 150. return book; 151. } 152. } 153. return null; 154. } 155. 156. /*===================================================================*/ 157. 158. /** 159. * 代表命令的抽象类 160. */ 161. private abstract class Command { 162. 163. protected abstract String execute(); 164. } 165. 166. /////////////////////////////////////////////////// 列出所有图书 167. private class Command1 extends Command { 168. 169. protected String execute() { 170. for (Book book : getBooks()) { 171. System.out.println(book); // 这里会自动调用 book.toString() 172. } 173. return "命令完成。"; 174. } 175. 176. private ArrayList<Book> getBooks() { 177. ArrayList<Book> result = new ArrayList<Book>(); 178. 179. for (Book book : books) { 180. if (isValid(book)) { 181. result.add(book); 182. } 183. } 184. return result; 185. } 186. 187. // 考虑到第 1、2、3 条命令大体相同,这里提供了一个给子类覆写的方法 188. protected boolean isValid(Book book) { 189. return true; 190. } 191. } 192. 193. ///////////////////////////////////////////////////// 列出已借出的书。 194. // 注意它的父类不是 Command,而是 Command1。这样节省了很多重复代码 195. private class Command2 extends Command1 { 196. 197. @Override 198. protected boolean isValid(Book book) { 199. return book.isBorrowed(); 200. } 201. } 202. 203. //////////////////////////////////////////////////////// 列出过期未还的书 204. private class Command3 extends Command1 { 205. 206. @Override 207. protected boolean isValid(Book book) { 208. // 判断一本书接触过期与否的方法最好在 Book 类中去实现。 209. return book.isExpired(); 210. } 211. } 212. 213. /////////////////////////////////////////////// 创建图书 214. private class Command5 extends Command { 215. 216. protected String execute() { 217. String type = getType(); 218. String name = getName(); 219. if (getBookByName(name) == null) { 220. books.add(new Book(type, name)); 221. return "图书添加成功。"; 222. } else { 223. return "图书添加失败:名称已存在。"; 224. } 225. } 226. 227. // 获得用户输入的书名 228. private String getName() { 229. return prompt("请输入书名:", NOT_EMPTY_PATTERN); 230. } 231. 232. // 获得用户选择的图书类型 233. private String getType() { 234. return prompt(TYPE_MENU, DIGIT_CHOICE_PATTERN); 235. } 236. } 237. 238. /////////////////////////////////////////////////////// 列出所有读者 239. private class Command4 extends Command { 240. 241. protected String execute() { 242. for (Reader reader : readers) { 243. System.out.println(reader); 244. } 245. return "命令完成。"; 246. } 247. } 248. 249. /////////////////////////////////////////////////////// 创建读者 250. private class Command6 extends Command { 251. 252. protected String execute() { 253. String name = getName(); 254. if (getReaderByName(name) == null) { 255. readers.add(new Reader(name)); 256. return "读者创建成功。"; 257. } else { 258. return "读者创建失败:名字已经存在。"; 259. } 260. } 261. 262. public String getName() { 263. return prompt("请输入读者名字:", NOT_EMPTY_PATTERN); 264. } 265. } 266. 267. /////////////////////////////////////////////////////// 借书 268. private class Command7 extends Command { 269. 270. protected String execute() { 271. Reader reader = getReader(); 272. if (reader == null) { 273. System.out.println("命令取消。"); 274. return ""; 275. } 276. 277. Book book = getBook(); 278. if (book == null) { 279. System.out.println("命令取消。"); 280. return ""; 281. } 282. 283. String borrowDate = getBorrowDate(); 284. 285. book.borrowBy(reader.getName(), borrowDate); 286. reader.addBorrowCount(); 287. 288. return "成功借出。"; 289. } 290. 291. private String getBorrowDate() { 292. String now = new SimpleDateFormat(LibrarySimulator.DATE_PATTERN).format(new Date()); 293. String date = null; 294. while (date == null || !date.matches(DATE_FORMAT_PATTERN)) { 295. date = prompt("请输入结束日期(如" + now + ")", NOT_EMPTY_PATTERN); 296. } 297. return date; 298. } 299. 300. private Book getBook() { 301. Book book = null; 302. while (book == null || book.isBorrowed()) { 303. String bookName = prompt("请输入图书名字:", null); 304. if (bookName.equals("")) { 305. return null; 306. } 307. 308. book = getBookByName(bookName); 309. if (book == null) { 310. System.out.println("图书不存在。"); 311. } else if (book.isBorrowed()) { 312. System.out.println("图书已经被借出。"); 313. } 314. } 315. return book; 316. } 317. 318. private Reader getReader() { 319. Reader reader = null; 320. while (reader == null || !reader.canBorrow()) { 321. String readerName = prompt("请输入读者名字:", null); 322. if (readerName.equals("")) { 323. return null; 324. } 325. 326. reader = getReaderByName(readerName); 327. if (reader == null) { 328. System.out.println("读者不存在。"); 329. } else if (!reader.canBorrow()) { 330. System.out.println("该读者已经借了" + Reader.MAX_BORROW + " 本书,不能继续借了。"); 331. } 332. } 333. return reader; 334. } 335. } 336. 337. ///////////////////////////////////////////// 还书 338. private class Command8 extends Command { 339. 340. protected String execute() { 341. Reader reader = getReader(); 342. if (reader == null) { 343. System.out.println("命令取消。"); 344. return ""; 345. } 346. 347. Book book = getBook(reader); 348. if (book == null) { 349. System.out.println("命令取消。"); 350. return ""; 351. } 352. 353. reader.reduceBorrowCount(); 354. book.returned(); 355. return "操作成功。"; 356. } 357. 358. private Book getBook(Reader reader) { 359. Book book = null; 360. while (book == null || !reader.getName().equals(book.getBorrower())) { 361. String bookName = prompt("请输入图书名字:", null); 362. if (bookName.equals("")) { 363. return null; 364. } 365. 366. book = getBookByName(bookName); 367. if (book == null) { 368. System.out.println("图书不存在。"); 369. } else if (!reader.getName().equals(book.getBorrower())) { 370. System.out.println("该读者没有借出这本书。"); 371. } 372. } 373. return book; 374. } 375. 376. private Reader getReader() { 377. Reader reader = null; 378. while (reader == null) { 379. String readerName = prompt("请输入读者名字:", null); 380. if (readerName.equals("")) { 381. return null; 382. } 383. 384. reader = getReaderByName(readerName); 385. if (reader == null) { 386. System.out.println("读者不存在。"); 387. } 388. } 389. return reader; 390. } 391. } 392.} 393. 394.// 图书 395.class Book { 396. 397. public static final int EXPIRE_DAYS = 21; // 可借出天数,超过就算过期 398. 399. private String type; 400. 401. private String name; 402. 403. private String borrowedBy = null; 404. 405. private String borrowDate = null; 406. 407. Book(String type, String name) { 408. this.type = type; 409. this.name = name; 410. } 411. 412. @Override 413. public String toString() { 414. String str = String.format("类别:%s 书名:%s", LibrarySimulator.TYPES.get(type), name); 415. if (isBorrowed()) { 416. str += " 借出人:" + borrowedBy + " 借出时间:" + borrowDate; 417. } 418. return str; 419. } 420. 421. public boolean isBorrowed() { 422. return borrowedBy != null; 423. } 424. 425. public String getName() { 426. return name; 427. } 428. 429. public String getBorrowDate() { 430. return borrowDate; 431. } 432. 433. /** 434. * 图书借出 435. * 436. * @param name 读者名字 437. * @param date 借出日期。格式:参见 {@link LibrarySimulator#DATE_PATTERN} 438. */ 439. public void borrowBy(String name, String date) { 440. this.borrowedBy = name; 441. this.borrowDate = date; 442. } 443. 444. public boolean isExpired() { 445. if (borrowDate == null) { 446. return false; // 没有借出的书不出现在过期未还列表当中,所以这里返回 false。 447. } 448. 449. // 从当前时间往前推 3 个星期,如果还在借书日期之后,说明借书已经超过 3 个星期了 450. String threeWksAgo = get3WeeksAgo(); 451. return threeWksAgo.compareTo(borrowDate) > 0; 452. } 453. 454. // 获得 3 个星期前的日期 455. private String get3WeeksAgo() { 456. SimpleDateFormat f = new SimpleDateFormat(LibrarySimulator.DATE_PATTERN); 457. Calendar c = Calendar.getInstance(); 458. c.add(Calendar.DAY_OF_MONTH, -EXPIRE_DAYS); 459. return f.format(c.getTime()); 460. } 461. 462. public void returned() { 463. this.borrowBy(null, null); 464. } 465. 466. public String getBorrower() { 467. return borrowedBy; 468. } 469.} 470. 471.// 读者 472.class Reader { 473. 474. // 每位读者最多可同时借出 3 本书 475. public static final int MAX_BORROW = 3; 476. 477. private String name; 478. 479. private int borowCount = 0; 480. 481. public int getBorowCount() { 482. return borowCount; 483. } 484. 485. Reader(String name) { 486. this.name = name; 487. } 488. 489. public String getName() { 490. return name; 491. } 492. 493. public void addBorrowCount() { 494. borowCount++; 495. } 496. 497. public void reduceBorrowCount() { 498. borowCount--; 499. } 500. 501. public boolean canBorrow() { 502. return borowCount < MAX_BORROW; 503. } 504. 505. @Override 506. public String toString() { 507. return name; 508. } 509.}
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索图书
, string
, private
, execute方法未用到
, return
, 借书还书
, null
reader
,以便于您获取更多的相关知识。
时间: 2024-09-21 11:30:51