用 Java 模拟一个图书馆。包含创建图书、创建读者、借书、还书、列出全部图书、列出全部读者、列出已借出的图书、列出过期未还的图书等功能。

每一个读者最多仅仅能借 3 本书,每一个书最多仅仅能借 3 个星期,超过就算过期。

这个样例跟 http://blog.csdn.net/yidinghe/article/details/3940437 相比,添加了 Java 8 特有的语法,包含:Lambda 表达式,java.time 日期 API,streaming API 等。功能也比前者略微完好了些。体积有所减小。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Collectors; /**
* 图书馆样例 Java 8 版本号
* created at 2014/11/4
*
* @author Yiding
*/
public class LibraryManager { public static final Scanner SCANNER = new Scanner(System.in); public static final String NUMBERS_ONLY = "^\\d+$"; // 表示仅仅同意输入数字 public static final String ANY_CONTENT = "^\\S+$"; // 表示能够输入不论什么内容 public static void main(String[] args) {
new LibraryManager().start();
} //////////////////////////////////////////////////////////////// private Library library = new Library(); private ArrayList<Command> commands = new ArrayList<>(); private String mainMenu; /**
* 构造方法
*/
public LibraryManager() {
initCommands();
initStudents();
initBooks();
} private void initBooks() {
this.library.addBook("论程序猿的自我修养", "带鱼", BookType.科学类.toString());
this.library.addBook("印度四大名著全集", "阿达木", BookType.文学类.toString());
this.library.addBook("睡眠的优点", "程序猿阿迪", BookType.科学类.toString());
this.library.addBook("架构师2014年10月刊", "漂亮女人网", BookType.杂志.toString());
} private void initStudents() {
this.library.students.add(new Student("张三"));
this.library.students.add(new Student("李四"));
this.library.students.add(new Student("王五"));
} /**
* 初始化命令和主菜单
*/
private void initCommands() {
addCommand(new ListCommand<>("全部图书:", () -> library.books), "查询全部图书");
addCommand(new ListCommand<>("全部学生:", () -> library.students), "查询全部学生");
addCommand(new AddBookCommand(), "加入图书");
addCommand(new DeleteBookCommand(), "删除图书");
addCommand(new BorrowBookCommand(), "借阅图书");
addCommand(new ReturnBookCommand(), "归还图书");
addCommand(new ListCommand<>("全部借阅过期的图书:", library::expiredBooks), "查询借阅过期的图书");
addCommand(new ExitCommand(), "退出"); this.mainMenu = toMenu("请输入命令", this.commands);
} private void addCommand(Command command, String title) {
command.title = title;
this.commands.add(command);
} /**
* 開始运行交互
*/
private void start() {
CommandResult result; // 在 while 条件中推断命令的运行结果是否表示要退出程序
// 仅仅有 ExitCommand 的运行结果是 CommandResult.EXIT
do { try {
String command = prompt(mainMenu, NUMBERS_ONLY); // 选择命令
result = executeCommand(command); // 运行命令
} catch (CommandCancelException e) {
result = CommandResult.FAIL;
} System.out.println(result.prompt + "\n");
} while (result != CommandResult.EXIT);
} /**
* 打印一条提示消息并返回用户的输入
*
* @param prompt 提示消息
* @param pattern 指定格式,假设用户的输入不符合格式则会重复提示又一次输入。为空则不检查用户输入
*
* @return 用户的输入
*/
private String prompt(String prompt, String pattern) {
String userInput; // 在 while 条件中推断用户输入的内容是否符合 pattern 指定的格式
// 假设 pattern 为 null 则不做推断
do {
System.out.print(prompt);
userInput = SCANNER.nextLine(); // 用户直接回车时,表示取消命令运行
if (userInput.equals("")) {
throw new CommandCancelException();
} } while (pattern != null && !userInput.matches(pattern)); return userInput;
} // 打印一组选项并返回用户选择的选项内容
private String prompt(String prompt, List<?> options) {
int index = promptIndex(prompt, options);
return options.get(index - 1).toString();
} // 打印一组选项并返回用户选择的位置
private int promptIndex(String prompt, List<? > options) {
String menu = toMenu(prompt, options);
int index; do {
index = Integer.parseInt(prompt(menu, NUMBERS_ONLY));
} while (index == 0 || index > options.size()); return index;
} /**
* 生成菜单内容
*
* @param prompt 提示,在列出全部选项后打印出来
* @param options 选项
*
* @return 主菜单内容
*/
private <T> String toMenu(String prompt, List<T> options) {
final ArrayList<String> lines = new ArrayList<>();
final AtomicInteger counter = new AtomicInteger(); options.forEach((t) -> {
int index = counter.incrementAndGet();
String line = index + ": " + t.toString();
lines.add(line);
}); return String.join("\n", lines) + "\n" + prompt + "(1-" + lines.size() + "):";
} /**
* 运行用户命令
*
* @param command 用户命令序号
*
* @return 运行结果
*/
private CommandResult executeCommand(String command) {
int index = Integer.parseInt(command); if (index > 0 && index <= commands.size()) {
return commands.get(index - 1).execute();
} else {
return CommandResult.OK;
}
} //////////////////////////////////////////////////////////////// static enum CommandResult {
OK("命令已完毕。"), FAIL("命令已取消。"), EXIT(""); public String prompt; // 在每一个命令结束时打印出来 CommandResult(String prompt) {
this.prompt = prompt;
} } static enum BookType {文学类, 科学类, 杂志} // 表示用户取消命令的异常
static class CommandCancelException extends RuntimeException { } static class Book { public static final int EXPIRE_BORROW_DAYS = 21; public String name; public String author; public String type; public String borrowedBy; public String borrowDate; Book(String name, String author, String type) {
this.name = name;
this.author = author;
this.type = type;
} public boolean isBorrowed() {
return this.borrowedBy != null;
} @Override
public String toString() {
return name + ",作者:" + author + "。" + type +
(isBorrowed() ? " -- 已被'" + borrowedBy + "'于" + borrowDate + "借出" : "");
} public boolean isExpired() {
if (!isBorrowed()) {
return false;
} // 从当前时间反推过期的借阅时间。假设实际借阅时间在过期的借阅时间之前,则表示过期了
LocalDate maxBorrowDate = LocalDate.now().minus(EXPIRE_BORROW_DAYS, ChronoUnit.DAYS);
String maxBorrowDateStr = DateTimeFormatter.ofPattern("yyyyMMdd").format(maxBorrowDate);
return this.borrowDate.compareTo(maxBorrowDateStr) < 0;
}
} static class Student { public static final int MAX_BORROW = 3; public String name; Student(String name) {
this.name = name;
} @Override
public String toString() {
return name;
}
} //////////////////////////////////////////////////////////////// class Library { private List<Book> books = new ArrayList<>(); private List<Student> students = new ArrayList<>(); /**
* 加入书籍
*
* @param bookName 书名
* @param author 作者
* @param type 类型
*
* @return 运行结果
*/
public CommandResult addBook(String bookName, String author, String type) {
if (books.stream().anyMatch((b) -> b.name.equals(bookName))) {
System.out.println("加入失败:书名已存在");
return CommandResult.FAIL;
} this.books.add(new Book(bookName, author, type));
return CommandResult.OK;
} public List<Book> availableBooks() {
return this.books.stream().filter((b) -> !b.isBorrowed()).collect(Collectors.toList());
} public List<Book> borrowedBooks() {
return this.books.stream().filter(Book::isBorrowed).collect(Collectors.toList());
} public List<Book> expiredBooks() {
return this.books.stream().filter(Book::isExpired).collect(Collectors.toList());
} /**
* 删除书籍
*
* @param index 序号
*
* @return 运行结果
*/
public CommandResult deleteBook(int index) {
this.books.remove(index);
return CommandResult.OK;
} public int countBorrowedBooks(String student) {
return (int) this.books.stream().filter((b) -> student.equals(b.borrowedBy)).count();
}
} //////////////////////////////////////////////////////////////// /**
* 表示命令的抽象类
*/
static abstract class Command { public String title; // 命令标题,将显示在主菜单中 abstract CommandResult execute(); @Override
public String toString() {
return title;
}
} // 列出满足要求的对象
class ListCommand<T> extends Command { private Supplier<List<T>> supplier; // 查询满足要求的对象的方法 private String title; // 输出标题 ListCommand(String title, Supplier<List<T>> supplier) {
this.title = title;
this.supplier = supplier;
} @Override
CommandResult execute() {
System.out.println("\n" + title);
supplier.get().forEach(System.out::println);
return CommandResult.OK;
}
} // 加入图书
class AddBookCommand extends Command { @Override
CommandResult execute() {
return library.addBook(
prompt("请输入书名:", ANY_CONTENT),
prompt("请输入作者:", ANY_CONTENT),
prompt("请选择书籍类型:", Arrays.asList(BookType.values()))
);
}
} // 删除图书
class DeleteBookCommand extends Command { @Override
CommandResult execute() {
if (library.books.isEmpty()) {
System.out.println("没有可删除的书籍。");
return CommandResult.FAIL;
} int index = promptIndex("请选择书籍序号", library.books);
return library.deleteBook(index - 1);
}
} // 借阅图书
class BorrowBookCommand extends Command { @Override
CommandResult execute() {
List<Book> availableBooks = library.availableBooks();
if (availableBooks.isEmpty()) {
System.out.println("没有可借阅的图书。");
return CommandResult.FAIL;
} int index = promptIndex("请选择要借阅的图书", availableBooks);
Book book = availableBooks.get(index - 1); String student = prompt("请选择借阅者:", library.students);
if (library.countBorrowedBooks(student) >= Student.MAX_BORROW) {
System.out.println("该同学不能借阅很多其它图书了。");
return CommandResult.FAIL;
} String bDate = prompt("请输入借阅日期(YYYYMMDD):", "^\\d{8}$"); book.borrowedBy = student;
book.borrowDate = bDate;
return CommandResult.OK;
}
} // 归还图书
class ReturnBookCommand extends Command { @Override
CommandResult execute() {
List<Book> borrowedBooks = library.borrowedBooks();
if (borrowedBooks.isEmpty()) {
System.out.println("没有图书须要归还。 ");
return CommandResult.FAIL;
} int index = promptIndex("请选择已借阅的图书", borrowedBooks);
Book book = borrowedBooks.get(index - 1);
book.borrowedBy = null;
book.borrowDate = null;
System.out.println("图书已归还。");
return CommandResult.OK;
}
} // 退出程序
class ExitCommand extends Command { @Override
CommandResult execute() {
return CommandResult.EXIT;
}
}
}

