Welcome 微信登录

首页 / 软件开发 / JAVA / Java小例子:图书馆课程设计

Java小例子:图书馆课程设计2011-04-05用 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. 列出所有的书
" +21."2. 列出已借出的书
" +22."3. 列出过期未还的书
" +23."4. 列出所有读者
" +24."5. 创建图书
" +25."6. 创建读者
" +26."7. 借书
" +27."8. 还书
" +28."9. 退出
" +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) + "
";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 + "
");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.@Override198.protected boolean isValid(Book book) {199.return book.isBorrowed();200.}201.}202.203.//////////////////////////////////////////////////////// 列出过期未还的书204.private class Command3 extends Command1 {205.206.@Override207.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.@Override413.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.@Override506.public String toString() {507.return name;508.}509.}