当我们将java的语法学的差不多的时候,其实可以 将这些语法进行一个整合,用一个小小的项目来练下手,比如比较典型的图书管理系统,我最近已经实现这个,那么让我来看看浅谈以下如何实现的吧。
首先上图片:
首先在图片中我们就可以看到,我们运行代码的时候,我们要输入我们的名字,然后选择我们登录的身份,选择不同当然进入的界面就不一样,我们抽取两个很显而易见的对象:书、人
书当然对应的是一个书架,而人嘛,自然对应的就是管理员和使用者。
既然对象我们提取出来了,那我们就先把框架搭好,然后在一一对里面的具体操作进行实现。
那么我们首先去创建我们的三个包来管理下我们的操作:
Book包:来管理我们书籍和书架状况的。
Ifunction包:管理我们的具体业务操作的。
User:来管理下我们的用户的。
首先我们来对我们的Book包内创建两个类:Book、BookList(名字可以自定义)
我们在Book类中对我们的书进行一些初始化操作:
操作之前,我们先看看书籍是咋样的:
里面包含了:书籍名、作者、价格、类型、是否借出
所以代码展示如下:
private String name;
private String author;
private int price;
private String type;
private boolean isLend;
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 void isreturn(boolean lend){
isLend=lend;
}
@Override
public String toString() {//重写下toString方法
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
((isLend==true)?", 已借出":", 未借出")+
//", isLend=" + isLend +
'}';
}
Book类里面暂时写完了,后面还得加点东西。
接下来我们来往BookList写
private int usedSize;
public Book[] books = new Book[10];//先固定数组里有10个
public BookList(){
//书籍可以随机给
books[0]=new Book("三国演义","罗贯中",10,"小说");
books[1]=new Book("西游记","吴承恩",23,"小说");
books[2]=new Book("红楼梦","曹雪芹",17,"小说");
this.usedSize = 3;
}
public int getUsedSize() {
return usedSize;
}
public void setUsedSize(int usedSize) {
this.usedSize = usedSize;
}
到这里,书和书籍暂时写完了。
现在要写用户操作了,先之前先往User包里写三个类:
Admin:管理员用户
Normal User:普通用户
User:是作为以上两个类的父类。
那么为什么要写这个User呢?
当然是为了使其代码职责分明、便于扩展
例如,两个用户子类中肯定包含菜单这个功能的,如果两个都写 menu方法会显得有些臃肿了,那么直接在User里写更好,让两个子类重写下就行了。
那么三个类代码如下:
public abstract class User {
//既然menu是抽象方法,那么这个类是抽象类
protected String name;
protected Ifunction[] ifunctions;
public User (String name){
this.name=name;
}
abstract public int menu();//这个menu是两个子类实现的,那么就直接定义为抽线方法,
}
public class Admin extends User{
public Admin(String name) {
super(name);
};
public int menu(){
System.out.println("*********2.管理员菜单*************");
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);
};
public int menu() {
System.out.println("*********2.普通用户菜单*************");
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;
}
}
这三个类暂时写完了,框架搭的七七八八了,那么解析哎来我们要如何将他们一一运行了组合起来了:
当然我们在目前的项目中直接创建个Main类来代表程序的运行的整合:
先上代码:
public static User Login() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的姓名:");
String name = scanner.nextLine();
System.out.println("请选择你的身份:1.管理员 2.普通用户");
int choice = scanner.nextInt();
if (choice == 1) {
Admin admin = new Admin(name);
return admin;
} else {
NormalUser normalUser = new NormalUser( name);
return normalUser;
}
}
public static void main(String[] args) {
BookList list = new BookList();
User user = Login();
while(true){
user.menu();
}
}
}
解释下为啥要这样做:
首先我们 构建一个login方法,在里面写登录的一些具体操作
比如,我们一开始给的图片里,开始语句不就是:请输入你的姓名,然后请选择你的身份
然后在我们的ifelse判断语句中,无论进入那个,都会实例化Admin或者NomalUser对象,所以自然而然将放回值设为User
接着在main方法里,肯定先实例化一个Booklist对象啦,然后在login()方法的返回值给到user引用,这样就进行了了向上转型,然后在while循环里我们就发生了动态绑定。
现在我们的框架已经基本做完了,运行的话,就会出现最初文章开头的两张图片。
接下来,实现下具体的功能内容。
同样在具体实现之前,先建立一个包:function
包内内容如图所示:
当然我们可想而知:一些管理员和普通用户共有的方法就不要写多一个了,直接就共用了。
那这个接口Ifunction什么意思呢?
想下,如果每个功能都是实现自己的方法,那就显得有些麻烦和臃肿,
那倒不如创建接口,里面写个work方法的声明,然后让每个类实现这个接口就行。
这些方面后续添加。
这个接口的代码如下:
public interface Ifunction {
void work(BookList list);
}
接下来,首先第一点怎么实现选择菜单的数字后,就能实现的相关操作呢。
那我们实在User这个类中实现,为啥呢?因为,管理员和普通用户都是继承这个User的,所以当我们在User里面实现下相关操作的方法声明,再到两个用户具体实现下。
那么User里面是咋样实现的呢?
请看代码:
public abstract class User {
protected String name;
protected Ifunction[] ifunctions;
public User (String name){
this.name=name;
}
abstract public int menu();
public void DoFunction(int choice, BookList list){
//既然是操作功能,肯定是要将书架传过去的。
this.ifunctions[choice].work(list);
}
}
代码里面声明一个接口数组,然后再实现一个操作功能的方法。
那么这个接口数组是咋样的,怎么用的?
请看两个用户的代码:
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
this.ifunctions = new Ifunction[]{
new Exit(),
new FIndBook(),
new LendBook(),
new ReturnBook()
};
//即在原有的代码上添加这段代码
}
public class Admin extends User{
public Admin(String name) {
super(name);
this.ifunctions=new Ifunction[]{
new Exit(),
new FIndBook(),
new AddBook(),
new DelBook(),
new ShowBook()
};
//同样在原有代码上进行添加即可
}
在两个用户中的代码中的接口数组中,我们初始化了一些已经实现Ifunction的类作为元素。
这里要说的是,当我们输入0的时候是要退出系统的,所以要将new Exit()实例对象放在前面。
当然你也可以将退出系统设置为其他数字。
接口数组是这个作用,那么操作功能的方法作用在哪呢
请看代码:
public static void main(String[] args) {
BookList list = new BookList();
User user = Login();
while(true) {
int choice= user.menu();
user.DoFunction(choice, list);
}
}
自然体现在这了,当我们将菜单打印出来后,在输入其他操作时,就可以调用这个方法,然后就可以操作这个接口数组,接口数组某个功能元素再被调用,然后具体功能就可以实现了。
ok,搞定这个后,我们接下来一一实现function里的类。
先实现管理员的吧:
第一个功能:添加图书
先看看我们是怎么样添加的吧。
我们在BookList中的books数组中显示:有书名、有作者、有价格、类型
所以我们按照这样的顺序来添加就是了。
代码:
public class AddBook implements Ifunction {
public void work(BookList list){
System.out.println("正在新增图书:");
if(list.isfull()){
System.out.println("图书已满,暂不能新增!");
return ;
}
System.out.println("请输入新增图书的名字:");
Scanner scanner=new Scanner(System.in);
String name=scanner.nextLine();
System.out.println("请输入新增图书的作者:");
String author=scanner.nextLine();
System.out.println("请输入新增图书的价格:");
int price=scanner.nextInt();
System.out.println("请输入新增图书的类型:");
String type=scanner.next();
//把书的信息放进Book
Book newbook=new Book(name,author,price,type);
//找到数组最后一个位置
int current=list.getUsedSize();
//得到的书放到数组最后一个位置
list.setBooks(current,newbook);
//不要忘了UsedSize+1
list.setUsedSize(current+1);
System.out.println("新增图书成功!");
}
}
代码中值得注意的点:如果我们的书架满了,就不能添加了。
还有这个isfull方法,我们要写在书架上这个类上:
代码所示:
public class BookList {
public boolean isfull(){
if(this.usedSize==books.length){
return true;
}
return false;
}
//同理,这段代码在原来的代码上添加即可。
}
第二个功能:删除图书
如何实现的呢?
我们得先找到书籍在哪,然后将把后一本书覆盖到前一本书,如此便可实现删除。
代码:
public class DelBook implements Ifunction{
public void work(BookList list){
System.out.println("删除图书中:");
System.out.println("请输入你要删除的图书:");
Scanner scanner=new Scanner(System.in);
String name=scanner.nextLine();
//找到删除书籍的下标
int current=list.getUsedSize();
int i=0;
int pos=-1;
for(i=0;i<current;i++){
Book book=list.getbook(i);
if(book.getName().equals(name)){
//找到这本书,记录下标
pos=i;
break;
}
}
if(i>=current){
System.out.println("你删除的书不存在!");
return;
}
//开始删除了
for(int j=pos;j< current-1;j++){
//后一本覆盖前一本书的数据
Book book=list.getbook(j+1);
list.setBooks(j,book);
}
list.setUsedSize(current-1);//不要忘了usedsize-1
list.setBooks(current-1,null);//真正意义的删除时把删除的书籍置为null
System.out.println("数据删除成功!");
}
}
值得注意的点:useized-1。
第三个功能:显示图书
怎么显示呢?
很显然用一个循环直接将书架上的书一个个打印出来即可。
public class ShowBook implements Ifunction {
public void work(BookList list){
System.out.println("图书信息如下:");
//知道当前有多少本书
int current=list.getUsedSize();
for(int i=0;i<current;i++){
Book book=list.books[i];
System.out.println(book);
}
}
}
接下来就是管理员和普通用户所共有的功能了。
第一个功能实现:查阅图书
怎么大概实现呢?
思路:找到图书就直接打印信息。
上代码:
public class FindBook implements Ifunction {
public void work(BookList list){
System.out.println("正在查找图书…………");
System.out.println("请输入你要查找的图书名:");
Scanner scanner=new Scanner(System.in);
String bookname=scanner.nextLine();
//要知道你找到书名的数组下标
int currentsized= list.getUsedSize();
boolean found=false;
for(int i=0;i<currentsized;i++){
Book book=list.books[i];
if(book.getName().equals(bookname)) {
System.out.println("找到这本书,信息如下:");
System.out.println(book);
found=true;
}
}
if(!found){
System.out.println("找不到你想要的书!");
}
}
}
值得注意的是,如果书架上有同名的书籍,应打印全部出来。
第二个功能实现:退出系统
那怎么退出呢?
同样的将我们书架上的每一个置为null,然后调用一个系统方法退出。
上代码:
public class Exit implements Ifunction{
public void work(BookList list){
System.out.println("退出系统中:");
//退出系统前每一本书都置为空
int current=list.getUsedSize();
for(int i=0;i<current;i++){
list.setBooks(i,null);
}
System.exit(0);
System.out.println("退出成功!");
}
}
里面有一个setbook方法,这个方法是将书架上一个元素置空.
public class BookList {
public void setBooks(int pos,Book book){
books[pos]=book;
//同样在原来的基础上增加即可
}
}
接下来是普通用户独有的功能
第一个功能:借阅图书
如何借阅呢?
输入你要借阅的图书名字,然后遍历书架,找到之后,把未借出的信息改为借出。
上代码:
public void work(BookList list){
System.out.println("借阅图书:");
System.out.println("请输入你要借阅的书籍:");
Scanner scanner=new Scanner(System.in);
String name=scanner.nextLine();
int current=list.getUsedSize();
for(int i=0;i<current;i++){
Book book=list.getbook(i);
if(book.getName().equals(name)){
if(!book.isLend()){
book.isreturn(true);
System.out.println("书籍借阅成功!");
return ;
}else{
System.out.println("书籍已借阅,无法再次借阅!");
return ;
}
}
}
System.out.println("借阅失败!");
}
}
当然,这里有一点要说的是,如果在程序运行过程中,你的书籍借阅过后,就不能再次借阅了,所以需要加一个判断语句进行判断。
那如何将执行呢?
那么我们在Book中加一个isreturn的方法:
public class Book {
public boolean isLend(){
return isLend;
}
//同样的在原来的基础上添加即可
}
然后呢,最后一个功能为:归还图书。
那么图书怎么归还呢?
很显然,和上面的借阅差不多。
输入你要归还的图书名字,然后遍历书架,找到之后,把借出的信息改为未借出。
上代码:
public class ReturnBook implements Ifunction{
public void work(BookList list){
System.out.println("归还图书中 :");
System.out.println("请输入归还书籍:");
Scanner scanner=new Scanner(System.in);
String name=scanner.nextLine();
int current=list.getUsedSize();
for(int i=0;i<current;i++){
Book book=list.getbook(i);
if(book.getName().equals(name)){
if(book.isLend()){
book.isreturn(false);
System.out.println("书籍归还成功!");
return;
}else {
System.out.println("书籍暂未借出,无法归还!");
return;
}
}
}
System.out.println("书籍归还失败!");
}
}
还需注意一个问题,就是当书籍没借出的时候,应该是不能归还的。
其实跟上面借阅的代码很类似的,只需把输出语句改一下内容即可。
至此,我们运行代码后,就可以成功运行一个图书管理系统的简易版本了。
完!