赞
踩
ps:
此工程分为四个包,分别是input(用于输入输出和给出提示信息),command(定义行为),user(普通用户和管理员用户)和main(主函数)
- package 图书管理系统;
-
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.command.IExecutable;
- import 图书管理系统.input.Input;
- import 图书管理系统.input.QuitException;
- import 图书管理系统.user.User;
- import 图书管理系统.user.UserStorage;
-
- public class Main {
- // 由于输入过程,需要处理一些杂事
- // 1) 打印提示信息
- // 2) 读取用户输入
- // 3) 用户有没有按 Ctrl + D 退出
- // 直接封装一个对象去处理输入的问题
- public static void main(String[] args) {
- // 0. 实例化一个负责处理输入的对象
- Input input = new Input();
-
- // 1. 我们的书架对象,在应用运行过程中,只需要一份
- // 2. 改从文件中加载数据
- BookStorage bookStorage = BookStorage.loadFromFile();
-
- try {
- // 1. 用户登录
- // 我们需要一个用户管理的对象,由该对象完成用户登录的具体操作
- // 1.1. 要求用户输入
- // 1.2. 判断用户角色 ...
- UserStorage userStorage = new UserStorage();
- User user = userStorage.login(input);
-
- // 2. 进入一个循环中
- while (true) {
- // 2.1 打印用户角色对应的菜单,并且让用户选择
- // execute : 执行
- // executable : 具备可以执行的能力
- // IExecutable : 计划用接口去表示
- // command: 命令
- IExecutable command = input.menuAndSelect(user);
- // 2.2 根据用户的选择,执行对应的操作命令
- command.execute(bookStorage, user, input);
- }
- } catch (QuitException exc) {
- // 用户要退出,我们什么都不做
- }
-
- // 3. 用户退出,打印退出信息
- System.out.println("欢迎下次使用");
- }
- }
book包:
- package 图书管理系统.book;
-
- import 图书管理系统.user.User;
-
- public class Book implements Comparable {
- public String name;
- public String author;
- public String type;
- public int price;
- public String borrowedBy;
-
- @Override
- public int compareTo(Object o) {
- Book b=(Book) o;
- return name.compareTo(b.name);// 自然顺序是以书名为顺序
- // 书名也是 String 类型,也得遵守对象的比较规则
- }
-
- @Override
- public String toString() {
- //强行用StringBuilder
- String.format("《%s》by %s,[%s],%d",name,author,type,price);
- StringBuilder sb=new StringBuilder();
- if (borrowedBy==null){
- sb.append("可借用!");
- }else {
- sb.append("被");
- sb.append(borrowedBy);
- sb.append("借走了");
- }
- return sb.toString();
- }
-
- public boolean isBorrowed(){
- return borrowedBy==null;
- }
-
- public boolean equalsByName(String name){
- return this.name.equals(name);// 1. 也是为了封装,看起是一行一个方法
- // 2. name 是 String 类型,判断相等性,也需要使用 equals 判断
- }
-
- public void borrowed(User user){
- borrowedBy=user.getUsername();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Book book = (Book) o;
- return name.equals(book.name);
- }
-
- public boolean isBorrowedBy(User user){
- if (borrowedBy==null){
- return false;
- }
- return borrowedBy.equals(user.getUsername());
- }
-
- public void returned(User user){//换书操作
- borrowedBy=null;
- }
- }
- package 图书管理系统.book;
-
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.lang.reflect.Array;
- import java.util.Arrays;
- import java.util.Scanner;
-
- public class BookStorage {
- private Book[] array;
- private int size;
-
- public BookStorage(){
- array=new Book[20];
- size=0;
- }
-
- // 要让静态方法能使用,也得使用静态属性
- private static final File file=new File("C:\\java data\\.metadata\\book-storage.txt");
- //直接使用类名调用的一定是静态方法
- public static BookStorage loadFromFile(){
- BookStorage bookStorage=new BookStorage();
- if (!file.exists()){
- return bookStorage; //说明第一次运行,创建一个空对象
- }
- //开始加载
- try {
- Scanner sc=new Scanner(file,"UTF-8");
- while (sc.hasNextLine()){
- String line=sc.nextLine();
- // split 按照指定字符串,进行切割
- String[] group=line.split("@");
- if (group.length!=5){
- throw new RuntimeException("文件格式不对");
- }
- String name=group[0];
- String author=group[1];
- String type=group[2];
- String priceStr=group[3];
-
- int price;
- try{
- price=Integer.parseInt(priceStr);
- }catch (NumberFormatException exc){
- throw new RuntimeException("价格不是数字");
- }
- String borrowedByStr=group[4];
- String borrowedBy;
- if (borrowedByStr.equals("null")){
- borrowedBy=null;// 把字符串 "null" 转成 null
- }else {
- borrowedBy=borrowedByStr;
- }
- Book book=new Book();
- book.name=name;
- book.author = author;
- book.type = type;
- book.price = price;
- book.borrowedBy = borrowedBy;
-
- bookStorage.add(book);
- }
- sc.close();
- return bookStorage;
- }catch (IOException e){
- throw new RuntimeException(e);
- }
-
- }
-
- public void add(Book book) {
- //尾插
- ensureCapacity();
- array[size++]=book;
- saveToFile();
- }
-
- public Book[] toArray(){
- //return array; // 直接返回可不可以? 语法上成立。不可以
- // 理论有 两条:
- // 1. 返回 array,它的长度是 array.length ,但我们真正的书籍只有 size 本
- // 应该是返回一个 长度是 size 的数组,而不是长度是 array.length 的数组
- // 2. 一旦把 array 返回出去之后(数组对象逃逸了)
- // 别人会怎么操作数组对象,我们完全无法控制
- // 所以可能打破顺序表的一致性问题。比如 Arrays.fill(array, null)
- // size > 0 但是 array 中全部是 null
- return Arrays.copyOf(array,size);
- // 实际上还是有风险的,因为只是浅拷贝
- // 如果使用者有意还是无意改了 Book 对象属性
- // 我们还是会收到影响的
- // 最好的办法是做深拷贝,但这里不做那么复杂了
- }
-
-
- private void ensureCapacity() {
- if (size<array.length){
- return;
- }
- array= Arrays.copyOf(array,array.length*2);
- }
-
- // TODO: 我们这里隐含一个假设,就是我们的书架中,不允许出现同名的书籍
- // TODO: 否则删除的时候操作有歧义
- // TODO: 这个判断,我们在 AddBookCommand 中是没有操作
- public Book searchByName(String name){
- for (int i=0;i<size;i++){
- Book book=array[i];
- if (book.equals(name)){
- return book;
- }
- }
- return null;
- }
-
- // 原则上,如果顺序表要保持原有顺序的情况下,删除某个元素(可能在中间)
- // 则时间复杂度必然是 O(n) 的
- // 我们这里需要保持顺序么?array 中的原始顺序其实在当前需求下不是那么重要!
- public void remove(Book name){
- for (int i=0;i<size;i++){
- Book item=new Book();
- if (item.equals(name)){
- array[i]=array[size-1];
- array[size-1]=null;
- size--;
- return;
- }
- }
- saveToFile();
- }
-
- // 普通方法,保存是当前 BookStorage 对象的内容
- public void saveToFile() {
- try{
- PrintWriter writer=new PrintWriter(file,"UTF-8");
- for (int i=0;i<size;i++){
- Book book=array[i];
- StringBuilder sb=new StringBuilder();
- sb.append(book.name);
- sb.append("@");
- sb.append(book.author);
- sb.append("@");
- sb.append(book.type);
- sb.append("@");
- sb.append(book.price);
- sb.append("@");
- sb.append(book.borrowedBy);
- writer.println(sb.toString());
-
- }
- writer.flush();
- writer.close();
- }catch (IOException exc){
- throw new RuntimeException(exc);
- }
- }
-
-
-
- }
input包:
- package 图书管理系统.input;
-
- import 图书管理系统.command.IExecutable;
- import 图书管理系统.user.User;
-
- import java.util.Scanner;
-
- public class Input {
- Scanner scanner=new Scanner(System.in);
- public String prompt(String prompt){
- System.out.println(prompt+":");
- System.out.print(">");
- if (!scanner.hasNextLine()){//说明用户按下了ctrl+D,想要退出
- throw new QuitException();//通过异常向外部通知
- }
- return scanner.nextLine();
- }
-
- public IExecutable menuAndSelect(User user){
- IExecutable[] supportedCommands = user.getSupportedCommands();
- while (true){
- showMenu(supportedCommands);
- // 角色不同,理论上拥有的功能不同
- // 需要当前用户信息
- String selectStr=prompt("请选择您要进行的操作");
- try {
- int select=Integer.parseInt(selectStr);
- if (select>=1&select<=supportedCommands.length){
- return supportedCommands[select-1];
- }
- System.out.println("请输入正确的序号!");
- }catch (NumberFormatException exc){
- System.out.println("请输入正确的数字");
- }
- }
- }
-
- private void showMenu(IExecutable[] supportedCommands) {
- // 2. 遍历并打印每个命令的名称,显示操作菜单
- System.out.println("----------------");
- for (int i=0;i<supportedCommands.length;i++){
- IExecutable command=supportedCommands[i];
- System.out.printf(" %2d. %s\n", i + 1, command.getName());
- }
- System.out.println("----------------");
- }
-
- }
- package 图书管理系统.input;
-
- public class QuitException extends RuntimeException{
- }
user包:
- package 图书管理系统.user;
-
- import 图书管理系统.command.IExecutable;
-
- public abstract class User {
- private String username;
-
- public User(String name){
- this.username=name;
- }
- public String getUsername(){
- return username;
- }
- // 所以也完全不知道支持哪些命令
- // 应该定义成抽象方法,供子类去实现
- public abstract IExecutable[] getSupportedCommands();
- }
-
- package 图书管理系统.user;
-
- import 图书管理系统.command.*;
-
- public class AdminUser extends User {
- public AdminUser(String name) {
- super(name);
- }
-
- @Override
- public IExecutable[] getSupportedCommands() {
- return new IExecutable[] {
- // 管理员支持 添加书籍命令
- new AddBookCommand(),
- // 管理员支持 删除书籍命令
- new RemoveBookCommand(),
- // 管理员支持 根据书名列出书籍命令
- new ListBookOrderByNameCommand(),
- // 管理员支持 根据价格列出书籍命令
- new ListBookOrderByPriceCommand(),
- // 管理员支持 根据借阅情况列出书籍命令
- new ListBookOrderByBorrowedCommand()
- };
- }
- }
- package 图书管理系统.user;
-
- import 图书管理系统.command.*;
-
- public class CommandUser extends User {
- public CommandUser(String name) {
- super(name);
- }
-
- @Override
- public IExecutable[] getSupportedCommands() {
- return new IExecutable[] {
- new ListBookOrderByNameCommand(),
- new ListBookOrderByPriceCommand(),
- new ListBookOrderByBorrowedCommand(),
- new BorrowBookCommand(),
- new ReturnBookCommand()
- };
- }
- }
- package 图书管理系统.user;
-
- import 图书管理系统.input.Input;
-
- public class UserStorage {
- // 提前定义一些用户名,作为管理员
- private static final String[] ADMIN_USERNAMES={
- "文佳怡",
- "耿超扬"
- };
-
- private boolean isAdmin(String name){
- for (String admin:ADMIN_USERNAMES){
- if (admin.equals(name)){
- return true;
- }
- }
- return false;
- }
-
- public User login(Input input){
- // 1. 先让用户输入用户名
- //prompt:提示符
- String username=input.prompt("请输入用户名");
- // 2. 根据用户名,角色是管理员还是普通的用户
- // 3. 根据不同的角色,创建不同的用户
- // admin: 管理员
- if (isAdmin(username)){
- return new AdminUser(username);
- }else {
- return new CommandUser(username);
- }
- }
- }
comand:
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.input.Input;
- import 图书管理系统.user.User;
-
- import java.lang.reflect.Array;
- import java.util.Arrays;
- import java.util.Comparator;
-
- // 由于 AbsListBookCommand 是 抽象类,允许出现抽象方法
- public abstract class AbsListBookCommand implements IExecutable {
- protected abstract Comparator getComparator();
-
- @Override
- public void execute(BookStorage bookStorage, User user, Input input) {
- Comparator comparator=getComparator();
- Book[] books=bookStorage.toArray();
- if (comparator==null){
- Arrays.sort(books);
- }else {
- Arrays.sort(books,comparator);
- }
- for (Book book:books){
- System.out.println(book);
- }
- }
- }
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.input.Input;
- import 图书管理系统.user.User;
-
- public class AddBookCommand implements IExecutable {
- @Override
- public String getName() {
- return "添加书籍";
- }
-
- @Override
- public void execute(BookStorage bookStorage, User user, Input input) {
- System.out.println("开始添加书籍,首先读取书籍信息:");
- String name = input.prompt("请输入书籍名称");
- String author = input.prompt("请输入书籍作者");
- String type = input.prompt("请输入书籍类型");
- int price;
- while (true) {
- try {
- String priceStr = input.prompt("请输入书籍价格(必须是数字)");
- price = Integer.parseInt(priceStr);
- break;
- } catch (NumberFormatException exc) {
- System.out.println("价格格式错误");
- }
- }
- // 刚加架的书肯定没被借阅
- Book book = new Book();
- book.name = name;
- book.author = author;
- book.type = type;
- book.price = price;
- book.borrowedBy = null;
-
- System.out.println("将书籍添加到 书架上");
- bookStorage.add(book);
-
- System.out.println(user.getUsername() + " 完成了 添加书籍的操作: " + name);
- }
- }
-
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.input.Input;
- import 图书管理系统.user.User;
-
- public class BorrowBookCommand implements IExecutable {
- @Override
- public void execute(BookStorage bookStorage, User user, Input input) {
- // 通过书名,完成借阅
- System.out.println("开始借阅书籍,首先读取书籍信息:");
- String name = input.prompt("请输入书籍名称");
-
- Book book = bookStorage.searchByName(name);
- if (book == null) {
- // 没有找到
- System.out.println("没有这本书 " + name + ",无法借阅");
- return;
- }
-
- if (book.isBorrowed()) {
- System.out.println("书籍已经被 " + book.borrowedBy + " 借走,暂时不允许借阅");
- return;
- }
-
- // 由于 book 返回的引用,指向的书籍对象,和 BookStorage 中保存的 Book 对象是同一个对象
- // 通过 book 引用修改,也会让 BookStorage 中生效
- book.borrowed(user);
- bookStorage.saveToFile();
-
- System.out.println(user.getUsername() + " 完成了 借阅书籍的操作: " + name);
- }
-
- @Override
- public String getName() {
- return "借阅书籍";
- }
- }
-
- package 图书管理系统.command;
-
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.input.Input;
- import 图书管理系统.user.User;
-
- public interface IExecutable {
- void execute(BookStorage bookStorage, User user, Input input);
- String getName();
- }
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
-
- import java.util.Comparator;
-
- public class ListBookOrderByBorrowedCommand extends AbsListBookCommand {
- private final Comparator comparator = new Comparator() {
- @Override
- public int compare(Object o1, Object o2) {
- Book b1 = (Book) o1;
- Book b2 = (Book) o2;
-
- int br1 = b1.borrowedBy == null ? 0 : 1;
- int br2 = b2.borrowedBy == null ? 0 : 1;
-
- return br1 - br2; // 未借走的书籍比较“小”
- }
- };
-
- @Override
- public String getName() {
- return "根据借阅情况排序,列出书籍";
- }
-
- @Override
- protected Comparator getComparator() {
- return comparator;
- }
- }
- package 图书管理系统.command;
-
- import java.util.Comparator;
-
- public class ListBookOrderByNameCommand extends AbsListBookCommand {
- @Override
- public String getName() {
- return "根据书名排序,列出书籍";
- }
-
- @Override
- protected Comparator getComparator() {
- return null;
- }
- }
-
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
-
- import java.util.Comparator;
-
- public class ListBookOrderByPriceCommand extends AbsListBookCommand {
- private static class PriceComparator implements Comparator {
-
- @Override
- public int compare(Object o1, Object o2) {
- Book b1 = (Book) o1;
- Book b2 = (Book) o2;
-
- return b1.price - b2.price;
- }
- }
-
- private final Comparator comparator = new PriceComparator();
-
- @Override
- protected Comparator getComparator() {
- return comparator;
- }
-
- @Override
- public String getName() {
- return "根据价格排序,列出书籍";
- }
- }
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.input.Input;
- import 图书管理系统.user.User;
-
- public class RemoveBookCommand implements IExecutable {
- @Override
- public String getName() {
- return "删除书籍";
- }
-
- @Override
- public void execute(BookStorage bookStorage, User user, Input input) {
- // 只支持按照名称删除
- System.out.println("开始删除书籍,首先读取要删除的书籍信息:");
- String name = input.prompt("请输入书籍名称");
- // 增加一些业务逻辑:如果书籍已经借走,则不允许删除
- Book book = bookStorage.searchByName(name);
- if (book == null) {
- // 没有找到
- System.out.println("没有这本书 " + name + ",无法删除");
- return;
- }
- // 看起来 book.isBorrowed() 和 book.borrowedBy != null 是逻辑等价的
- // 应该用 book.isBorrowed() 比 后边更好,为什么?
- // 从职责划分的角度(封装)
- // 提到了方法的重用挺好,但这里的原因不是这个
- if (book.isBorrowed()) {
- System.out.println("书籍已经被 " + book.borrowedBy + " 借走,暂时不允许删除");
- return;
- }
-
- bookStorage.remove(book);
-
- System.out.println(user.getUsername() + " 完成了 删除书籍的操作: " + name);
- }
- }
- package 图书管理系统.command;
-
- import 图书管理系统.book.Book;
- import 图书管理系统.book.BookStorage;
- import 图书管理系统.input.Input;
- import 图书管理系统.user.User;
-
- public class ReturnBookCommand implements IExecutable {
- @Override
- public void execute(BookStorage bookStorage, User user, Input input) {
- // 通过书名,完成归还
- System.out.println("开始借阅书籍,首先读取书籍信息:");
- String name = input.prompt("请输入书籍名称");
-
- Book book = bookStorage.searchByName(name);
- if (book == null) {
- // 没有找到
- System.out.println("没有这本书 " + name + ",无法归还");
- return;
- }
-
- if (!book.isBorrowed()) {
- System.out.println("书籍没有被借走,不需要归还");
- return;
- }
-
- if (!book.isBorrowedBy(user)) {
- System.out.println("书籍不是被 " + user.getUsername() + " 借走的,无法归还");
- return;
- }
-
- book.returned(user);
- bookStorage.saveToFile();
-
- System.out.println(user.getUsername() + " 完成了 归还书籍的操作: " + name);
- }
-
- @Override
- public String getName() {
- return "归还书籍";
- }
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。