- 问题描述
- 解决思路
该问题模拟日常生活中快递柜取件问题。在程序中,有管理员和用户两个不同身份人员,能进行的操作也不同,为此可以使用switch-case语句进行判断然后进入不同的界面。而在管理员操作功能也有多个,可以再次使用switch-case语句,进行嵌套使用实现。不过为了更好的理解程序,在观看代码时思路不会混乱,可以将第二个switch-case语句包装成新的方法,在第一个语句中调用方法即可实现。
在程序的设计中采用MVC框架(模型-视图-控制器),V-放置页面显示的所有内容,包括欢迎页面、退出页面、身份选择页面、功能选择页面等等;M-放置与数据库操作有关的方法,即增删改查方法,各个方法之间没有鲁逻辑连接,逻辑连接通过控制器实现;最后通过C-调用M和V中的各个方法,实现各个页面的显示和功能。
使用MVC框架的好处:减少耦合性。各个页面的显示互不相关,增删改查的实现过程互不相关。在进行后期代码的修改,功能的添加删除等改动代码量大大减少。在进行代码的阅读时也能容易理解,每个功能模块可以单独理解,最后通过控制器的逻辑连接进行理解即可。 - 程序代码
视图展示Views.java
package com.vanessa.express;
import java.util.Scanner;
public class Views {
Scanner input = new Scanner(System.in);
/**
* 欢迎页面
*/
public void welcome(){
System.out.println("欢迎使用胡萝卜小区快递管理系统!");
}
/**
* 退出页面
*/
public void byebye(){
System.out.println("欢迎下次使用!");
}
/**
* 身份选择页面
* @return 0.退出 1.管理员 2.用户
*/
public int menu(){
System.out.println("请选择您的身份:0.退出 1.管理员 2.用户");
String text = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(text);
} catch (NumberFormatException e){ }
if(0>num || 2<num){
System.out.println("输入有误,请重新输入!");
menu();
}
return num;
}
/**
* 管理员功能选择页面
* @return 0.退出 1.快递录入 2.删除快递 3.修改快递 4.查看所有快递
*/
public int aMenu(){
System.out.println("请选择您要执行的操作:0.返回上级目录 1.录入快递 2.删除快递 3.修改快递 4.查看所有快递");
String text = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(text);
} catch (NumberFormatException e){ }
if(0>num || 4<num){
System.out.println("输入有误,请重新输入!");
aMenu();
}
return num;
}
/**
* 用户取快递页面
*/
public int uMenu(){
System.out.print("请输入您的取件码进行取件:");
String text = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(text);
} catch (NumberFormatException e){ }
if(100000>num || 9999999<num){
System.out.println("输入有误,请重新输入!");
uMenu();
}
return num;
}
/**
* 录入快递页面
* @return e
*/
public Express insert(){
System.out.print("请输入快递单号:");
String code = input.nextLine();
System.out.print("请输入快递公司:");
String company = input.nextLine();
Express e = new Express();
e.setCode(code);
e.setCompany(company);
return e;
}
/**
* 获取快递单号
* @return 快递单号
*/
public String findByCode(){
System.out.print("请输入要操作的快递单号:");
String code = input.nextLine();
return code;
}
/**
* 询问是否确认删除页面
* @return 0.退出 1.确认删除 2.取消操作
*/
public int delete(){
System.out.println("是否确认删除? 0.退出 1.确认删除 2.取消操作");
String text = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(text);
} catch (NumberFormatException e){ }
if(0>num || 2<num){
System.out.println("输入有误,请重新输入!");
delete();
}
return num;
}
/**
* 修改快递单号页面
* @return 修改后的快递
*/
public Express update(Express e){
System.out.print("请输入新的快递单号:");
String newCode = input.nextLine();
System.out.print("请输入新的快递公司:");
String company = input.nextLine();
e.setCode(newCode);
e.setCompany(company);
return e;
}
/**
* 打印快递信息
* @param e
*/
public void printExpress(Express e) {
if (e != null) {
System.out.println("快递信息如下,快递公司:" + e.getCompany() + ",快递单号:" + e.getCode() + ",取件码:" + e.getNumber());
}
}
/**
* 打印所有快递信息
* @param es
*/
public void printAll(Express[][] es){
if (es==null || es.length==0){
System.out.println("快递系统中暂无快递");
return;
}
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
if (es[i][j] != null) {
System.out.print("第" + (i + 1) + "排" + (j + 1) + "列");
printExpress(es[i][j]);
}
//printExpress(es[i][j]);
}
}
}
/**
* 删除快递成功页面
*/
public void deleteSuccess(){
System.out.println("已经成功删除快递!");
}
/**
* 取件成功页面
*/
public void successPickup(){
System.out.println("成功取件!");
}
/**
* 重复存储快递页面
*/
public void expressExist(){
System.out.println("此单号快递在快递柜中已经存在,请勿重复存储!");
}
/**
* 对应单号快递不存在页面
*/
public void expressNotExist(){
System.out.println("快递柜不存在此单号快递,请重新输入!");
}
}
数据存取
Express.java表示快递,其中包含有关快递的相关属性:快递单号、快递公司和取件码已经相关get()、set()、toString()等方法。
package com.vanessa.express;
import java.util.Objects;
public class Express {
private String company; //快递公司
private String code; //快递单号
private int number; //取件码
@Override
public String toString() {
return "Express{" +
"company='" + company + '\'' +
", code=" + code +
", number=" + number +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Express)) return false;
Express express = (Express) o;
return Objects.equals(code, express.code);
}
@Override
public int hashCode() {
return Objects.hash(code);
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
ExpressDao.java包含与数据库的操作方法,即增删改查(各个方法之间任何的逻辑,都是独立的)。
package com.vanessa.express;
import java.util.Random;
public class ExpressDao {
private Express[][] data = new Express[10][];
private int size; //当前存储的快递数
private Random random = new Random();
{
for (int i=0;i<10;i++){
data[i] = new Express[10];
}
}
/**
* 存取快递
* @param e
* @return 存快递成功则返回true,没有位置则返回false
*/
public boolean add(Express e){
if (size == 100){
return false;
}
int x = -1;
int y = -1; //随机生成快递所在行和列
while (true){
x = random.nextInt(10);
y = random.nextInt(10);
if (data[x][y] == null){//此位置无快递
break;
}
}
int number = randomNumber();
e.setNumber(number); //设置快递的取件码
data[x][y] = e;
size++;
return true;
}
/**
* 随机生成取件码
* @return 快递系统中不存在的取件码
*/
public int randomNumber(){
/*int number = random.nextInt(900000)+100000;
Express e = findByNumber(number);
if(e != null){
randomCode();//取件码已经存在,重新分配取件码
}
return number;*/
while (true){
int number = random.nextInt(900000)+100000;
Express e = findByNumber(number);
if(e == null){
return number;//取件码不重复,可以直接使用
}
}
}
/**
* 根据取件码查询快递
* @param number 取件码
* @return查询结果,查找到则返回快递信息,否则返回null
*/
public Express findByNumber(int number){
for (int i=0;i<10;i++){
for (int j=0;j<10;j++){
if(data[i][j] != null) {
if (data[i][j].getNumber() == number) {
return data[i][j];
}
}
}
}
return null;
}
/**
* 根据单号查询快递
* @param code 单号
* @return查询结果,查找到则返回快递信息,否则返回null
*/
public Express findByCode(String code){
Express e = new Express();
e.setCode(code);
for (int i=0;i<10;i++){
for (int j=0;j<10;j++){
if (e.equals(data[i][j])){
return data[i][j];
}
}
}
return null;
}
/**
* 删除快递
* @param e 需要删除的快递
*/
public void delete(Express e){
d:for (int i=0;i<10;i++){
for (int j=0;j<10;j++){
if (e.equals(data[i][j])){
data[i][j] =null;
size--;
break d;
}
}
}
}
/**
* 修改快递单号,思路:将要修改的快递删除,再将单号修改后重新添加
* @param oldE
* @param newE
*/
public void update(Express oldE,Express newE){
delete(oldE);
add(newE);
}
/**
* 查询所有快递信息
* @return 将每一个快递信息
*/
public Express[][] all(){
return data;
}
}
调度数据Main.java
用于将V和M联系起来的内容。通过用户的数字输入,跳转到不同的页面并实现相应的功能。
package com.vanessa.express;
public class Main {
private static Views v = new Views();
private static ExpressDao d = new ExpressDao();
public static void main(String[] args) {
v.welcome();
w:while (true) {
int menu = v.menu();
switch (menu) {
case 0:
break w;
case 1:
administrator();
break;
case 2:
user();
break;
}
}
v.byebye();
}
/**
* 用户各个功能实现
*/
private static void user() {
boolean b = true;
while (b) {
int number = v.uMenu();
Express e = d.findByNumber(number);
if (e == null) {
v.expressNotExist();
b = true;
} else {
v.printExpress(e);
v.successPickup();
d.delete(e);//取件成功后将该快递从快递柜中删除
b = false;
}
}
}
/**
* 管理员各个功能实现
*/
private static void administrator() {
while (true){
int menu = v.aMenu();
switch (menu){
case 0: return;//返回上一层
case 1: {//录入快递
Express e1 = v.insert();
Express e2 = d.findByCode(e1.getCode());//通过快递单号判断该快递是否已经存在
if (e2 == null){
d.add(e1);
v.printExpress(e1);
} else {//该单号快递已经存在快递柜中
v.expressExist();
}
}
break;
case 2: {//删除快递
boolean b = true;
while (b) {
String code = v.findByCode();//获取快递单号
Express e = d.findByCode(code);//在快递数组中通过快递单号查找快递
if (e == null) {//不存在该单号快递
v.expressNotExist();
b = true;
} else {
v.printExpress(e);
int type = v.delete();
if (type == 1) {
d.delete(e);
v.deleteSuccess();
}
b = false;
}
}
/*Express e = d.findByCode(code);
if (e == null){
v.expressNotExist();
} else {
v.printExpress(e);
int type = v.delete();
if (type == 1) {
d.delete(e);
v.deleteSuccess();
}
}*/
}
break;
case 3: {//修改快递
boolean b = true;
while (b) {
String code = v.findByCode();
Express e = d.findByCode(code);
if (e == null) {
v.expressNotExist();
b = true;
} else {
v.update(e);//调用该方法修改快递单号和快递公司
v.printExpress(e);
b = false;
}
}
}
break;
case 4: {//查看所有快递
Express[][] data = d.all();
v.printAll(data);
}
break;
}
}
- 遇到的问题
(1)空指针问题
问题描述:当快递为空时,调用get方法获取数据进行条件判断时出错。解决方法:在进行if前添加语句if(data[i][j] !=null)进行判断,可使进入判断语句中的data[i][j]均不为空。
问题描述:在135行代码中,当快递为空时,调用get方法出现。
解决方法:先判断再进行输出。
(2)逻辑问题
问题描述:在进行删除快递操作时,如果输入单号错误,进入了修改单号操作。
原因:break放在整个操作里面,在中括号之中判断语句未执行到break无法退出,直接进行到下一个case,即修改快递单号的操作中。
解决方法:将break移至中括号外,待case执行完所有语句后执行。
5. 进一步完善
在进行取件操作时,如果输入的取件码是错误的,会返回至身份选择页面,想要实现:当输入取件码错误后,输出提示信息并重新让用户输入取件码。
在删除快递操作时,快递信息不存在时返回至上一层。
在修改快递操作时,快递信息不存在时返回至上一层。
以上使用while循环语句进行即可,创建boolean变量继续判断是否进行下一次循环,如果输入错误,则将boolean变量赋值为true使其进入下一次循环;如果输入正确,则将boolean变量赋值为false,退出循环。
6. 小总结
通过该实验的学习过程,对于Java编程规范有了更深的理解,编程的习惯也更规范化。代码仍存在一定的不完善之处,大家共同进步!