OOP点菜题目-blog作业
Posted Zankjavablog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OOP点菜题目-blog作业相关的知识,希望对你有一定的参考价值。
一.三次题目集概览
这三次题目集中
-
第一次:总九道题目,难度较低,比较基础,适合过渡。
-
第二次:总四道题目,难度较第一次难一点,java的面向对象性开始体现,类间关系及类与类之间属性方法的调用难度加大,java的难处初显。
-
第三次:总七道题目,难易结合,7-1 菜单计价程序-3是第二周两个菜单题目的延续且难度较大,第三、四题也包括新的知识点HashSet、TreeMap的使用。
总的来说,这三周的pta的大作业题目都非常的有价值。
下面我将讲解几次题目集里面的点菜计价程序1~3的心得。
二.设计思路与分析
1.首先给出第一次点菜计价程序的代码
1 import java.util.Scanner;
2 public class Main
3 public static void main(String[] args)
4 Scanner input = new Scanner(System.in)
5 String order = new String(" ");
6 double sum=0;
7 int large=0;
8 while(true)
9 if(input.hasNext("end")) break;
10 order=input.next();
11 large=input.nextInt();
12 sum+=cal(order,large);
13
14 System.out.println((int)sum);
16
17 public static float cal(String order,int large)
18 switch(order)
19 case "西红柿炒蛋":
20 switch(large)
21 case 1:
22 return 15f;
23
24 case 2:
25 return (float)Math.round((float)(15*1.5));
26
27 case 3:
28 return (float)15*2;
29
30 default:break;
31
32 break;
33
34 case "清炒土豆丝":
35 switch(large)
36 case 1:
37 return (float)12;
38
39 case 2:
40 return (float)Math.round((float)(12*1.5));
41
42 case 3:
43 return (float)12*2;
44
45 default:break;
46
47 break;
48
49 case "麻婆豆腐":
50 switch(large)
51 case 1:
52 return (float)12;
53
54 case 2:
55 return (float)Math.round((float)(12*1.5));
56
57 case 3:
58 return (float)12*2;
59
60 default:break;
61
62 break;
63
64 case "油淋生菜":
65 switch(large)
66 case 1:
67 return (float)9;
68
69 case 2:
70 return (float)Math.round((float)(9*1.5));
71
72 case 3:
73 return (float)9*2;
74
75 default:break;
76
77 break;
78
79 default:
80 System.out.println(order+" does not exist");
81 ;
82
83 return 0;
84
85
使用if-else谢第一个点菜计价程序的思路较为简单,因为代码输入格式比较单一,所以静态main方法中不需要像后面的几次点菜计价程序一样在静态main方法中有很多的匹配格式的语句,
首先来看这段代码的结构,这段代码中,只定义了一个主类,除了主类没有其他类,至于题目给出的类,因为题目要求简单,我们只需要将这些类的方法变为静态方法加到主类中即可。
以下代码作用是接收用户输入的点菜信息,并且将每一道菜的总价加入到总价格sum中:
while(!a.equals("end")) if(a.charAt(0)!=\'t\') int price; price=in.nextInt(); d=new Dish(a,price); menu.add(d);
然后我们来看一下UML图:
2.然后是点菜计价程序2,这道题目较第一次的点菜计价程序难度更大,需要更严密的代码逻辑,废话不多说,上代码:
1 package java1;
2
3
4 import java.util.Scanner;
5 public class Main
6 public static void main(String args[])
7 Scanner input = new Scanner(System.in);
8 int x;
9 int s=0;
10 int biao=0;
11 Menu menu = new Menu();
12 Order order = new Order();
13 int orderNum;
14 int[] yesorno=new int[100];
15 String dishname;
16 int xss = 0;
17 int num;
18 int portion;
19 int unit_price;
20 dishname =" ";
21 while(true)
22 dishname = input.next();
23 if(dishname.equals("end")) break;
24 if(!isNumber(dishname))
25 unit_price = input.nextInt();
26 menu.addDish(dishname,unit_price);
27
28 else
29 orderNum=Integer.parseInt(dishname);
30 dishname=input.next();
31 if(dishname.equals("delete"))
32 if(s==0)
33 biao=order.alll;
34 s++;
35
36 yesorno[order.alll]=order.delARecordByOrderNum(orderNum);
37 /*if(yesorno[order.alll]!=-1)
38 for(int i=0;i<menu.i;i++)
39 if(order.records[orderNum-1].d.name.equals(menu.dishs[i].name)) break;
40 else if(i==menu.i-1) yesorno[order.alll]=-1;
41
42 */
43 order.alll++;
44 continue;
45
46 else biao=order.alll;
47 portion=input.nextInt();
48 num=input.nextInt();
49 if(menu.searthDish(dishname)!=-1)
50 xss=menu.searthDish(dishname);
51 order.addARecord(orderNum,dishname,xss,portion,num);
52
53 else order.addARecord(orderNum,dishname,0,portion,num);
54
55
56 for(x=0;x<order.alll;x++)
57 if(yesorno[x]!=-1)
58 if(yesorno[x]!=11)
59 if(order.records[x].d.unit_price==0)
60 System.out.println(order.records[x].d.name+" does not exist");
61
62 else
63 System.out.printf("%d %s %d\\n",order.records[x].orderNum,order.records[x].d.name,order.records[x].price);
64
65
66
67
68 if(yesorno[x]==-1) System.out.println("delete error;");
69
70 if(x!=0) System.out.printf("%d",order.getTotalPrice(biao));
71 else System.out.print(0);
72 input.close();
73
74
75 public static boolean isNumber(String str)
76 for (int i = str.length();--i>=0;)
77 if (!Character.isDigit(str.charAt(i)))
78 return false;
79
80
81 return true;
82
83
84
85 class Dish
86 String name;
87 int unit_price;
88 int getPrice(int portion)
89 switch(portion)
90 case 1:return unit_price;
91 case 2:return (int)(unit_price*1.5+0.5);
92 case 3:return 2*unit_price;
93 default:break;
94
95 return portion;
96
97
98 class Menu
99 int flag=0;
100 int jilu=0;
101 int i=0;
102 Dish[] dishs=new Dish[100];
103 int searthDish(String dishName)
104 jilu=0;
105 for(int s=0;s<i;s++)
106 if(dishs[s].name.equals(dishName))
107 jilu=dishs[s].unit_price;
108 flag=1;
109
110
111 if(flag==0) return -1;
112 else return jilu;
113
114 void addDish(String dishName,int unit_price)
115 dishs[i]=new Dish();
116 dishs[i].name=dishName;
117 dishs[i].unit_price=unit_price;
118 i++;
119
120
121 class Record
122 int flag=0;
123 int orderNum=0;
124 Dish d=new Dish();
125 int price;
126 int portion;
127 int num;
128 int getPrice()
129 return d.getPrice(portion)*num;
130
131
132 class Order
133 Record[] records=new Record[100];
134 int alll=0;
135 int summary=0;
136 int getTotalPrice(int s)
137 for(int i=0;i<=s;i++)
138 if(records[i].flag==0)
139 summary+=records[i].getPrice();
140
141 return summary;
142
143 void addARecord(int orderNum,String dishName,int price,int portion,int num)
144 records[alll]=new Record();
145 records[alll].orderNum=orderNum;
146 records[alll].d.name=dishName;
147 records[alll].d.unit_price=price;
148 records[alll].portion=portion;
149 records[alll].num=num;
150 records[alll].price=records[alll].getPrice();
151 alll++;
152
153 int delARecordByOrderNum(int orderNum)
154 for(int i=0;i<alll;i++)
155 if(records[i].orderNum==orderNum)
156 records[alll]=new Record();
157 records[alll].flag=0;
158 records[i].flag=1;
159 return 11;
160
161 else if(i==alll-1)
162 records[alll]=new Record();
163 return -1;
164
165
166 return 1;
167
168
对于点菜2,题目难点是格式匹配,相信大家都有所体会,我先解释我这段代码是怎么做到格式匹配的,然后讲述一种更好的方法来进行格式匹配。
首先,对于我的代码格式匹配是这部分:
首先,通过 while(true)
循环读取用户输入,循环条件为 true 表示一直等待用户输入,直到用户输入 "end" 手动结束循环。循环体内部分别处理两种用户输入情况:输入的是菜名或菜品数量,还是需要删除某个订单。
在输入菜名时,首先使用 input.next()
方法读取用户输入的菜名,然后通过 isNumber(String str)
方法判断输入内容是否为数字。如果不是数字,则说明该输入为菜名并接着通过 input.nextInt()
方法读取对应的单价,并将菜品名称和单价添加到菜单(Menu
)中;如果是数字,则说明这个订单已经存在,接下来读取数量和规格并通过 order.addARecord()
方法添加到订单记录(Order
)中。
当输入需要删除某个订单时,首先读取用户输入的订单号,然后判断是否需要删除该订单(如果输入为 "delete" 则删除,否则不删除)。如果需要删除,则通过 order.delARecordByOrderNum()
方法删除该订单记录。同时,在删除过程中,将删除的结果存储在 yesorno[]
数组中(1 表示删除成功,-1 表示删除失败),最终将所有订单删除的结果输出到控制台。
循环结束后,通过 getTotalPrice()
方法计算点餐总价格,并将结果输出到控制台。
以上是这段代码的实现过程。
小总结
该菜单计价程序二相比与计价程序一增加了用户删菜的功能,模板其实是和菜单计价程序-1差不多的,不过该题的菜单并不是固定的,不想第一题那样就四道菜,它可能就两道菜,这是因为该题的输入格式相比较菜单计价程序-1不同了,该题先输入菜品记录格式也就是菜单,接着输入点菜记录格式,接着输入删除记录格式或这end,这里就有一个小技巧了,由于第一题的数据输入我将输入的数据分为String类型和int类型来分别表示菜名和份额,但由于第二题它并不是按照一定的顺序输入一个String类型数据接着输入int类型,它可能int类型数据输入完还要输入int类型数据这样输入格式就愈加复杂了,我发现菜单类的输入与订单类的输入两个输入的长度是不同的,所以我创建了一个字符数组b以空格字符间隔,调用订单类order中方法delARecordByOrderNum()实现删除菜品并计总价时排除该菜品。
点菜2UML图如下:
然后就是怎么用更好的方法做到格式匹配。
正则表达式
正则表达式(Regular Expression)是由一些字符组成的模式,用来匹配和搜索字符串。在我的代码中,可以通过正则表达式提供的方法对输入的信息进行验证。下面举例说明:
-
验证输入是否是数字: 在代码中有一个自定义的方法
isNumber
,用于判断输入的内容是否是数字。可以通过正则表达式实现同样的功能,代码如下:// 使用正则表达式判断字符串是否是数字 public static boolean isNumber(String str) Pattern pattern = Pattern.compile("[0-9]*"); return pattern.matcher(str).matches();
[0-9]*
表示匹配任意个数字,这里表示输入必须是由数字组成的字符串。 -
验证输入的菜品价格是否是正整数: 在输入菜品时,需要输入菜品的名称和价格。程序通过使用Scanner的
nextInt()
方法获取价格,但是如果输入的不是整数会导致程序崩溃。因此可以通过正则表达式验证输入的价格是否合法,代码如下:// 使用正则表达式判断字符串是否是正整数 public static boolean isPositiveInteger(String str) Pattern pattern = Pattern.compile("^[1-9]\\\\d*$"); return pattern.matcher(str).matches();
^
表示匹配行首,$
表示匹配行尾,[1-9]
表示第一位必须是1-9中的一个,\\\\d*
表示后面跟任意个数字。因此该表达式匹配任意个正整数。
通过在代码中使用正则表达式验证用户输入的字符串内容是否符合规范,可以保证程序的稳定性和安全性。
可见正则表达式可以简化代码,而且能够更加简单的应用,减少在写代码时,代码的逻辑问题,不过因为当时知识有限,还不知道正则表达式,更别说将其应用到点菜2中,对于正则表达式的学习,可以参考网站RegExr: Learn, Build, & Test RegEx。(注意使用时要导入java.util.regex.Pattern)
3.点菜计价程序3,代码如下:
package java; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Scanner; public class Main public static void main(String[] args) Scanner in = new Scanner(System.in); Menu menu=new Menu(); Dish d; String a ;//接受内容 a = in.next(); //创建菜单 while(!a.equals("end")) if(a.charAt(0)!=\'t\') int price; price=in.nextInt(); d=new Dish(a,price); menu.add(d); else break; a=in.next(); //订单,此时的a="table" ArrayList<Order> orders = new ArrayList<Order>(); while(!a.equals("end")) int table=in.nextInt(); //接收第几桌 //接受订单信息 Order order = new Order(menu,table); orders.add(order); a=in.next(); //接收日期 String b = in.next(); //接收时间 order.account(a,b); System.out.println("table "+table+": "); while(true) a=in.next(); if(a.equals("end")||a.equals("table")) break; String m=in.nextLine(); String[] p = m.split(" "); if(p.length==4) //给本桌点餐 int orderNum = Integer.parseInt(a); String dishName = p[1]; int portion = Integer.parseInt(p[2]); int num = Integer.parseInt(p[3]); //查找是否有此菜名 d = menu.searthDish(dishName);//接受菜品 if(d==null)//未找到,说明没有该菜品 System.out.println(dishName+" does not exist"); else //找到了,添加订单 Record r = order.addARecord(orderNum, dishName, portion, num); System.out.println(orderNum+" "+dishName+" "+r.getPrice()); if(p.length==5) //为别桌点菜 int orderNum = Integer.parseInt(p[1]); String dishName = p[2]; int portion = Integer.parseInt(p[3]); int num = Integer.parseInt(p[4]); //查找是否有此菜名 d = menu.searthDish(dishName);//接受菜品 if(d==null)//未找到,说明没有该菜品 System.out.println(dishName+" does not exist"); else //找到了,添加订单 Record r = order.addARecord(orderNum, dishName, portion, num); System.out.println(orderNum+" table "+table +" pay for table "+a+" "+r.getPrice()); if(p.length==2) //删除 int orderNum = Integer.parseInt(a); String dishName = p[1]; if(dishName.equals("delete")) order.delARecordByOrderNum(orderNum);//删除订单信息 for(int i=0;i<orders.size();i++) if(orders.get(i).acc==0) System.out.println("table "+orders.get(i).table+" out of opening hours"); else System.out.println("table "+orders.get(i).table+ ": "+orders.get(i).getTotalPrice()); in.close(); //菜品类:对应菜谱上一道菜的信息。 class Dish String name;// 菜品名称 int unit_price; // 单价 Dish(String name,int price) this.name = name; this.unit_price = price; int getPrice(int portion) // 计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) float bl[]= 1,1.5f,2; return Math.round(unit_price*bl[portion-1]); //菜谱类:对应菜谱,包含饭店提供的所有菜的信息。 class Menu ArrayList<Dish> dishs = new ArrayList<Dish>();// 菜品数组,保存所有菜品信息 public void add(Dish dish) //菜单加一道菜 for(int i=0;i<dishs.size();i++) if(dish.name.equals(dishs.get(i).name)) //找到了相同菜名,就替换 dishs.set(i, dish); return ; //未找到相同菜名,就增加 dishs.add(dish); Dish searthDish(String dishName) // 根据菜名在菜谱中查找菜品信息,返回Dish对象。 for(int i=0;i<dishs.size();i++) if(dishs.get(i).name.equals(dishName)) return dishs.get(i); return null; //点菜记录类:保存订单上的一道菜品记录 class Record int orderNum;//序号\\ Dish d;// 菜品 int portion;// 份额(1/2/3代表小/中/大份) int num;//份数1,2,3,4,5 public Record(int orderNum,Dish d,int portion,int num) this.orderNum=orderNum; this.d=d; this.portion=portion; this.num=num; int getPrice() // 计价,计算本条记录的价格 return d.getPrice(portion)*num; //订单类:保存用户点的所有菜的信息。 class Order ArrayList<Record> records = new ArrayList<Record>();// 保存订单上每一道的记录 Menu menu; int table; float acc; void account(String a,String b) //a接收日期,b接收时间 //计算星期几w String[] s = a.split("/"); if(s[1].length()==1) s[1]="0"+s[1]; if(s[2].length()==1) s[2]="0"+s[2]; a = s[0]+"-"+s[1]+"-"+s[2]; SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal=Calendar.getInstance(); Date date=null; try date = format.parse(a); catch (ParseException e) // TODO Auto-generated catch block e.printStackTrace(); cal.setTime(date); int w=cal.get(Calendar.DAY_OF_WEEK)-1; if(w<=0) w=7; //处理时间 String[] time = b.split("/"); int h=Integer.parseInt(time[0]); int m=Integer.parseInt(time[1]); if(w>=1&&w<=5) if(h>=17&&(h<20||(h==20&&m<30))) acc=0.8f; else if((h>10||(h==10&&m>=30))&&(h<14||(h==14&&m<30))) acc=0.6f; else if((h>9||(h==9&&m>=30))&&(h<21||(h==21&&m<30))) acc=1; int getTotalPrice() // 计算订单的总价 int total=0; if(records==null) return 0; for(int i=0;i<records.size();i++) total+=records.get(i).getPrice(); return Math.round(acc*total); public Order(Menu menu,int table) this.menu = menu; this.table = table; //根据菜名点菜 Record addARecord(int orderNum,String dishName,int portion,int num) //不用判断菜品是否存在,main里会判断,在这里一定会存在 Record r = new Record(orderNum,menu.searthDish(dishName),portion,num); records.add(r); return r; void delARecordByOrderNum(int orderNum) //根据序号删除一条记录 for(int i=0;i<records.size();i++) if(records.get(i).orderNum==orderNum) records.remove(i); return ;//删除成功 System.out.println("delete error;");//删除失败
点菜三要求比点菜2多了不少,不仅要考虑点菜时间,还要考虑有效点菜时间内点菜的折扣,以及代点菜,代点菜价格计算等等。
首先,对于日期,我们可以使用java.util.Date中的Date类,对于Date类,它是Java中用于表示日期和时间的类。它代表自1970年1月1日00:00:00 GMT以来经过的毫秒数,因此可以用于表示日期和时间的绝对值,也可以用于比较两个日期和时间之间的差距。Date类提供了多种构造函数来创建Date对象,其中最常用的是无参构造函数和带long类型的参数的构造函数。无参构造函数将当前时间作为默认值,带参数的构造函数将传入的毫秒数转换为对应的日期和时间Date类还提供了一系列方法用于获取和设置日期及时间。例如,getYear()、getMonth()、getDay()、getHours()、getMinutes()、getSeconds()等方法可以分别获取年、月、日、小时、分钟和秒的值,而setYear()、setMonth()、setDay()、setHours()、setMinutes()、setSeconds()等方法可以设置相应的值。除了基本的日期和时间处理,Date类还可以与其他Java类一起使用,例如Calendar类和SimpleDateFormat类,以便进行更复杂的日期和时间处理。我们可以使用SimpleDateFormat初始化Date的格式,然后使用getYear()等方法获取时间,来对其进行判断是否合法和折扣计算。
程序的运行步骤:
在主方法的开头,先使用 Scanner
类创建一个键盘输入的对象 in
,以便于接收用户在控制台输入的信息。紧接着创建了一个菜单对象 menu
,用于保存所有饭店提供的菜的信息,并创建了一个空的菜品对象 d
,以便之后从控制台输入中获取每一道点的菜品信息并存储到菜单中。
程序在读取用户的输入时,首先使用 in.next()
方法读取控制台输入的字符串并保存到变量 a
中。接着开始进入循环,并通过判断字符串第一个字母是不是 \'t\'
来决定当前的输入是菜品信息还是订单信息。
如果输入的字符串第一个字母不是 \'t\'
,则表示正在输入菜品信息,此时通过 in.nextInt()
方法读取下一个输入作为菜品的价格,然后将当前输入的菜品名和价格封装成一个菜品对象 d
,最后将该菜品对象 d
添加到菜单对象 menu
的菜品数组中。循环继续,直到遇到输入字符串 "end"
,退出循环。
如果输入的字符串第一个字母是 \'t\'
,则表示正在输入订单信息,此时会使用 in.nextInt()
方法读取下一个输入作为当前桌号的数字,并根据菜单和该桌号创建一个新的订单对象 order
并保存到一个订单列表 orders
中。接着程序会提示用户输入订单的日期和时间,并通过处理输入的日期和时间,计算出是否在营业时间内,之后将该桌号的所有点餐记录保存到订单对象 order
的记录列表中,最后程序继续循环,等待用户操作并输入下一条指令。
对于代点菜:
程序通过 in.nextLine()
方法读取控制台输入的剩余内容,并使用 String
类的 split(" ")
方法将其按空格分隔成一个字符串数组 p
,其中第一个元素代表点餐的序号,第二个元素代表点餐的菜品名称,接下来的元素依次代表菜品份额和份数。根据数组 p
的长度可以判断该操作是代点菜还是给本桌点餐。
如果 p
数组的长度为 4,则说明这是为本桌点菜,即当前桌号点的菜品。程序首先从菜单对象中查找该菜品,并将该菜品封装成一个菜品对象 d
,然后将订单号、菜品名称、菜品份额和菜品份数传递给订单对象 order
的 addARecord()
方法,以添加一条订单记录。如果没找到该菜品,则输出 "该菜品不存在" 的提示信息。
如果 p
数组的长度为 5,则说明这是为别桌点菜,即另一个桌号要点的菜品。与上述情况类似,程序首先从菜单对象中查找该菜品,并将该菜品封装成一个菜品对象 d
,然后将订单号、菜品名称、菜品份额和菜品份数传递给订单对象 order
的 addARecord()
方法,以添加一条订单记录。同时,程序还输出 "table x pay for table y" 的提示信息,表示当前桌号为 x 的顾客为另一个桌号为 y 的顾客点了菜品。
如果 p
数组的长度为 2,则说明这是删除一条订单记录的指令。程序将第一个元素解析为订单号,并将第二个元素解析为菜品名称,然后调用订单对象 order
的 delARecordByOrderNum()
方法删除一条订单记录。
小总结:
点菜计价程序3显然比2要难很多,但是只要肯花时间,足够细致,这道题目还是很好写的,这道题目同样可以使用正则表达式,简化步骤。
最后是代码UML:
三.踩坑心得
点菜1:
- 程序要求四舍五入,我一开始是用if语句控制的,毕竟就只有两种情况是需要四舍五入的,最终改进成通过使用(int)(price+0.5)解决。
- 不能乱加访问修饰词:
- 方法中传入的参数名字尽量与该类中存在的变量名不同,如果相同,要用this.指代该类中的变量。
点菜2:
- 程序有两种输入错误提示,“** does not exist”和“delete error”,这时需要注意这两个提示的输出顺序,否则会提示格式错误
- 题目有一个只包含菜单的测试点,即输入菜单后不进行其他操作就输入end结束程序,我的代码用两个while语句把用户输入分成两个bufen,因此需要在第一个while语句中添加if(parts[0].equals("end")) System.out.println(0); return;语句来提前结束程序
点菜3:
点菜3几乎没遇到什么坑。
四.主要困难及改进建议
1.代码的复杂度高,编程的质量不高,我认为要减少选择语句if else,改用switch或者数组,这样可以提高程序运行效率。
2.对于类的理解不够,一个类里面的属性与方法,应该有单一原则,单一职责原则核心思想是一个类,最好就做一件事。就如老师上课所说的类与类之间的关联性越小越好,而我所写的一些程序,互相关联的太多,导致不太好改。测试对于编码质量是非常重要的,虽然我们pta不对这个做要求,我们也应该对自己所编写的代码持有高度的严谨性,尽可能提高代码质量。
五.总结
通过此次作业,我学到了如何根据需求对各个类进行设计和实现。在解决实际问题的过程中,需要将问题分解为较小的问题,并分别对其进行考虑和解决。同时,还需要掌握基本的输入输出方法、数据类型和常用的语法结构。在解决实际问题的过程中,需要动手去实践,并不断地尝试和学习。在编码过程中,需要注意代码规范和注释的准确性,以便提高代码的可读性和可维护性。最后,在经历一段时间的编程训练后,我相信我的编程水平会有所提高,能够更加熟练自如地处理各种实际问题。
OOP作业总结
关于OOP第三阶段的作业总结
阅读提示:本文目录导航,PC端页面位于文章右侧,移动端点击文章标题右侧小图标,需下滑后(顶部图片消失)目录才完全显示,可根据目录跳转文章位置。
一、前言
题目集七
- 知识点: 类的继承、多态性使用方法以及接口的应用。
- 题量: 较小
- 难度:
\\( \\begin{split} &7-1 \\quad ★★✩✩✩ \\\\&7-2 \\quad ★★✩✩✩ \\end{split} \\)
题目集八
- 知识点: 设计模式的具体运用。
- 题量: 较小
- 难度:
\\( \\begin{split} &7-1 \\quad ★★★✩✩ \\end{split} \\)
题目集九
- 知识点: 设计模式的具体运用。
- 题量: 较小
- 难度:
\\( \\begin{split} &7-1 \\quad ★★★✩✩ \\end{split} \\)
二、设计与分析
(1)题目集7(7-1)、(7-2)两道题目的递进式设计分析总结
(7-1):
(7-2):
分析:
(7-1):
设计父类Shape
,圆形(Circle)
、矩形(Rectangle)
、三角形(Triangl)
及梯形(Trapezoid)
继承Shape
,实现Comparable接口
,重写CompareTo()方法
实现排序,使用ArrayList
存储对应图形。设计DealCardList
类。
@Override
public int compareTo(Card o) {
return Double.compare(o.getShape().getArea(), shape.getArea());
}
(7-2):
在7-1的基础上,依照面向对象设计的单一职责原则
,开-闭
原则,进行设计。使用ArrayList
存储对应图形,重写toString()
方法,遍历ArrayList
输出时满足格式要求。
public void cardSort() {
Collections.sort(circles);
Collections.sort(rectangles);
Collections.sort(trapezoids);
Collections.sort(triangles);
}
(2)题目集8和题目集9两道ATM机仿真题目的设计思路分析总结
题目集4(7-3):
二维图形继承三维图形,利用继承提高代码的复用性。开闭原则的体现,面向修改关闭,面向拓展开放。
题目集6(7-5):
Rectangle,Circle, Triangle
均继承自抽象类 Shape
,Shape
实现Comparable
,重写compareTo()
使三种图形可比较面积。使用ArraysList<Shape>
存储,可直接使用Collections.sort()
abstract class Shape implements Comparable<Shape> {
public abstract double getArea();
public abstract boolean validate();
@Override
public int compareTo(Shape shape) {
return Double.compare(getArea(), shape.getArea());
}
@Override
public String toString() {
return String.format("%.2f", getArea());
}
public static double areaSum(ArrayList<Shape> shapes) {
double area = 0;
for (Shape aShape : shapes) {
area += aShape.getArea();
}
return area;
}
}
题目集6(7-6):
Rectangle
、Circle
均实现GetArea
接口,不同类的相同行为。
(3)三次题目集中用到的正则表达式技术的分析总结
题目集4(7-1) 水文数据校验:
需要校验的数据大致如下:
2015/8/2 4:00|133.8400|133.070|1.11/1.21|75.780
2015/8/2 6:00|133.840|133.080|11.11/1.11|72.8a0
2015/8/2 8:00|133.830|133.070|1.11/1.11|73.890
2015/8/2 10:00|133.820|133.080|1.11/1.11|74.380
exit
设计思路:
String[] singleDataList = data.split("\\\\|");
先把每行数据根据|
分割, 如果不能分割出5份(singDataList.length != 5
)则属于Wrong Format
。分割完成后,再对分割出的5部分单独校验。
1.日期
"[1-9][0-9]{0,3}/([1-9]|1[0-2])/([1-9]|[1-2][0-9]|3[0-1])\\\\s((1?[02468])|(2[02]))\\\\:00"
正则表达式可拆分编写,太长不利于维护,查错。
以上并未校验闰年2月情况太多不适合用正则表达式,借助日期合法校验类。
public static boolean checkDay(String str) {
//得 - 分割
String ss = str.replaceAll("/", "-");
ss = ss +":00";
SimpleDateFormat sd = new SimpleDateForma("yyyy-MM-dd HH:mm:ss");//括号内为日期格式,y代表份,M代表年份中的月份(为避免与小时中的分钟数m冲突,处用M),d代表月份中的天数
try {
sd.setLenient(false);//此处指定日期/时间解析是不严格,在true是不严格,false时为严格
sd.parse(ss);//从给定字符串的开始解析文本,以生一个日期
} catch (Exception e) {
return false;
}
return true;
}
2.水位,流量
"[1-9][0-9]{0,2}(\\\\.[0-9]{1,3})?"
3.开度
"[1-9]\\\\.([0-9]{2})\\\\s*/\\\\s*[1-9]\\\\.([0-9]{2})"
题目集5(7-4)统计Java程序中关键词的出现次数:
1.去除空格
StringBuilder check = new StringBuilder(all.toString().replaceAll("\\\\s+", ""));
2.处理""
str = str.replaceAll("\\"(.*)\\"", " ");
3.处理注释
StringBuilder(all.toString().replaceAll("/\\\\*(.*)\\\\*/", " ")); all = new StringBuilder(all.toString().replaceAll("\\\\[(.*)\\\\]", " "));
4.处理非字母数字字符
StringBuilder(all.toString().replaceAll("[^a-zA-Z0-9]", " "));
题目集6(7-1)QQ号校验:
if (s.matches("[1-9][0-9]{4,14}"))
题目集6(7-3)验证码校验:
if (s.matches("[0-9a-zA-Z]{4}"))
题目集6(7-4)学号校验:
if (s.matches("2020(1[1-7]|61|7[1-3]|8[1-2])(0[1-9]|[1-3][0-9]|40)"))
(4)题目集5(7-4)中Java集合框架应用的分析总结
先将所有关键字存入List
List<String> kewWordList = Arrays.asList("abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally",
"float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long",
"native", "new", "null", "package", "private", "protected", "public", "return", "short", "static",
"strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try",
"void", "volatile", "while");
遍历分解后的文本,使用HashMap
,关键字作为key
,数量作为value
建立映射关系,若单词在List
中存在,则对应的value++
。
Map<String, Integer> ans = new HashMap<>();
String[] singleWordList = all.toString().split("\\\\s+");
for (String keyWord : kewWordList) {
ans.put(keyWord, 0);
}
for (String singleWord : singleWordList) {
if (kewWordList.contains(singleWord)) {
ans.replace(singleWord, ans.get(singleWord) + 1);
}
}
使用replace()
来更新key
对应的value
。
三、踩坑心得
题目集4(7-1) 水文数据校验:
1.日期合法性考虑不完善,正则表达式未考虑闰年2月和30天,31天的月份。
使用checkDay()
对日期进行二次校验。
题目集5(7-4)统计Java程序中关键词的出现次数:
1.未考虑\\* *\\注释方法。
2.据说字符数超过800之后的部分关键词不计入才得分。(测试数据又有问题????)
题目集5(7-5)日期问题面向对象设计(聚合二):
求前n天,后n天用 \\(O(n)\\) 的求法超时了,一次应该+/-一个月或一年。
四、改进建议
题目集5(7-5)日期问题面向对象设计(聚合二),判断是否满月,减去当月的天数,复杂度任很高,判断满年可继续降低时间复杂度。
五、总结
- 学到了什么: 通过本阶段的学习,进一步掌握了正则表达式的使用。进一步了解了封装,继承,多态,接口,抽象类。
- 进一步学习: 七大设计原则的实际体现,体会其优点。
- 课程建议及意见: 课程自由度高,给学生充分的自学时间,作业循序渐进,梯度适中,无需要改进的地方。
但PTA作业的 测试数据反复出锅,麻烦修正一下。
以上是关于OOP点菜题目-blog作业的主要内容,如果未能解决你的问题,请参考以下文章