ID #12587

Java小例子:图书馆课程设计

用 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.} 

2011-07-02 11:26
阅读:
I'm VC , Just U know Y
本站部分文章来源于互联网,版权归原作者所有。

延伸阅读:

用Java程序编写记事本

不用spring,hibernate超傻瓜JAVA开发(javabean+数组)

用Java编写计算器的几种常见的做法

proxool.default (HouseKeeper.java:149)异常解决办法

九大因素让Java EE 6成为你的省钱法宝