一、前言 第二次在博客園上發佈面向對象程式設計題目集的總結博客。經過幾周的學習,面向對象的理念更加深入。雖然已經學了些面向對象程式設計,學好這部分內容還是有較大難度。 關於知識點 本次的題目集所體現的知識點已經不僅限於Java的語法知識,還需要考慮設計問題,不能看到題目就開始進行代碼編寫,需要考慮類 ...
一、前言
第二次在博客園上發佈面向對象程式設計題目集的總結博客。經過幾周的學習,面向對象的理念更加深入。雖然已經學了些面向對象程式設計,學好這部分內容還是有較大難度。
- 關於知識點
本次的題目集所體現的知識點已經不僅限於Java的語法知識,還需要考慮設計問題,不能看到題目就開始進行代碼編寫,需要考慮類和類之間的關係,題目的代碼量也較於前幾次提升了不少。題目集四主要還是語法的鞏固,學會去使用一些新的知識,例如題目集中的第七題中使用一些新的類來解決問題。題目集五前四題是關於正則表達式的知識點,後兩題是日期問題,需要用到類的聚合關係。題目集六主要涉及類的繼承與多態的內容,後面的有些題目未給出類圖,需要自行設計考慮類之間的關係。
- 關於題量
題量比較適中,平均每次題目集都是5-6題,除了有些題目不大好設計比較花時間。
- 關於難度
由於涉及了面向對象設計原理和法則(例如遵從迪米特法則、開閉原則等),難度較於前幾次自然有所增加。但是在部分題目有類圖的情況下,難度適中,除了一些題目敘述較長未能進行較好的設計。
二、設計與分析
- 題目集三7-1 菜單計價程式-3
設計點菜計價程式,根據輸入的信息,計算並輸出總價格。
輸入內容按先後順序包括兩部分:菜單、訂單,最後以"end"結束。
菜單由一條或多條菜品記錄組成,每條記錄一行
每條菜品記錄包含:菜名、基礎價格 兩個信息。
訂單分:桌號標識、點菜記錄和刪除信息、代點菜信息。每一類信息都可包含一條或多條記錄,每條記錄一行或多行。
桌號標識獨占一行,包含兩個信息:桌號、時間。
桌號以下的所有記錄都是本桌的記錄,直至下一個桌號標識。
點菜記錄包含:序號、菜名、份額、份數。份額可選項包括:1、2、3,分別代表小、中、大份。
不同份額菜價的計算方法:小份菜的價格=菜品的基礎價格。中份菜的價格=菜品的基礎價格1.5。小份菜的價格=菜品的基礎價格2。如果計算出現小數,按四捨五入的規則進行處理。
刪除記錄格式:序號 delete
標識刪除對應序號的那條點菜記錄。
如果序號不對,輸出"delete error"
代點菜信息包含:桌號 序號 菜品名稱 份額 分數
代點菜是當前桌為另外一桌點菜,信息中的桌號是另一桌的桌號,帶點菜的價格計算在當前這一桌。
程式最後按輸入的先後順序依次輸出每一桌的總價(註意:由於有代點菜的功能,總價不一定等於當前桌上的菜的價格之和)。
每桌的總價等於那一桌所有菜的價格之和乘以折扣。如存在小數,按四捨五入規則計算,保留整數。
折扣的計算方法(註:以下時間段均按閉區間計算):
周一至周五營業時間與折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其餘時間不營業。
周末全價,營業時間:9:30-21:30
如果下單時間不在營業範圍內,輸出"table " + t.tableNum + " out of opening hours"
參考以下類的模板進行設計:菜品類:對應菜譜上一道菜的信息。
Dish {
String name;//菜品名稱
int unit_price; //單價
int getPrice(int portion)//計算菜品價格的方法,輸入參數是點菜的份額(輸入數據只能是1/2/3,代表小/中/大份) }
菜譜類:對應菜譜,包含飯店提供的所有菜的信息。
Menu {
Dish\[\] dishs ;//菜品數組,保存所有菜品信息
Dish searthDish(String dishName)//根據菜名在菜譜中查找菜品信息,返回Dish對象。
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
}
點菜記錄類:保存訂單上的一道菜品記錄
Record {
int orderNum;//序號\\
Dish d;//菜品\\
int portion;//份額(1/2/3代表小/中/大份)\\
int getPrice()//計價,計算本條記錄的價格\\
}
訂單類:保存用戶點的所有菜的信息。
Order {
Record\[\] records;//保存訂單上每一道的記錄
int getTotalPrice()//計算訂單的總價
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一條菜品信息到訂單中。
delARecordByOrderNum(int orderNum)//根據序號刪除一條記錄
findRecordByNum(int orderNum)//根據序號查找一條記錄
}
### 輸入格式:
桌號標識格式:table + 序號 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 時間(24小時制格式: HH/MM/SS)
菜品記錄格式:
菜名+英文空格+基礎價格
如果有多條相同的菜名的記錄,菜品的基礎價格以最後一條記錄為準。
點菜記錄格式:序號+英文空格+菜名+英文空格+份額+英文空格+份數註:份額可輸入(1/2/3), 1代表小份,2代表中份,3代表大份。
刪除記錄格式:序號 +英文空格+delete
代點菜信息包含:桌號+英文空格+序號+英文空格+菜品名稱+英文空格+份額+英文空格+分數
最後一條記錄以“end”結束。
### 輸出格式:
按輸入順序輸出每一桌的訂單記錄處理信息,包括:
1、桌號,格式:table+英文空格+桌號+”:”
2、按順序輸出當前這一桌每條訂單記錄的處理信息,
每條點菜記錄輸出:序號+英文空格+菜名+英文空格+價格。其中的價格等於對應記錄的菜品\*份數,序號是之前輸入的訂單記錄的序號。如果訂單中包含不能識別的菜名,則輸出“\*\* does not exist”,\*\*是不能識別的菜名
如果刪除記錄的序號不存在,則輸出“delete error”
最後按輸入順序一次輸出每一桌所有菜品的總價(整數數值)格式:table+英文空格+桌號+“:”+英文空格+當前桌的總價
本次題目不考慮其他錯誤情況,如:桌號、菜單訂單順序顛倒、不符合格式的輸入、序號重覆等,在本系列的後續作業中會做要求。
輸入格式:
桌號標識格式:table + 序號 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 時間(24小時制格式: HH/MM/SS)
菜品記錄格式:
菜名+英文空格+基礎價格
如果有多條相同的菜名的記錄,菜品的基礎價格以最後一條記錄為準。
點菜記錄格式:序號+英文空格+菜名+英文空格+份額+英文空格+份數註:份額可輸入(1/2/3), 1代表小份,2代表中份,3代表大份。
刪除記錄格式:序號 +英文空格+delete
代點菜信息包含:桌號+英文空格+序號+英文空格+菜品名稱+英文空格+份額+英文空格+分數
最後一條記錄以“end”結束。
輸出格式:
按輸入順序輸出每一桌的訂單記錄處理信息,包括:
1、桌號,格式:table+英文空格+桌號+“:”
2、按順序輸出當前這一桌每條訂單記錄的處理信息,
每條點菜記錄輸出:序號+英文空格+菜名+英文空格+價格。其中的價格等於對應記錄的菜品\*份數,序號是之前輸入的訂單記錄的序號。如果訂單中包含不能識別的菜名,則輸出“\*\* does not exist”,\*\*是不能識別的菜名
如果刪除記錄的序號不存在,則輸出“delete error”
最後按輸入順序一次輸出每一桌所有菜品的總價(整數數值)格式:table+英文空格+桌號+“:”+英文空格+當前桌的總價
本次題目不考慮其他錯誤情況,如:桌號、菜單訂單順序顛倒、不符合格式的輸入、序號重覆等,在本系列的後續作業中會做要求。
輸入樣例:
麻婆豆腐 12 油淋生菜 9 table 1 2023/3/22 12/2/3 1 麻婆豆腐 2 2 2 油淋生菜 1 3 end
輸出樣例:
table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1: 38
輸入樣例1:
麻婆豆腐 12 油淋生菜 9 table 1 2023/3/22 17/0/0 1 麻婆豆腐 2 2 2 油淋生菜 1 3 1 delete end
輸出樣例1:
table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1: 22
輸入樣例2:
table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1 out of opening hours
輸出樣例2:
table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1 out of opening hours
輸入樣例3:
麻婆豆腐 12 油淋生菜 9 table 1 2022/12/5 15/03/02 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣雞絲 1 2 5 delete 7 delete table 2 2022/12/3 15/03/02 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣雞絲 1 2 7 delete end
輸出樣例3:
table 1: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣雞絲 does not exist delete error; delete error; table 2: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣雞絲 does not exist delete error; table 1 out of opening hours table 2: 63
輸入樣例4:
麻婆豆腐 12 油淋生菜 9 table 1 2022/12/3 19/5/12 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣雞絲 1 2 table 2 2022/12/3 15/03/02 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣雞絲 1 2 1 4 麻婆豆腐 1 1 7 delete end
輸出樣例4:
table 1: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣雞絲 does not exist table 2: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣雞絲 does not exist 4 table 2 pay for table 1 12 delete error; table 1: 63 table 2: 75
此題需要設計Dish類、Menu類、Record類、Order類,類與類之間存在著關聯和依賴等關係。值得註意的是,本題需要考慮訂單的格式問題,也需要考慮時間的問題,考慮營業時間及其折扣。題目敘述較長,需要記好需要實現的功能。
- 題目集五 7-5 日期問題面向對象設計(聚合一)
參考題目7-2的要求,設計如下幾個類:DateUtil、Year、Month、Day,其中年、月、日的取值範圍依然為:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 設計類圖如下:
應用程式共測試三個功能:
- 求下n天
- 求前n天
- 求兩個日期相差的天數
註意:嚴禁使用Java中提供的任何與日期相關的類與方法,並提交完整源碼,包括主類及方法(已提供,不需修改)
輸入格式:
有三種輸入方式(以輸入的第一個數字劃分[1,3]):
- 1 year month day n //測試輸入日期的下n天
- 2 year month day n //測試輸入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //測試兩個日期之間相差的天數
輸出格式:
- 當輸入有誤時,輸出格式如下:
Wrong Format
- 當第一個數字為1且輸入均有效,輸出格式如下:
year-month-day
- 當第一個數字為2且輸入均有效,輸出格式如下:
year-month-day
- 當第一個數字為3且輸入均有效,輸出格式如下:
天數值
輸入樣例1:
3 2014 2 14 2020 6 14
輸出樣例1:
2312
輸入樣例2:
2 1935 2 17 125340
輸出樣例2:
1591-12-17
輸入樣例3:
1 1999 3 28 6543
輸出樣例3:
2017-2-24
輸入樣例4:
0 2000 5 12 30
輸出樣例4:
Wrong Format
本題需要設計出Year、Month、Day三個類對時間進行處理,在類中判斷有效性、獲取前一天(月、年)或者後一天(月、年),在DateUtil類中實現輸出日期格式、判斷日期的有效性、獲取前n天和後n天的日期、獲取兩個日期間隔的天數等功能。這道題主要需要註意的是判斷日期的有效性、閏年時二月份有29天、在增減天數時需要判斷是否為日期、月份的最大最小值進行日期的改動。設計好獲取日期的前後n天後,可以直接調用這個方法來完成獲取日期間的天數。
代碼實現:
1 import java.util.Scanner; 2 class Main { 3 public static void main(String[] args) { 4 Scanner input = new Scanner(System.in); 5 int year = 0; 6 int month = 0; 7 int day = 0; 8 9 int choice = input.nextInt(); 10 11 if (choice == 1) { // test getNextNDays method 12 int m = 0; 13 year = Integer.parseInt(input.next()); 14 month = Integer.parseInt(input.next()); 15 day = Integer.parseInt(input.next()); 16 17 DateUtil date = new DateUtil(year, month, day); 18 19 if (!date.checkInputValidity()) { 20 System.out.print("Wrong Format"); 21 System.exit(0); 22 } 23 24 m = input.nextInt(); 25 26 if (m < 0) { 27 System.out.print("Wrong Format"); 28 System.exit(0); 29 } 30 System.out.println(date.getNextDays(m).showDate()); 31 } else if (choice == 2) { // test getPreviousNDays method 32 int n = 0; 33 year = Integer.parseInt(input.next()); 34 month = Integer.parseInt(input.next()); 35 day = Integer.parseInt(input.next()); 36 37 DateUtil date = new DateUtil(year, month, day); 38 39 if (!date.checkInputValidity()) { 40 System.out.println("Wrong Format"); 41 System.exit(0); 42 } 43 44 n = input.nextInt(); 45 46 if (n < 0) { 47 System.out.println("Wrong Format"); 48 System.exit(0); 49 } 50 System.out.println(date.getPreviousDays(n).showDate()); 51 } else if (choice == 3) { //test getDaysofDates method 52 year = Integer.parseInt(input.next()); 53 month = Integer.parseInt(input.next()); 54 day = Integer.parseInt(input.next()); 55 56 int anotherYear = Integer.parseInt(input.next()); 57 int anotherMonth = Integer.parseInt(input.next()); 58 int anotherDay = Integer.parseInt(input.next()); 59 60 DateUtil fromDate = new DateUtil(year, month, day); 61 DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay); 62 63 if (fromDate.checkInputValidity() && toDate.checkInputValidity()) { 64 System.out.print(fromDate.getDaysofDates(toDate)); 65 } else { 66 System.out.print("Wrong Format"); 67 System.exit(0); 68 } 69 } 70 else{ 71 System.out.print("Wrong Format"); 72 System.exit(0); 73 } 74 75 } 76 } 77 78 79 class Year { 80 private int value; 81 public Year() { 82 83 }//無參構造方法 84 85 public Year(int value) { 86 this.value = value; 87 }//有參構造方法 88 89 public int getValue() { 90 return value; 91 } 92 93 public void setValue(int value) { 94 this.value = value; 95 } 96 97 public boolean isLeapYear() { 98 boolean isLeapYear; 99 isLeapYear = ((value % 4 == 0 && value % 100 != 0) || value % 400 == 0); 100 return isLeapYear; 101 }//判斷是否為閏年 102 103 public boolean validate() { 104 boolean validate; 105 validate = (value >= 1900 && value <= 2050); 106 return validate; 107 }//判斷年份有效性 108 109 public void yearIncrement() { 110 value++; 111 }//年份加1 112 113 public void yearReduction() { 114 value--; 115 }//年份減1 116 } 117 118 class Month { 119 private int value; 120 private Year year; 121 public Month() { 122 123 }//無參構造方法 124 125 public Month(int yearValue, int monthValue) { 126 this.year = new Year(yearValue); 127 this.value = monthValue; 128 }//有參構造方法 129 130 public int getValue() { 131 return value; 132 } 133 134 public void setValue(int value) { 135 this.value = value; 136 } 137 138 public Year getYear() { 139 return year; 140 } 141 142 public void setYear(Year year) { 143 this.year = year; 144 } 145 146 public void resetMin() { 147 value = 1; 148 }//設置月份最小值 149 150 public void resetMax() { 151 value = 12; 152 }//設置月份最大值 153 154 public boolean validate() { 155 boolean validate; 156 validate = (value >= 1 && value <= 12); 157 return validate; 158 }//判斷月份有效性 159 160 public void monthIncrement() { 161 if (validate()) { 162 if (value == 12) { 163 getYear().yearIncrement(); 164 resetMin(); 165 } else { 166 value++; 167 } 168 } 169 }//月份加1 170 171 public void monthReduction() { 172 if (validate()) { 173 if (value == 1) { 174 getYear().yearReduction(); 175 resetMax(); 176 } else { 177 value--; 178 } 179 } 180 }//月份減1 181 } 182 183 class Day { 184 private int value; 185 private Month month; 186 private int[] mon_maxnum = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 187 public Day() { 188 189 }//無參構造方法 190 191 public Day(int yearValue, int monthValue, int dayValue) { 192 this.month = new Month(yearValue, monthValue); 193 this.value = dayValue; 194 }//有參構造方法 195 196 public int getValue() { 197 return value; 198 } 199 200 public void setValue(int value) { 201 this.value = value; 202 } 203 204 public Month getMonth() { 205 return month; 206 } 207 208 public void setMonth(Month month) { 209 this.month = month; 210 } 211 212 public void resetMin() { 213 value = 1; 214 }//設置日期最小值 215 216 public void resetMax() { 217 if (validate()) { 218 value = mon_maxnum[month.getValue() - 1]; 219 }//設置日期為該月最大日期 220 } 221 222 public boolean validate() { 223 boolean validate = false; 224 if (month.getValue() == 2 && getMonth().getYear().isLeapYear()) { 225 mon_maxnum[1] = 29; 226 } else { 227 mon_maxnum[1] = 28; 228 } 229 if (getMonth().validate()) { 230 validate = (value >= 1 && value <= mon_maxnum[month.getValue() - 1]); 231 } 232 return validate; 233 }//判斷日期有效性 234 235 public void dayIncrement() { 236 value++; 237 if (!validate()){ 238 resetMin(); 239 getMonth().monthIncrement(); 240 } 241 }//日期加1,月底時月份加1日期為1 242 243 public void dayReduction() { 244 if (value == 1) { 245 getMonth().monthReduction(); 246 resetMax(); 247 } else { 248 value--; 249 } 250 }//日期減1,當為日期為1時,月份減1,若是1月,年份減1 251 } 252 253 class DateUtil { 254 private Day day; 255 public DateUtil() { 256 257 } 258 259 public DateUtil(int d, int m, int y) { 260 this.day = new Day(d, m, y); 261 } 262 263 public Day getDay() { 264 return day; 265 } 266 267 public void setDay(Day d) { 268 this.day = d; 269 } 270 271 public boolean checkInputValidity() { 272 boolean checkInputValidity; 273 checkInputValidity = (getDay().validate() && getDay().getMonth().validate() 274 && getDay().getMonth().getYear().validate()); 275 return checkInputValidity;