我们现在想利用Java语法实现一个图书馆的图书管理系统,我们先来看一下最后的成果大概是什么样的。
可以看到,我们通过登录,进入到了管理系统,之后,我们可以对身份进行选择,并进行对应的操作。那么现在,让我们开始实现吧!
1)
首先,图书馆,一定有各种各样的书,他们可能各不相同,但他们一定都是书。因此,我们就可以抽象出书这个类,通过书这个类实例化出各种对象,也就是各种各样的书。因此我们新建一个包,命名为Book,并在这个包中创建出书这个类。
那么我们创建出书这个类,就要写出成员属性,一本书都有什么属性呢?我认为可以有书名,作者,价格,类型,是否被借出等性质。而这些性质应当被封装,所以我们可以用private修饰。那么,我们可以如此定义:
private String name;
private String author;
private int price;
private String type;
private boolean isborrowed;//默认为false
需要注意,当我们定义isborrowed之后,默认它为false即并未借出。
那么接下来,我们可以快速生成构造方法进行初始化,并快速生成get和set方法来方便我们进行使用。我们右键选择generate,通过construct生成构造方法,getter and setter生成get set方法。
public Book(String name, String author, int price, String type) {
this.name = name;
this.author = author;
this.price = price;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isIsborrowed() {
return isborrowed;
}
public void setIsborrowed(boolean isborrowed) {
this.isborrowed = isborrowed;
}
这样,我们就完成了对书这个类的创建。
2)
那么,当我们有了书,又该如何对书进行操作呢。可以想到在现实生活中,我们在图书馆中借书还书都是通过“书架”进行操作,我们借书就从书架上拿走,还书就把书放回书架,那么,我们就可以抽象出书架这样一个类,对我们的书进行操作。那么我们就在当前包底下创建booklist,把书放到书架上。那么书架上,是各种各样的书,我们又该怎么表示呢?没错,我们可以创建一个数组,数组中的元素都是书,这样,我们通过下标找出书架上的书,并对它进行操作,这样问题不就解决了?同时,我们也需要知道当前书架上的书有多少本,这样我们才能通过下标对书进行操作。同时,我们可以通过构造方法对书架进行初始化,我们可以在书架上先放上几本书,我是这样完成的:
private Book[]books=new Book[100];
public Booklist() {
this.books[0] = new Book("西游记","吴承恩",30,"小说");
this.books[1]=new Book("三国演义","罗贯中",35,"小说");
this.books[2]=new Book("java程序设计","时间幻灭",50,"学习");
}
int usedsize=3;
public int getUsedsize() {
return usedsize;
}
public void setUsedsize(int usedsize) {
this.usedsize = usedsize;
}
这样,我们对书架这个类的定义也基本完成。
3)
下面,我们发现,我们对书进行了很多操作,那么,操作,也可以被抽象成类,但我们有各种不一样的操作,每一个操作都可以抽象成一个类。,我们先定义一个Operation这样一个操作的包,再在这个包底下定义操作。我们举一个例子,比如增加图书这样一个操作,我们定义AddOperation,并构造成员方法来进行图书的增加,具体方法的实现我们先放一放,先构造出大框架:
其他操作也可以以此类推,那么我们发现,每一个操作中都要有一个成员方法work来进行该操作,那么既然方法都一样,但只是其中的内容不一样,我们就可以想到我们学过的接口,用一个接口来先写好work方法,后面所有的操作对这个方法进行重写,这样可以让代码更加严谨。那么,我们可以定义一个IOperation这样一个接口,然后写出work这样一个方法。因为我们最后都要对work这个方法进行重写,因此这里的work方法没必要写内容,那么,我们可以把这个方法定义为抽象方法,同时,我们的接口也要变成抽象类。
public interface IOoperation {
abstract void work(BookList bookList);
}
然后我们可以把所有操作作为类先定义出来,继承我们上面的接口,重写work方法,我们可以先不实现具体的操作,先进行定义,就像AddOperation一样,我们依次先把所有类定义好。我们可以把他们把这些操作都放到同一个包中。
4)
下面我们就要针对用户进行编辑,用户分为管理员和普通用户,针对用户不同的角色,我们显示的菜单也会不同,因此我们需要定义管理员和普通用户两个类。那么我们可以思考,两者是否有共性呢?我想是有的,两者都有自己的姓名,都有自己的菜单,那么对于两者的共性,我们可以自然而然的想到我们学过的父类,我们可以先定义一个User类用来继承,它具有姓名这个属性,有菜单这样一个方法,我们发现,我们并不需要在这里实现菜单这个方法,因为它会被继承重写成两个不同的菜单,所以可以定义成抽象类,同时这个User类也会变成抽象类。
public abstract class User {
protected String name;
public User(String name) {
this.name = name;
}
public abstract int menu();
}
下面我们就可以定义用户和管理员两个类对name进行继承,对方法进行重写。我们可以把它们放进同一个包。
5)主方法
接下来我们要进行主方法的书写。我们定义了操作,也定义了用户,那么我们怎么将它们联系起来呢?
首先,我们一定要先确认用户的身份。这里我们可以定义一个登录的方法,由用户选择自己的身份。
public static User login(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入您的姓名->");
String name=scanner.next();
System.out.println("请输入您的身份(0:管理员/1:普通用户)->");
int log= scanner.nextInt();
if(log==0){
AdminUser adminUser=new AdminUser(name);
return adminUser;
} else {
NormalUser normalUser=new NormalUser(name);
return normalUser;
}
}
我们可以观察上面这个代码。我们能够发现我们返回的是user这个类。而我们通过选择返回了两个不同的用户。在这里我们用到了向上转型的知识。把子类对象给到了父类。通过父类的引用,引用了子类的对象。发生了动态绑定。我们的返回值可以用user来接收。而此时的user会根据返回值的不同调整为普通用户或者管理员。
User user=login();
像这样,我们就得到了用户的身份。那么我们要根据身份进入不同的菜单,进行不同的操作。首先我们要明确当我们进入这个系统时,不主动选择退出的选项。这个系统是不会退出的。那么我们就要定义一个死循环while(true)。
当我们进入这个循环时,我们去应该已经拿到了对应的菜单。那么下面我们就去编辑各自的菜单。
public int menu() {
System.out.println("************************");
System.out.println("hello "+ this.name + " 欢迎来到管理员菜单!");
System.out.println("1. 查找图书");
System.out.println("2. 新增图书");
System.out.println("3. 删除图书");
System.out.println("4. 显示图书");
System.out.println("0. 退出系统");
System.out.println("************************");
System.out.println("请输入你的操作:");
}
我们可以很简单的把菜单显示的东西做出来。那么下面我们发现我们需要选择进行的操作。那么我们就正常读取就好了。最后返回我们的选择。
public int menu() {
System.out.println("************************");
System.out.println("hello "+ this.name + " 欢迎来到管理员菜单!");
System.out.println("1. 查找图书");
System.out.println("2. 新增图书");
System.out.println("3. 删除图书");
System.out.println("4. 显示图书");
System.out.println("0. 退出系统");
System.out.println("************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
可是我们尽管做出了选择,但是好像跟我们的操作没有什么联系。怎样才能建立这样的关联呢?我们每一个选择都对应一个数字。这样我们可以自然而然想到数组我们不妨在user这个类里定义一个IOoperations数组,当我们选出了一个choice,我们就将它传到数组中,我们将每一个操作都当成数组中的一个元素,而choice就代表下标。通过choice来调用这些操作。
public abstract class User {
protected String name;
public IOoperation[] iOoperations;//只是定义没有初始化大小
public User(String name) {
this.name = name;
}
public abstract int menu();
public void dooperation(int choice, BookList bookList){
iOoperations[choice].work(bookList);
}
}
同时我们每一个类中都有work方法,我们可以定义一个dooperation方法将choice传进去,对work方法进行调用,我们每一个操作不同,对应的work方法就不同,这样我们就可以调用这里面的操作了,同时操作的是书架,因此我们要把书架也传进去。
对应的,我们在重写用户和管理员这两个类时,可以对iooperations这个数组进行初始化,将我们的一系列操作都传进去。
public class AdminUser extends User{
public AdminUser(String name) {
super(name);
this.iOoperations=new IOoperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new ShowOperation()
};
}
@Override
public int menu() {
System.out.println("************************");
System.out.println("hello "+ this.name + " 欢迎来到管理员菜单!");
System.out.println("1. 查找图书");
System.out.println("2. 新增图书");
System.out.println("3. 删除图书");
System.out.println("4. 显示图书");
System.out.println("0. 退出系统");
System.out.println("************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
this.iOoperations=new IOoperation[]{
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation(),
};
}
@Override
public int menu() {
System.out.println("************************");
System.out.println("hello "+ this.name + " 欢迎来到普通用户菜单!");
System.out.println("1. 查找图书");
System.out.println("2. 借阅图书");
System.out.println("3. 归还图书");
System.out.println("0. 退出系统");
System.out.println("************************");
System.out.println("请输入你的操作:");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
同时在主方法中我们通过调用menu方法得到了一个返回值choice,那么我们再将返回值和书架一同传入do operation这个方法中,就可以完成两者的联系了。
public static void main(String[] args) {
BookList bookList=new BookList();
User user=login();
while(true){
int choice = user.menu();
//user是哪个对象? choice是几? ---》 能够确定:我能够操作哪个1.对象的哪个2.方法?
//通过这两个变量 可以确定了 但是怎么联系起来??
/**
* 1. 先让双方 存好 对应自己的操作
* 2. 就是调用对应的操作!
*/
user.dooperation(choice, bookList);
/* System.out.println(choice);
System.out.println(user);*/
}
}
这样一个大致的框架就完成了,剩下的就是具体各个操作的实现了。