第二次blog作业
1.前言
作为一个java和面向对象的初学者,在写题目这方面确实是处处碰壁,但学习最重要的是坚持,希望我能够坚持下去。对于这三次的题目集,就难度而言是比较难的,难在一些测试点需要经过深层次的思考,还要通过大量的测试测试出来,必须承认的是考到的一些知识在题目中都有相应的提示,不去仔细琢磨的话就容易吃亏。题量倒是不大,最占用时间的就是那两个菜单程序,需要花费很多时间,而且缺少连续的
时间去专心去写,会导致做题思路断掉,这也会浪费一些时间。对于知识点的考察也不算太难,主要有正则表达式,程序的封装性,还有组合,聚合关系的应用,字符串的相关处理等。还是第五次题目集好点,相应的难度较低,其他两次由于有菜单计价在所以难度成直线上升。
2.设计与分析
7-1 菜单计价程序-3
这个题目的命名为3,在当时看到的时候我就在怀疑是否有1-2,后面出了4发现确实是缺少了,难度一下就激增了,差点就放弃了。先说下对于数据的处理,这个题目的难点在于对于字符串数据的处理和代点菜,判断读取到的字符串所包含的信息从而实现数据录入。首先就是判断菜单与桌号的问题,本次
作业由于不考虑格式错误和数据非法,所以可以直接录入菜单信息,这里需要注意读取相同菜名的时候需要更新菜单价格,然后再读取到table的时候就跳出读取菜名的循环,接着进入读取点菜信息,对于桌号判断只需要判断以下在不在时间范围内就行,其他没有会出问题的地方。点菜记录字符串有多种长度
,2为删除记录,4为本桌点菜,5为代点菜,先判断长度,再根据长度进行数据的录入,点菜记录重复删除就输出delete error;,可能
会有多桌菜,所以要再加一个判断在点菜记录里面,或者加在你的循环条件中。最后读取到end时,跳出所有循环,再开始输出相关的桌号的总价。类的结构呢,可能就是
桌类::记录时间和桌号(感觉时间应该放在订单里,当时写得有点着急)
订单类:记录点菜记录
点菜记录类:点菜序号,点菜的菜品,份额,份数,是否被删
代点菜记录类:点菜序号,点菜的菜品,份额,份数,是否被删,被点桌序号
菜单类:静态的菜单
菜品类:菜名,单价
类图:
SourceMonitor:
在上面的类图中,我将对于处理数据的一些函数和过程大部分放在了主函数,感觉这像是面向过程编程,还是得慢慢改过来,还有使用对象数组储存对象,推荐使用ArrayList,这里我为了对应题目所给代码提示,选择使用对象数组,在使用过程中带来了很大的不便,所以要用好用的东西,还有桌类和order类,我感觉可以混合在一起,这里我为了区分打折功能和储存点菜数据,分成了两个类,便于后期修改和完善。
代码如下,觉得太长请折叠,就在代码右上角
import java.util.Scanner;
import java.time.*;
import java.time.LocalDate;
import java.time.LocalTime;
public class Main{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Table tables[] = new Table[0]; //设置一个餐桌对象数组
Menu menu = new Menu(); //创建一个菜单类
String s = in.nextLine();
while(s.indexOf("table")==-1) { //更新菜单
menu.updateMenu(s);
s = in.nextLine();
if(s.equals("end"))
System.exit(0);
}
while(s.indexOf("end")==-1) { //订单处理
Table table = new Table();
table.setDateTime(s);
System.out.println("table "+table.getNum()+": ");
s = in.nextLine();
while(s.indexOf("table")==-1&&s.indexOf("end")==-1&&s.split(" ").length==2) { //判断菜品是否更新
menu.updateMenu(s);
s = in.nextLine();
}
int count = 0,count1 = 0;
while(s.indexOf("table")==-1&&s.indexOf("end")==-1) { //判断是否进行下一个订单或结束
if(s.indexOf("delete")!=-1) {
table.getOrder().deleteRecord(s,menu);
}else {
if(s.split(" ").length==4) {
table.getOrder().updateRecord(s);
if(table.getOrder().getRecord(count).getExit()==1)
System.out.println(table.getOrder().getRecord(count).getOrderNum()+" "+table.getOrder().getRecord(count).getD().getName()
+" "+table.getOrder().getRecord(count).getPrice1());
else
System.out.println(table.getOrder().getRecord(count).getName()+" does not exist");
count++;
}
else {
table.getOrder().updateOtherRecord(s); //更新餐桌信息
if(table.getOrder().getOtherRecord(count1).getExit()==1)
System.out.println(table.getOrder().getOtherRecord(count1).getOrderNum()+" table "+
table.getNum()+" pay for table "+table.getOrder().getOtherRecord(count1).getTableNum()
+" "+table.getOrder().getOtherRecord(count1).getPrice1());
else
System.out.println(table.getOrder().getOtherRecord(count1).getName()+" does not exist");
}
}
s = in.nextLine();
}
table.setTotal();
tables = Main.updateTables(tables,table);
}
if(tables!=null) {
for(int i =0;i<tables.length;i++)
if(!tables[i].checkOrderTime())
System.out.println("table "+tables[i].getNum()+" out of opening hours");
else
System.out.println("table "+tables[i].getNum()+": "+
tables[i].getTotal());
}
}
public static Table[] updateTables(Table []tables,Table table) { //在餐桌类数组中加入对象
int num = 0;
if(tables!=null)
num = tables.length;
Table []tables1 = new Table[num+1]; //更新桌信息
for(int i = 0;i<num;i++) {
tables1[i] = tables[i];
}
tables1[num] = table;
return tables1;
}
}
class Order { //订单类
private Record[] records = new Record[1]; //保存订单上每一道的记录
private OtherRecord[] other_records = new OtherRecord[1];//保存代点菜信息
public Record getRecord(int i) {
return records[i];
}
public OtherRecord getOtherRecord(int i) { //获得代点信息
return other_records[i];
}
int getTotalPrice(int discount) { //计算订单的总价
int num = 0;
for(Record record:records) {
if(record.getExit()==1)
num+=record.getPrice();
}
if(other_records!=null)
for(OtherRecord otherRecord:other_records) //获得为它桌点菜的价钱
if(otherRecord.getExit()==1)
num+=otherRecord.getPrice1();
return (int)(discount/10.0*num+0.5);
}
public void updateRecord(String s) { //更新点菜信息
int num = 0;
if(records!=null)
num = records.length;
Record[] records1 = new Record[num+1]; //更新数组
for(int i =0;i<num;i++)
records1[i] = records[i];
String str[] = s.split(" ");
if(Menu.searchDish(str[1])!=null) { //判断是否存在该菜品
records1[num] = addRecord(Integer.parseInt(str[0]),Menu.searchDish(str[1]),
Integer.parseInt(str[2]),Integer.parseInt(str[3]));
}else {
records1[num] = addRecord(Integer.parseInt(str[0]),null,
Integer.parseInt(str[2]),Integer.parseInt(str[3]));
records1[num].setExit(0);
records1[num].setName(str[1]);
}
records = records1;
}
public Record addRecord(int n,Dish dish,int portion,int num) { //设置一个新的记录
return new Record(n,dish,portion,num);
}
public OtherRecord addOtherRecord(int table,int n,Dish dish,int portion,int num) {
return new OtherRecord(table,n,dish,portion,num); //设置一个新的代点菜记录
}
public void updateOtherRecord(String s) { //更新代点信息
int num = 0;
if(other_records!=null)
num = other_records.length;
OtherRecord[] other_records1 = new OtherRecord[num+1]; //更新数组,增添元素
for(int i =0;i<num;i++)
other_records1[i] = other_records[i];
String str[] = s.split(" ");
if(Menu.searchDish(str[2])!=null) { //判断是否存在该菜品
other_records1[num] = addOtherRecord(Integer.parseInt(str[0]),
Integer.parseInt(str[1]),Menu.searchDish(str[2]),
Integer.parseInt(str[3]),Integer.parseInt(str[4]));
}else {
other_records1[num] = addOtherRecord(Integer.parseInt(str[0]),
Integer.parseInt(str[1]),null,
Integer.parseInt(str[3]),Integer.parseInt(str[4]));
other_records1[num].setExit(0);
other_records1[num].setName(str[2]);
}
other_records = other_records1;
}
public void deleteRecord(String s,Menu menu) { //删除本桌点菜信息
int count = 0;
String []str = s.split(" ");
if(records!=null) {
for(int i=0;i<records.length;i++)
if(records[i].getOrderNum()==Integer.parseInt(str[0])&&records[i].getExit()==1) {
records[i].setDelete(0);
count =1;
}
if(count!=1){
if(other_records!=null)
for(OtherRecord r1:other_records) //判断为其它桌点菜的记录
if(r1.getOrderNum()==Integer.parseInt(str[0])&&r1.getExit()==1){
r1.setDelete(0);
r1.setExit(0);
count = 2;
}
if(count!=2||other_records==null)
System.out.println("delete error;");
}
}
}
}
class Record { //点菜记录类
private int orderNum; //序号\\
private Dish d; //菜品\\
private int portion; //份额(1/2/3代表小/中/大份)\\
private int dishnum ; //份数
private int delete = 1; //标记取消此条点菜信息
private int exit = 1; //标记当前点餐消息是否为真
private String name;
public int getExit() { //获得当前点餐消息是否为真
return exit;
}
public void setExit(int exit) { //设置是否被删,或菜品不存在
this.exit = exit;
}
public Record(int n,Dish dish,int portion1,int num1){ //构造方法
this.orderNum = n;
this.d = dish;
this.portion = portion1;
this.dishnum = num1;
}
int getPrice() { //获得本次点菜实际金额
return d.getPrice(portion,dishnum,delete);
}
int getPrice1() { //获得本次点菜客观金额(还未被删)
return d.getPrice(portion, dishnum);
}
public int getOrderNum() { //获得点菜序号
return orderNum;
}
public Dish getD() { //获得菜品
return d;
}
public void setDelete(int delete) { //设置是否被删
this.delete = delete;
}
public String getName() { //获得名字
return name;
}
public void setName(String name) { //设置名字
this.name = name;
}
}
class OtherRecord{ //代点菜信息
private int tableNum; //代点菜信息
private int orderNum; //序号\\
private Dish d; //菜品\\
private int portion; //份额(1/2/3代表小/中/大份)\\
private int dishnum ; //份数
private int delete = 1; //判断是否被删
private int exit = 1; //判断信息是否为真
String name;
public String getName() { //获得点菜的名字
return name;
}
public void setName(String name) { //设置点菜的名字,以便后续输出格式控制
this.name = name;
}
public int getExit() { //获得是否存在的信息
return exit;
}
public void setExit(int exit) { //设置是否存在
this.exit = exit;
}
public OtherRecord(int table1,int n,Dish dish,int portion1,int num1){ //构造方法
this.tableNum = table1;
this.orderNum = n;
this.d = dish;
this.portion = portion1;
this.dishnum = num1;
}
int getPrice1() { //获得本次点菜记录价格
return d.getPrice(portion,dishnum);
}
public int getOrderNum() { //获得点菜序号
return orderNum;
}
public void setDelete(int delete) { //设置是否被删除
this.delete = delete;
}
public int getTableNum() {
return tableNum;
}
}
class Menu { //菜谱类
static Dish dishs[] ; //菜品数组
public void updateMenu(String s) { //更新菜单
String [] str = s.split(" ");
String name = str[0];
int price = Integer.parseInt(str[1]);
int num = 0,count=0;
if(dishs!=null) {
num = dishs.length;
for(Dish dish:dishs)
if(dish.getName().equals(str[0])){ //判断是否重复出现
count = 1;
dish.updatePrice(s);
}
}
if(count==0) {
Dish[] dishs1 = new Dish[num+1]; //更新菜品数组
for(int i = 0;i<num;i++)
dishs1[i] = dishs[i];
dishs = dishs1;
dishs[num] = addDish(name,price);
}
}
Dish addDish(String dishName,int unit_price) { //新设置一个菜品
return new Dish(dishName,unit_price);
}
public static Dish searchDish(String s) { //搜寻菜品
for(Dish d:dishs) {
if(d.getName().equals(s))
return d;
}
return null;
}
}
class Table{ //餐桌信息类
private int num; //餐桌序号
private Order order = new Order(); //本桌订单
private LocalDate order_date; //点餐日期
private LocalTime order_time; //时间
final LocalTime amtime = LocalTime.of(10, 29,59); //周一到周五的上午营业时间
final LocalTime amtime1 = LocalTime.of(14, 30,1);
final LocalTime pmtime = LocalTime.of(16,59,59); //周一到周五的晚上营业时间
final LocalTime pmtime1 = LocalTime.of(20, 30,1);
final LocalTime time1 = LocalTime.of(9, 29,59); //周末的营业时间段
final LocalTime time = LocalTime.of(21,30,1);
private int total = 0; //当前订单总价
public Order getOrder() {
return order;
}
// public void setOrder(Order order) {
// this.order = order;
// }
public void setTotal() { //设置总价结单
total = getOrder().getTotalPrice(getDiscount());
}
public int getTotal() { //获得总价
return total;
}
public boolean checkOrderTime() { //检测点菜时间是否准确
int num = order_date.getDayOfWeek().getValue();
if(num>0&&num<6) {
return amtime.isBefore(order_time) && amtime1.isAfter(order_time) ||
pmtime.isBefore(order_time) && pmtime1.isAfter(order_time);
}
else {
if(time1.isBefore(order_time)&&time.isAfter(order_time))
return true;
else if(time1.isBefore(order_time)&&order_time.getMinute()==30&&order_time.getSecond()==0)
return true;
}
return false;
}
public int getDiscount() {
int num = order_date.getDayOfWeek().getValue();
if(num>0&&num<6) {
if(amtime.isBefore(order_time)&&amtime1.isAfter(order_time)) //上午折扣
return 6;
if(pmtime.isBefore(order_time)&&pmtime1.isAfter(order_time)) { //下午折扣
return 8;
}
}
return 10; //周日的折扣
}
public int getNum() { //获得当前桌号
return this.num;
}
public void setDateTime(String s) { //设置订单创建时间
String [] str = s.split(" ");
this.num = Integer.parseInt(str[1]);
String str1[] = str[2].split("/"); //时间获取
this.order_date = LocalDate.of(Integer.parseInt(str1[0]),
Integer.parseInt(str1[1]),Integer.parseInt(str1[2]));
str1 = str[3].split("/");
this.order_time = LocalTime.of(Integer.parseInt(str1[0]),
Integer.parseInt(str1[1]),Integer.parseInt(str1[2]));
}
}
class Dish { //菜品类
String name; //菜品名称
int unit_price; //单价
int getPrice(int portion,int num) { //获得当前菜品需要支付金额
int money;
if(portion==1)
money = unit_price*num;
else if(portion==2) {
money = (int)(unit_price*1.5+0.5)*num;
}else
money = 2*unit_price*num;
return money;
}
int getPrice(int portion,int num,int delete){ //获得被删除的支付金额
int money;
if(portion==1)
money = unit_price*num*delete;
else if(portion==2) {
money = (int)(unit_price*1.5+0.5)*num*delete;
}else
money = 2*unit_price*num*delete;
return money;
}
public Dish() { //无参构造方法
}
public Dish(String name,int unit_price) { //有参构造方法
this.name = name;
this.unit_price = unit_price;
}
public String getName() { //获得菜品名
return name;
}
public void updatePrice(String s) { //更新单价
String [] str = s.split(" ");
unit_price = Integer.parseInt(str[1]);
}
}
题目集5:
7-5:日期问题面向对象设计
这个题目的具体设计已经给出了,不能使用java关于日期类的知识,只能自己敲键盘了,大致需要注意日期闰年平年的day合法性问题,求前n天和求下n天都是慢慢的增加1或减1,题目所给类图的类间关系是聚合,与依赖关系类似,说实话,对这个有点迷糊,具体情况具体分析,应该看使用者怎么去使用它。这里需要使用一种字符串处理函数来对数据进行一些处理,String里面的split函数能够根据你给的字符去切割目标字符串,我感觉这个方法是十分便捷的。
类图:
SourceMonitor
最大的圈复杂度是八,就是主函数里面的连环判断多了点,多于6好像就挺离谱了,看来我的代码问题很大,在这里建议将这个圈复杂度搞低一点,将自己的代码优化一下再提交,不然很容易被判定为有问题,我这个类图好像都是依赖图的表现形式,但我敢肯定是按照老师所给类图来写的,可能是因为依赖和聚合两者十分相似。这里的“聚合”是month里面包含day属性,year有month属性,DateUtil有year属性。
代码 如果影响,可以在代码右上角点击折叠
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(); //输入选择
if(n<1||n>3) {
System.out.println("Wrong Format");
System.exit(0);
}
int y = in.nextInt(),m = in.nextInt(),d = in.nextInt(); //日期,月份,年份
switch (n){
case 1 : n = in.nextInt(); //求下n天
DateUtil date = new DateUtil(d,m,y);
if(!date.checkInputValidity()){ //检测数据合法性
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println(date.getNextNDays(n).showDate());
break;
case 2 :n = in.nextInt(); //求前n天
DateUtil date1 = new DateUtil(d,m,y);
if(!date1.checkInputValidity()){ //检查数据合法性
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println(date1.getPreviousNDays(n).showDate());
break;
case 3 : DateUtil date2 = new DateUtil(d,m,y); //求两个日期的差值
y = in.nextInt(); //输入另一个日期
m = in.nextInt();
d = in.nextInt();
DateUtil date3 = new DateUtil(d,m,y);
if((!date2.checkInputValidity())||(!date3.checkInputValidity())){//检测数据合法性
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println(date2.getDaysofDates(date3));
break;
default: System.out.println("Wrong Format"); //数据格式错误
}
}
}
class DateUtil {
private Day day;
public DateUtil() { //无参构造方法
}
public DateUtil(int d,int m,int y){ //含参构造方法
this.day = new Day(y,m,d);
}
public Day getDay() { //get,set
return day;
}
public void setDay(Day day) {
this.day = day;
}
public boolean checkInputValidity(){ //检测数据合法性
if(day.getMonth().getYear().validate()&&
day.getMonth().validate()&& day.validate()) {
return true;
} else
return false;
}
public boolean compareDates(DateUtil date){ //比较两个日期的差值
int a = day.getMonth().getYear().getValue()*12*365+
day.getMonth().getValue()*30+ day.getValue();//将一年看出365天,一月30天计算,减少判断
int b = date.getDay().getMonth().getYear().getValue()*12*365+
date.getDay().getMonth().getValue()*30+ date.getDay().getValue();
return a > b;
}
public boolean equalTwoDates(DateUtil date){ //比较两个日期是否相等
int a = day.getMonth().getYear().getValue()*12*365+
day.getMonth().getValue()*30+ day.getValue(); //原理同上
int b = date.getDay().getMonth().getYear().getValue()*12*365+
date.getDay().getMonth().getValue()*30+ date.getDay().getValue();
return a == b;
}
public String showDate(){ //日期格式化
String date = "";
date += day.getMonth().getYear().getValue(); //字符串连接
date += "-"+day.getMonth().getValue()+"-";
date += day.getValue();
return date;
}
public DateUtil getNextNDays(int n){ //求下n天
DateUtil date = new DateUtil(day.getValue(),day.getMonth().
getValue(),day.getMonth().getYear().getValue()); //新开一个类
while(n>0){
date.getDay().dayIncrement();
n--;
}
return date;
}
public DateUtil getPreviousNDays(int n){ //求前n天
DateUtil date = new DateUtil(day.getValue(),day.getMonth().
getValue(),day.getMonth().getYear().getValue());//新开一个对象,保证原对象的数据不会改变
while(n>0){
date.getDay().dayReduction();
n--;
}
return date;
}
public int getDaysofDates(DateUtil date){ //获得两个日期之间的差值
int n = 0;
if(compareDates(date)) {
DateUtil date1 = new DateUtil(date.getDay().getValue(), date.getDay().
getMonth().getValue(),date.getDay().getMonth().getYear().getValue());//新开一个日期对象
while(!equalTwoDates(date1)){
n++;
date1.getDay().dayIncrement();
}
}else{
DateUtil date1 = new DateUtil(day.getValue(),day.getMonth().
getValue(),day.getMonth().getYear().getValue()); //新开一个日期对象
while(!date1.equalTwoDates(date)){
n++;
date1.getDay().dayIncrement();
}
}
return n;
}
}
class Year { //年份类
private int value;
public Year() { //不含参构造
}
public Year(int value) { //含参构造方法
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public boolean isLeapYear(){ //判断是否闰年
if(value%4==0&&value%100!=0)
return true;
else return value % 400 == 0;
}
public boolean validate(){ //判断年份是否合法
if(value>2050||value<1900)
return false;
else
return true;
}
public void yearIncrement(){ //年份加一
value++;
}
public void yearReduction(){ //年份减一
value--;
}
}
class Day{ //日期类
private int value; //日期
private Month month = new Month();
private final int[][] mon_maxnum = {{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31}};
public Day() { //无参构造
}
public Day(int yearValue,int monthValue,int dayValue){//含参构造方法
this.month = new Month(yearValue,monthValue);
this.value = dayValue;
}
public Month getMonth() { //set,get
return month;
}
public void setMonth(Month month) {
this.month = month;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public void resetMin(){ //日期复位为1
value = 1;
}
public void resetMax(){ //日期设为最大值
int n = 0;
if(getMonth().getYear().isLeapYear())
n = 1;
value = mon_maxnum[n][month.getValue()-1];
}
public boolean validate(){ //检测是否合法
int n = 0;
if(getMonth().getYear().isLeapYear())
n = 1;
return value <= mon_maxnum[n][month.getValue() - 1] && value >= 1;
}
public void dayIncrement(){ //日期加1
int n = 0;
if(getMonth().getYear().isLeapYear()) //判断是否为闰年
n = 1;
value++;
if(value>mon_maxnum[n][month.getValue()-1]) { //确保数据合法
month.monthIncrement();
resetMin();
}
}
public void dayReduction(){ //日期减1
value--;
if(value<=0){
month.monthReduction();
resetMax();
}
}
}
class Month { //月份·类
private int value;
private Year year = new Year();
public Month() { //无参构造方法
}
public Month(int yearValue,int monthValue) { //含参构造方法
this.value = monthValue;
this.year = new Year(yearValue);
}
public int getValue() { //get,set
return value;
}
public void setValue(int value) {
this.value = value;
}
public Year getYear() {
return year;
}
public void setYear(Year year) {
this.year = year;
}
public void resetMin(){ //月份设置为1
value = 1;
}
public void resetMax(){ //月份设置为12
value = 12;
}
public boolean validate(){ //检查月份的合法性
return value >= 1 && value <= 12;
}
public void monthIncrement(){ //月份加1
value++;
if(value>12){ //确保数据合法
getYear().yearIncrement();
resetMin();
}
}
public void monthReduction(){ //月份减一
value--;
if(value<=0){ //确保数据合法
getYear().yearReduction();
resetMax();
}
}
}
7-6 日期问题面向对象设计
这一题所给的关系是聚合关系,与上一题不一样的聚合关系,DateUtil里面有year,month,day属性,day和month,year并没有直接的关系,像鼠标和键盘的关系。老实说这个题目对于聚合的解释是比较有实际意义的,通过这个例子确实能够加深对于这些关系的理解,这里需要感谢老师,希望多多出这种题目。对于数据的处理大致与上一题类似,只是对于数据的检测需要更改一下,这个可以先year,再month检查,也可以在DateUtil里面进行检查,建议在year它们各自的类里面进行检查,较为符合单一职责原则。
类图:
source monitor
这个复杂度达到13了,看来已经是lj代码了,写得过于复杂了。这个评定我也不清楚这是怎么判定的,只记得与if-else的圈有关。在这个类图里面,DateUtil和year,month,day就像是电脑,鼠标,键盘的关系,这个结构还是挺好辨认的,相比较于上一题,我感觉这种关系似乎更加好用,但是它的耦合关系好像更强,推荐还是使用上一种聚合吧,复杂度更小一点。
代码,可折叠,在代码右上方
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(); //输入选择
if(n<1||n>3) {
System.out.println("Wrong Format");
System.exit(0);
}
int y = in.nextInt(),m = in.nextInt(),d = in.nextInt(); //日期,月份,年份
switch (n){
case 1 : n = in.nextInt(); //求下n天
DateUtil date = new DateUtil(y,m,d);
if(!date.checkInputValidity()){ //检测数据合法性
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println(date.showDate()+" next "+n+" days is:"+date.getNextNDays(n).showDate());
break;
case 2 :n = in.nextInt(); //求前n天
DateUtil date1 = new DateUtil(y,m,d);
if(!date1.checkInputValidity()){ //检查数据合法性
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println(date1.showDate()+" previous "+n+" days is:"+date1.getPreviousNDays(n).showDate());
break;
case 3 : DateUtil date2 = new DateUtil(y,m,d); //求两个日期的差值
y = in.nextInt(); //输入另一个日期
m = in.nextInt();
d = in.nextInt();
DateUtil date3 = new DateUtil(y,m,d);
if((!date2.checkInputValidity())||(!date3.checkInputValidity())){//检测数据合法性
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println("The days between "+date2.showDate()+" and " +
date3.showDate()+" are:"+date2.getDaysofDates(date3));
break;
default: System.out.println("Wrong Format"); //数据格式错误
}
}
}
class DateUtil {
private Day day;
private Year year;
private Month month;
private final int[][] mon_maxnum = {{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31}};
public DateUtil() { //无参构造方法
}
public DateUtil(int y,int m,int d){ //含参构造方法
this.year = new Year(y);
this.month = new Month(m);
this.day = new Day(d);
}
public Year getYear() {
return year;
}
public void setYear(Year year) {
this.year = year;
}
public Month getMonth() {
return month;
}
public void setMonth(Month month) {
this.month = month;
}
public Day getDay() { //get,set
return day;
}
public void setDay(Day day) {
this.day = day;
}
public void setDayMin(){ //日期复位
day.setValue(1);
}
public void setDayMax(){
int n = 0; //记录是否是闰年
if(year.isLeapYear()) //判断
n = 1;
day.setValue(mon_maxnum[n][month.getValue()-1]);
}
public boolean checkInputValidity(){ //检测数据合法性
int n = 0; //记录是否是闰年
if(year.isLeapYear()) //判断
n = 1;
if(year.validate()&&month.validate()) {
return day.getValue()>0 && day.getValue()<=mon_maxnum[n][month.getValue()-1];
} else
return false;
}
public boolean compareDates(DateUtil date){ //比较两个日期的差值
int a = year.getValue()*12*365+ month.getValue()
*30+ day.getValue();//将一年看出365天,一月30天计算,减少判断
int b = date.getYear().getValue()*12*365+
date.getMonth().getValue()*30+date.getDay().getValue();
return a > b;
}
public boolean equalTwoDates(DateUtil date){ //比较两个日期是否相等
int a = year.getValue()*12*365+ month.getValue()
*30+ day.getValue();//将一年看出365天,一月30天计算,减少判断
int b = date.getYear().getValue()*12*365+
date.getMonth().getValue()*30+date.getDay().getValue();
return a == b;
}
public String showDate(){ //日期格式化
String date = "";
date += year.getValue(); //字符串连接
date += "-"+month.getValue()+"-";
date += day.getValue();
return date;
}
public DateUtil getNextNDays(int n){ //求下n天
DateUtil date = new DateUtil(year.getValue(),month.
getValue(),day.getValue()); //新开一个对象,保证原对象的数据不会改变
while(n>0){
date.getDay().dayIncrement();
int num = 0; //记录是否是闰年
if(date.year.isLeapYear()) //判断
num = 1;
if(date.getDay().getValue()>mon_maxnum[num][date.getMonth().getValue()-1]){ //判断day是否超出范围
if(date.getMonth().getValue()==12){ //判断是不是12月
date.getMonth().resetMin(); //月份设置为1
date.getYear().yearIncrement(); //年份加一
date.getDay().setValue(1); //将日期重新设置为1
}else{
date.getMonth().monthIncrement();//月份加一
date.getDay().setValue(1); //将日期设置为1
}
}
n--;
}
return date;
}
public DateUtil getPreviousNDays(int n){ //求前n天
DateUtil date = new DateUtil(year.getValue(),month.
getValue(),day.getValue()); //新开一个对象,保证原对象的数据不会改变
while(n>0){
date.getDay().dayReduction();
int num = 0; //记录是否是闰年
if(date.getYear().isLeapYear()) //判断
num = 1;
if(date.getDay().getValue()<1){ //判断day是否超出范围
if(date.getMonth().getValue()==1){ //判断是不是1月
date.getMonth().resetMax(); //月份设置为12
date.getYear().yearReduction(); //年份减一
date.getDay().setValue(mon_maxnum[num][date.getMonth().getValue()-1]); //将日期重新设置
}else{
date.getMonth().monthReduction();//月份减一
date.getDay().setValue(mon_maxnum[num][date.getMonth().getValue()-1]); //将日期重新设置
}
}
n--;
}
return date;
}
public int getDaysofDates(DateUtil date){ //获得两个日期之间的差值
int n = 0;
if(compareDates(date)) {
DateUtil date1 = new DateUtil(date.getYear().getValue(), date.
getMonth().getValue(),date.getDay().getValue());//新开一个日期对象
while(!equalTwoDates(date1)){
int num = 0; //记录是否是闰年
if(date1.getYear().isLeapYear()) //判断
num = 1;
if(date1.getDay().getValue()>mon_maxnum[num][date1.getMonth().getValue()-1]){ //判断day是否超出范围
if(date1.getMonth().getValue()==12){ //判断是不是12月
date1.getMonth().resetMin(); //月份设置为1
date1.getYear().yearIncrement(); //年份加一
date1.getDay().setValue(1); //将日期重新设置为1
}else{
date1.getMonth().monthIncrement();//月份加一
date1.getDay().setValue(1); //将日期设置为1
}
}
n++;
date1.getDay().dayIncrement();
}
}else{
DateUtil date1 = new DateUtil(year.getValue(),month.
getValue(),day.getValue()); //新开一个对象,保证原对象的数据不会改变
while(!date1.equalTwoDates(date)){
n++;
date1.getDay().dayIncrement();
int num = 0; //记录是否是闰年
if(date1.getYear().isLeapYear()) //判断
num = 1;
if(date1.getDay().getValue()>mon_maxnum[num][date1.getMonth().getValue()-1]){ //判断day是否超出范围
if(date1.getMonth().getValue()>=12){ //判断是不是12月
date1.getMonth().resetMin(); //月份设置为1
date1.getYear().yearIncrement(); //年份加一
date1.getDay().setValue(1); //将日期重新设置为1
}else{
date1.getMonth().monthIncrement();//月份加一
date1.getDay().setValue(1); //将日期设置为1
}
}
}
}
return n;
}
}
class Year { //年份类
private int value;
public Year() { //不含参构造
}
public Year(int value) { //含参构造方法
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public boolean isLeapYear(){ //判断是否闰年
if(value%4==0&&value%100!=0)
return true;
else return value % 400 == 0;
}
public boolean validate(){ //判断年份是否合法
return value<=2020 && value>=1820;
}
public void yearIncrement(){ //年份加一
value++;
}
public void yearReduction(){ //年份减一
value--;
}
}
class Day{ //日期类
private int value; //日期
public Day() { //无参构造
}
public Day(int dayValue){//含参构造方法
this.value = dayValue;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public void dayIncrement(){ //日期加1
value++;
}
public void dayReduction(){ //日期减1
value--;
}
}
class Month { //月份·类
private int value;
public Month() { //无参构造方法
}
public Month(int value) {
this.value = value;
}
public int getValue() { //get,set
return value;
}
public void setValue(int value) {
this.value = value;
}
public void resetMin(){ //月份设置为1
value = 1;
}
public void resetMax(){ //月份设置为12
value = 12;
}
public boolean validate(){ //检查月份的合法性
return value >=1 && value <= 12;
}
public void monthIncrement(){ //月份加1
value++;
}
public void monthReduction(){ //月份减一
value--;
}
}
题目集6
7-1 菜单计价程序-4
这个题目集只有一题,在看到只有一题的时候我就知道不简单,结果并没有给我惊喜,确实挺难的。老师在发布这个作业之后就附上了一句话“预计代码行数1000+,时间20h+”,当时看到这个之后心都凉了,之前还是有5-7题分摊一下难度,这下直接一题。话不多说开始分析,先分析难点,我个人这个题目的难点在于它有比较多的一个格式判断和数据格式多种错误夹杂在一起,需要写比较多的语句去一一检查,举个例子在读到点菜记录时会出现end,table,还有菜谱信息,删除信息,代点菜等等情况,这些要是合在一个函数里面一一检查的话就会导致代码太过于累赘,为了体现单一职责原则,只能够分开在多个函数里面去检查。检查的方式使用正则表达式比较好一点,对于每条合法的数据都有一个格式,可以依靠这个格式去把正则表达式写出来。例如
在检查菜谱时,我们只需要使用split函数根据空格切割一下得到字符串数组,再将第二个字符串与它比对,不合法就输出“wrong format”,其它相关处理也类似。不管处理菜谱信息还是点菜信息,都有对应的格式,判断的过程应该是:格式 > 数据合法 > 数据比对,以上三个如果有一个通过不了就判断是错误的,输出相关错误并不记录这条,如果通过以上就可以认为是合法的数据可以记录。这里还有对于桌号的一个注意事项
如果这个语句出现table了,那么只要它的时间超出工作范围,或时间数据不合法,格式错误,都可以忽略下面的一些点菜记录,这点和菜单计价程序3有些不同,菜单计价程序3中如果时间超出工作范围,依旧需要处理那一桌的点菜信息,这个点卡了我两个晚上,着实是被搞心态了一波。还有一个需要注意的是格式方面如果多一个空格依旧会被认为是错得,这是我经过熬夜测试一晚上得出的结论。
对于题目所涉及的算法,并没有什么很难的地方,就计价得时候需要将菜名和份额相等的加在一起计算单价,对于最后计价的时候需要注意题目的提示:
这个很重要,我被它卡了一个晚上。最后,题目的测试点所给的提示有时候并不是造成你这个测试点错误的主要原因,我之前有几个代点菜和时间错误的测试点死活过不去,最后发现是代码的计价这方面的算法出现问题。
类结构:
SourceMonitor
在这张类图中,我是将Menu设置成只有一个菜单,就像那个单例模式,但当时并没有想到这去,代码上有些不一样。本来是想为order,Record,dish类都搞一个抽象父类的,但写着写着就忘记了里氏代换法则,忘记往父类添加抽象方法了,过于草率了。order类里面有Record,table里面有order类,通过Menu类名访问菜单,agent处理数据的储存和判断。除了这些之外我觉得还缺少一个代点菜记录类,因为这个代点菜比本桌菜多了一个信息,那就是代点的那个桌号。SourceMonitor上面的图大多都看不太懂,只看得懂931行,10个文件,最大复杂度11,怎么计算的我不是太懂,复杂度过大代码质量就不是太行。
代码,觉得过长就可以选择折叠,在代码右上角
import java.util.ArrayList;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Duration;
import java.util.Scanner;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args){
Agent agent = new Agent();
agent.start();
}
}
public class Menu {
protected static ArrayList<AbstractDish> dishList = new ArrayList<>();//菜品数组,保存所有菜品信息
public ArrayList<AbstractDish> getDishList() { //获得菜单
return dishList;
}
public static AbstractDish searchDish(String dishName){ //查找菜品
if(dishList==null)
return null;
for(int i = 0;i<dishList.size();i++)
if(dishList.get(i).getName().equals(dishName))
return (Dish)dishList.get(i);
return null;
}
public void addDish(String dishName,int unit_price,Boolean special){ //增加菜品
AbstractDish dish = null;
if(searchDish(dishName)==null) {
dish = new Dish(dishName, unit_price, special);
dishList.add(dish);
}
else
searchDish(dishName).setUnit_price(unit_price);
}
}
public abstract class AbstractDish {
private String name;
private int unit_price;
private Boolean isSpecial;
public AbstractDish() {
}
public Boolean getSpecial() {
return isSpecial;
}
public void setSpecial(Boolean special) {
isSpecial = special;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AbstractDish(String name, int price,Boolean special) {
this.name = name;
this.unit_price = price;
this.isSpecial = special;
}
public int getUnit_price(){
return unit_price;
}
public void setUnit_price(int unit_price) {
this.unit_price = unit_price;
}
public abstract int getPrice(int portion);
/*public abstract int getSpecialPrice(int portion);*/
}
public class Order extends AbstractOrder {
public Order(ArrayList<AbstractRecord> records) { //含参构造函数
super(records);
}
public Order() { //无参构造函数
}
@Override
public void addARecord(int orderNum, String dishName, int portion, int num) { //增加本桌点菜记录
AbstractRecord record = new Record(orderNum, Menu.searchDish(dishName), portion, num);
recordList.add(record);
}
@Override
public void addAOtherRecord( int otherTable,int orderNum,String dishName, int portion, int num) { //增加代点记录
AbstractRecord record = new Record(orderNum, otherTable,Menu.searchDish(dishName), portion, num);
recordList.add(record);
}
@Override
public boolean checkRecordValid(String s,Menu menu,int tableNum,int same){ //设置并检查点菜记录的合法性
if(s.charAt(s.length()-1)==' '){
System.out.println("wrong format");
return false;
}
String record = "[1-9][0-9]{0,}"; //点菜记录序号
String table = "[1-9][0-9]{0,}"; //table号
String portion = "[1-9]"; //份额
String allNum = "[1-9][0-9]{0,}"; //份数
String str[] = s.split(" ");
if(str.length<2||str.length>5){
System.out.println("wrong format");
return false;
}
if(str.length==4&&(!str[0].matches(record)||!str[2].matches(portion)||!str[3].matches(allNum))){
System.out.println("wrong format");
return false;
}
if(str.length==5&&(!str[0].matches(table)||!str[1].matches(record)||!str[3].matches(portion)||!str[4].matches(allNum))){
System.out.println("wrong format");
return false;
}
int num;
if(str.length==4)
num = Integer.parseInt(str[0]);
else
num = Integer.parseInt(str[1]);
for(int i = 0;i<recordList.size();i++){ //查看序号是否重复
if(str.length==4&&recordList.get(i).getOrderNum()==num){
System.out.println("record serial number sequence error");
return false;
}
}
if(str.length==4&&recordList.size()>0&&num<=recordList.get(recordList.size()-1).getOrderNum()){ //排查序号是否按顺序
System.out.println("record serial number sequence error");
return false;
}
int count = 0;
boolean special = false;
if (str.length == 4) { //本桌菜
for (int i = 0; i < menu.getDishList().size(); i++) {
if (menu.getDishList().get(i).getName().equals(str[1])){
if(menu.getDishList().get(i).getSpecial())
special = true;
count = 1;
break;
}
}
if(count!=1){
System.out.println(str[1]+" does not exist");
return false;
}
if(!checkPortion(Integer.parseInt(str[0]),Integer.parseInt(str[2]),special))
return false;
if(!checkNum(Integer.parseInt(str[0]),Integer.parseInt(str[3])))
return false;
addARecord(Integer.parseInt(str[0]),str[1],Integer.parseInt(str[2]),Integer.parseInt(str[3]));
System.out.println(num+" "+str[1]+" "+recordList.get(recordList.size()-1).getPrice());
return true;
}else if(str.length==5){ //代点菜信息
// if(!Agent.checkTableNum(Integer.parseInt(str[0]))){
// return false;
// }
if(!Agent.searchTableNum(Integer.parseInt(str[0]))){
return false;
}
for (int i = 0; i < menu.getDishList().size(); i++) {
if (menu.getDishList().get(i).getName().equals(str[2])){
if(menu.getDishList().get(i).getSpecial())
special = true;
count = 1;
break;
}
}
if(count!=1){
System.out.println(str[2]+" does not exist");
return false;
}
if(!checkPortion(Integer.parseInt(str[0]),Integer.parseInt(str[3]),special))
return false;
if(!checkNum(Integer.parseInt(str[0]),Integer.parseInt(str[4])))
return false;
addAOtherRecord(Integer.parseInt(str[0]),Integer.parseInt(str[1]),str[2],Integer.parseInt(str[3]),Integer.parseInt(str[4]));
// System.out.println(Integer.parseInt(str[1])+" "+str[2]+" "+recordList.get(recordList.size()-1).getPrice());
System.out.println(Integer.parseInt(str[1])+" table "+tableNum+" pay for table "+Integer.parseInt(str[0])+" "+recordList.get(recordList.size()-1).getPrice());
return true;
}
System.out.println("wrong format");
return false;
}
@Override
public void setOrderRecord(String s,Menu menu,int tableNum,int same){ //接受输入的点菜信息
String str[] = s.split(" ");
if(str.length!=4&&str.length!=5){
checkIsDish(s);
return;
}
if(str.length!=4&&str.length!=5){
System.out.println("wrong format");
return ;
}
checkRecordValid(s,menu,tableNum,same); //创建并检查点菜信息
}
@Override
public boolean checkPortion(int recordNum,int portion,boolean special) { //检测份额
if(special){
if(portion!=1&&portion!=3&&portion!=2){
System.out.println(recordNum+" portion out of range "+ portion);
return false;
} else {
return true;
}
} else if(portion<=0||portion>3){
System.out.println(recordNum+" portion out of range "+portion);
return false;
}
return true;
}
@Override
public boolean checkNum(int recordNum,int num) { //检测份数
if(num>15||num<=0){
System.out.println(recordNum+" num out of range "+num);
return false;
}
return true;
}
@Override
public void deleteRecord(String s){ //删除点菜记录
String recordNum = "[0-9]{0,}";
String str[] = s.split(" ");
if(!str[0].matches(recordNum)){
System.out.println("wrong format");
return;
}
int num = Integer.parseInt(str[0]); //要删除的点菜信息序号
int count = 0;
for(int i=0;i<recordList.size();i++){
if(recordList.get(i).getOrderNum()==num){
count = 1;
if(recordList.get(i).isDelete()){
System.out.println("deduplication "+num);
return ;
}
recordList.get(i).setDelete(true);
break;
}
}
if(count !=1){
System.out.println("delete error");
return;
}
}
@Override
public int getAllPrice(){ //打折前的金额
int sum = 0;
for(int i = 0;i<recordList.size();i++){
sum+=recordList.get(i).getPrice();
}
return sum;
}
@Override
public boolean checkIsDish(String s){ //检查是否是菜谱信息
String price = "[1-9][0-9]{0,}";
if(s.charAt(s.length()-1)==' '){
System.out.println("wrong format");
return false;
}
String str[] = s.split(" ");
if(str.length==2&&str[1].matches(price)){
System.out.println("invalid dish");
return false;
} else if(str.length==3&&str[1].matches(price)&&str[2].equals("T")){
System.out.println("invalid dish");
return false;
}
System.out.println("wrong format");
return false;
}
@Override
public void addSameRecord(){ //将本桌菜相同份额的相加
for(int i = 0;i<recordList.size();i++){
for(int j = i+1;j<recordList.size();j++){
if(recordList.get(i).getD()==recordList.get(j).getD()
&&recordList.get(i).getPortion()==recordList.get(j).getPortion()&&!recordList.get(i).isDelete()&&recordList.get(j).isDelete()) {
recordList.get(i).setNum(recordList.get(i).getNum() + recordList.get(j).getNum());
recordList.get(j).setDelete(true);
}
}
}
}
}
package pta6;
public class Record extends AbstractRecord{
public Record(int orderNum, AbstractDish d, int portion, int num) {
super(orderNum, (Dish) d, portion, num);
}
public Record(int orderNum, int other,AbstractDish d, int portion, int num) {
super(orderNum, other, (Dish) d, portion, num);
}
public Record() {
}
@Override
public int getPrice() {
if(isDelete())
return 0;
return getD().getPrice(portion)*num;
}
}
public class Table {
private int tableNum;
private boolean isValid = true;
private LocalDate tableDate;
public LocalDate getTableDate() {
return tableDate;
}
// public void setTableDate(LocalDate tableDate) {
// this.tableDate = tableDate;
// }
private LocalTime tableTime;
final int [][] workDate = {{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};
final LocalTime amtime = LocalTime.of(10, 29,59); //周一到周五的上午营业时间
final LocalTime amtime1 = LocalTime.of(14, 30,1);
final LocalTime pmtime = LocalTime.of(16,59,59); //周一到周五的晚上营业时间
final LocalTime pmtime1 = LocalTime.of(20, 30,1);
final LocalTime time1 = LocalTime.of(9, 29,59); //周末的营业时间段
final LocalTime time = LocalTime.of(21,30,1);
final LocalDate workDate1 = LocalDate.of(2022,1,1);
final LocalDate workDate2 = LocalDate.of(2023,12, 31);
Order order = new Order();
public Table(int tableNum,Order order) {
this.tableNum = tableNum;
this.order = order;
}
public Table() {
}
public LocalTime getTableTime() {
return tableTime;
}
// public void setTableTime(LocalTime tableTime) {
// this.tableTime = tableTime;
// }
public int getTableNum() {
return tableNum;
}
public boolean isValid() {
return isValid;
}
public void setValid(boolean valid) {
isValid = valid;
}
// public void setTableNum(int tableNum) {
// this.tableNum = tableNum;
// }
public Order getOrder() {
return order;
}
// public void setOrder(Order order) {
// this.order = order;
// }
public void setTableNum(String s){
this.tableNum = Integer.parseInt(s);
}
// public void setTableDay(int year,int month,int day){ //设置订单创建日期
// this.tableDate = LocalDate.of(year,month,day);
// }
public void setTableDate(String s){ //设置订单创建时间
String str[] = s.split("/");
this.tableDate = LocalDate.of(Integer.parseInt(str[0]), Integer.parseInt(str[1]), Integer.parseInt(str[2]));
}
public boolean checkWorkDate(){ //检查订单是否在工作日期
if(tableDate.isBefore(workDate1)){
System.out.println("not a valid time period");
return false;
}
if(tableDate.isAfter(workDate2)){
System.out.println("not a valid time period");
return false;
}
return true;
}
public boolean checkTime(){ //检查订单创建时间
// String str[] = s.split("/");
// String strTime = "[0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2}";
// if(s.matches(strTime))
// return true;
// else
// System.out.println("wrong format");
// setTableTime(s);
int num = tableDate.getDayOfWeek().getValue(); //获得星期几
if(num>0&&num<6) {
if(amtime.isBefore(tableTime)&&amtime1.isAfter(tableTime)||
pmtime.isBefore(tableTime)&&pmtime1.isAfter(tableTime)) {
return true;
}
}
else {
if(time1.isBefore(tableTime)&&time.isAfter(tableTime))
return true;
else if(time1.isBefore(tableTime)&&tableTime.getMinute()==30&&tableTime.getSecond()==0)
return true;
}
System.out.println("table "+getTableNum()+" out of opening hours");
return false;
}
public void setTableTime(String s){ //设置当前桌的创建时间
String str[] = s.split("/");
if(Integer.parseInt(str[0])!=24)
this.tableTime = LocalTime.of(Integer.parseInt(str[0]),Integer.parseInt(str[1]),Integer.parseInt(str[2]));
else
this.tableTime = LocalTime.of(Integer.parseInt(str[0])-1,Integer.parseInt(str[1]),Integer.parseInt(str[2]));
}
public boolean checkTableNum(String s){ //检查桌号
String num = "([1-9]|[1-4][0-9]|5[0-5])"; //桌号
String num1 = "[1-9][0-9]{1,}"; //数字
if(s.matches(num))
return true;
else if(s.matches(num1))
System.out.println(s+" table num out of range");
else
System.out.println("wrong format");
return false;
}
public boolean setTable(String s){ //设置餐桌信息,并检查相关信息是否正确
String tableString = "table [1-9][0-9]{0,} [0-9]{4}/[0-9]{1,2}/[0-9]{1,2} [0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2}"; //桌号信息正则表达式
if(!s.matches(tableString)){
System.out.println("wrong format");
return false;
}
String str[] = s.split(" ");
// if(!str[0].equals("table"))
// return false;
if(checkTableNum(str[1])) //检查桌号
setTableNum(str[1]);
else
return false;
if(!isValidDate(Integer.parseInt(str[2].split("/")[0]),
Integer.parseInt(str[2].split("/")[1]),Integer.parseInt(str[2].split("/")[2])))//检查年份日期格式
return false;
else
setTableDate(str[2]);
if(!checkWorkDate()){ //检查是否在工作时间
//System.out.println("not a valid time period");
return false;
}
if(checkTimeValid(str[3])) //检查时间(时分秒)
setTableTime(str[3]);
else
return false;
return true;
}
// public boolean isLeapYear(int year){
// if((year%4==0&&year%100!=0)||year%400==0)
// return true;
// return false;
// }
public int getAllPrice(){
return order.getAllPrice();
}
public int getToTalPrice(){
//return (int)(order.getTotalPrice(tableDate)*(getDiscount()/10.0)+0.5);
int sum = 0; //普通菜的总价
int sum1 = 0; //特色菜的总价
int weekNum = tableDate.getDayOfWeek().getValue();
if(weekNum<6)
weekNum = 7;
else
weekNum = 10;
for(int i = 0;i<order.recordList.size();i++){
if(order.recordList.get(i).getD().getSpecial())
sum1+=(int)(order.recordList.get(i).getPrice()*(weekNum/10.0)+0.5);
else
sum+=(int)(order.recordList.get(i).getPrice()*(getDiscount()/10.0)+0.5);
}
//return (int)(sum1*(weekNum/10.0)+sum*(getDiscount()/10.0)+0.5);
return sum1+sum;
}
public int getDiscount(){ //活的折扣
int num = tableDate.getDayOfWeek().getValue();
if(num>0&&num<6) {
if(amtime.isBefore(tableTime)&&amtime1.isAfter(tableTime)) //上午折扣
return 6;
if(pmtime.isBefore(tableTime)&&pmtime1.isAfter(tableTime)) { //下午折扣
return 8;
}
}
return 10; //周日的折扣
}
public boolean checkTimeValid(String s){ //检查时间的合法性
String str[] = s.split("/");
String time = "[0-9]{1,2}";
for(int i = 0;i<str.length;i++){
if(!str[i].matches(time)){
System.out.println("wrong format");
return false;
}
}
int hour = Integer.parseInt(str[0]);
int minute = Integer.parseInt(str[1]);
int second = Integer.parseInt(str[2]);
if(hour<0||hour>24||minute>=60||minute<0||second<0||second>=60){
System.out.println(tableNum+" date error");
return false;
}
if(hour==24&&(minute!=0||second!=0)){
System.out.println(tableNum+" date error");
return false;
}
return true;
}
public boolean checkTime1(){ //检查订单是否在工作时间范围,但不输出错误
int num = tableDate.getDayOfWeek().getValue();
if(num>0&&num<6) { //周一到周五
return amtime.isBefore(tableTime) && amtime1.isAfter(tableTime) ||
pmtime.isBefore(tableTime) && pmtime1.isAfter(tableTime);
}
else {
if(time1.isBefore(tableTime)&&time.isAfter(tableTime))
return true;
else return time1.isBefore(tableTime) && tableTime.getMinute() == 30 && tableTime.getSecond() == 0;
}
}
public boolean isValidDate(int year, int month, int day) { //检查日期是否合法
try {
LocalDate.of(year, month, day);
return true;
} catch (DateTimeException e) {
System.out.println(tableNum+" date error");
return false;
}
}
public void addPortion(Table table){ //将份额和菜名相等的份数加起来
for(int i = 0;i<order.recordList.size();i++)
for(int j = 0;j<table.order.recordList.size();j++){
if(!order.recordList.get(i).isDelete()&&order.recordList.get(i).isDelete()&&order.recordList.get(i).getD()==table.order.recordList.get(j).getD()
&&order.recordList.get(i).getPortion()==table.order.recordList.get(j).getPortion()) {
order.recordList.get(i).setNum(order.recordList.get(i).num + table.order.recordList.get(j).num);
table.order.recordList.get(j).setDelete(true);
}
}
}
}
public abstract class AbstractRecord {
private int orderNum; //点菜信息序号
private AbstractDish d;
protected int num; //份额
protected int portion; //份数
private boolean delete = false;
int otherTable = 0;
public AbstractRecord(int orderNum,Dish d,int portion,int num) {
this.orderNum = orderNum;
this.d = d;
this.num = num;
this.portion = portion;
}
public AbstractRecord(int orderNum,int other,Dish d,int portion,int num) {
this.orderNum = orderNum;
this.otherTable = other;
this.d = d;
this.num = num;
this.portion = portion;
}
public int getNum() {
return num;
}
public boolean isDelete() {
return delete;
}
public void setDelete(boolean delete) {
this.delete = delete;
}
public void setNum(int num) {
this.num = num;
}
public AbstractRecord() {
}
public int getOrderNum() {
return orderNum;
}
public void setOrderNum(int orderNum) {
this.orderNum = orderNum;
}
public AbstractDish getD() {
return d;
}
public void setD(Dish d) {
this.d = d;
}
public int getPortion() {
return portion;
}
public void setPortion(int portion) {
this.portion = portion;
}
public abstract int getPrice();
}
public class Agent {
static ArrayList<Table>tableList = new ArrayList<>();
Menu menu = new Menu();
public Agent(ArrayList<Table>table,Menu menu) {
this.tableList = table;
this.menu = menu;
}
public Agent() {
}
public void start(){
int same = 0; //记录桌号是否相等
Scanner in = new Scanner(System.in);
String s = in.nextLine();
while(s.split(" ").length<=3&&!s.equals("end")){ //增加菜品
if(s.equals("")){ //判断是否空行
System.out.println("wrong format");
s = in.nextLine();
continue;
}
String str[] = s.split(" "); //切割字符串
if(checkDishValid(s)) {
if(str.length==2) //长度为三为特色菜
this.menu.addDish(str[0], Integer.parseInt(str[1]), false);
else
this.menu.addDish(str[0], Integer.parseInt(str[1]),true);
}
s = in.nextLine();
}
while(s.indexOf("end")==-1){ //创建订单
if(s.equals("")){ //识别空行
System.out.println("wrong format");
s = in.nextLine();
continue;
}
String str[] = s.split(" ");
if(!str[0].equals("table")||str.length!=4) { //table格式检查
System.out.println("wrong format");
s = in.nextLine();
String str1[] = s.split(" ");
while(!str1[0].equals("table")&&!str1[0].equals("end")){ //本桌信息作废
s = in.nextLine();
str1 = s.split(" ");
}
if(str1[0].equals("table")){
continue;
}
break;
}
Table table = new Table(); //创建一个新桌
if(!table .setTable(s)){ //检查桌号时间各信息
table.setValid(false);
s = in.nextLine();
while(!s.split(" ")[0].equals("table")&&!s.equals("end")) //出现table,但其它数据格式错误,忽略点菜信息
s = in.nextLine();
if(s.split(" ")[0].equals("table"))
continue;
break;
}
if(!table.checkTime()){ //检查table的时间是否在工作时间内
s = in.nextLine();
while(!s.split(" ")[0].equals("table")&&!s.equals("end"))
s = in.nextLine();
if(s.split(" ")[0].equals("table")||s.equals("end")) {
// tableList.add(table);
continue;
}
}
same = 0;
// if(table.checkTime1()&&checkSameTable(table)!=null){
// //table = checkSameTable(table.getTableNum(),table);
// same = 1;
// }
// else
System.out.println("table "+table.getTableNum()+": ");
s = in.nextLine();
while(s.indexOf("table")==-1&&s.indexOf("end")==-1){
if(s.equals("")){
System.out.println("wrong format");
s = in.nextLine();
continue;
}
if(!table.isValid()){
break;
}
if(s.indexOf("delete")==-1){
table.getOrder().setOrderRecord(s,menu, table.getTableNum(),same);
}
else if(s.indexOf("delete")!=-1) //删除点菜记录
table.getOrder().deleteRecord(s);
else
System.out.println("wrong format");
s = in.nextLine();
}
if(table.isValid()) { //插入桌信息
// int count = 0;
// for(int i=0;i<tableList.size();i++){
// if(tableList.get(i).getTableNum()>table.getTableNum()){
// tableList.add(i,table);
// count = 1;
// break;
// }
// }
// if(count!=1)
tableList.add(table);
}
}
//输出订单总量信息
boolean calculate[] = new boolean[tableList.size()];
for(int i = 0;i<tableList.size();i++){
if(calculate[i])
continue;
if(!tableList.get(i).checkTime1()&&checkSameTable(i,tableList.get(i))!=null) //判断是否在工作时间之外和后续是否有相同桌
continue;
if(!tableList.get(i).checkTime()){
continue;
}
if(tableList.get(i).isValid()) {
tableList.get(i).order.addSameRecord();
int beforeSum = 0;
int afterSum = 0;
for(int j = i+1;j<tableList.size();j++){
if(checkSameTable(j,tableList.get(j))!=null)
calculate[j] = true;
else
continue;
if(tableList.get(j).checkTime1()&&checkSameTable(j,tableList.get(j))!=null){
// //table = checkSameTable(table.getTableNum(),table);
// same = 1;
// beforeSum+=tableList.get(j).getAllPrice();
// afterSum+=tableList.get(j).getToTalPrice();
tableList.get(i).addPortion(tableList.get(j));
beforeSum+=tableList.get(j).getAllPrice();
afterSum+=tableList.get(j).getToTalPrice();
// calculate[j]=true;
}
}
beforeSum += tableList.get(i).getAllPrice();
afterSum += tableList.get(i).getToTalPrice();
// System.out.println("table " + tableList.get(i).getTableNum() + ": " + tableList.get(i).getOrder().getAllPrice() + " " +
// tableList.get(i).getToTalPrice());
System.out.println("table "+tableList.get(i).getTableNum() +": "+beforeSum+" "+afterSum);
}
}
/*if(tableList.size()==0)
System.out.println("wrong format");*/
}
public boolean checkDishValid(String s){ //检查菜谱信息合法性
String rightPrice = "[1-9][0-9]{0,}"; //菜谱单价格式
String str[] = s.split(" ");
if(str.length<2||str.length>3){
System.out.println("wrong format");
return false;
}
if(str[1].indexOf(".")!=-1){
System.out.println("wrong format");
return false;
}
if(!str[1].matches(rightPrice)){
System.out.println("wrong format");
return false;
}
if(str.length==2&&Integer.parseInt(str[1])>0&&Integer.parseInt(str[1])<=300)
return true;
if(str.length==3&&Integer.parseInt(str[1])>0&&str[2].equals("T")&&Integer.parseInt(str[1])<=300)
return true;
if(str.length==3&&!str[2].equals("T")){
System.out.println("wrong format");
}
else
System.out.println(str[0]+" price out of range "+str[1]);
return false;
}
// public static boolean checkTableNum(int num){ //检查桌号是否存在
// for(int i = 0;i<tableList.size();i++){
// if(tableList.get(i).getTableNum()==num){
// System.out.println("Table number :"+num+" does not exist");
// return false;
// }
// }
// return true;
// }
public static boolean searchTableNum(int be_tabled){
for(int i = 0;i<tableList.size();i++){
if(tableList.get(i).getTableNum()==be_tabled)
return true;
}
System.out.println("Table number :"+be_tabled+" does not exist");
return false;
}
public Table checkSameTable(int num,Table table){ //检查桌号时间是否存在
for(int i= 0;i<tableList.size();i++){
if(num==i)
continue;
if(table.getTableNum() == tableList.get(i).getTableNum()&&checkSameTime(table,tableList.get(i)))
return tableList.get(i);
}
return null;
}
public boolean checkSameTime(Table table1,Table table2){ //比较是否是同一时间段,以便合并相同桌号
LocalTime time1 = LocalTime.of(10,29,59);//上午
LocalTime time2 = LocalTime.of(14,30,1);
LocalTime time3 = LocalTime.of(16,59,59); //下午
LocalTime time4 = LocalTime.of(20,30,1);
int workDay = table1.getTableDate().getDayOfWeek().getValue();
if(table1.getTableDate().until(table2.getTableDate(),ChronoUnit.DAYS)!=0){
return false;
}
Duration duration = Duration.between(table1.getTableTime(),table2.getTableTime());
if(workDay<6){
if(time1.isBefore(table1.getTableTime())&&time1.isBefore(table2.getTableTime())&&time2.isAfter(table1.getTableTime())&&time2.isAfter(table2.getTableTime()))
return true;
else if(time3.isBefore(table1.getTableTime())&&time3.isBefore(table2.getTableTime())&&time4.isAfter(table1.getTableTime())&&time4.isAfter(table2.getTableTime()))
return true;
else
return false;
}
if(Math.abs(duration.toSeconds())>=3600||!table2.checkTime1()){
return false;
}
return true;
}
}
public class Dish extends AbstractDish{ //菜品类
public Dish() {
}
public Dish(String name, int price,Boolean special) {
super(name, price,special);
}
@Override
public int getPrice(int portion) { //获得当前份额和份数的价格
if(portion==1)
return getUnit_price();
else if(portion==2)
return (int)(getUnit_price()*1.5+0.5);
else
return getUnit_price()*2;
}
}
package pta6;
import java.time.LocalDate;
import java.util.ArrayList;
public abstract class AbstractOrder {
ArrayList<AbstractRecord> recordList = new ArrayList<>();
public AbstractOrder(ArrayList<AbstractRecord> records) {
this.recordList = records;
}
protected AbstractOrder() {
}
public abstract void addARecord(int orderNum,
String dishName, int portion, int num); //增加点菜记录
public abstract boolean checkPortion(int recordNum, int portion, boolean special); //检查份额
public abstract boolean checkNum(int recordNum, int num); //检查份数
public abstract boolean checkRecordValid(String s, Menu menu, int tableNum, int same); //检查点菜合法性
public abstract void addAOtherRecord(int otherTable, int orderNum, String dishName, int portion, int num);//设置代点菜信息
public abstract void setOrderRecord(String s,Menu menu,int tableNum,int same); //设置点菜信息
public abstract void deleteRecord(String s); //删除点菜记录
public abstract int getAllPrice(); //获得没打折的价格
public abstract boolean checkIsDish(String s); //检查是否存在该dish
public abstract void addSameRecord(); //将相同份额的份数相加
}
采坑心得
这三次题目集就是比较有难度的一个阶段,从难度来讲,真的是让人难以接受,虽然过程痛苦,代码写得不咋地,但总归熬了过来,以下就是一些心得体会:
1、对于题目要认真去做,一些知识点要掌握好,正则表达式和那个split函数就是后面解题的关键。
2、要认真读题目,特别对于长的题目一定要读三遍以上,不然就容易走弯路,陷入“你以为”,结果你以为的都是错的。
3、在写代码之前要先做一些类间关系的构建和思考,不然就会在写代码时陷入一种迷茫的境地,不知道自己在干什么。
4、非常重要的就是写代码一定要有注释,不仅方便自己阅读和修改,也影响批改人阅读。
5、看问题要全面,测试点的提示对自己不一定有用,如测试点提示时间错误,结果竟然是某个算法没有写对,对于题目的要求和思考的层面还不够清晰。
6、要善于使用java一些好用的函数或者好用的结构去写代码,这样能够使复杂问题变得简单化,如果是用c语言写那个菜单计价程序的话估计就完蛋了,压根没啥想法思路。
改进建议
对于这几次题目集,千言万语尽在建议中:
1、对于题目难度希望有一个明显升高的过程,不能一下就蹦高了,很容易让人够不着,那下一次就更加会认为够不着。
2、题目的量的还是挺足的,希望能够出点针对性强一点的。
3、希望下次对于题目的一些解释能够多些,一些测试用例也多点,这样有助于我们理解题意,减少许多不必要的时间浪费。
4、希望上课的时候能够多一点实例化的演示,加深我们的理解。
总结:
课程上:经过一个多月的学习我是真真切切的感受到了面向对象这门课的难度在逐渐升高,确实如同老师所说,不是C语言能够比的,对于课上的一些知识和题目,都有一定的扩展,这是C语言所没有的,最近在上模式这方面的内容,归根结底还是继承和多态,解耦几个字,感觉难度有点小大,对于工厂方法模式怎么符合开闭原则有点迷糊,可能是对于配置文件的使用不够了解导致我无法理解。在模式混合用这块,不是很理解,模式与模式之间的关系,应用到代码上的长处和短处。
题目上:对于这三次题目集,难度是出奇的诡异,题目集4中,最难的放在前面,而后面的题目中有解题要用的东西,这种排列顺序很让人疑惑,很多人在看到第一题就已经放弃了,还好我是从后面先做的。其实对于这些题目的难度就体现在我们刚刚接触这方面的东西,之前做的题目都没有与这相差这么大,让我们有些迷惑,在看到这种题目之后变得手足无措,希望以后的题目可以循序渐进,不要一高一低,好在最后坚持了下来,不然将严重打击自信心。还有某些题目的测试点真的是坑,需要大量的时间来踩,比如题目集6,恰恰我们缺的就是时间,导致最后交的时候没来得及整理代码就交上去了,造成代码太过杂乱无章,注释也缺少许多。
其它:经过这三次题目集的训练,又增加了我对面向对象的封装性和一些设计原则的理解,果然只有动手多练才能学到东西,纸上谈兵无用,正则表达式,继承,单一职责等等,不经过大量的训练,很难对其有一些深入的理解。每次做这些题目集,总会学到许多新奇好用的东西,那个spilt函数就是一个很好的例子,后面的题目都需要用它。面向对象的思想和技术确实是十分的好用,可以将许多的复杂问题变得简单化,但可惜的是自己并没有完全的从面向过程转移过来,还是需要不断地练习矫正自己的思维定式。对于题目而言,题目的描述就是需求,我们要学会从描述中去提取需求,这样才能在以后得路上走得更远,这次题目集我就是对于一些题目的描述和要求没有认真去思考,导致浪费了好多时间,这点我是极其的悲愤的。还有自己也对于一些基本的代码编排和基本知识掌握不牢,正则表达式频频出错,大大拖延了写题的速度,这点还是需要加强。
标签:题目,int,value,day,date,getValue,public From: https://www.cnblogs.com/hz-blogs/p/17360542.html