第二次博客作业
一、前言
近段时间主要进行了菜单计价程序的迭代。并进行了期中测试。
涉及到了封装、继承、多态、类与类之间的联系、哈希表、日期类的使用、正则表达式、java程序整体设计原则等知识。
题量上,第二次、第三次菜单计价较为简单,第四次菜单计价对比之前主要增加了异常情况的分析和一些相关输出,第五次和第四次一样,均在第三次菜单的基础上进行迭代,增加了特色菜和菜系、口味的概念,并且对一些相关的输出增加了一定要求,代码量就迅速增加,难度较大。
期中考试:
期中考试有四道题,层层递进的,不断迭代,题目较为简单但由于考试过程中处理报错时间过长,导致没能及时完成。
期中涉及到的知识点:
- 使用ArrayList存储Shape对象。
- 使用while循环根据用户选择创建不同类型的形状对象并添加到ArrayList中。
- 使用Comparator接口的naturalOrder()方法对列表进行排序。
- 实现Comparable接口来定义Shape对象之间的比较规则。
- 创建Point类来表示坐标点。
- 创建抽象类Shape,并在子类Circle和Rectangle中实现抽象方法
二、设计与分析
菜单计价程序2

import java.util.Scanner; class Dish { String name; int unit_price; public void setname(String name) { this.name = name; } public String getname() { return name; } public void setunit_price(int unit_price) { this.unit_price = unit_price; } public int getunit_price() { return unit_price; } int getPrice(int portion) { if (portion == 1) return unit_price; else if (portion == 2) return (int) Math.round(unit_price * 1.5); else if (portion == 3) return unit_price * 2; else return 0; } } class Menu { Dish[] dishs = new Dish[50]; int count = 0;// 菜数量 public Dish searchDish(String dishName) { for (Dish dish : dishs) { if (dish != null && dish.name.equals(dishName)) { return dish; } } return null; } Dish addDish(String dishName, int unit_price) { if(searchDish(dishName)!=null) { Dish dishd=searchDish(dishName); dishd.setunit_price(unit_price); return dishd; } else { Dish dishm = new Dish(); dishm.setname(dishName); dishm.setunit_price(unit_price); dishs[count] = dishm; count++; return dishm; } } } class Record { int orderNum; Dish dish; int portion; int num; int getTotalPrice() { return num * dish.getPrice(portion); } } class Order { Record[] records = new Record[50]; int totalPrice = 0; int getTotalPrice() { for (Record record : records) { if (record != null) { totalPrice += record.getTotalPrice(); } } return totalPrice; } Record addARecord(int orderNum, String dishName, int portion, int num, Menu menu) { Record record = new Record(); Dish dish = menu.searchDish(dishName); if (dish == null) { System.out.println(dishName + " does not exist"); return null; } record.orderNum = orderNum; record.dish = dish; record.portion = portion; record.num = num; records[orderNum - 1] = record; System.out.println(record.orderNum + " " + record.dish.name + " " + record.getTotalPrice()); return record; } void delARecordByOrderNum(int orderNum)// 根据序号删除一条记录 { if (records[orderNum - 1] != null) { records[orderNum - 1] = null; } else { System.out.println("delete error;"); } } Record findRecordByNum(int orderNum)// 根据序号查找一条记录 { for (Record record : records) { if (record != null && record.orderNum == orderNum) { return record; } } return null; } } public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); Order order = new Order(); Menu menu = new Menu(); String b = ""; b = input.nextLine(); String[] a = new String[50]; int orderNum = 1; while (!b.equals("end")) { a = b.split(" "); if (a.length == 2 && !a[1].equals("delete")) { int unit_price = Integer.parseInt(a[1]); menu.addDish(a[0], unit_price); } if (a.length == 4) { int portion = Integer.parseInt(a[2]); int num = Integer.parseInt(a[3]); order.addARecord(orderNum, a[1], portion, num, menu); orderNum++; } if (a.length == 2 && a[1].equals("delete")) { int deleteOrderNum = Integer.parseInt(a[0]); order.delARecordByOrderNum(deleteOrderNum); } b = input.nextLine(); } System.out.println(order.getTotalPrice()); } }
分析:
Menu 类:对控制台输入的字符进行分析处理,判断是订单信息还是增加菜品信息。此类负责管理菜单项,其中 addDish 方法可用于将新的餐品(属性为名字和价格)添加到菜单列表中。另外, findDishByName 方法可用于查找指定名称的餐品。
Dish 类: 表示某一道菜品,包含了名称、单价等基本属性及操作方法。
Record 类:表示用户购买的一条记录,即某个餐品和对应数量组成的记录。其中 price 方法用于计算当前条目的总价格,分为小份中份和大份。
Order 类:表示订单,可以通过菜单和记录列表来创建一个 Order 对象。addARecord 和 delARecordByOrderNum 两个方法可用于添加或删除错误的记录。getTotalPrice 方法可用于获取整个订单的总价值。
本次迭代封装了每个类,使各部分的功能职责分开了。
菜单计价程序4

sourse Monitor 报表内容:

实验代码:
import java.text.ParseException; import java.time.DateTimeException; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Scanner; public class Main { public static boolean isNumeric(String string) { int intValue; try { intValue = Integer.parseInt(string); return true; } catch (NumberFormatException e) { return false; } } public static void main(String[] args) throws ParseException { Menu menu = new Menu(); ArrayList<Table> tables = new ArrayList<Table>(); Scanner input = new Scanner(System.in); String str1 = new String(); int i = 0; int portion = 0, quota = 0; while (true) {// 输入菜单 Dish temp = new Dish(); int isRepeat = -1; str1 = input.nextLine(); if (str1.matches("[\\S]* [1-9][\\d]*")) { String[] token = str1.split(" "); temp.name = token[0]; temp.unit_price = Integer.parseInt(token[1]); if (temp.unit_price > 300) { System.out.println(temp.name + " price out of range " + temp.unit_price); continue; } temp.isT = false; isRepeat = menu.searchDish(temp.name); if (isRepeat != -1) { menu.dishs.remove(isRepeat); } menu.dishs.add(temp); } else if (str1.matches("[\\S]* [\\d]* T")) { String[] token = str1.split(" "); temp.name = token[0]; temp.unit_price = Integer.parseInt(token[1]); if (temp.unit_price > 300) { System.out.println(temp.name + " price out of range " + temp.unit_price); continue; } temp.isT = true; if (isRepeat != -1) { menu.dishs.remove(isRepeat); } menu.dishs.add(temp); } else if (str1.equals("end")) { break; } else if (str1.matches("tab.*")) { break; } else { System.out.println("wrong format"); continue; } } while (!str1.equals("end")) { Table temp = new Table(); boolean isRepeat = false; int repeatNum = 0; if (str1.matches("table.*")) { if (str1.matches("table [1-9][\\d]* [\\d]*/[\\d][\\d]?/[\\d][\\d]? [\\d][\\d]?/[\\d][\\d]?/[\\d][\\d]?")) { String[] token = str1.split(" "); String[] Date = token[2].split("/"); String[] Time = token[3].split("/"); int[] intDate = new int[3]; int[] intTime = new int[3]; for (i = 0; i < 3; i++) { intDate[i] = Integer.parseInt(Date[i]); intTime[i] = Integer.parseInt(Time[i]); } temp.num = Integer.parseInt(token[1]); if (temp.num > 55) { System.out.println(temp.num + " table num out of range"); str1 = input.nextLine(); continue; } try { temp.time = LocalDateTime.of(intDate[0], intDate[1], intDate[2], intTime[0], intTime[1], intTime[2]); temp.getWeekDay(); } catch (DateTimeException e) { System.out.println(temp.num + " date error"); str1 = input.nextLine(); continue; } if (!(temp.time.isAfter(LocalDateTime.of(2022, 1, 1, 0, 0, 0)) && temp.time.isBefore(LocalDateTime.of(2024, 1, 1, 0, 0, 0)))) { System.out.println("not a valid time period"); str1 = input.nextLine(); continue; } // 判断桌号是否重复 if (temp.isOpen()) { for (i = 0; i < tables.size(); i++) { // 有重复的桌号 if (temp.num == tables.get(i).num && tables.get(i).isOpen()) { Duration duration = Duration.between(temp.time, tables.get(i).time); // 同一天 if (duration.toDays() == 0) { // 在周一到周五 if (temp.weekday > 0 && temp.weekday < 6) { // 在同一时间段 if (temp.time.getHour() < 15 && tables.get(i).time.getHour() < 15) { temp = tables.get(i); isRepeat = true; repeatNum = i; break; } } // 在周末 else { // 时间相差小于一小时 if (duration.toHours() < 3600) { temp = tables.get(i); repeatNum = i; isRepeat = true; break; } } } } } } if(!isRepeat) { System.out.println("table " + temp.num + ": "); } } else { System.out.println("wrong format"); str1 = input.nextLine(); continue; } // 本桌开始点菜 while (true) { str1 = input.nextLine(); if (str1.matches("[1-9][\\d]* [\\S]* [\\d] [1-9][\\d]*")) { String[] token = str1.split(" "); portion = Integer.parseInt(token[2]); quota = Integer.parseInt(token[3]); if (temp.order.records.size() > 0) { if (Integer.parseInt( token[0]) <= temp.order.records.get(temp.order.records.size() - 1).orderNum) { System.out.println("record serial number sequence error"); continue; } } if (menu.searchDish(token[1]) == -1) { System.out.println(token[1] + " does not exist"); continue; } if (portion > 3 || portion < 1) { System.out.println(Integer.parseInt(token[0]) + " portion out of range " + portion); continue; } if (quota > 15) { System.out.println(Integer.parseInt(token[0]) + " num out of range " + quota); continue; } temp.od(menu, token[0], token[1], portion, quota); } // 判断是否为删除订单 else if (str1.matches("[1-9][\\d]* delete")) { String[] token = str1.split(" "); temp.order.delARecordByOrderNum(Integer.parseInt(token[0])); } // 判断是否为夹杂菜单 else if (str1.matches("[\\S]* [\\d]*")) { System.out.println("invalid dish"); continue; } else if (str1.matches("[\\S]* [\\d]* T")) { System.out.println("invalid dish"); continue; } // 判断是否为代点 else if (str1.matches("[\\d]* [\\d]* [\\S]* [\\d] [1-9][\\d]*")) { String[] token = str1.split(" "); // 判断代点桌号是否存在 boolean exist = false; for (int j = 0; j < tables.size(); j++) { if (tables.get(j).num == Integer.parseInt(token[0])) { exist = true; break; } } if (exist) { System.out.print(Integer.parseInt(token[1]) + " table " + temp.num + " pay for table " + Integer.parseInt(token[0]) + " "); Record treat = new Record(); treat.d = menu.dishs.get(menu.searchDish(token[2])); portion = Integer.parseInt(token[3]); quota = Integer.parseInt(token[4]); treat.portion = portion; treat.quota = quota; System.out.print(treat.getPrice() + "\n"); temp.sum += treat.getPrice(); } // 若不存在则输出内容 else { System.out.println("Table number :" + Integer.parseInt(token[0]) + " does not exist"); } } else if (str1.equals("end")) { break; } else if(str1.matches("ta.*")){ break; } else { System.out.println("wrong format"); continue; } } } else if (str1.matches("t.*")) { isRepeat = true; temp = tables.get(tables.size()); while (true) { str1 = input.nextLine(); if (str1.matches("[1-9][\\d]* [\\S]* [\\d] [1-9][\\d]*")) { String[] token = str1.split(" "); portion = Integer.parseInt(token[2]); quota = Integer.parseInt(token[3]); // 判断订单号是否由小到大排列 if (temp.order.records.size() > 0) { if (Integer.parseInt( token[0]) <= temp.order.records.get(temp.order.records.size() - 1).orderNum) { System.out.println("record serial number sequence error"); continue; } } if (menu.searchDish(token[1]) == -1) { System.out.println(token[1] + " does not exist"); continue; } if (portion > 3 || portion < 1) { System.out.println(Integer.parseInt(token[0]) + " portion out of range " + portion); continue; } if (quota > 15) { System.out.println(Integer.parseInt(token[0]) + " num out of range " + quota); continue; } temp.od(menu, token[0], token[1], portion, quota); } // 判断是否为删除订单 else if (str1.matches("[1-9][\\d]* delete")) { String[] token = str1.split(" "); temp.order.delARecordByOrderNum(Integer.parseInt(token[0])); } // 判断是否为夹杂菜单 else if (str1.matches("[\\S]* [\\d]*")) { System.out.println("invalid dish"); continue; } else if (str1.matches("[\\S]* [\\d]* T")) { System.out.println("invalid dish"); continue; } // 判断是否为代点 else if (str1.matches("[\\d]* [\\d]* [\\S]* [\\d] [1-9][\\d]*")) { String[] token = str1.split(" "); // 判断代点桌号是否存在 boolean exist = false; for (int j = 0; j < tables.size(); j++) { if (tables.get(j).num == Integer.parseInt(token[0])) { exist = true; break; } } if (exist) { System.out.print(Integer.parseInt(token[1]) + " table " + temp.num + " pay for table " + Integer.parseInt(token[0]) + " "); Record treat = new Record(); treat.d = menu.dishs.get(menu.searchDish(token[2])); portion = Integer.parseInt(token[3]); quota = Integer.parseInt(token[4]); treat.portion = portion; treat.quota = quota; System.out.print(treat.getPrice() + "\n"); temp.sum += treat.getPrice(); } // 若不存在则输出内容 else { System.out.println("Table number :" + Integer.parseInt(token[0]) + " does not exist"); } } else if (str1.equals("end")) { break; } else { System.out.println("wrong format"); continue; } } if (tables.size() != 0) { tables.get(tables.size() - 1).order.records.addAll(temp.order.records); } } else { str1 = input.nextLine(); continue; } // 本桌点菜结束,进入下一桌 if (isRepeat) { tables.remove(repeatNum); } temp.getSum(); tables.add(temp); } // 最终输出桌号订单信息 for (i = 0; i < tables.size(); i++) { if (tables.get(i).isOpen()) { System.out .println("table " + tables.get(i).num + ": " + tables.get(i).origSum + " " + tables.get(i).sum); } else System.out.println("table " + tables.get(i).num + " out of opening hours"); } } static class Dish { String name; int unit_price; boolean isT = false; } static class Record { int orderNum; Dish d; int portion; int quota; boolean isDeleted = false; int getPrice() { if (portion == 2) return (int) Math.round(1.5 * d.unit_price) * quota; else if (portion == 3) return 2 * d.unit_price * quota; else return d.unit_price * quota; } } static class Menu { ArrayList<Dish> dishs = new ArrayList<Dish>(); int searchDish(String dishName) { for (int i = 0; i < dishs.size(); i++) { if (dishName.equals(dishs.get(i).name)) { return i; } } return -1; } Dish addDish(String dishName, int unit_price) { Dish newDish = new Dish(); newDish.name = dishName; newDish.unit_price = unit_price; return newDish; } } static class Order { // Record[] records = new Record[20]; ArrayList<Record> records = new ArrayList<Record>(); Record addARecord(int orderNum, String dishName, int portion, int quota, Menu menu) { Record newRecord = new Record(); newRecord.orderNum = orderNum; newRecord.d = menu.dishs.get(menu.searchDish(dishName)); newRecord.portion = portion; newRecord.quota = quota; System.out.println(newRecord.orderNum + " " + newRecord.d.name + " " + newRecord.getPrice()); return newRecord; } int searchReocrd(String name) { for (int i = 0; i < records.size(); i++) { if (records.get(i).d.name == name) { return i; } } return -1; } boolean delARecordByOrderNum(int orderNum) { int i = 0, flag = 0; for (i = 0; i < records.size(); i++) { if (records.get(i).orderNum == orderNum) { if (records.get(i).isDeleted == false) { records.get(i).isDeleted = true; } else { System.out.println("deduplication " + orderNum); } flag++; } } if (flag == 0) { System.out.println("delete error;"); return false; } return true; } } static class Table { Order order = new Order(); int num; LocalDateTime time; int weekday; long sum = 0; long origSum = 0; void od(Menu menu, String str1, String str2, int portion, int quota) { { order.records.add(order.addARecord(Integer.parseInt(str1), str2, portion, quota, menu)); } } void getWeekDay() { weekday = time.getDayOfWeek().getValue(); } void getSum() { for (int i = 0; i < order.records.size(); i++) { if (!order.records.get(i).isDeleted) { origSum += order.records.get(i).getPrice(); if (order.records.get(i).d.isT) { if (weekday > 0 && weekday < 6) { sum += Math.round(order.records.get(i).getPrice() * 0.7); } else { sum += order.records.get(i).getPrice(); } } else { if (weekday > 0 && weekday < 6) { if (time.getHour() >= 17 && time.getHour() < 20) sum += Math.round(order.records.get(i).getPrice() * 0.8); if (time.getHour() == 20) { if (time.getMinute() <= 30) sum += Math.round(order.records.get(i).getPrice() * 0.8); } if (time.getHour() >= 10 && time.getHour() < 14) sum += Math.round(order.records.get(i).getPrice() * 0.6); if (time.getHour() == 14) { if (time.getMinute() <= 30) sum += Math.round(order.records.get(i).getPrice() * 0.6); } } else sum+=order.records.get(i).getPrice(); } } } } boolean isOpen() { if (weekday > 0 && weekday < 6) { if (time.getHour() >= 17 && time.getHour() < 20) return true; if (time.getHour() == 20) { if (time.getMinute() <= 30) return true; } if (time.getHour() > 10 && time.getHour() < 14) return true; if (time.getHour() == 10) { if (time.getMinute() >= 30) return true; } if (time.getHour() == 14) { if (time.getMinute() <= 30) return true; } } else { if (time.getHour() > 9 && time.getHour() < 21) return true; if (time.getHour() == 9) { if (time.getMinute() >= 30) return true; } if (time.getHour() == 21) { if (time.getMinute() <= 30) return true; } } return false; } } }
分析:
本题代码在菜单计价程序3的基础上进行修改。首先是类设计方面,舍弃了菜单计价程序3中将价格以属性的形式存放在Order类中,而实将其抽象出一个Table类,用来存放桌号信息以及记录每一桌打折前和打折后的价格。在Dish类中,添加一个属性type,用来区分是否为特色菜。在Order类中添加属性discount2,用来存放特色菜的打折信息。ArrayList<Table>类型的tables属性则是取代了菜单计价程序3中的tableprice属性,用来记录每一桌的情况。添加ArrayList<Record>类型的repeaatrecords属性则是为了解决重复删除时的输出问题。在Order类的方法中,也有了很大的改变,首先是计算总价的方法getTotalPrice(),添加了计算打折前和打折后价钱的代码。
重点在于异常处理代码的更新修改:
第一个while循环中,用户输入的菜单信息会被解析并添加到菜单(Menu)中。下面是异常输入处理的具体步骤:
- 用户输入的菜单信息通过Scanner对象input接收,并使用split方法按空格分割成字符串数组。
- 使用isNumeric静态方法判断数组的第一个元素是否为数字,如果不是,则表示输入的菜品名称格式错误。
- 如果数组长度为2,则表示输入的菜品信息中包含了特价菜标记"T",需要将菜品名称和价格分别提取出来。
- 如果数组长度为1,则表示输入的菜品信息中不包含特价菜标记,直接将菜品名称和价格设置为数组的第一个元素。
- 将菜品名称和价格添加到菜单(Menu)的动态数组中。
在第二个while循环中,用户输入的桌号和点餐信息会被解析并进行相应的处理。下面是异常输入处理的具体步骤:
- 用户输入的桌号和点餐信息通过Scanner对象input接收,并使用split方法按空格分割成字符串数组。
- 使用isNumeric静态方法判断数组的第一个元素是否为数字,如果不是,则表示格式错误,并具体进行分析,判断具体错误类型。
- 将桌号、菜品序号、份数和数量分别提取出来,并进行相应的处理,比如判断菜品序号是否存在、计算订单金额等。最后进入相应的处理逻辑,输出异常状况提示字符
菜单计价程序5

import java.util.Map.Entry; import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String a; a=scanner.nextLine(); while(!a.equals("end")) { input.judgement(a); a=scanner.nextLine(); } table.show(); custome.show(); } } class Table { Order order; int num; int year; int month; int day; int shi; int fen; int miao; int week; public Table(){ } public boolean check() { int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (month >= 1 && month <= 12) { int maxDay = days[month - 1] + ((month == 2 && ((year % 100 == 0 && year % 400 == 0) || year % 4 == 0)) ? 1 : 0); return day >= 1 && day <= maxDay; } return false; } boolean checkorder(int x){//检查点菜序号 return true; } } class recheck1 { int fenshu; void addfind(){ while(fenshu==0) { int i=0; fenshu++; } } } class table { int tablenum;//桌号 String time;//点菜时间 int year=0,month=0,day=0,ww=0,hh=0,mm=0,ss=0; boolean flag=true;//判断时间是否正确 double count=0,specialcount=0;//折扣 Order eatorder=new Order(); Order buyorder=new Order(); int sum=0,truesum1=0;//计算总价 double truesum=0; int a1=0,b1=0,c1=0;//记录dishtype对应菜份数 int a2=0,b2=0,c2=0;//总辣酸甜diahdegree static int n=0;//记录当前处理桌号 static boolean newtable(String a) { table t=new table(); t.input(a); if(t.flag) { Data.t.put(t.tablenum, t); n=t.tablenum; return true; } return false; } void input(String time)//预处理 { this.time=time; timechange(); timecount(); pdflag(); } void getTotalPrice()//计算桌总价 { if(flag) { for(Record it:buyorder.records){ int n=it.price; sum+=n; if(it.d.special) truesum+=(int)(n*specialcount+0.5); else truesum+=(int)(n*count+0.5); } truesum1=(int)(truesum+0.5); System.out.print("table "+tablenum+": "+sum+" "+truesum1); } } void getTotalkoweidu() { for(Record it:eatorder.records){ if(it.d.special) { if(it.d.dishtype==1) { int y=it.num; a1+=y; a2+=it.口味*y; } else if(it.d.dishtype==2) { int y=it.num; b1+=y; b2+=it.口味*y; } else if(it.d.dishtype==3) { int y=it.num; c1+=y; c2+=it.口味*y; } } } if(a1==0&&b1==0&&c1==0) System.out.print(" "); if(a1!=0) { a2=(int)(a2*1.0/a1+0.5); System.out.print(" 川菜 "+a1); switch(a2) { case 0:System.out.print(" 不辣");break; case 1:System.out.print(" 微辣");break; case 2:System.out.print(" 稍辣");break; case 3:System.out.print(" 辣");break; case 4:System.out.print(" 很辣");break; case 5:System.out.print(" 爆辣");break; } } if(b1!=0) { b2=(int)(b2*1.0/b1+0.5); System.out.print(" 晋菜 "+b1); switch(b2) { case 0:System.out.print(" 不酸");break; case 1:System.out.print(" 微酸");break; case 2:System.out.print(" 稍酸");break; case 3:System.out.print(" 酸");break; case 4:System.out.print(" 很酸");break; } } if(c1!=0) { c2=(int)(c2*1.0/c1+0.5); System.out.print(" 浙菜 "+c1); switch(c2) { case 0:System.out.print(" 不甜");break; case 1:System.out.print(" 微甜");break; case 2:System.out.print(" 稍甜");break; case 3:System.out.print(" 甜"); break; } } System.out.print("\n"); } void timecount()//运用时间计算折扣 { if(ww>=1&&ww<=5) { specialcount=0.7; if(hh>=17&&hh<20) count=0.8; else if(hh==20&&mm<30) count=0.8; else if(hh==20&&mm==30&&ss==0) count=0.8; else if(hh>=11&&hh<=13||hh==10&&mm>=30) count=0.6; else if(hh==14&&mm<30) count=0.6; else if(hh==14&&mm==30&&ss==0) count=0.6; } else { specialcount=1.0; if(hh>=10&&hh<=20) count=1.0; else if(hh==9&&mm>=30) count=1.0; else if(hh==21&&mm<30||hh==21&&mm==30&&ss==0) count=1.0; } } void pdflag()//判断时间是否正确 { if(count==0) { System.out.println("table "+tablenum+" out of opening hours"); flag=false; } else { System.out.println("table "+tablenum+": "); flag=true; } } void timechange()//时间转换 { String[] arr1=time.split(" "); tablenum=Integer.parseInt(arr1[1]);//桌号 String[] arr2=arr1[2].split("/"); String[] arr3=arr1[3].split("/"); year=Integer.parseInt(arr2[0]);//时间 month=Integer.parseInt(arr2[1]); day=Integer.parseInt(arr2[2]); Calendar c = Calendar.getInstance(); c.set(year,month-1,day);//设置时间 ww=c.get(Calendar.DAY_OF_WEEK); hh=Integer.parseInt(arr3[0]);//时间 mm=Integer.parseInt(arr3[1]); ss=Integer.parseInt(arr3[2]); if(ww==1) ww=7; else ww--; } static void show() { Set<Entry<Integer,table>> entrySet = Data.t.entrySet(); for(Map.Entry<Integer,table> entry : entrySet){ entry.getValue().getTotalPrice(); entry.getValue().getTotalkoweidu(); } } } class Record { Dish d=new Dish(); int orderNum=0; int portion=0; int num=0;//份数 int tablenum=0; int 口味=0; boolean flag=false; int price=0; void getPrice(boolean flag1)//判断是否为带点菜,true为是,t表示自己桌号 { int n=0; if(d!=null) { price=num*d.getPrice(portion); if(flag1) { System.out.println(orderNum+" table "+table.n+" pay for table "+tablenum+" "+price); } else { System.out.println(orderNum+" "+d.name+" "+price); } } } } class Order { List<Record> records=new ArrayList<Record>(); int j=0; void addARecord(String a,boolean flag1)//添加一条菜品信息到订单中。 { String[]arr=a.split(" "); boolean flag=false;//判断是否为代点菜 int orderNum=0,portion=0,tablenum=0,num=0,口味=0; String name=""; if(arr.length==4)//自己点不是特色菜 { orderNum=Integer.parseInt(arr[0]); name=arr[1]; portion=Integer.parseInt(arr[2]); num=Integer.parseInt(arr[3]); } else if(arr.length==5) { if(arr[1].matches("^/d{1,}$"))//代点不是特色菜 { tablenum=Integer.parseInt(arr[0]); orderNum=Integer.parseInt(arr[1]); name=arr[2]; portion=Integer.parseInt(arr[3]); num=Integer.parseInt(arr[4]); flag=true; } else//自己点特色菜 { orderNum=Integer.parseInt(arr[0]); name=arr[1]; 口味=Integer.parseInt(arr[2]); portion=Integer.parseInt(arr[3]); num=Integer.parseInt(arr[4]); } } else if(arr.length==6)//代点特色菜 { tablenum=Integer.parseInt(arr[0]); orderNum=Integer.parseInt(arr[1]); name=arr[2]; 口味=Integer.parseInt(arr[3]); portion=Integer.parseInt(arr[4]); num=Integer.parseInt(arr[5]); flag=true; } Record r=new Record(); r.tablenum=tablenum; r.orderNum=orderNum; r.d.name=name; r.portion=portion; r.num=num; r.口味=口味; r.d=Data.c.searthDish(a,flag1); if(r.d!=null) { if(flag1) r.getPrice(flag); records.add(r); } } void delARecordByOrderNum(String a,boolean flag1)//根据序号删除一条记录 { boolean flag=false; String[]arr=a.split(" "); int orderNum=Integer.parseInt(arr[0]); for(int i = 0; i < records.size(); i++) { Record value = records.get(i); // 符合条件,删除元素 if(value.orderNum==orderNum) { records.remove(i); flag=true; } } //不存在 if(flag==false&&flag1) { System.out.println("delete error;"); } } } class Menu { Map <String,Dish>dishs =new HashMap<>(); int i=0;//用于记录菜品总数 void addDish(String a) { String[] arr=a.split(" "); Dish d=new Dish(); d.name=arr[0]; if(arr.length==4)//特色菜 { d.special=true; d.unit_price=Integer.parseInt(arr[2]); if(arr[1].equals("川菜")) d.dishtype=1; else if(arr[1].equals("晋菜")) d.dishtype=2; else if(arr[1].equals("浙菜")) d.dishtype=3; } else//普通菜 { d.unit_price=Integer.parseInt(arr[1]); } dishs.put(d.name,d); } Dish searthDish(String a,boolean flag1) //根据菜名在菜谱中查找菜品信息,返回Dish对象。 { String dishName; String[] arr=a.split(" "); Dish d=new Dish(); if(arr[1].matches("^[0-9]{1,}$")) { dishName=arr[2]; } else dishName=arr[1]; if(dishs.containsKey(dishName)) { d=dishs.get(dishName); if(d.special&&arr.length==5) { int diahdegree=0; if(arr[1].matches("^[0-9]{1,}$")) { diahdegree=Integer.parseInt(arr[3]); } else { diahdegree=Integer.parseInt(arr[2]); } if(d.dishtype==1) { if(diahdegree!=0&&diahdegree!=1&&diahdegree!=2&&diahdegree!=3&&diahdegree!=4&&diahdegree!=5) { if(flag1) System.out.println("spicy num out of range :"+diahdegree); return null; } } else if(d.dishtype==2) { if(diahdegree!=0&&diahdegree!=1&&diahdegree!=2&&diahdegree!=3&&diahdegree!=4) { if(flag1) System.out.println("acidity num out of range :"+diahdegree); return null; } } else if(d.dishtype==3) { if(diahdegree!=0&&diahdegree!=1&&diahdegree!=2&&diahdegree!=3) { if(flag1) System.out.println("sweetness num out of range :"+diahdegree); return null; } } } return d; } else { if(flag1) System.out.println(dishName+" does not exist"); return null; } } } class Dish { String name="";//菜品名称 int unit_price; //单价 boolean special=false; int dishtype=0; int getPrice(int portion) { if (portion == 1) return unit_price; else if (portion == 2) return (int) Math.round(unit_price * 1.5); else if (portion == 3) return unit_price * 2; else return 0; } public void setname(String name) { this.name = name; } public String getname() { return name; } public void setunit_price(int unit_price) { this.unit_price = unit_price; } public int getunit_price() { return unit_price; } } class custome { String name; String phone_number; int sum=0; List<Integer>tablenum=new ArrayList<>(); // table 1 : tom 13605054400 2023/5/6 12/30/00 //约束条件:客户姓名不超过10个字符, //手机号11位,前三位必须是180、181、189、133、135、136其中之一。 static void newcustome(String x) { //分割 String[] arr=x.split(" "); custome m=new custome(); if(arr[3].matches("^.{1,10}$")&&arr[4].matches("^(180|181|189|133|135|136)[0-9]{8}$")) { m.name=arr[3]; m.phone_number=arr[4]; if(!Data.allcustome.containsKey(m.name)) Data.allcustome.put(m.name,m); Data.allcustome.get(m.name).addtable(table.n);//添加桌号 } else { System.out.println("wrong format"); } } static void show() { Set<Entry<String, custome>> entrySet = Data.allcustome.entrySet(); for(Map.Entry<String,custome> entry : entrySet) { entry.getValue().getttprice(); } } //table 1 : tom 13605054400 2023/5/1 18/30/00 void addtable(int n) { tablenum.add(n); } void getttprice() { Iterator it =tablenum.iterator(); while(it.hasNext()) { sum+=Data.t.get(it.next()).truesum; } System.out.println(name+" "+phone_number+" "+sum); } } class Data { static Map<String,custome> allcustome = new TreeMap<>(new Comparator<String>() { public int compare(String o1, String o2) { return o1.compareTo(o2); } }); static Map<Integer,table>t=new HashMap<>(); static Menu c=new Menu(); } class input//判断输入内容 { static void judgement(String a) { String[]arr=a.split(" | "); //分割 int len = arr.length; if(len==7&&arr[0].equals("table")&&arr[1].matches("^[1-9][0-9]{0,}$")&&arr[2].equals(":")&&arr[3].matches("^.{1,10}$")&&arr[4].matches("^[0-9]{11}$")&&arr[5].matches("^[0-9]{4}/[1-9][0-9]{0,1}/[1-9][0-9]{0,1}$")) { if(table.newtable(arr[0]+" "+arr[1]+" "+arr[5]+" "+arr[6])) { custome.newcustome(a); } } else if(len==2) { if(arr[1].equals("delete")&&arr[0].matches("^[0-9]{1,}$")&&table.n!=0) { Data.t.get(table.n).buyorder.delARecordByOrderNum(a,true); Data.t.get(table.n).eatorder.delARecordByOrderNum(a,false); } else if(arr[1].matches("^[0-9]{1,}$")) { Data.c.addDish(a); } } else if(len==4) { if(arr[3].equals("T")&&arr[1].matches("^(川菜)|(晋菜)|(浙菜)$")&&arr[2].matches("^[0-9]{1,}$")) Data.c.addDish(a); else if(arr[0].matches("^[0-9]{1,}$")&&arr[2].matches("^[0-9]{1,}$")&&arr[3].matches("^[0-9]{1,}$")&&(table.n!=0)) { Data.t.get(table.n).buyorder.addARecord(a,true); Data.t.get(table.n).eatorder.addARecord(a,false); } } else if(len==5&&arr[0].matches("^[1-9][0-9]{0,}$")&&(table.n!=0)) { if(arr[1].matches("^[0-9]{1,}$")) { Data.t.get(table.n).buyorder.addARecord(a,true); Data.t.get(Integer.parseInt(arr[1])).eatorder.addARecord(a,false); } else { Data.t.get(table.n).buyorder.addARecord(a,true); Data.t.get(table.n).eatorder.addARecord(a,false); } } else if(len==6&&table.n!=0&&Data.t.containsKey(Integer.parseInt(arr[1]))) { Data.t.get(table.n).buyorder.addARecord(a,true); Data.t.get(Integer.parseInt(arr[1])).eatorder.addARecord(a,false); } else if(table.n!=0||len!=2&&len!=4&&len!=5&&len!=6) { System.out.println("wrong format"); } } }
分析:
本次菜单在第三次菜单计价上增加了口味,如酸甜辣度、特色菜种类,并且对输出进行调整,增加了用户个人信息的记录,增加了一些异常处理情况:
其中错误处理和逻辑判断:
对用户的输入进行了错误处理,如输入非法字符、数字等情况的处理,提醒用户重新输入正确的信息。
程序在添加菜品、删除菜品、修改菜品等操作时,会对菜品是否存在进行判断,避免出现空指针异常。
在添加订单记录时,程序会对订单号、桌号是否重复进行判断,以保证订单信息的准确性。
代码使用了一个if-else语句来判断菜系类型。这个判断是基于用户输入的cuisine变量值,判断用户选择的是川菜、晋菜还是浙菜。在每个菜系的判断分支中,代码进一步使用了if-elif-else语句来判断口味。这个判断是基于用户输入的taste_level变量值,判断用户选择的是不辣、微辣、稍辣、辣、很辣还是爆辣等不同的口味级别。在每个菜系和口味的判断分支中,输出相应的特色菜。特色菜的名称和描述是通过specialties来存储,并根据不同的菜系和口味进行索引和输出。
期中测试:
1、
import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); double radius; radius=scanner.nextDouble(); Cricle circle=new Cricle(); circle.Cricle(radius); circle.sum(); } } class Cricle{ private double radius; public void Cricle(double radius1){ this.radius=radius1; } public void sum(){ if(radius<=0) System.out.print("Wrong Format"); else System.out.print(String.format("%.2f",(radius*radius*Math.PI))); } }
分析:
在Circle类中,定义了一个私有的radius属性,以及一个接受半径参数的构造函数。sum方法用于计算圆的面积,如果半径小于等于0,则输出"Wrong Format",否则输出计算得到的圆的面积,保留两位小数。
2、
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); double x1 = input.nextDouble(); double y1 = input.nextDouble(); double x2 = input.nextDouble(); double y2 = input.nextDouble(); Point a1 = new Point(x1, y1); Point a2 = new Point(x2, y2); Rectangle rectangle = new Rectangle(a1, a2); rectangle.getArea(); } } class Point { double x; double y; public Point(double x, double y) { this.x = x; this.y = y; } } class Rectangle { Point a1; Point a2; public Rectangle(Point p1, Point p2) { this.a1 = p1; this.a2 = p2; } public void getArea() { double length = Math.abs(a2.x - a1.x); double height = Math.abs(a2.y - a1.y); System.out.println(String.format("%.2f", (length * height))); } }
分析:
程序首先通过Scanner从用户输入中获取圆的半径,然后创建一个Circle对象并调用其sum方法来计算并输出圆的面积。
通过Scanner从用户输入中获取四个double类型的值,分别代表两个点的横纵坐标。然后创建两个Point对象表示这两个点,以及一个Rectangle对象来表示由这两个点构成的矩形,并调用其getArea方法来计算并输出矩形的面积。
在Point类中,定义了两个double类型的属性x和y,以及一个接受x和y参数的构造函数。
在Rectangle类中,定义了两个Point类型的属性a1和a2,以及一个接受p1和p2参数的构造函数,用于初始化这两个属性。getArea方法用于计算矩形的面积,通过获取矩形的长和宽,然后进行计算,最后使用String.format方法将结果输出并保留两位小数。
Shape抽象类和Comparable接口:定义了抽象类Shape,并且让它实现了Comparable接口,以便可以对Shape对象进行比较和排序。在Shape类中声明了抽象方法getArea(),用于获取图形的面积。实现了compareTo方法,通过比较图形的面积来进行排序。
Circle类和Rectangle类:分别表示圆形和矩形,它们都继承自Shape类并实现了getArea()方法,用于计算各自的面积。这样设计使得可以将不同类型的图形放入同一个ArrayList中进行统一处理。
Point类:表示二维平面上的点,被Rectangle类使用。
Main类:包含了main方法,用于接收用户输入的图形类型和参数,并将创建的图形对象加入到ArrayList中。随后使用sort方法进行排序,最后输出各图形的面积
3、
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int choice = input.nextInt(); switch (choice) { case 1://Circle double radius = input.nextDouble(); Shape circle = new Circle(radius); printArea(circle); break; case 2://Rectangle double x1 = input.nextDouble(); double y1 = input.nextDouble(); double x2 = input.nextDouble(); double y2 = input.nextDouble(); Point leftTopPoint = new Point(x1, y1); Point lowerRightPoint = new Point(x2, y2); Rectangle rectangle = new Rectangle(leftTopPoint, lowerRightPoint); printArea(rectangle); break; } } public static void printArea(Shape shape) { System.out.println(String.format("%.2f", shape.getArea())); } } abstract class Shape { abstract double getArea(); } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override double getArea() { return Math.PI * radius * radius; } } class Rectangle extends Shape { private Point leftTopPoint; private Point lowerRightPoint; public Rectangle(Point leftTopPoint, Point lowerRightPoint) { this.leftTopPoint = leftTopPoint; this.lowerRightPoint = lowerRightPoint; } @Override double getArea() { double length = Math.abs(lowerRightPoint.x - leftTopPoint.x); double height = Math.abs(lowerRightPoint.y - leftTopPoint.y); return length * height; } } class Point { double x; double y; public Point(double x, double y) { this.x = x; this.y = y; } }
4、
import java.util.Scanner; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); ArrayList<Shape> list = new ArrayList<>(); int choice = input.nextInt(); while (choice != 0) { switch (choice) { case 1://Circle double radius = input.nextDouble(); Shape circle = new Circle(radius); list.add(circle); break; case 2://Rectangle double x1 = input.nextDouble(); double y1 = input.nextDouble(); double x2 = input.nextDouble(); double y2 = input.nextDouble(); Point leftTopPoint = new Point(x1, y1); Point lowerRightPoint = new Point(x2, y2); Rectangle rectangle = new Rectangle(leftTopPoint, lowerRightPoint); list.add(rectangle); break; } choice = input.nextInt(); } list.sort(Comparator.naturalOrder()); // 正向排序 for (Shape shape : list) { System.out.print(String.format("%.2f", shape.getArea()) + " "); } } } // 定义抽象类Shape实现Comparable接口 abstract class Shape implements Comparable<Shape> { abstract double getArea(); @Override public int compareTo(Shape other) { return Double.compare(this.getArea(), other.getArea()); } } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override double getArea() { return Math.PI * radius * radius; } } class Rectangle extends Shape { private Point leftTopPoint; private Point lowerRightPoint; public Rectangle(Point leftTopPoint, Point lowerRightPoint) { this.leftTopPoint = leftTopPoint; this.lowerRightPoint = lowerRightPoint; } @Override double getArea() { double length = Math.abs(lowerRightPoint.x - leftTopPoint.x); double height = Math.abs(lowerRightPoint.y - leftTopPoint.y); return length * height; } } class Point { double x; double y; public Point(double x, double y) { this.x = x; this.y = y; } }
在三的基础上进行了类的重构,是代码更容易维护。
三、踩坑心得
第四次第五次迭代过程对第三次做了很大调整,这也从侧面反映出第三次菜单程序的代码并不够完善,不符合一些基本的java类设计原则,如:开闭原则、单一原则、合成复用原则。这为我今后的学习提供了很大参考学习价值,让我明白怎样去调整优化代码。
开始使用字符个数和长度匹配字符但这种方式繁复且不易区分,判断语句不够精炼,后来通过使用正则表达式对用户输入进行匹配和验证,程序能够有效地处理用户的输入,并在输入不符合要求时给出相应的错误提示,提高了程序的健壮性和用户体验
菜单三的测试中,不断出现运行超时的情况,经过修改,使用了哈希表代替数组进行存储查找,结果改善了很多。
在比较字符串时,推荐使用equals()方法而不是"=="运算符,以确保比较的是字符串的内容而不是引用。
三、改进建议
希望可以把补练时间延长,可以不计入成绩,这样可以在后期测试新代码的测试点通过情况,以便更好优化后期代码,课堂可以针对大作业一些比较难的点进行具体分析。
四、总结
通过近段时间的练习,对类的设计逻辑方法,程序的设计原则和类的封装、继承、多态有了更为清晰的认知。有效的提高了代码能力,同时能够对代码进行一定的分析与优化。同时对异常处理太try-catch有了更为清晰的了解,并且能使用它解决一些简单问题。对菜单的迭代,也让我明白一个好的程序,是应该符合一些基本原则的,例如开闭原则,能够更加灵活地增加新的代码功能模块。通过自己的思考和查阅相关资料,我成功地解决了一些问题并提高了对Java编程的理解能力。一步一步逐渐完善自己设计,这是个艰辛但成果很愉悦的过程,这些作业也培养了我对编程语言的学习和探索能力,老师出题可谓是用心良苦。总而言之,通过近几周的学习,我对Java相关类的编写和接口的使用有了更好地认识。
浙公网安备 33010602011771号