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

用 Java 模拟一个图书馆。包括创建图书、创建读者、借书、还书、列出所有图书、列出所有读者、列出已借出的图书、列出过期未还的图书等功能。每个读者最多只能借 3 本书,每个书最多只能借 3 个星期,超过就算过期。

下面是一个命令行下的实现。这个例子的主要目的是向初学者展示内部类的好处。Command 及其子类都是 LibrarySimulator 的内部类。它们可以无阻碍的访问 LibrarySimulator 的成员。使用内部类,而不是大量的 if-else,让程序更容易扩展。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.*;
 
/**
 * 一个图书馆的课程设计。主要功能:
 * 1. 创建图书
 * 2. 创建读者
 * 3. 借书
 * 4. 还书
 * 5. 列出所有书
 * 6. 列出已借书
 * 7. 列出超过日期未还的书
 */
public class LibrarySimulator {
 
    // 主菜单
    private static final String MAIN_MENU = "1. 列出所有的书\n" +
            "2. 列出已借出的书\n" +
            "3. 列出过期未还的书\n" +
            "4. 列出所有读者\n" +
            "5. 创建图书\n" +
            "6. 创建读者\n" +
            "7. 借书\n" +
            "8. 还书\n" +
            "9. 退出\n" +
            "请输入序号:";
 
    // 选择图书类型的菜单。在借书和添加图书的时候都会用到
    private static final String TYPE_MENU;
 
    // 表示一个数字的正则表达式
    private static final String DIGIT_CHOICE_PATTERN = "^\\d$";
 
    // 表示非空字符串
    private static final String NOT_EMPTY_PATTERN = "\\S.*";
 
    // 日期格式
    static final String DATE_PATTERN = "yyyy/MM/dd";
 
    // 验证用户输入日期的正则表达式
    static final String DATE_FORMAT_PATTERN = "^\\d{4}/\\d{2}/\\d{2}$";
 
    // 预定义的图书类型
    static HashMap<String, String> TYPES = new LinkedHashMap<String, String>();
 
    static {
        TYPES.put("1", "科学类");
        TYPES.put("2", "文学类");  // 新的类别可以继续在后面添加
        TYPE_MENU = createTypeMenu();
    }
 
    // 生成选择类别的菜单
    private static String createTypeMenu() {
        String str = "";
        for (String index : TYPES.keySet()) {
            str += index + ". " + TYPES.get(index) + "\n";
        }
        return str + "请选择书的类型:";
    }
 
 
    private HashMap<Integer, Command> commands = new HashMap<Integer, Command>();
 
    private ArrayList<Book> books = new ArrayList<Book>();
 
    private ArrayList<Reader> readers = new ArrayList<Reader>();
 
    // 程序入口。这里创建一个 LibrarySimulator 用于模拟界面。
    public static void main(String[] args) {
        new LibrarySimulator().start();
    }
 
    /**
     * 构造函数
     */
    public LibrarySimulator() {
        commands.put(1, new Command1());
        commands.put(2, new Command2());
        commands.put(3, new Command3());
        commands.put(4, new Command4());
        commands.put(5, new Command5());
        commands.put(6, new Command6());
        commands.put(7, new Command7());
        commands.put(8, new Command8());
    }
 
    /**
     * 这里接受用户输入,执行操作,然后再等待用户输入,这样不停的循环。
     */
    private void start() {
        String index = prompt(MAIN_MENU, DIGIT_CHOICE_PATTERN);
 
        while (!index.equals("9")) {
            executeCommand(index);
            index = prompt(MAIN_MENU, DIGIT_CHOICE_PATTERN);
        }
    }
 
    // 根据序号执行命令
    private void executeCommand(String index) {
        Command command = commands.get(Integer.parseInt(index));
        if (command != null) {
            String result = command.execute();
            System.out.println(result + "\n");
        }
    }
 
    // 打印一条提示信息,然后读取并返回用户输入
    private String prompt(String message, String pattern) {
        System.out.print(message);
        if (pattern == null) {
            return readInput();
        } else {
            String result = "";
            while (!result.matches(pattern)) {
                result = readInput();
            }
            return result;
        }
    }
 
    // 读取用户输入
    private String readInput() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
 
