目录
一、目的
利用前面所学的知识点:类,抽象类,封装,继承,多态,接口等进行的一个简单的代码练习。
二、任务
1、简单的登录
2、管理端
添加书籍、删除书籍、按名称排序、按价格排序、按借阅情况排序、退出
3、用户端
按名称排序 、按价格排序、按借阅情况排序、借阅书籍、归还书籍、退出
三、设计思路
我们首先需要一个Main函数来作为我们程序执行的路口。Main中首先需要完成用户的登录过程,然后进入循环,打印出用户的可选择项目,然后根据用户的输入来执行相应的操作。
首先我们可以将图书抽象成为一个类,然后用一个书架来记录这些书对象的信息,我们需要将信息写在文件中,每次运行时需要将文件信息加载到对象中。
我们可以将输入封装为一个类。这个类需要有一个(prompt)方法来返回用户的输入信息。还需要借助这个方法以及打印菜单的(showMenu)方法完成对用户的选择执行相应的操作的方法。
因为输入的用户有两种类型,我们定义一个抽象类来供具体的用户类来继承。我们还可以额外定义一个类来完成用户的登录,以及管理员用户的判断。
完成登录操作之后就需要进入循环完成对应用户的功能了,我们可以将用户的功能用一个接口实现,然后执行对应的操作。
四、基本框架
以下是主函数的设计,只需要看框架,所以省略了包的导入,(整体代码贴在文末)
public class Main {
public static void main(String[] args) {
//0.实例化一个负责处理输入的对象
Input input=new Input();
//改成从文件中来加载数据
BookStorage bookStorage = BookStorage.loadFromFile();
try {
//1.用户登录
//1.1需要一个用户管理对象完成登录的具体操作
UserStorage useerStorage=new UserStorage();
//1.2判断用户角色
User user=useerStorage.login(input);
//2.进入循环
while(true){
//2.1打印用户的菜单,斌且让用户选择
//用一个接口来体现这种能力
IExecutable command=input.menuAndSelect(user);
command.execute(bookStorage,user,input);
}
}catch (QuitException exc){
}
//3.用户退出
System.out.println("欢迎下次使用!!!");
}
}
input类的框架
public class Input {
private final Scanner scanner= new Scanner(System.in);
public String prompt(String prompt) throws QuitException {
//此部分用于返回输入信息
}
public IExecutable menuAndSelect(User user) {
//此部分要根据用户对象读取其支持的功能,然后打印出可选择菜单,然后让用户做出选择
while (true){
//1.需要得到这个角色支持那些命令
IExecutable[] supportedcommands=user.getSupportedComands();
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) {
//此部分需要协助上部分打印菜单
for (int i = 0; i < supportedcommands.length; i++) {
IExecutable command=supportedcommands[i];
System.out.printf(" %2d. %s\n",i+1,command.getName());
}
}
}
UseStroage类的框架
public class UserStorage {
private static final String[] ADMIN ={
//此部分记录管理员的信息,可用于比对
};
public User login(Input input) {
//调用input中的方法来完成登录,并且根据用户输入的信息返回不同的用户类的对象
}
private boolean isAdmin(String username) {
//用于协助判别是否管理员
}
}
user抽象类
public abstract class User {
private String username; //记录用户名称
public User(String username) {
this.username = username; //构造方法
}
public String getUsername() {
return username; //读取用户名方法,方便后续操作
}
public abstract IExecutable[] getSupportedComands(); //读取用户支持的指令
}
普通用户类
public class AdminUser extends User {
public AdminUser(String username) {
super(username);
}
@Override
public IExecutable[] getSupportedComands() {
//此操作是为了得到IExecutable[]列表,其中每个元素为实现了IExecutable的类。
return new IExecutable[]{
new AddBookCommand(),
new RemoveBookCommand(),
new ListBookOrderByNamecommand(),
new ListBookOrderByPriceCommand(),
new ListBookOrderByBorrowedCommand(),
new Quite()
};
}
}
管理员用户类
public class CommonUser extends User {
public CommonUser(String username) {
super(username);
}
@Override
public IExecutable[] getSupportedComands() {
return new IExecutable[]{
new ListBookOrderByNamecommand(),
new ListBookOrderByPriceCommand(),
new ListBookOrderByBorrowedCommand(),
new BorrowOperation(),
new ReturnOperation(),
new Quite()
};
}
}
IExecutable接口,用于命令的实现
public interface IExecutable {
void execute(BookStorage bookStorage, User user, Input input);//用于执行具体操作
String getName();//便于打印命令信息
}
book类
public class Book implements Comparable {
public String name;
public String author;
public int price;
public String type;
public String BorrowedBy;
@Override
public int compareTo(Object o) {
Book b=(Book) o;
return name.compareTo(b.name);
}
@Override
public String toString(){
String s=String.format("书名:《%s》 作者:%s 价格:%d 类型:%s ",name,author,price,type);
StringBuilder sb = new StringBuilder(s);
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) {
//为了封装写成了这样
//name属于String类型,需要equals判断。
return this.name.equals(name);
}
@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 void borrow(User user) {
BorrowedBy= user.getUsername();
}
public boolean isBorrowedBy(User user) {
if(this.BorrowedBy==null){
return false;
}
return this.BorrowedBy.equals(user.getUsername());
}
public void returnBook(User user) {
this.BorrowedBy=null;
}
}
BookStorage类
public class BookStorage {
private Book[] array;
private int size;
public BookStorage() {
this.array = new Book[20];
this.size =0;
}
private static final File file=new File("此处为文件路径");
public static BookStorage loadFromFile() {
//读取文件
}
public void add(Book book){
//尾插
}
private void ensureCapacity() {
//扩容
}
public Book[] toArray() {
}
public Book searchByName(String name) {
}
public void remove(Book book) {
}
public void saveToFile() {
//将文件保存
}
}
思考:整体的框架如上,其中很多类的方法都是在实现的过程中为完成指定功能而添加的。我们大致整理一下思路。
首先程序开始运行,new一个input对象用于输入,然后调用BookStorage中的静态方法loadFromFile()来读取文件信息,返回一个bookStorage对象。然后new一个useStorage对象调用对象的实例方法login(input)传入input对象,然后在login中调用prompt()方法,然后根据输入new出user对象并且返回。
然后进入循环,调用input的menuAndSelect(user)方法,传入user对象。在该方法中,调用user的实例方法getSupportedComands()返回一个IExecutable[]类型的supportedcommands对象
,然后执行showMenu(supportedcommands)打印出可执行的信息,然后调用prompt()方法读取用户输入的信息,然后最终返回对应操作的对象command。
最后执行该command对象的execute(bookStorage,user,input)方法。这些方法就是我们需要具体完成的功能(我们用一个接口IExecutable来供这些类来实现)。
五、实现细节
其中有三个功能是排序这些书籍,于是我们可以用一个抽象类来完成,并且可以通过重写比较器的方法来来完成排序。
抽象类的代码:
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.toString());
}
System.out.println();
System.out.println("排序完成");
System.out.println();
}
}
其中一个排序功能的实现:
public class ListBookOrderByBorrowedCommand extends AbsListBookCommand{
private static class BorrowedComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Book b1=(Book) o1;
Book b2=(Book) o2;
int borrowed1=b1.BorrowedBy==null ? 1:0;
int borrowed2=b2.BorrowedBy==null ? 1:0;
return borrowed2-borrowed1;
}
}
private final Comparator comparator=new BorrowedComparator();
//BorrowedComparator只使用了一次,可以用匿名类来实现。在此不作展示
@Override
protected Comparator getComparator() {
return comparator;
}
@Override
public String getName() {
return "按借阅情况排序并列出";
}
}
添加书籍:按要求输入书籍信息,然后new一个book对象并且初始化,然后尾插到bookstorage对象中。
删除书籍:按要求输入信息,查找到该书的下标,将最后一本书移到该书的位置,然后让最后一本书设为null然后size--。
借阅书籍:将book的BorrowedBy属性设置为user的名字。
归还书籍:将book的BorrowedBy属性设置为null。
以上4个操作都需要将信息保存到文件中。
六、总结
以上部分可以对我们的基础知识做一个回顾。还需要熟悉这种模板设计模式,并且使用这种面向对象的编程思想。