Java 小样例:图书馆课程设计(Java 8 版)的更多相关文章

  1. Java课程设计(2019版)

    参考资料 Java课程设计参考资料(2018-12-26更新) Java课程设计常见问题(程序部署.数据库.JSP) 项目开发参考-阿里巴巴Java开发手册(正式版) 更多参考资料请查看QQ群文件中的 ...

  2. 基于mysql和Java Swing的简单课程设计

    摘要 现代化的酒店组织庞大.服务项目多.信息量大.要想提高效率.降低成本.提高服务质量和管理水平,进而促进经济效益,必须利用电脑网络技术处理宾馆酒店经营数据,实现酒店现代化的信息管理.本次课程设计运用 ...

  3. Java单例设计模式(实现Java的一个类只有一个对象)

    单例设计模式的定义:单例设计模式是一种软件设计模式,在它的核心包含一个称为单例类的核心类. 核心便是希望一个类只有一个对象.  如何实现类在内存中只有一个对象呢? 第一步:构造私有:第二步:本身提供一 ...

  4. Java课程设计——象棋(201521123042 姚佳希)

    1. 团队课程设计博客链接 Java课程设计(团队版) 2 个人负责模块或任务说明 ChessBoard类创建棋盘及界面. ChessPoint类创建棋盘格点及界面. ChessPiece类创建棋子及 ...

  5. Java课程设计---索引

    一.基础配置 ============================================================== 1.Java课程设计---Eclipse基本环境配置 2.J ...

  6. JAVA课程设计-计算器(201521123028 李家俊)

    1.团队课程设计博客链接 http://www.cnblogs.com/DevilRay/p/7064482.html 2.个人负责模板或任务说明 主要负责计算器图形界面 包括操作按钮,菜单项以及输出 ...

  7. Java课程设计——博客作业教学数据分析系统(201521123082 黄华林)

    Java课程设计--博客作业教学数据分析系统(201521123082 黄华林) 一.团队课程设计博客链接 博客作业教学数据分析系统(From:网络五条狗) 二.个人负责模块或任务说明 1.网络爬虫 ...

  8. Java课程设计——扫雷(winmine)

    因为是我的课程设计,要是有冲突就不好了,转载注明出处!!! 程序很简单,毕竟我是搞acm的,我就只介绍一下闪光点. 中心空白搜索的时候,我用的DFS: 有一点是要注意的,就是JFrame不支持重画,还 ...

  9. java(课程设计之记事本界面部分代码公布)

    代码:涉及记事本的一些界面......!! /* *java课程设计之记事本(coder @Gxjun) * 编写一个记事本程序 * 要求: * 用图形用户界面实现. * 能实现编辑.保存.另存为.查 ...

随机推荐

  1. C#用链式方法

    C#用链式方法表达循环嵌套   情节故事得有情节,不喜欢情节的朋友可看第1版代码,然后直接跳至“三.想要链式写法” 一.起缘 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中 ...

  2. 基于visual Studio2013解决面试题之0306打印第一次只出现一次的字符

     题目

  3. PLSQL数据导入

    导入数据 (1)      首先以管理员身份登录plsql; (2)      新建命令窗口 (3)      创建用户,设置帐号,密码 创建语句:create user usernameidenti ...

  4. mysql高可用架构方案之二(keepalived+lvs+读写分离+负载均衡)

    mysql主从复制与lvs+keepalived实现负载高可用 文件夹 1.前言    4 2.原理    4 2.1.概要介绍    4 2.2.工作原理    4 2.3.实际作用    4 3方 ...

  5. RGB HSV HLS三种色彩模式转换(C语言实现)

    Android项目上处理图像的代码(注释全部去掉) ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ...

  6. POJ1273_Drainage Ditches(网络流)

    Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 54887   Accepted: 2091 ...

  7. BAPI总的数据库提交和回滚

    BAPI事物中的数据提交和回滚必须通过调用SAP标准业务对象BAPI SERVICE(对象类型SAP0001)的BAPI方法bapiservic.transactioncommit和bapiservi ...

  8. javascript (十三) 函数

    JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function: function functionname() { 这里是要执行的代码 } 当调用该函数时,会执行 ...

  9. [读书笔记]黑客与画家[Hackers.and.Painters]

    (书生注:这本书写的不错.针对程序员,可以带来不同角度的想法,有助于反思自己的程序员工作.我甚至从中发现了自己爱用铅笔的原因...  尤其是其中关于黑客的定义,包括黑客认为的乐趣和目的,让人更深层次思 ...

  10. Linux 双网卡绑定技术

    bond技术是在linux2.4以后加入内核. 一般步骤是1.把bonding模块加入内核, 2 编辑要绑定的网卡设置,去除地址设定 3 添加bond设备,设置地址等配置 4  重启网络 5 在交换机 ...