    // 根据名字查找读者。找不到则返回 null。
    private Reader getReaderByName(String readerName) {
        for (Reader reader : readers) {
            if (reader.getName().equals(readerName)) {
                return reader;
            }
        }
        return null;
    }
 
    // 根据名字查找图书。找不到则返回 null。
    private Book getBookByName(String bookName) {
        for (Book book : books) {
            if (book.getName().equals(bookName)) {
                return book;
            }
        }
        return null;
    }
 
    /*===================================================================*/
 
    /**
     * 代表命令的抽象类
     */
    private abstract class Command {
 
        protected abstract String execute();
    }
 
    /// 列出所有图书
    private class Command1 extends Command {
 
        protected String execute() {
            for (Book book : getBooks()) {
                System.out.println(book);   // 这里会自动调用 book.toString()
            }
            return "命令完成。";
        }
 
        private ArrayList<Book> getBooks() {
            ArrayList<Book> result = new ArrayList<Book>();
 
            for (Book book : books) {
                if (isValid(book)) {
                    result.add(book);
                }
            }
            return result;
        }
 
        // 考虑到第 1、2、3 条命令大体相同,这里提供了一个给子类覆写的方法
        protected boolean isValid(Book book) {
            return true;
        }
    }
 
    / 列出已借出的书。
    // 注意它的父类不是 Command,而是 Command1。这样节省了很多重复代码
    private class Command2 extends Command1 {
 
        @Override
        protected boolean isValid(Book book) {
            return book.isBorrowed();
        }
    }
 
     列出过期未还的书
    private class Command3 extends Command1 {
 
        @Override
        protected boolean isValid(Book book) {
            // 判断一本书接触过期与否的方法最好在 Book 类中去实现。
            return book.isExpired();
        }
    }
 
    /// 创建图书
    private class Command5 extends Command {
 
        protected String execute() {
            String type = getType();
            String name = getName();
            if (getBookByName(name) == null) {
                books.add(new Book(type, name));
                return "图书添加成功。";
            } else {
                return "图书添加失败:名称已存在。";
            }
        }
 
        // 获得用户输入的书名
        private String getName() {
            return prompt("请输入书名:", NOT_EMPTY_PATTERN);
        }
 
        // 获得用户选择的图书类型
        private String getType() {
            return prompt(TYPE_MENU, DIGIT_CHOICE_PATTERN);
        }
    }
 
    /// 列出所有读者
    private class Command4 extends Command {
 
        protected String execute() {
            for (Reader reader : readers) {
                System.out.println(reader);
            }
            return "命令完成。";
        }
    }
 
    /// 创建读者
    private class Command6 extends Command {
 
        protected String execute() {
            String name = getName();
            if (getReaderByName(name) == null) {
                readers.add(new Reader(name));
                return "读者创建成功。";
            } else {
                return "读者创建失败:名字已经存在。";
            }
        }
 
        public String getName() {
            return prompt("请输入读者名字:", NOT_EMPTY_PATTERN);
        }
    }
 
    /// 借书
    private class Command7 extends Command {
 
        protected String execute() {
            Reader reader = getReader();
            if (reader == null) {
                System.out.println("命令取消。");
                return "";
            }
 
            Book book = getBook();
            if (book == null) {
                System.out.println("命令取消。");
                return "";
            }
 
            String borrowDate = getBorrowDate();
 
            book.borrowBy(reader.getName(), borrowDate);
            reader.addBorrowCount();
 
            return "成功借出。";
        }
 
        private String getBorrowDate() {
            String now = new SimpleDateFormat(LibrarySimulator.DATE_PATTERN).format(new Date());
            String date = null;
            while (date == null || !date.matches(DATE_FORMAT_PATTERN)) {
                date = prompt("请输入借出日期(如" + now + ")", NOT_EMPTY_PATTERN);
            }
            return date;
        }
 
        private Book getBook() {
            Book book = null;
            while (book == null || book.isBorrowed()) {
                String bookName = prompt("请输入图书名字:", null);
                if (bookName.equals("")) {
                    return null;
                }
 
                book = getBookByName(bookName);
                if (book == null) {
                    System.out.println("图书不存在。");
                } else if (book.isBorrowed()) {
                    System.out.println("图书已经被借出。");
                }
            }
            return book;
        }
 
