一.案例说明
本案例并主要是对集合的综合运用,并且实现集合的CRUD功能。也是对javaEE基础知识的综合运用,运用面向对象的思想(面向过程分析,以及封装、继承、多态)实现简单的需求分析。
本案例也存在一些bug,一些细节后续再改进(修改版本1.3)。
二.案例需求分析
根据功能先划分类别(封装不同的类来实现不同的需求)。
1.Country类
用于封装各个国家信息的数据。
2.Check类
这是专门用于对录入的信息进行校验。
3.OperationMethod类
操作方法类,所有功能的实现都封装在这个类中。包括添加奥运奖牌信息、查看奥运奖牌信息、修改奥运奖牌信息、删除奥运奖牌信息、返回功能、继续录入功能等。
4.Menu类
包括主菜单、二级菜单、返回菜单等。
5.StartSMS类
这是主程序,用于测试程序运行的类。
三.代码实现(所有的类都在一个包下,cn.jason)
1.country类
package cn.jason;
/**
* 这是封装所有国家信息的类
*
* @blog http://blog.csdn.net/yan_yuhan
* @author Jason
* @version 1.2
* @2016年9月15日 上午0:41:13
*/
public class Country {
// 定义国家名称
private String countryName;
// 定义金牌数
private String gold;
// 定义银牌数
private String sliver;
// 定义铜牌数
private String copper;
// 定义奖牌总数,按照奖牌总数排序
private int medalSum;
// 国家类的无参构造
public Country() {
super();
}
// 国家类的有参构造
public Country(String countryName, String gold, String sliver, String copper) {
super();
this.countryName = countryName;
this.gold = gold;
this.sliver = sliver;
this.copper = copper;
}
// get和set方法
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public String getGold() {
return gold;
}
public void setGold(String gold) {
this.gold = gold;
}
public String getSliver() {
return sliver;
}
public void setSliver(String sliver) {
this.sliver = sliver;
}
public String getCopper() {
return copper;
}
public void setCopper(String copper) {
this.copper = copper;
}
public int getMedalSum() {
return Integer.parseInt(gold) + Integer.parseInt(sliver) + Integer.parseInt(copper);
}
// 重写toString方法
@Override
public String toString() {
return "国家名字是: " + countryName + "\t金牌奖牌数是:" + gold + "\t银牌数是:" + sliver + "\t铜牌数是:" + copper;
}
}
2.Check类
package cn.jason;
import java.util.Scanner;
/**
* 这是用于对信息校验的类
*
* @blog http://blog.csdn.net/yan_yuhan
* @author Jason
* @version 1.2
* @2016年9月15日 上午0:41:13
*/
public class Check {
// 创建键盘录入对象
private Scanner sc = new Scanner(System.in);
/**
* 这是校验录入的字符串是否为符合中文要求
*/
public boolean judgeString(String countryName) {
// 定义匹配中文的正则表达式
String regex = "[\u4e00-\u9fa5]+";
// 对字符串进行校验
if (!countryName.matches(regex)) {
System.out.println("你输入的不符合要求,这是中文版系统,请输入中文国家名称:");
return false;
}
return true;
}
/**
* 这是校验奖牌数量是不是数字的方法
*
* @param string
* 传过来的参数
*/
public boolean judgeInteger(String string) {
// 定义匹配数字的正则表达式
String regex = "\\d+";
// 对字符串进行校验
if (!string.matches(regex)) {
System.out.println("你输入的不符合要求,这是中文版系统,请输入中文国家名称:");
return false;
}
return true;
}
}
3.OperationMethod类
package cn.jason;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;
import java.util.Scanner;
import java.util.TreeSet;
/**
* 这是用户操作的类
*
* @blog http://blog.csdn.net/yan_yuhan
* @author Jason
* @version 1.2
* @2016年9月15日 上午0:41:13
*/
public class OperationMethod {
// 创建集合对象
// 这里集合必须是静态,静态保证只要一个对象。如果不是静态,多个类之间调用会出现多次创建集合对象,导致元素读取异常。
public static List<Country> list = new ArrayList<Country>();
// 创建校验类对象
private static Check check = new Check();
// 创建键盘录入对象
private Scanner sc = new Scanner(System.in);
/**
* 这是添加国家信息的方法
* 分别对字符串进行校验,如果校验成功。那么直接把国家的名称、金牌、银牌
* 铜牌的数量信息封装到国家对象中,然后把国家对象存储到集合中。
*/
public void addCountryIfo() {
// 录入国家名称
System.out.println("请输入国家名称:");
String countryName = sc.nextLine();
// 校验字符串是否正确
if (!check.judgeString(countryName))
addCountryIfo();
// 查看录入的信息是否重复
for (Country country : list) {
if (countryName.equals(country.getCountryName())) {
System.out.println("你添加的国家姓名已经存在");
addCountryIfo();
}
}
// 对金牌、银牌、铜牌的校验
boolean flag = false;
String gold = null;
String sliver = null;
String copper = null;
while (true) {
// 录入金牌数量
System.out.println("请输入金牌数量:");
gold = sc.nextLine();
// 对金牌的数据类型进行校验
if (check.judgeInteger(gold))
break;
}
while (true) {
// 录入银牌数量
System.out.println("请输入银牌数量:");
sliver = sc.nextLine();
// 对银牌的数据类型进行校验
if (check.judgeInteger(sliver))
break;
}
while (true) {
// 录入铜牌数量
System.out.println("请输入铜牌数量:");
copper = sc.nextLine();
// 对铜牌的数据类型进行校验
if (check.judgeInteger(copper))
break;
}
// 把国家信息封装到国家对象中
Country c = new Country(countryName, gold, sliver, copper);
// 把封装好的国家对象存储到集合中
list.add(c);
// 调用继续输入菜单
continueInput();
}
/**
* 这是继续输入的方法
* 当提示是否继续添加元素时,如果输入"y",那么调用添加功能继续添加元素。 如果输入"n",那么调用返回上一级菜单。
* 否则进行信息错误提示,要求重新输入。
*/
public void continueInput() {
System.out.println("是否继续添加元素?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
// 调用增加元素的方法
addCountryIfo();
else if (choice.equalsIgnoreCase("n")) {
// 调用返回菜单
new Menu().returnMain();
} else {
System.out.println("你输入有误,请重新输入");
// 调用再次输入方法
continueInput();
}
}
/**
* 这是查找全部信息的方法
* 如果集合长度大于0,那么输出排好序的信息。否则进行错误提示。
*/
public void findAll() {
// 先对集合长度进行判断
if (list.size() > 0)
// 如果长度大于0就遍历集合,并且对元素按照金牌总数排序
SortMedal(list);
else
// 对错误信息进行提示
System.out.println("没有任何国家信息");
//返回上一级菜单
new Menu().returnFindMenu();
}
/**
* 这是查询奥运奖牌信息的方法
* 当提示是否要全部查看信息时,进行匹配字符串,如果是"y",那么查看全部信息。 如果是"n",那么进行逐个查看。
* 对集合长度判断是否大于0,如果集合还没有录入数据,那么不应该继续输入,所以进行校验。
*/
public void findSingle() {
// 定义布尔标记
boolean flag = false;
do {
// 接收录入数据
System.out.println("请输入要查看国家的名称:");
String newCountryName = sc.nextLine();
// 校验字符串是否符合要求
if (check.judgeString(newCountryName)) {
flag = true;
}
if (list.size() > 0) {
// 遍历集合
for (Country country : list) {
if (country.getCountryName().equals(newCountryName)) {
System.out.println(country);
flag = true;
break;
}
}
} else {
System.out.println("抱歉,没有国家信息");
break;
}
// 提示是否继续查看下一个国家信息
System.out.println("是否要继续查看下一个国家信息?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
flag = false;
if (choice.equalsIgnoreCase("n"))
break;
else
System.out.println("你输入有误,请重新输入");
} while (!flag);
//返回查询菜单
new Menu().returnFindMenu();
// 调用返回主菜单方法
new Menu().returnMain();
}
/**
* 这是按照金牌总数排序的方法
* 先创建TreeSet集合对象,把list集合的数据存储到TreeSet集合中排好序,
* 然后遍历TreeSet集合输出数据。
*/
public void SortMedal(List<Country> list) {
// 用TreeSet集合进行排序
TreeSet<Country> ts = new TreeSet<Country>(new Comparator<Country>() {
@Override
public int compare(Country o1, Country o2) {
return o2.getMedalSum() - o1.getMedalSum();
}
});
// 把list集合元素存储到TreeSet集合
for (Country country : list) {
ts.add(country);
}
// 遍历TreeSet集合,输出数据
for (Country country : ts) {
System.out.println(country);
}
}
/**
* 这是修改金牌数量的方法
* 先对国家名称进行校验,校验正确后录入金牌的数量 然后遍历集合进行移除原集合的信息,在添加新的金牌数量存储到集合中
* 最后进行提示,修改成功,返回上一级菜单。
*/
public void modifyGold() {
// 接收校验正确的国家名称
String newCountryName = retrunCountryName();
String gold = null;
while (true) {
// 录入金牌数量
System.out.println("请输入金牌数量:");
gold = sc.nextLine();
// 校验字符串
if (check.judgeInteger(gold))
break;
}
// 遍历集合进行修改金牌数量
for (Country country:list) {
if (country.getCountryName().equals(newCountryName)) {
// 添加新的信息
country.setGold(gold);
break;
}
}
// 对修改操作进行提示
System.out.println("修改成功");
// 返回修改菜单
new Menu().returnModifyGoldMenu();
// 返回主菜单
new Menu().returnMain();
}
/**
* 这是修改银牌数量的方法
* 先对国家名称进行校验,校验正确后录入金牌的数量 然后遍历集合进行移除原集合的信息,在添加新的银牌数量存储到集合中
* 最后进行提示,修改成功,返回上一级菜单。
*/
public void modifySliver() {
// 拿到校验好的国家名称
String newCountryName = retrunCountryName();
String sliver = null;
while (true) {
// 录入金牌数量
System.out.println("请输入银牌数量:");
sliver = sc.nextLine();
// 校验字符串
if (check.judgeInteger(sliver))
break;
}
// 遍历集合进行修改金牌数量
for (Country country:list) {
if (country.getCountryName().equals(newCountryName)) {
country.setSliver(sliver);
break;
}
}
System.out.println("修改成功");
// 返回修改菜单
new Menu().returnModifySliverMenu();
// 返回主菜单
new Menu().returnMain();
}
/**
* 这是修改铜牌数量的方法
* 先对国家名称进行校验,校验正确后录入金牌的数量 然后遍历集合进行移除原集合的信息,在添加新的铜牌数量存储到集合中
* 最后进行提示,修改成功,返回上一级菜单。
*/
public void modifyCopper() {
// 拿到校验好的国家名称
String newCountryName = retrunCountryName();
String copper = null;
while (true) {
// 录入金牌数量
System.out.println("请输入铜牌数量:");
copper = sc.nextLine();
// 校验字符串
if (check.judgeInteger(copper))
break;
}
// 遍历集合进行修改金牌数量
for (Country country:list) {
if (country.getCountryName().equals(newCountryName)) {
country.setCopper(copper);
break;
}
}
System.out.println("修改成功");
// 返回修改菜单
new Menu().returnModifyCopperMenu();
// 返回主菜单
new Menu().returnMain();
}
/**
* 这是对奖牌数量修改时,对重复代码进行封装的一个返回国家名称方法
* 对金牌、银牌、铜牌进行修改时,都要验证国家名称才能修改。
*
* @return 校验好的国家名称
*/
public String retrunCountryName() {
// 定义标记控制循环
boolean flag = false;
String newCountryName = null;
do {
System.out.println("请输入要修改的国家名称:");
newCountryName = sc.nextLine();
if (check.judgeString(newCountryName)) {
// 遍历集合并且对国家名称进行校验
for (Country country : list) {
if (country.getCountryName().equals(newCountryName)) {
flag = true;
break;
}
}
if (!flag) {
// 对错误信息进行校验
System.out.println("抱歉,你输入的国家信息不存在");
// 返回修改菜单
new Menu().returnModifyGoldMenu();
// 返回主菜单
new Menu().returnMain();
}
}
} while (!flag);
return newCountryName;
}
/**
* 这是清除全部信息的方法
* 当要求输入时,输入"y",那么清除全部信息。如果输入"n",那么返回清除菜单。否则进行错误提示,要求重新输入。
* 此方法没有管理员权限,所以可以直接清除。登录注册信息后续改进。
*
*
*
*
*/
public void clearAll() {
// 定义一个布尔标记
boolean flag = false;
do {
System.out.println("是否要清除全部信息?清除后不可恢复,请慎重。y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y")) {
// 如果是,那么清除全部信息
list.clear();
flag = true;
// 清除提示
System.out.println("清除成功");
}
if (choice.equalsIgnoreCase("n")) {
flag = true;
}
if (!flag)
System.out.println("你输入有误,请重新输入");
} while (!flag);
// 返回清除菜单
new Menu().returnClearMenu();
}
/**
* 这是清除单个奥运信息的方法
* 当提示是否要全部清除。当国家名称匹配后进行清除。如果匹配不成功,那么进行错误提示,要求重新输入。
* 然后进行下一步操作
*/
public void clearSingle() {
// 定义一个布尔标记
boolean flag = false;
String newCountryName = null;
while (true) {
// 接收信息提示
System.out.println("请输入要清除的国家名称:");
newCountryName = sc.nextLine();
// 对字符串进行校验
if (check.judgeString(newCountryName))
break;
}
// 对修改后的操作进行提示
for (Country country : list) {
if (country.getCountryName().equals(newCountryName)) {
// 清除当前国家对象
list.remove(country);
System.out.println("清除成功");
flag = true;
break;
}
}
// 如果没有匹配成功,那么对错误信息进行提示
if (!flag)
System.out.println("你输入有误,没有此信息");
// 返回清除菜单
new Menu().returnClearMenu();
// 返回主菜单
new Menu().returnMain();
}
}
4.Menu类
package cn.jason;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Scanner;
/**
* 这是系统所有菜单的类
*
* @blog http://blog.csdn.net/yan_yuhan
* @author Jason
* @version 1.2
* @2016年9月15日 上午0:41:13
*/
public class Menu {
// 创建键盘录入对象
private Scanner sc = new Scanner(System.in);
// 创建操作类对象
private static OperationMethod om = new OperationMethod();
/**
* 这是主菜单的方法 分别显示五级菜单供客户选择。
*/
public void mainMenu() {
System.out.println("**-------------欢迎来到奥运奖牌中文信息系统-------------**\n");
System.out.println("\t\t1.添加奥运奖牌信息\n");
System.out.println("\t\t2.查看奥运奖牌信息\n");
System.out.println("\t\t3.修改奥运奖牌信息\n");
System.out.println("\t\t4.删除奥运奖牌信息\n");
System.out.println("\t\t5.退出系统");
System.out.println("请选择:");
// 调用二级菜单
secondMenu();
}
/**
* 这是根据主菜单做出相应选择的菜单
* 对用户的选择进行判断,分别执行不同的功能模块。
*/
public void secondMenu() {
// 创建标记
boolean flag = false;
do {
// 接收录入的数据
String choice = sc.nextLine();
// 对选择进行switch语句判断
switch (choice) {
case "1":
// 调用添加元素的方法
om.addCountryIfo();
break;
case "2":
// 调用查询菜单
findMenu();
break;
case "3":
// 调用修改菜单
modifyMenu();
break;
case "4":
// 调用清除菜单
clearMenu();
break;
case "5":
// 退出系统提示
System.out.println("欢迎使用奥运奖牌信息系统");
break;
default:
//对错误信息提示
System.out.println("你输入有误,请重新输入");
flag = true;
break;
}
} while (flag);
}
/**
* 这是查找信息的菜单
* 根据用户的选择进行执行相关模块
*/
public void findMenu() {
System.out.println("**-------------查看奥运奖牌信息>查看方式-------------**\n");
System.out.println("\t\t1.全部查看\n");
System.out.println("\t\t2.部分查看\n");
System.out.println("请选择,输入数字或按'n'返回上一级菜单:");
// 对用户的选择进行判断,分别执行不同的功能模块。
findSecondMenu();
}
/**
* 这是查找菜单的子菜单的方法
* 对用户的选择进行判断,分别执行不同的功能模块。
*/
public void findSecondMenu() {
// 定义标记控制循环
boolean flag = false;
do {
// 接收录入的数据
String choice = sc.nextLine();
// 对选择进行选择性判断,并执行不同的模块
switch (choice) {
case "1":
//执行全部查找,并且按照奖牌总数排序
om.findAll();
break;
case "2":
//调用单个查找方法
om.findSingle();
break;
case "n":
// 返回主菜单
mainMenu();
break;
default:
// 进行错误提示
System.out.println("你输入有误,请重新输入");
flag = true;
break;
}
} while (flag);
}
/**
* 这是返回查找菜单的方法
* 如果输入"y",那么返回查找菜单,如果是"n",那么返回主菜单,否则输入有误,要求重新输入
*/
public void returnFindMenu() {
// 定义标记
boolean flag = false;
System.out.println("是否返回查看菜单?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
findMenu();
// 如果是,返回主菜单
else if (choice.equalsIgnoreCase("n")) {
// 如果不是,那么继续进行单个清除
returnMain();
} else {
// 对错误信息进行提示
System.out.println("你输入有误,请重新输入");
returnFindMenu();
}
}
/**
* 这是修改奥运奖牌信息的子菜单
* 根据用户的选择,执行相应的模块
*/
public void modifyMenu() {
System.out.println("**-------------修改奥运奖牌信息>修改方式-------------**\n");
System.out.println("\t\t1.修改金牌数量\n");
System.out.println("\t\t2.修改银牌数量\n");
System.out.println("\t\t3.修改铜牌数量\n");
System.out.println("请选择,输入数字或按'n'返回上一级菜单:");
// 对用户的选择进行判断,分别执行不同的功能模块。
modifySecondMenu();
}
/**
* 这是对修改菜单进行相应操作的方法
* 对用户的选择进行判断,分别执行不同的功能模块。
*/
public void modifySecondMenu() {
// 定义标记控制循环
boolean flag = false;
do {
// 接收录入的数据
String choice = sc.nextLine();
// 对选择进行选择性判断,并执行不同的模块
switch (choice) {
case "1":
// 调用修改金牌数量功能
om.modifyGold();
break;
case "2":
// 调用修改银牌数量功能
om.modifySliver();
break;
case "3":
// 调用修改铜牌数量功能
om.modifyCopper();
break;
case "n":
// 返回主菜单
mainMenu();
break;
default:
// 进行错误提示
System.out.println("你输入有误,请重新输入");
flag = true;
break;
}
} while (flag);
}
/**
* 这是判断是否返回修改金牌数量的菜单
*/
public void returnModifyGoldMenu() {
// 定义布尔标记
boolean flag = false;
System.out.println("是否返回修改菜单?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
// 如果是,返回修改主菜单
modifyMenu();
else if (choice.equalsIgnoreCase("n")) {
// 如果不是返回修改菜单,继续进行修改金牌数量
om.modifyGold();
} else {
// 对错误进行提示
System.out.println("你输入有误,请重新输入");
returnModifyGoldMenu();
}
}
/**
* 这是判读是否返回修改银牌数量的菜单
*/
public void returnModifySliverMenu() {
// 定义标记
boolean flag = false;
System.out.println("是否返回修改菜单?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
// 如果是,返回修改主菜单
modifyMenu();
else if (choice.equalsIgnoreCase("n")) {
// 如果不是,继续进项银牌数量修改功能
om.modifySliver();
} else {
// 对错误信息进行提示
System.out.println("你输入有误,请重新输入");
returnModifySliverMenu();
}
}
/**
* 这是判断是否返回修改铜牌数量的菜单
*/
public void returnModifyCopperMenu() {
// 定义标记
boolean flag = false;
System.out.println("是否返回修改菜单?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
// 如果是,返回修改主菜单
modifyMenu();
else if (choice.equalsIgnoreCase("n")) {
// 如果不是,继续进行铜牌数量的修改
om.modifyCopper();
} else {
// 对错误信息进行提示
System.out.println("你输入有误,请重新输入");
returnModifyCopperMenu();
}
}
/**
* 这是清除菜单的子菜单
* 根据用户不同的选择,执行相应的模块
*/
public void clearMenu() {
System.out.println("**-------------删除奥运奖牌信息>删除方式-------------**\n");
System.out.println("\t\t1.清除全部信息\n");
System.out.println("\t\t2.清除单个信息\n");
System.out.println("请选择,输入数字或按'n'返回上一级菜单:");
// 调用二级菜单
clearSecondMenu();
}
/**
* 这是清除菜单执行方式的方法
* 根据不同的选择,执行相应的功能
*/
public void clearSecondMenu() {
// 定义标记控制循环
boolean flag = false;
do {
// 接收录入的数据
String choice = sc.nextLine();
// 对选择进行选择性判断,并执行不同的模块
switch (choice) {
case "1":
//调用全部清除功能
om.clearAll();
break;
case "2":
//调用单个清除的功能
om.clearSingle();
break;
case "n":
// 返回主菜单
mainMenu();
break;
default:
// 进行错误提示
System.out.println("你输入有误,请重新输入");
flag = true;
break;
}
} while (flag);
}
/**
* 这是是否返回清除菜单的方法
* 如果输入"y",那么返回清除菜单。如果是"n",那么返回主菜单
* 否则进行错误提示,要求重新输入。
*/
public void returnClearMenu() {
// 定义标记
boolean flag = false;
System.out.println("是否返回清除菜单?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
// 如果是,返回主菜单
clearMenu();
else if (choice.equalsIgnoreCase("n")) {
// 如果不是,那么继续进行当个清除
returnMain();
} else {
// 对错误信息进行提示
System.out.println("你输入有误,请重新输入");
returnClearMenu();
}
}
/**
* 这是返回上主菜单的方法
* 当提示是否返回上一级菜单时,如果输入"y",那么直接返回主菜单。 如果输入"n",那么直接退出系统
*/
public void returnMain() {
// 定义标记
boolean flag = false;
System.out.println("是否返回主菜单?y/n");
String choice = sc.nextLine();
if (choice.equalsIgnoreCase("y"))
// 如果是,返回主菜单
mainMenu();
else if (choice.equalsIgnoreCase("n")) {
// 如果不是,退出系统
System.out.println("欢迎使用奥运奖牌信息系统");
} else {
// 对错误信息进行提示
System.out.println("你输入有误,请重新输入");
returnMain();
}
}
}
5.StartSMS类
package cn.jason;
/**
* 这是系统启动类
*
* @blog http://blog.csdn.net/yan_yuhan
* @author Jason
* @version 1.2
* @2016年9月15日 上午0:46:52
*/
public class StartSMS {
public static void main(String[] args) {
// 创建菜单对象
Menu menu = new Menu();
// 调用主菜单
menu.mainMenu();
}
}
四.案例截图
五.归纳总结
1.类中多次使用的对象可以以静态成员变量出现在成员位置。两个类中的成员位置要是创建对象,不能相互调用。否则会出现每一次调用每一次重新创建对象,尤其是集合会出现信息读写异常。
2.功能方法独立封装
多个功能要多次使用就单独封装一个方法,避免方法乱用,导致代码不明确。如多级菜单返回,单独封装返回菜单。