        private Reader getReader() {
            Reader reader = null;
            while (reader == null || !reader.canBorrow()) {
                String readerName = prompt("请输入读者名字:", null);
                if (readerName.equals("")) {
                    return null;
                }
 
                reader = getReaderByName(readerName);
                if (reader == null) {
                    System.out.println("读者不存在。");
                } else if (!reader.canBorrow()) {
                    System.out.println("该读者已经借了" + Reader.MAX_BORROW + " 本书,不能继续借了。");
                }
            }
            return reader;
        }
    }
 
    / 还书
    private class Command8 extends Command {
 
        protected String execute() {
            Reader reader = getReader();
            if (reader == null) {
                System.out.println("命令取消。");
                return "";
            }
 
            Book book = getBook(reader);
            if (book == null) {
                System.out.println("命令取消。");
                return "";
            }
 
            reader.reduceBorrowCount();
            book.returned();
            return "操作成功。";
        }
 
        private Book getBook(Reader reader) {
            Book book = null;
            while (book == null || !reader.getName().equals(book.getBorrower())) {
                String bookName = prompt("请输入图书名字:", null);
                if (bookName.equals("")) {
                    return null;
                }
 
                book = getBookByName(bookName);
                if (book == null) {
                    System.out.println("图书不存在。");
                } else if (!reader.getName().equals(book.getBorrower())) {
                    System.out.println("该读者没有借出这本书。");
                }
            }
            return book;
        }
 
        private Reader getReader() {
            Reader reader = null;
            while (reader == null) {
                String readerName = prompt("请输入读者名字:", null);
                if (readerName.equals("")) {
                    return null;
                }
 
                reader = getReaderByName(readerName);
                if (reader == null) {
                    System.out.println("读者不存在。");
                }
            }
            return reader;
        }
    }
}
 
// 图书
class Book {
 
    public static final int EXPIRE_DAYS = 21;   // 可借出天数,超过就算过期
 
    private String type;
 
    private String name;
 
    private String borrowedBy = null;
 
    private String borrowDate = null;
 
    Book(String type, String name) {
        this.type = type;
        this.name = name;
    }
 
    @Override
    public String toString() {
        String str = String.format("类别:%s  书名:%s", LibrarySimulator.TYPES.get(type), name);
        if (isBorrowed()) {
            str += "  借出人:" + borrowedBy + "  借出时间:" + borrowDate;
        }
        return str;
    }
 
    public boolean isBorrowed() {
        return borrowedBy != null;
    }
 
    public String getName() {
        return name;
    }
 
    public String getBorrowDate() {
        return borrowDate;
    }
 
    /**
     * 图书借出
     *
     * @param name 读者名字
     * @param date 借出日期。格式:参见 {@link LibrarySimulator#DATE_PATTERN}
     */
    public void borrowBy(String name, String date) {
        this.borrowedBy = name;
        this.borrowDate = date;
    }
 
    public boolean isExpired() {
        if (borrowDate == null) {
            return false;   // 没有借出的书不出现在过期未还列表当中,所以这里返回 false。
        }
 
        // 从当前时间往前推 3 个星期,如果还在借书日期之后,说明借书已经超过 3 个星期了
        String threeWksAgo = get3WeeksAgo();
        return threeWksAgo.compareTo(borrowDate) > 0;
    }
 
    // 获得 3 个星期前的日期
    private String get3WeeksAgo() {
        SimpleDateFormat f = new SimpleDateFormat(LibrarySimulator.DATE_PATTERN);
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, -EXPIRE_DAYS);
        return f.format(c.getTime());
    }
 
    public void returned() {
        this.borrowBy(null, null);
    }
 
    public String getBorrower() {
        return borrowedBy;
    }
}
 
// 读者
class Reader {
 
    // 每位读者最多可同时借出 3 本书
    public static final int MAX_BORROW = 3;
 
    private String name;
 
    private int borowCount = 0;
 
    public int getBorowCount() {
        return borowCount;
    }
 
    Reader(String name) {
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
 
    public void addBorrowCount() {
        borowCount++;
    }
 
    public void reduceBorrowCount() {
        borowCount--;
    }
 
    public boolean canBorrow() {
        return borowCount < MAX_BORROW;
    }
 
    @Override
    public String toString() {
        return name;
    }
}


PS: 这种小东西竟然被丢到首页上去了,绝不是我的意思。太丢人了。

 

 

 

 

  • 5
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值