一、6-8作业总结
(1)第六次作业:第一次作业分了两个题,一个电信1题目非常长,给出了类图,类很多工作量很大。还一个题以容器类为例展现了接口,多态的用处和效果,题目给出的提示非常多,按照题目来,再加上一些测试代码,可以运用equals类实现。
(2)第七次作业:第二次作业分了三个小题,第一个还是电信系列,在第六次作业的电信1基础上加了手机计费,代码将会更复杂。第二、三题比较简单,题目都给出了大部分代码,只需要修改,看仔细点就行。主要用到了Collection ,ArrayList,hash这些常用类,使用sort方法实现排序,其实电信系列也用到了这些类。
(3)第八次作业:也是分为三个小题,还是电信系列,不过这次是手机接收短信计费,比较简单,在之前的代码上加上短信计费的具体计费方式就行。第二小题主要考察内部类,第三个小题题目就叫动物声音模拟器,和第六次作业中的容器类类似,考察多态,没有什么复杂的算法,掌握了多态的思想就会比较简单。
二、设计与分析
1.第6次作业:7-1 电信计费系列1-座机计费
作者 蔡轲
单位 南昌航空大学
实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
输入格式:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码除区号外由是7-8位数字组成。
本题只考虑计费类型0-座机计费,电信系列2、3题会逐步增加计费类型。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合\"yyyy.MM.dd HH:mm:ss\"格式。提示:使用SimpleDateFormat类。
以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
注意:
本题非法输入只做格式非法的判断,不做内容是否合理的判断(时间除外,否则无法计算),比如:
1、输入的所有通讯信息均认为是同一个月的通讯信息,不做日期是否在同一个月还是多个月的判定,直接将通讯费用累加,因此月租只计算一次。
2、记录中如果同一电话号码的多条通话记录时间出现重合,这种情况也不做判断,直接 计算每条记录的费用并累加。
3、用户区号不为南昌市的区号也作为正常用户处理。
输出格式:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,
单位元)。假设每个用户初始余额是100元。
每条通讯信息单独计费后累加,不是将所有时间累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
建议类图:
参见图1、2、3,可根据理解自行调整:
图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
图3
图3是计费规则的相关类,这些类的核心方法是: calCost(ArrayList<CallRecord> callRecords)。 该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。 输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。 LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是 座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。 (提示:可以从UserRecords类中获取各种类型的callRecords)。
后续扩展说明:
后续题目集将增加手机用户,手机用户的计费方式中除了与座机计费类似的主叫通话费之外,还包含市外接听电话的漫游费以及发短信的费用。在本题的设计时可统一考虑。
通话记录中,手机需要额外记录拨打/接听的地点的区号,比如:
座机打手机:t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
短信的格式:m-主叫号码,接收号码,短信内容
m-18907910010 13305862264 welcome to jiangxi
m-13305862264 18907910010 thank you
分析:本题要求比较多,但给出了类图,需要先根据类图建立好这些类,在考虑如何实现,最后测试,根据结果作出适当调整。不过需要注意,最后输出的通信记录需要按电话这串字符从小到大排序的,还要写一个类用来判断格式,需要判断闰年。
代码如下:(代码很长已全部折叠)
1 import java.math.RoundingMode; 2 import java.util.*; 3 import java.text.SimpleDateFormat; 4 import java.text.ParseException; 5 import java.math.BigDecimal; 6 7 public class Main { 8 9 public static void main(String[] args) { 10 11 InputDeal inputdeal = new InputDeal(); 12 13 ArrayList<User> users = new ArrayList<>(); 14 15 Scanner in = new Scanner(System.in); 16 17 String input = in.nextLine(); 18 //格式正确,格式错误不管 0791,江西省内各地市区号包括:0790~0799以及0701 19 // t-079186300001 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:25 20 while (!input.equals(\"end\")) { 21 if (1 == inputdeal.check(input)) { 22 writeUser(users, input); 23 } else if (2 == inputdeal.check(input)) { 24 writeRecord(users, input); 25 } 26 input = in.nextLine(); 27 } 28 users.sort(new Comparator<User>() { 29 @Override 30 public int compare(User u1, User u2) { 31 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 32 return 1; 33 } else { 34 return -1; 35 } 36 } 37 }); 38 for (User u : users) { 39 System.out.print(u.getNumber() + \" \"); 40 41 double tip = u.calCost(); 42 output(u.calCost()); 43 System.out.print(\" \"); 44 //System.out.printf(\"%.2f \",tip); 45 double bal = u.calBalance(); 46 output(u.calBalance()); 47 48 } 49 50 } 51 public static void output(double out) { 52 53 BigDecimal numb = new BigDecimal(out); 54 out = numb.setScale(2, RoundingMode.HALF_UP).doubleValue(); 55 System.out.print(out); 56 } 57 public static void writeUser(ArrayList<User> users, String input) { 58 User user1 = new User(); 59 String[] inputs = input.split(\" \"); 60 String num = inputs[0].substring(2); 61 for (User i : users) { 62 if (i.getNumber().equals(num)) { 63 return; 64 } 65 } 66 user1.setNumber(num); 67 int mode = Integer.parseInt(inputs[1]); 68 if (mode == 0) { 69 user1.setChargeMode(new LandlinePhoneCharging()); 70 } 71 users.add(user1); 72 } 73 74 public static void writeRecord(ArrayList<User> users, String input) { 75 String[] inputs = input.split(\" \"); 76 inputs[0] = inputs[0].replace(\"t-\", \"\"); 77 78 User callu = null, answeru = null; 79 CallRecord callrecord = new CallRecord(inputs); 80 81 for (User i : users) { 82 if (i.getNumber().equals(inputs[0])) { 83 callu = i; 84 } 85 if (i.getNumber().equals(inputs[1])) { 86 answeru = i; 87 } 88 if (callu != null && answeru != null) { 89 break; 90 } 91 } 92 93 if (callu != null) { 94 if (callrecord.getCallType() == 1) { 95 callu.getUserRecords().addCallingInCityRecords(callrecord); 96 } else if (callrecord.getCallType() == 2) { 97 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 98 } else { 99 callu.getUserRecords().addCallingInLandRecords(callrecord); 100 } 101 } 102 103 if (answeru != null) { 104 if (callrecord.getCallType() == 1) { 105 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 106 } else if (callrecord.getCallType() == 2) { 107 108 answeru.getUserRecords().addAnswerInProvinceRecords(callrecord); 109 } else { 110 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 111 } 112 } 113 114 } 115 } 116 117 abstract class ChargeMode { 118 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 119 120 public abstract double calCost(UserRecords userRecords); 121 122 public abstract double getMonthlyRent(); 123 124 public ArrayList<ChargeRule> getChargeRules() { 125 return chargeRules; 126 } 127 128 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 129 this.chargeRules = chargeRules; 130 } 131 } 132 /* 133 * 类:用户通讯所有信息记录 134 * 属性:市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、 135 * 市内接听电话、省内(不含市内)接听电话、省外接听电话的记录 136 * 以及发送短信、接收短信的记录 137 * 功能:按地址分别记录通话信息 138 * */ 139 class UserRecords { 140 141 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 142 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 143 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 144 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 145 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 146 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 147 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 148 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 149 150 public void addCallingInCityRecords(CallRecord callRecord) { 151 callingInCityRecords.add(callRecord); 152 } 153 154 public void addCallingInProvinceRecords(CallRecord callRecord) { 155 callingInProvinceRecords.add(callRecord); 156 } 157 158 public void addCallingInLandRecords(CallRecord callRecord) { 159 callingInLandRecords.add(callRecord); 160 } 161 162 public void addAnswerInCityRecords(CallRecord callRecord) { 163 answerInCityRecords.add(callRecord); 164 } 165 166 public void addAnswerInProvinceRecords(CallRecord callRecord) { 167 answerInProvinceRecords.add(callRecord); 168 } 169 170 public void addAnswerInLandRecords(CallRecord callRecord) { 171 answerInLandRecords.add(callRecord); 172 } 173 174 public void addSendMessageRecords(MessageRecord callRecord) { 175 sendMessageRecords.add(callRecord); 176 } 177 178 public void addReceiveMessageRecords(MessageRecord callRecord) { 179 receiveMessageRecords.add(callRecord); 180 } 181 182 public ArrayList<CallRecord> getCallingInCityRecords() { 183 return callingInCityRecords; 184 } 185 186 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 187 this.callingInCityRecords = callingInCityRecords; 188 } 189 190 public ArrayList<CallRecord> getCallingInProvinceRecords() { 191 return callingInProvinceRecords; 192 } 193 194 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 195 this.callingInProvinceRecords = callingInProvinceRecords; 196 } 197 198 public ArrayList<CallRecord> getCallingInLandRecords() { 199 return callingInLandRecords; 200 } 201 202 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 203 this.callingInLandRecords = callingInLandRecords; 204 } 205 206 public ArrayList<CallRecord> getAnswerInCityRecords() { 207 return answerInCityRecords; 208 } 209 210 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 211 this.answerInCityRecords = answerInCityRecords; 212 } 213 214 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 215 return answerInProvinceRecords; 216 } 217 218 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 219 this.answerInProvinceRecords = answerInProvinceRecords; 220 } 221 222 public ArrayList<CallRecord> getAnswerInLandRecords() { 223 return answerInLandRecords; 224 } 225 226 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 227 this.answerInLandRecords = answerInLandRecords; 228 } 229 230 public ArrayList<MessageRecord> getSendMessageRecords() { 231 return sendMessageRecords; 232 } 233 234 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 235 this.sendMessageRecords = sendMessageRecords; 236 } 237 238 public ArrayList<MessageRecord> getReceiveMessageRecords() { 239 return receiveMessageRecords; 240 } 241 242 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 243 this.receiveMessageRecords = receiveMessageRecords; 244 } 245 246 } 247 /* 248 * 座机计费方式 249 * 250 * */ 251 class LandlinePhoneCharging extends ChargeMode { 252 253 final double monthlyRent = 20; 254 255 public LandlinePhoneCharging() { 256 super(); 257 chargeRules.add(new LandPhoneInCityRule()); 258 chargeRules.add(new LandPhoneInProvinceRule()); 259 chargeRules.add(new LandPhoneInlandRule()); 260 } 261 262 @Override 263 public double calCost(UserRecords userRecords) { 264 double sumCost = 0; 265 for (ChargeRule rule : chargeRules) { 266 sumCost += rule.calCost(userRecords); 267 } 268 return sumCost; 269 } 270 271 @Override 272 public double getMonthlyRent() { 273 return monthlyRent; 274 } 275 276 } 277 /* 类:输入格式判断InputDeal 278 * 功能:判断输入格式是否正确,时间是否合理 279 * 280 * */ 281 class InputDeal { 282 283 public int check(String input) { 284 String[] inputs = input.split(\" \"); 285 if (inputs.length == 2) { 286 if (inputs[0].matches(\"^u-\\\\d{11,13}$\")) { 287 if (Integer.parseInt(inputs[1]) >= 0 && Integer.parseInt(inputs[1]) <= 2) { 288 return 1; 289 } 290 } 291 } else if (inputs.length == 6) { 292 if (check1(inputs[2]) && check1(inputs[4])) 293 if (check2(inputs[3]) && check2(inputs[5])) 294 if (inputs[0].matches(\"[t]-0791\\\\d{7,8}\") && inputs[1].matches(\".\\\\d{9,11}\")) 295 return 2; 296 297 } 298 return 0; 299 } 300 301 private boolean check2(String string) { 302 return string.matches(\"^([0-1]?\\\\d|2[0-3]):([0-5]\\\\d):([0-5]\\\\d)$\"); 303 } 304 305 public static boolean check1(String dateString) { 306 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 307 if (!dateString.matches(\"\\\\d{4}+.\\\\d{1,2}+.\\\\d{1,2}+\")) { 308 return false; 309 } 310 // 得到年月日 311 String[] array = dateString.split(\"\\\\.\"); 312 int year = Integer.parseInt(array[0]); 313 int month = Integer.parseInt(array[1]); 314 int day = Integer.parseInt(array[2]); 315 316 if (month < 1 || month > 12) { 317 return false; 318 } 319 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 320 if (isLeapYear(year)) { 321 monthLengths[2] = 29; 322 } else { 323 monthLengths[2] = 28; 324 } 325 int monthLength = monthLengths[month]; 326 return day >= 1 && day <= monthLength; 327 } 328 329 /** 是否是闰年 */ 330 private static boolean isLeapYear(int year) { 331 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 332 } 333 334 } 335 /* 336 * 抽象类:通讯记录 337 * 属性:callingNumber拨打号码、answerNumber接听号码 338 * 339 * */ 340 abstract class CommunicationRecord { 341 protected String callingNumber; 342 protected String answerNumber; 343 344 public String getCallingNumber() { 345 return callingNumber; 346 } 347 348 public void setCallingNumber(String callingNumber) { 349 this.callingNumber = callingNumber; 350 } 351 352 public String getAnswerNumber() { 353 return answerNumber; 354 } 355 356 public void setAnswerNumber(String answerNumber) { 357 this.answerNumber = answerNumber; 358 } 359 360 } 361 362 abstract class ChargeRule { 363 364 abstract public double calCost(UserRecords userRecords); 365 366 } 367 /* 368 * 类:通话记录 369 * 属性:通话起始、结束时间;拨号人地址,接听人地址 370 * 功能:记录打电话双方的地址和通话时间 371 * 372 */ 373 class CallRecord extends CommunicationRecord { 374 private Date startTime; 375 private Date endTime; 376 private String callingAddressAreaCode; 377 private String answerAddressAreaCode; 378 // 379 public double getCallTime(){ 380 return endTime.getTime() - startTime.getTime(); 381 } 382 public int getCallType() { 383 if (callingAddressAreaCode.equals(answerAddressAreaCode)) { 384 return 1; 385 } 386 if (callingAddressAreaCode.matches(\"^079\\\\d$\") || callingAddressAreaCode.equals(\"0701\")) { 387 if (answerAddressAreaCode.matches(\"^079\\\\d$\") || answerAddressAreaCode.equals(\"0701\")) { 388 return 2; 389 } 390 } 391 return 3; 392 } 393 394 public CallRecord(String[] in) { 395 super(); 396 if (in[0].length() == 10) { 397 callingAddressAreaCode = in[0].substring(0, 3); 398 } else { 399 callingAddressAreaCode = in[0].substring(0, 4); 400 } 401 if (in[1].length() == 10) { 402 answerAddressAreaCode = in[1].substring(0, 3); 403 } else { 404 answerAddressAreaCode = in[1].substring(0, 4); 405 } 406 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy.MM.dd HH:mm:ss\", Locale.getDefault()); 407 try { 408 startTime = simpleDateFormat.parse(in[2] + \" \" + in[3]); 409 endTime = simpleDateFormat.parse(in[4] + \" \" + in[5]); 410 } catch (ParseException e) { 411 throw new RuntimeException(e); 412 } 413 414 } 415 416 public Date getStartTime() { 417 return startTime; 418 } 419 420 public void setStartTime(Date startTime) { 421 this.startTime = startTime; 422 } 423 424 public Date getEndTime() { 425 return endTime; 426 } 427 428 public void setEndTime(Date endTime) { 429 this.endTime = endTime; 430 } 431 432 public String getCallingAddressAreaCode() { 433 return callingAddressAreaCode; 434 } 435 436 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 437 this.callingAddressAreaCode = callingAddressAreaCode; 438 } 439 440 public String getAnswerAddressAreaCode() { 441 return answerAddressAreaCode; 442 } 443 444 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 445 this.answerAddressAreaCode = answerAddressAreaCode; 446 } 447 } 448 449 abstract class CallChargeRule extends ChargeRule {} 450 451 /* 452 * 市内 453 * */ 454 class LandPhoneInCityRule extends CallChargeRule { 455 456 @Override 457 public double calCost(UserRecords userRecords) { 458 double sumCost = 0; 459 for (CallRecord call : userRecords.getCallingInCityRecords()) { 460 long distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 461 if (distanceS < 0) { 462 continue; 463 } 464 long distanceM = (int) distanceS / 60; 465 if (distanceS % 60 != 0) { 466 distanceM += 1; 467 } 468 sumCost += distanceM * 0.1; 469 } 470 return sumCost; 471 } 472 473 } 474 /* 475 * 国内 476 * */ 477 class LandPhoneInlandRule extends CallChargeRule { 478 479 @Override 480 public double calCost(UserRecords userRecords) { 481 double sumCost = 0; 482 for (CallRecord call : userRecords.getCallingInLandRecords()) { 483 long distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 484 if (distanceS < 0) { 485 continue; 486 } 487 long distanceM = (int) distanceS / 60; 488 if (distanceS % 60 != 0) { 489 distanceM += 1; 490 } 491 sumCost += distanceM * 0.6; 492 } 493 return sumCost; 494 } 495 496 } 497 /* 498 * 省内 499 */ 500 class LandPhoneInProvinceRule extends CallChargeRule { 501 502 @Override 503 public double calCost(UserRecords userRecords) { 504 double sumCost = 0; 505 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 506 long distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 507 if (distanceS < 0) { 508 continue; 509 } 510 long distanceM = (int) distanceS / 60; 511 if (distanceS % 60 != 0) { 512 distanceM += 1; 513 } 514 sumCost += distanceM * 0.3; 515 } 516 return sumCost; 517 } 518 519 } 520 /* 521 * 类:短信记录 522 * 属性:短信内容 523 * 524 * */ 525 class MessageRecord extends CommunicationRecord { 526 527 private String message; 528 529 public String getMessage() { 530 return message; 531 } 532 533 public void setMessage(String message) { 534 this.message = message; 535 } 536 } 537 /* 538 * 类:用户 539 * 属性:用户通讯详细信息记录userRecords,话费余额,电话付费方式,电话号码 540 * 541 * */ 542 class User { 543 private UserRecords userRecords = new UserRecords(); 544 double balance = 100; 545 private ChargeMode chargeMode; 546 private String number; 547 548 public double calCost() { 549 return chargeMode.calCost(userRecords); 550 } 551 552 public double calBalance() { 553 return balance - chargeMode.getMonthlyRent() - calCost(); 554 } 555 556 public UserRecords getUserRecords() { 557 return userRecords; 558 } 559 560 public void setUserRecords(UserRecords userRecords) { 561 this.userRecords = userRecords; 562 } 563 564 public ChargeMode getChargeMode() { 565 return chargeMode; 566 } 567 568 public void setChargeMode(ChargeMode chargeMode) { 569 this.chargeMode = chargeMode; 570 } 571 572 public String getNumber() { 573 return number; 574 } 575 576 public void setNumber(String number) { 577 this.number = number; 578 } 579 580 }
View Code
结果:
分析:电信1的得分点最后还有一个没有过,但测试了很多输入样例都没有测出来。由上图可知,最后的代码平均深度,平均复杂度和最大深度差不多,不是很高,最大复杂度比较高,信息量实在是太多了,不过总体来说圈复杂度还是可以的。注释我都做了类的注释,但好像还是有点少了。
2.第7次作业:7-2 电信计费系列1-手机计费
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费:
u-13307912264 1
t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
输入:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,含手机和座机用户
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题在电信计费系列1基础上增加类型1-手机实时计费。
手机设置0或者座机设置成1,此种错误可不做判断。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合\"yyyy.MM.dd HH:mm:ss\"格式。提示:使用SimpleDateFormat类。
输入格式增加手机接打电话以及收发短信的格式,手机接打电话的信息除了号码之外需要额外记录拨打/接听的地点的区号,比如:
座机打手机:
t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:
t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
类图同上题,直接省略。
分析:上次题目中只写了座机的计费,本次需要再加上有关手机计费的类,同座机一样,分为市内,省内,国内三种计费方式。
代码如下:
1 import java.util.*; 2 import java.util.regex.Matcher; 3 import java.util.regex.Pattern; 4 import java.math.BigDecimal; 5 import java.text.SimpleDateFormat; 6 import java.text.ParseException; 7 8 public class Main { 9 public static void main(String[] args) { 10 Outputtool outputtool = new Outputtool(); 11 Inputdeal inputdeal = new Inputdeal(); 12 ArrayList<User> users = new ArrayList<>(); 13 Scanner in = new Scanner(System.in); 14 String input = in.nextLine(); 15 while (!input.equals(\"end\")) { 16 if (1 == inputdeal.check(input)) { 17 inputdeal.writeUser(users, input); 18 } else if (2 == inputdeal.check(input)) { 19 inputdeal.writeRecord(users, input); 20 } 21 input = in.nextLine(); 22 } 23 //排序 24 users.sort(new Comparator<User>() { 25 26 @Override 27 public int compare(User u1, User u2) { 28 if (u1.getNumber().charAt(0) == \'0\' && u2.getNumber().charAt(0) != \'0\') { 29 return -1; 30 } else if (u1.getNumber().charAt(0) != \'0\' && u2.getNumber().charAt(0) == \'0\') { 31 return 1; 32 } 33 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 34 return 1; 35 } else { 36 return -1; 37 } 38 } 39 }); 40 for (User u : users) { 41 System.out.print(u.getNumber() + \" \"); 42 outputtool.output(u.calCost()); 43 System.out.print(\" \"); 44 outputtool.output(u.calBalance()); 45 System.out.println(); 46 } 47 } 48 } 49 50 abstract class ChargeMode { 51 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 52 53 public abstract double calCost(UserRecords userRecords); 54 55 public abstract double getMonthlyRent(); 56 57 public ArrayList<ChargeRule> getChargeRules() { 58 return chargeRules; 59 } 60 61 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 62 this.chargeRules = chargeRules; 63 } 64 } 65 /* 66 * 类:用户 67 * 属性:用户通讯详细信息记录userRecords,话费余额,电话付费方式,电话号码 68 * 69 * */ 70 class User { 71 72 private UserRecords userRecords = new UserRecords(); 73 private double balance = 100; 74 private ChargeMode chargeMode; 75 private String number; 76 77 public double calCost() { 78 return chargeMode.calCost(userRecords); 79 } 80 81 public double calBalance() { 82 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 83 } 84 85 public UserRecords getUserRecords() { 86 return userRecords; 87 } 88 89 public void setUserRecords(UserRecords userRecords) { 90 this.userRecords = userRecords; 91 } 92 93 public ChargeMode getChargeMode() { 94 return chargeMode; 95 } 96 97 public void setChargeMode(ChargeMode chargeMode) { 98 this.chargeMode = chargeMode; 99 } 100 101 public String getNumber() { 102 return number; 103 } 104 105 public void setNumber(String number) { 106 this.number = number; 107 } 108 109 } 110 /* 111 * 类:用户通讯所有信息记录 112 * 属性:市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、 113 * 市内接听电话、省内(不含市内)接听电话、省外接听电话的记录 114 * 以及发送短信、接收短信的记录 115 * 功能:按地址分别记录通话信息 116 * */ 117 class UserRecords { 118 119 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 120 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 121 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 122 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 123 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 124 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 125 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 126 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 127 128 //记录信息,将通讯信息添加到对应列表 129 public void addCallingInCityRecords(CallRecord callRecord) { 130 callingInCityRecords.add(callRecord); 131 } 132 133 public void addCallingInProvinceRecords(CallRecord callRecord) { 134 callingInProvinceRecords.add(callRecord); 135 } 136 137 public void addCallingInLandRecords(CallRecord callRecord) { 138 callingInLandRecords.add(callRecord); 139 } 140 141 public void addAnswerInCityRecords(CallRecord callRecord) { 142 answerInCityRecords.add(callRecord); 143 } 144 145 public void addAnswerInProvinceRecords(CallRecord callRecord) { 146 answerInProvinceRecords.add(callRecord); 147 } 148 149 public void addAnswerInLandRecords(CallRecord callRecord) { 150 answerInLandRecords.add(callRecord); 151 } 152 153 public void addSendMessageRecords(MessageRecord callRecord) { 154 sendMessageRecords.add(callRecord); 155 } 156 157 public void addReceiveMessageRecords(MessageRecord callRecord) { 158 receiveMessageRecords.add(callRecord); 159 } 160 161 public ArrayList<CallRecord> getCallingInCityRecords() { 162 return callingInCityRecords; 163 } 164 165 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 166 this.callingInCityRecords = callingInCityRecords; 167 } 168 169 public ArrayList<CallRecord> getCallingInProvinceRecords() { 170 return callingInProvinceRecords; 171 } 172 173 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 174 this.callingInProvinceRecords = callingInProvinceRecords; 175 } 176 177 public ArrayList<CallRecord> getCallingInLandRecords() { 178 return callingInLandRecords; 179 } 180 181 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 182 this.callingInLandRecords = callingInLandRecords; 183 } 184 185 public ArrayList<CallRecord> getAnswerInCityRecords() { 186 return answerInCityRecords; 187 } 188 189 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 190 this.answerInCityRecords = answerInCityRecords; 191 } 192 193 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 194 return answerInProvinceRecords; 195 } 196 197 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 198 this.answerInProvinceRecords = answerInProvinceRecords; 199 } 200 201 public ArrayList<CallRecord> getAnswerInLandRecords() { 202 return answerInLandRecords; 203 } 204 205 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 206 this.answerInLandRecords = answerInLandRecords; 207 } 208 209 public ArrayList<MessageRecord> getSendMessageRecords() { 210 return sendMessageRecords; 211 } 212 213 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 214 this.sendMessageRecords = sendMessageRecords; 215 } 216 217 public ArrayList<MessageRecord> getReceiveMessageRecords() { 218 return receiveMessageRecords; 219 } 220 221 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 222 this.receiveMessageRecords = receiveMessageRecords; 223 } 224 225 } 226 /* 227 * 座机计费方式 228 * 229 * */ 230 class LandlinePhoneCharging extends ChargeMode { 231 232 private double monthlyRent = 20; 233 234 public LandlinePhoneCharging() { 235 super(); 236 chargeRules.add(new LandPhoneInCityRule()); 237 chargeRules.add(new LandPhoneInProvinceRule()); 238 chargeRules.add(new LandPhoneInlandRule()); 239 } 240 241 @Override 242 public double calCost(UserRecords userRecords) { 243 double sumCost = 0; 244 for (ChargeRule rule : chargeRules) { 245 sumCost += rule.calCost(userRecords); 246 } 247 return sumCost; 248 } 249 250 @Override 251 public double getMonthlyRent() { 252 return monthlyRent; 253 } 254 255 } 256 /* 257 * 手机计费方式 258 * 259 * */ 260 class MobilePhoneCharging extends ChargeMode { 261 262 private double monthlyRent = 15; 263 264 public MobilePhoneCharging() { 265 super(); 266 chargeRules.add(new MobilePhoneInCityRule()); 267 chargeRules.add(new MobilePhoneInProvinceRule()); 268 chargeRules.add(new MobilePhoneInlandRule()); 269 } 270 271 @Override 272 public double calCost(UserRecords userRecords) { 273 double sumCost = 0; 274 for (ChargeRule rule : chargeRules) { 275 sumCost += rule.calCost(userRecords); 276 } 277 return sumCost; 278 } 279 280 @Override 281 public double getMonthlyRent() { 282 return monthlyRent; 283 } 284 285 } 286 /* 类:输入格式判断InputDeal 287 * 功能:判断输入格式是否正确,时间是否合理 288 * 289 * */ 290 class Inputdeal { 291 292 public int check(String input) { 293 if (input.matches(\"u-0791\\\\d{7,8}\\\\s0\") || input.matches(\"u-1\\\\d{10}\\\\s[1]\")) { 294 return 1; 295 } else if (input.matches(\"((t-0791\\\\d{7,8}\\\\s\" + \"0\\\\d{9,11}\\\\s)|\" 296 + \"(t-0791\\\\d{7,8}\\\\s\" + \"1\\\\d{10}\\\\s\" + \"0\\\\d{2,3}\\\\s)|\" 297 + \"(t-1\\\\d{10}\\\\s\" + \"0\\\\d{2,3}\\\\s\" + \"0\\\\d{9,11}\\\\s)|\" 298 + \"(t-1\\\\d{10}\\\\s\" + \"0\\\\d{2,3}\\\\s\" + \"1\\\\d{10}\\\\s\" + \"0\\\\d{2,3}\\\\s))\" 299 300 + \"(((\\\\d{3}[1-9]|\\\\d{2}[1-9]\\\\d|\\\\d[1-9]\\\\d{2}|[1-9]\\\\d{3})\\\\.(((0?[13578]|1[02])\\\\.(0?\" 301 + \"[1-9]|[12]\\\\d|3[01]))|(([469]|11)\\\\.([1-9]|[12]\\\\d|30))|(2\\\\.([1-9]|1\\\\d|2[0-8]))))|(((\" 302 + \"\\\\d{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\\\.2\\\\.29))\" 303 + \"\\\\s([0-1]?\\\\d|2[0-3]):([0-5]\\\\d):([0-5]\\\\d)\\\\s\" 304 + \"(((\\\\d{3}[1-9]|\\\\d{2}[1-9]\\\\d|\\\\d[1-9]\\\\d{2}|[1-9]\\\\d{3})\\\\.((([13578]|1[02])\\\\.(\" 305 + \"[1-9]|[12]\\\\d|3[01]))|(([469]|11)\\\\.([1-9]|[12]\\\\d|30))|(2\\\\.([1-9]|1\\\\d|2[0-8]))))|(((\" 306 + \"\\\\d{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\\\.2\\\\.29))\" 307 + \"\\\\s([0-1]?\\\\d|2[0-3]):([0-5]\\\\d):([0-5]\\\\d)\")) { 308 return 2; 309 } 310 return 0; 311 } 312 313 @SuppressWarnings(\"unused\") 314 private boolean validatet(String string) { 315 if (!string.matches(\"^([0-1]?\\\\d|2[0-3]):([0-5]\\\\d):([0-5]\\\\d)$\")) { 316 return false; 317 } 318 return true; 319 } 320 321 public static boolean validate(String dateString) { 322 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 323 Pattern p = Pattern.compile(\"\\\\d{4}+[.]\\\\d{1,2}+[.]\\\\d{1,2}+\"); 324 Matcher m = p.matcher(dateString); 325 if (!m.matches()) { 326 return false; 327 } 328 329 // 得到年月日 330 String[] array = dateString.split(\"\\\\.\"); 331 int year = Integer.parseInt(array[0]); 332 int month = Integer.parseInt(array[1]); 333 int day = Integer.parseInt(array[2]); 334 335 if (month < 1 || month > 12) { 336 return false; 337 } 338 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 339 if (isLeapYear(year)) { 340 monthLengths[2] = 29; 341 } else { 342 monthLengths[2] = 28; 343 } 344 int monthLength = monthLengths[month]; 345 return day >= 1 && day <= monthLength; 346 } 347 348 /** 是否是闰年 */ 349 private static boolean isLeapYear(int year) { 350 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 351 } 352 353 public void writeUser(ArrayList<User> users, String input) { 354 User usernew = new User(); 355 String[] inputs = input.split(\" \"); 356 String num = inputs[0].substring(2); 357 for (User i : users) { 358 if (i.getNumber().equals(num)) { 359 return; 360 } 361 } 362 usernew.setNumber(num); 363 int mode = Integer.parseInt(inputs[1]); 364 if (mode == 0) { 365 usernew.setChargeMode(new LandlinePhoneCharging()); 366 } else if (mode == 1) { 367 usernew.setChargeMode(new MobilePhoneCharging()); 368 } 369 users.add(usernew); 370 } 371 372 public void writeRecord(ArrayList<User> users, String input) { 373 String[] inputs = input.split(\" \"); 374 375 User callu = null, answeru = null; 376 CallRecord callrecord = new CallRecord(inputs); 377 378 if (input.charAt(0) == \'t\') { 379 String out = inputs[0]; 380 String in = \"\"; 381 if (inputs.length == 6) { 382 in = inputs[1]; 383 } else if (inputs.length == 7) { 384 in = inputs[1]; 385 } else if (inputs.length == 8) { 386 in = inputs[2]; 387 } 388 389 for (User i : users) { 390 if (i.getNumber().equals(out)) { 391 callu = i; 392 } 393 if (i.getNumber().equals(in)) { 394 answeru = i; 395 } 396 if (callu != null && answeru != null) { 397 break; 398 } 399 } 400 401 if (callu != null) { 402 if (callrecord.getCallType().matches(\"^1[1-3]$\")) { 403 callu.getUserRecords().addCallingInCityRecords(callrecord); 404 } else if (callrecord.getCallType().matches(\"^2[1-3]$\")) { 405 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 406 } else { 407 callu.getUserRecords().addCallingInLandRecords(callrecord); 408 } 409 } 410 411 if (answeru != null) { 412 if (callrecord.getCallType().matches(\"^[1-3]1$\")) { 413 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 414 } else if (callrecord.getCallType().matches(\"^[1-3]2$\")) { 415 answeru.getUserRecords().addAnswerInProvinceRecords(callrecord); 416 } else { 417 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 418 } 419 } 420 } 421 422 } 423 424 } 425 /* 426 * 抽象类:通讯记录 427 * 属性:callingNumber拨打号码、answerNumber接听号码 428 * 429 * */ 430 abstract class CommunicationRecord { 431 protected String callingNumber; 432 protected String answerNumber; 433 434 public String getCallingNumber() { 435 return callingNumber; 436 } 437 438 public void setCallingNumber(String callingNumber) { 439 this.callingNumber = callingNumber; 440 } 441 442 public String getAnswerNumber() { 443 return answerNumber; 444 } 445 446 public void setAnswerNumber(String answerNumber) { 447 this.answerNumber = answerNumber; 448 } 449 450 } 451 452 abstract class ChargeRule { 453 454 abstract public double calCost(UserRecords userRecords); 455 456 } 457 /* 458 * 类:通话记录 459 * 属性:通话起始、结束时间;拨号人地址,接听人地址 460 * 功能:记录打电话双方的地址和通话时间 461 * 462 */ 463 class CallRecord extends CommunicationRecord { 464 private Date startTime; 465 private Date endTime; 466 private String callingAddressAreaCode; 467 private String answerAddressAreaCode; 468 469 public String getCallType() { 470 String type = \"\"; 471 /* 472 * type = 11,市内拨打市内 473 * type = 12,市内拨打省内 474 * type = 13,市内拨打省外 475 * type = 21,省内拨打市内 476 * type = 21,省内拨打省内 477 * type = 21,省内拨打省外 478 * */ 479 if (callingAddressAreaCode.equals(\"0791\")) { 480 type = type.concat(\"1\"); 481 } else if (callingAddressAreaCode.matches(\"^079[023456789]$\") || callingAddressAreaCode.equals(\"0701\")) { 482 type = type.concat(\"2\"); 483 } else { 484 type = type.concat(\"3\"); 485 } 486 487 if (answerAddressAreaCode.equals(\"0791\")) { 488 type = type.concat(\"1\"); 489 } else if (answerAddressAreaCode.matches(\"^079[023456789]$\") || answerAddressAreaCode.equals(\"0701\")) { 490 type = type.concat(\"2\"); 491 } else { 492 type = type.concat(\"3\"); 493 } 494 return type; 495 } 496 497 public CallRecord(String[] inputs) { 498 super(); 499 500 char type = inputs[0].charAt(0); 501 inputs[0] = inputs[0].substring(2); 502 503 String sd = null, st = null, ed = null, et = null; 504 505 if (type == \'t\') { 506 if (inputs.length == 6) { 507 sd = inputs[2]; 508 st = inputs[3]; 509 ed = inputs[4]; 510 et = inputs[5]; 511 callingAddressAreaCode = inputs[0].substring(0, 4); 512 answerAddressAreaCode = inputs[1].substring(0, 4); 513 } else if (inputs.length == 7) { 514 sd = inputs[3]; 515 st = inputs[4]; 516 ed = inputs[5]; 517 et = inputs[6]; 518 if (inputs[0].charAt(0) != \'0\') { //手机打给座机 519 if (inputs[2].length() == 10) { 520 answerAddressAreaCode = inputs[2].substring(0, 3); 521 } else { 522 answerAddressAreaCode = inputs[2].substring(0, 4); 523 } 524 callingAddressAreaCode = inputs[1]; 525 } else { //座机打给手机 526 if (inputs[0].length() == 10) { 527 callingAddressAreaCode = inputs[0].substring(0, 3); 528 } else { 529 callingAddressAreaCode = inputs[0].substring(0, 4); 530 } 531 answerAddressAreaCode = inputs[2]; 532 } 533 } else if (inputs.length == 8) { 534 sd = inputs[4]; 535 st = inputs[5]; 536 ed = inputs[6]; 537 et = inputs[7]; 538 callingAddressAreaCode = inputs[1]; 539 answerAddressAreaCode = inputs[3]; 540 } 541 } 542 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy.MM.dd HH:mm:ss\", Locale.getDefault()); 543 try { 544 startTime = simpleDateFormat.parse(sd + \" \" + st); 545 endTime = simpleDateFormat.parse(ed + \" \" + et); 546 } catch (ParseException e) { 547 } 548 549 } 550 551 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 552 super(); 553 this.startTime = startTime; 554 this.endTime = endTime; 555 this.callingAddressAreaCode = callingAddressAreaCode; 556 this.answerAddressAreaCode = answerAddressAreaCode; 557 } 558 559 public Date getStartTime() { 560 return startTime; 561 } 562 563 public void setStartTime(Date startTime) { 564 this.startTime = startTime; 565 } 566 567 public Date getEndTime() { 568 return endTime; 569 } 570 571 public void setEndTime(Date endTime) { 572 this.endTime = endTime; 573 } 574 575 public String getCallingAddressAreaCode() { 576 return callingAddressAreaCode; 577 } 578 579 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 580 this.callingAddressAreaCode = callingAddressAreaCode; 581 } 582 583 public String getAnswerAddressAreaCode() { 584 return answerAddressAreaCode; 585 } 586 587 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 588 this.answerAddressAreaCode = answerAddressAreaCode; 589 } 590 } 591 592 abstract class CallChargeRule extends ChargeRule { 593 594 } 595 /* 596 * 市内 597 * */ 598 class LandPhoneInCityRule extends CallChargeRule { 599 600 @Override 601 public double calCost(UserRecords userRecords) { 602 double sumCost = 0; 603 for (CallRecord call : userRecords.getCallingInCityRecords()) { 604 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 605 if (distanceS < 0) { 606 continue; 607 } 608 double distanceM = (int) distanceS / 60; 609 if (distanceS % 60 != 0) { 610 distanceM += 1; 611 } 612 if (call.getCallType().equals(\"11\")) { 613 sumCost += distanceM * 0.1; 614 } else if (call.getCallType().equals(\"12\")) { 615 sumCost += distanceM * 0.3; 616 } else if (call.getCallType().equals(\"13\")) { 617 sumCost += distanceM * 0.6; 618 } 619 } 620 return sumCost; 621 } 622 623 } 624 /* 625 * 国内 626 * */ 627 class LandPhoneInlandRule extends CallChargeRule { 628 629 @Override 630 public double calCost(UserRecords userRecords) { 631 double sumCost = 0; 632 for (CallRecord call : userRecords.getCallingInLandRecords()) { 633 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 634 if (distanceS < 0) { 635 continue; 636 } 637 double distanceM = (int) distanceS / 60; 638 if (distanceS % 60 != 0) { 639 distanceM += 1; 640 } 641 sumCost += distanceM * 0.6; 642 } 643 return sumCost; 644 } 645 646 } 647 /* 648 * 省内 649 */ 650 class LandPhoneInProvinceRule extends CallChargeRule { 651 652 @Override 653 public double calCost(UserRecords userRecords) { 654 double sumCost = 0; 655 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 656 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 657 if (distanceS < 0) { 658 continue; 659 } 660 double distanceM = (int) distanceS / 60; 661 if (distanceS % 60 != 0) { 662 distanceM += 1; 663 } 664 sumCost += distanceM * 0.3; 665 } 666 return sumCost; 667 } 668 669 } 670 /* 671 * 手机市内付费 672 */ 673 class MobilePhoneInCityRule extends CallChargeRule { 674 675 @Override 676 public double calCost(UserRecords userRecords) { 677 double sumCost = 0; 678 for (CallRecord call : userRecords.getCallingInCityRecords()) { 679 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 680 if (distanceS < 0) { 681 continue; 682 } 683 double distanceM = (int) distanceS / 60; 684 if (distanceS % 60 != 0) { 685 distanceM += 1; 686 } 687 if (call.getCallType().equals(\"11\")) { 688 sumCost += distanceM * 0.1; 689 } else if (call.getCallType().equals(\"12\")) { 690 sumCost += distanceM * 0.2; 691 } else if (call.getCallType().equals(\"13\")) { 692 sumCost += distanceM * 0.3; 693 } 694 695 } 696 return sumCost; 697 } 698 699 } 700 /* 701 * 手机国内 702 */ 703 class MobilePhoneInlandRule extends CallChargeRule { 704 705 @Override 706 public double calCost(UserRecords userRecords) { 707 double sumCost = 0; 708 for (CallRecord call : userRecords.getCallingInLandRecords()) { 709 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 710 if (distanceS < 0) { 711 continue; 712 } 713 double distanceM = (int) distanceS / 60; 714 if (distanceS % 60 != 0) { 715 distanceM += 1; 716 } 717 sumCost += distanceM * 0.6; 718 } 719 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 720 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 721 if (distanceS < 0) { 722 continue; 723 } 724 double distanceM = (int) distanceS / 60; 725 if (distanceS % 60 != 0) { 726 distanceM += 1; 727 } 728 sumCost += distanceM * 0.3; 729 } 730 return sumCost; 731 } 732 733 } 734 /* 735 * 手机省内 736 */ 737 class MobilePhoneInProvinceRule extends CallChargeRule { 738 739 @Override 740 public double calCost(UserRecords userRecords) { 741 double sumCost = 0; 742 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 743 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 744 if (distanceS < 0) { 745 continue; 746 } 747 double distanceM = (int) distanceS / 60; 748 if (distanceS % 60 != 0) { 749 distanceM += 1; 750 } 751 if (call.getCallType().equals(\"21\")) { 752 sumCost += distanceM * 0.3; 753 } else if (call.getCallType().equals(\"22\")) { 754 sumCost += distanceM * 0.3; 755 } else if (call.getCallType().equals(\"23\")) { 756 sumCost += distanceM * 0.3; 757 } 758 } 759 return sumCost; 760 } 761 762 } 763 764 class MessageRecord extends CommunicationRecord { 765 766 private String message; 767 768 public String getMessage() { 769 return message; 770 } 771 772 public void setMessage(String message) { 773 this.message = message; 774 } 775 } 776 /* 777 * 类:用户 778 * 属性:用户通讯详细信息记录userRecords,话费余额,电话付费方式,电话号码 779 * 780 * */ 781 class User { 782 783 private UserRecords userRecords = new UserRecords(); 784 private double balance = 100; 785 private ChargeMode chargeMode; 786 private String number; 787 788 public double calCost() { 789 return chargeMode.calCost(userRecords); 790 } 791 792 public double calBalance() { 793 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 794 } 795 796 public UserRecords getUserRecords() { 797 return userRecords; 798 } 799 800 public void setUserRecords(UserRecords userRecords) { 801 this.userRecords = userRecords; 802 } 803 804 public ChargeMode getChargeMode() { 805 return chargeMode; 806 } 807 808 public void setChargeMode(ChargeMode chargeMode) { 809 this.chargeMode = chargeMode; 810 } 811 812 public String getNumber() { 813 return number; 814 } 815 816 public void setNumber(String number) { 817 this.number = number; 818 } 819 820 } 821 822 class Outputtool { 823 824 @SuppressWarnings(\"deprecation\") 825 public void output(double out) { 826 BigDecimal numb = new BigDecimal(out); 827 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 828 System.out.print(out); 829 } 830 }
View Code
结果:
分析:这次代码我将输入格式判断之类的函数全都放到了一个inputdeal类中,对写入正确通信信息的方法进行了改进,最后所有测试点都过了。有source monitor的图可以看出,形状与上次代码的差不多,不过由于处理函数多了,总体的圈复杂度稍微增大了一些。
3.7-3 阅读程序,按照题目需求修改程序
题目略。
分析:这次题目里面给出了代码,只是有些细节问题,需要修改。但就是这些细节让我改了很久。因为他还考察Iterator,Collection这些陌生的类,后来看了很多网上的解释再去改,还是过不了,原来问题不在这,是输入scanner有问题,要把它放到循环外面。。。
代码略。
4.第8次作业:7-1 电信计费系列3-短信计费
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。
输入:
输入信息包括两种类型
1、逐行输入南昌市手机用户开户的信息,每行一个用户。
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐 3-手机短信计费)
例如:u-13305862264 3
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题只针对类型3-手机短信计费。
2、逐行输入本月某些用户的短信信息,短信的格式:
m-主叫号码,接收号码,短信内容 (短信内容只能由数字、字母、空格、英文逗号、英文句号组成)
m-18907910010 13305862264 welcome to jiangxi.
m-13305862264 18907910010 thank you.
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
类图及其他要求略。
分析:这次难度就降低了,只需要照着之前的框架写就行,不过最后700多行的代码它还显示太长了,我就把之前的座机,手机电话付费的删掉了,测试点也都能过。
代码如下:
1 import java.util.ArrayList; 2 import java.util.Comparator; 3 import java.util.Scanner; 4 import java.math.BigDecimal; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.Locale; 8 import java.text.ParseException; 9 10 public class Main { 11 12 public static void main(String[] args) { 13 14 Outputtool outputtool = new Outputtool(); 15 16 Inputdeal inputdeal = new Inputdeal(); 17 18 ArrayList<User> users = new ArrayList<>(); 19 20 Scanner in = new Scanner(System.in); 21 22 String input = in.nextLine(); 23 24 while (!input.equals(\"end\")) { 25 if (1 == inputdeal.check(input)) { 26 inputdeal.writeUser(users, input); 27 } else if (2 == inputdeal.check(input)) { 28 inputdeal.writeRecord(users, input); 29 } 30 input = in.nextLine(); 31 } 32 33 users.sort(new Comparator<User>() { 34 35 @Override 36 public int compare(User u1, User u2) { 37 if (u1.getNumber().charAt(0) == \'0\' && u2.getNumber().charAt(0) != \'0\') { 38 return -1; 39 } else if (u1.getNumber().charAt(0) != \'0\' && u2.getNumber().charAt(0) == \'0\') { 40 return 1; 41 } 42 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 43 return 1; 44 } else { 45 return -1; 46 } 47 } 48 }); 49 50 for (User u : users) { 51 System.out.print(u.getNumber() + \" \"); 52 outputtool.output(u.calCost()); 53 System.out.print(\" \"); 54 outputtool.output(u.calBalance()); 55 System.out.println(); 56 57 } 58 59 } 60 61 } 62 63 abstract class ChargeMode { 64 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 65 66 public abstract double calCost(UserRecords userRecords); 67 68 public abstract double getMonthlyRent(); 69 70 public ArrayList<ChargeRule> getChargeRules() { 71 return chargeRules; 72 } 73 74 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 75 this.chargeRules = chargeRules; 76 } 77 } 78 /* 79 * 类:用户 80 * 属性:用户通讯详细信息记录userRecords,话费余额,电话付费方式,电话号码 81 * 82 * */ 83 class User { 84 85 private UserRecords userRecords = new UserRecords(); 86 private double balance = 100; 87 private ChargeMode chargeMode; 88 private String number; 89 90 public double calCost() { 91 return chargeMode.calCost(userRecords); 92 } 93 94 public double calBalance() { 95 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 96 } 97 98 public UserRecords getUserRecords() { 99 return userRecords; 100 } 101 102 public void setUserRecords(UserRecords userRecords) { 103 this.userRecords = userRecords; 104 } 105 106 public ChargeMode getChargeMode() { 107 return chargeMode; 108 } 109 110 public void setChargeMode(ChargeMode chargeMode) { 111 this.chargeMode = chargeMode; 112 } 113 114 public String getNumber() { 115 return number; 116 } 117 118 public void setNumber(String number) { 119 this.number = number; 120 } 121 122 } 123 /* 124 * 类:用户通讯所有信息记录 125 * 属性:市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、 126 * 市内接听电话、省内(不含市内)接听电话、省外接听电话的记录 127 * 以及发送短信、接收短信的记录 128 * 功能:按地址分别记录通话信息 129 * */ 130 class UserRecords { 131 132 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 133 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 134 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 135 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 136 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 137 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 138 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 139 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 140 141 public void addCallingInCityRecords(CallRecord callRecord) { 142 callingInCityRecords.add(callRecord); 143 } 144 145 public void addCallingInProvinceRecords(CallRecord callRecord) { 146 callingInProvinceRecords.add(callRecord); 147 } 148 149 public void addCallingInLandRecords(CallRecord callRecord) { 150 callingInLandRecords.add(callRecord); 151 } 152 153 public void addAnswerInCityRecords(CallRecord callRecord) { 154 answerInCityRecords.add(callRecord); 155 } 156 157 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 158 answerInProvinceRecords.add(callRecord); 159 } 160 161 public void addAnswerInLandRecords(CallRecord callRecord) { 162 answerInLandRecords.add(callRecord); 163 } 164 165 public void addSendMessageRecords(MessageRecord callRecord) { 166 sendMessageRecords.add(callRecord); 167 } 168 169 public void addReceiveMessageRecords(MessageRecord callRecord) { 170 receiveMessageRecords.add(callRecord); 171 } 172 173 public ArrayList<CallRecord> getCallingInCityRecords() { 174 return callingInCityRecords; 175 } 176 177 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 178 this.callingInCityRecords = callingInCityRecords; 179 } 180 181 public ArrayList<CallRecord> getCallingInProvinceRecords() { 182 return callingInProvinceRecords; 183 } 184 185 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 186 this.callingInProvinceRecords = callingInProvinceRecords; 187 } 188 189 public ArrayList<CallRecord> getCallingInLandRecords() { 190 return callingInLandRecords; 191 } 192 193 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 194 this.callingInLandRecords = callingInLandRecords; 195 } 196 197 public ArrayList<CallRecord> getAnswerInCityRecords() { 198 return answerInCityRecords; 199 } 200 201 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 202 this.answerInCityRecords = answerInCityRecords; 203 } 204 205 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 206 return answerInProvinceRecords; 207 } 208 209 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 210 this.answerInProvinceRecords = answerInProvinceRecords; 211 } 212 213 public ArrayList<CallRecord> getAnswerInLandRecords() { 214 return answerInLandRecords; 215 } 216 217 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 218 this.answerInLandRecords = answerInLandRecords; 219 } 220 221 public ArrayList<MessageRecord> getSendMessageRecords() { 222 return sendMessageRecords; 223 } 224 225 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 226 this.sendMessageRecords = sendMessageRecords; 227 } 228 229 public ArrayList<MessageRecord> getReceiveMessageRecords() { 230 return receiveMessageRecords; 231 } 232 233 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 234 this.receiveMessageRecords = receiveMessageRecords; 235 } 236 237 } 238 239 /* 240 * 座机计费方式 241 * 不包括通话计费 242 * */ 243 class LandlinePhoneCharging extends ChargeMode { 244 245 private double monthlyRent = 20; 246 /* 247 public LandlinePhoneCharging() { 248 super(); 249 chargeRules.add(new LandPhoneInCityRule()); 250 chargeRules.add(new LandPhoneInProvinceRule()); 251 chargeRules.add(new LandPhoneInlandRule()); 252 } 253 */ 254 @Override 255 public double calCost(UserRecords userRecords) { 256 double sumCost = 0; 257 for (ChargeRule rule : chargeRules) { 258 sumCost += rule.calCost(userRecords); 259 } 260 return sumCost; 261 } 262 263 @Override 264 public double getMonthlyRent() { 265 return monthlyRent; 266 } 267 268 } 269 270 /* 271 * 手机计费方式 272 * 去掉通话计费 273 * */ 274 class MobilePhoneCharging extends ChargeMode { 275 276 private double monthlyRent = 15; 277 278 /*public MobilePhoneCharging() { 279 super(); 280 chargeRules.add(new MobilePhoneInCityRule()); 281 chargeRules.add(new MobilePhoneInProvinceRule()); 282 chargeRules.add(new MobilePhoneInlandRule()); 283 }*/ 284 285 @Override 286 public double calCost(UserRecords userRecords) { 287 double sumCost = 0; 288 for (ChargeRule rule : chargeRules) { 289 sumCost += rule.calCost(userRecords); 290 } 291 return sumCost; 292 } 293 294 @Override 295 public double getMonthlyRent() { 296 return monthlyRent; 297 } 298 299 } 300 /* 301 * 手机短信计费方式 302 * 303 * */ 304 class MobilePhoneMassageCharging extends ChargeMode { 305 306 private double monthlyRent = 0; 307 308 public MobilePhoneMassageCharging() { 309 super(); 310 chargeRules.add(new MobilePhoneMessageRule()); 311 } 312 313 @Override 314 public double calCost(UserRecords userRecords) { 315 double sumCost = 0; 316 for (ChargeRule rule : chargeRules) { 317 sumCost += rule.calCost(userRecords); 318 } 319 return sumCost; 320 } 321 322 @Override 323 public double getMonthlyRent() { 324 return monthlyRent; 325 } 326 327 } 328 329 class Inputdeal { 330 331 public int check(String input) { 332 if (input.matches(\"u-0791\\\\d{7,8}\\\\s[0]\") || input.matches(\"u-1\\\\d{10}\\\\s[13]\")) { 333 return 1; 334 } else if (input.matches(\"m-1\\\\d{10}\\\\s\" + \"1\\\\d{10}\\\\s\" + \"[\\\\da-zA-Z\\\\s.,]+\")) { 335 return 2; 336 } 337 return 0; 338 } 339 340 public void writeUser(ArrayList<User> users, String input) { 341 User usernew = new User(); 342 String[] inputs = input.split(\" \"); 343 String num = inputs[0].substring(2); 344 for (User i : users) { 345 if (i.getNumber().equals(num)) { 346 return; 347 } 348 } 349 usernew.setNumber(num); 350 int mode = Integer.parseInt(inputs[1]); 351 if (mode == 0) { 352 usernew.setChargeMode(new LandlinePhoneCharging()); 353 } else if (mode == 1) { 354 usernew.setChargeMode(new MobilePhoneCharging()); 355 } else if (mode == 3) { 356 usernew.setChargeMode(new MobilePhoneMassageCharging()); 357 } 358 users.add(usernew); 359 } 360 361 public void writeRecord(ArrayList<User> users, String input) { 362 String[] inputs = input.split(\" \"); 363 inputs[0] = inputs[0].substring(2); 364 365 User callu = null, answeru = null; 366 367 String out = inputs[0]; 368 String in = \"\"; 369 if (inputs.length == 6) { 370 in = inputs[1]; 371 } else if (inputs.length == 7) { 372 in = inputs[1]; 373 } else if (inputs.length == 8) { 374 in = inputs[2]; 375 } else { 376 in = inputs[1]; 377 } 378 379 for (User i : users) { 380 if (i.getNumber().equals(out)) { 381 callu = i; 382 } 383 if (i.getNumber().equals(in)) { 384 answeru = i; 385 } 386 if (callu != null && answeru != null) { 387 break; 388 } 389 } 390 391 if (input.charAt(0) == \'m\') { 392 MessageRecord messageRecord = new MessageRecord(input); 393 if (callu != null) { 394 callu.getUserRecords().addSendMessageRecords(messageRecord); 395 396 } 397 if (answeru != null) { 398 callu.getUserRecords().addReceiveMessageRecords(messageRecord); 399 } 400 } 401 402 } 403 404 } 405 /* 406 * 抽象类:通讯记录 407 * 属性:callingNumber拨打号码、answerNumber接听号码 408 * 409 * */ 410 abstract class CommunicationRecord { 411 protected String callingNumber; 412 protected String answerNumber; 413 414 public String getCallingNumber() { 415 return callingNumber; 416 } 417 418 public void setCallingNumber(String callingNumber) { 419 this.callingNumber = callingNumber; 420 } 421 422 public String getAnswerNumber() { 423 return answerNumber; 424 } 425 426 public void setAnswerNumber(String answerNumber) { 427 this.answerNumber = answerNumber; 428 } 429 430 } 431 432 abstract class ChargeRule { 433 434 abstract public double calCost(UserRecords userRecords); 435 436 } 437 /* 438 * 类:电话和短信具体信息记录 439 * 属性:通话起始、结束时间;拨号人地址,接听人地址 440 * 功能:记录短信接收双方的地址和通话时间 441 * 442 */ 443 class CallRecord extends CommunicationRecord { 444 private Date startTime; 445 private Date endTime; 446 private String callingAddressAreaCode; 447 private String answerAddressAreaCode; 448 449 public String getCallType() { 450 String type = \"\"; 451 if (callingAddressAreaCode.equals(\"0791\")) { 452 type = type.concat(\"1\"); 453 } else if (callingAddressAreaCode.matches(\"^079[023456789]$\") || callingAddressAreaCode.equals(\"0701\")) { 454 type = type.concat(\"2\"); 455 } else { 456 type = type.concat(\"3\"); 457 } 458 459 if (answerAddressAreaCode.equals(\"0791\")) { 460 type = type.concat(\"1\"); 461 } else if (answerAddressAreaCode.matches(\"^079[023456789]$\") || answerAddressAreaCode.equals(\"0701\")) { 462 type = type.concat(\"2\"); 463 } else { 464 type = type.concat(\"3\"); 465 } 466 467 return type; 468 } 469 470 public CallRecord(String[] inputs) { 471 super(); 472 473 char type = inputs[0].charAt(0); 474 475 String sd = null, st = null, ed = null, et = null; 476 477 if (type == \'t\') { 478 if (inputs.length == 6) { 479 sd = inputs[2]; 480 st = inputs[3]; 481 ed = inputs[4]; 482 et = inputs[5]; 483 callingAddressAreaCode = inputs[0].substring(0, 4); 484 answerAddressAreaCode = inputs[1].substring(0, 4); 485 } else if (inputs.length == 7) { 486 sd = inputs[3]; 487 st = inputs[4]; 488 ed = inputs[5]; 489 et = inputs[6]; 490 if (inputs[0].charAt(0) != \'0\') { 491 if (inputs[2].length() == 10) { 492 answerAddressAreaCode = inputs[2].substring(0, 3); 493 } else { 494 answerAddressAreaCode = inputs[2].substring(0, 4); 495 } 496 callingAddressAreaCode = inputs[1]; 497 } else { 498 if (inputs[0].length() == 10) { 499 callingAddressAreaCode = inputs[0].substring(0, 3); 500 } else { 501 callingAddressAreaCode = inputs[0].substring(0, 4); 502 } 503 answerAddressAreaCode = inputs[2]; 504 } 505 } else if (inputs.length == 8) { 506 sd = inputs[4]; 507 st = inputs[5]; 508 ed = inputs[6]; 509 et = inputs[7]; 510 callingAddressAreaCode = inputs[1]; 511 answerAddressAreaCode = inputs[3]; 512 } 513 } else if (type == \'m\') { 514 515 } 516 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy.MM.dd HH:mm:ss\", Locale.getDefault()); 517 try { 518 startTime = simpleDateFormat.parse(sd + \" \" + st); 519 endTime = simpleDateFormat.parse(ed + \" \" + et); 520 } catch (ParseException e) { 521 } 522 523 } 524 525 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 526 super(); 527 this.startTime = startTime; 528 this.endTime = endTime; 529 this.callingAddressAreaCode = callingAddressAreaCode; 530 this.answerAddressAreaCode = answerAddressAreaCode; 531 } 532 533 public Date getStartTime() { 534 return startTime; 535 } 536 537 public void setStartTime(Date startTime) { 538 this.startTime = startTime; 539 } 540 541 public Date getEndTime() { 542 return endTime; 543 } 544 545 public void setEndTime(Date endTime) { 546 this.endTime = endTime; 547 } 548 549 public String getCallingAddressAreaCode() { 550 return callingAddressAreaCode; 551 } 552 553 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 554 this.callingAddressAreaCode = callingAddressAreaCode; 555 } 556 557 public String getAnswerAddressAreaCode() { 558 return answerAddressAreaCode; 559 } 560 561 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 562 this.answerAddressAreaCode = answerAddressAreaCode; 563 } 564 } 565 566 abstract class CallChargeRule extends ChargeRule { 567 568 } 569 /* 570 * 类:手机短信计费 571 * 属性:通话起始、结束时间;拨号人地址,接听人地址 572 */ 573 class MobilePhoneMessageRule extends CallChargeRule { 574 575 @Override 576 public double calCost(UserRecords userRecords) { 577 double sumCost = 0; 578 int number = 0; 579 for (MessageRecord m : userRecords.getSendMessageRecords()) { 580 int length = m.getMessage().length(); 581 if (length <= 10) { 582 number++; 583 } else { 584 number += length / 10; 585 if (length % 10 != 0) { 586 number++; 587 } 588 } 589 } 590 if (number <= 3) { 591 sumCost = number * 0.1; 592 } else if (number <= 5) { 593 sumCost = 0.3 + 0.2 * (number - 3); 594 } else { 595 sumCost = 0.7 + 0.3 * (number - 5); 596 } 597 return sumCost; 598 } 599 600 } 601 602 class MessageRecord extends CommunicationRecord { 603 604 private String message; 605 606 public MessageRecord(String input) { 607 super(); 608 this.message = input.substring(26); 609 } 610 611 public String getMessage() { 612 return message; 613 } 614 615 public void setMessage(String message) { 616 this.message = message; 617 } 618 } 619 620 class Outputtool { 621 622 @SuppressWarnings(\"deprecation\") 623 public void output(double out) { 624 BigDecimal numb = new BigDecimal(out); 625 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 626 System.out.print(out); 627 } 628 }
View Code
结果:
分析:在之前两次电信题中已经打好了框架,只需加上短信详细的计费方法的类即可,总体的圈复杂度与之前的大同小异。
三、踩坑心得
1.电信系列1
(1)首先就是输入格式的判断,需要判断号码的格式是否正确,以及时间是否合理,因为时间有年,月,日,小时,分钟,秒。年要判断是否为闰年,月份也不一样等,所以判断格式是否正确就写了很长的代码。
(2)ArrayList类的使用,不只电信系列中用到了,这三次作业中几乎都用到了。数据太多了,必须用ArrayList建立一个对象来存储,还需要重写sort方法。
(3)类特别多,需要非常好的逻辑性,灵活运用抽象类或接口,写代码的很容易晕。可能是我还没有完全掌握抽象类的用法。
(4)需要用到一些之前没用过的类,例如:Comparator,SimpleDateFormat,Date。
四、改进建议
这三次作业的题目都比较详细,要么给出了UML图,要么直接给出了部分代码,或详细描述了类里面的成员方法。按照题目要求来,最后写出的代码都比较优良。但是写电信3的代码时,我的代码长度达到了800行左右,提交不了,说篇幅过长了,我只是缩减了一些本题可能用不到的代码(但其实是有用代码),说明前面写的代码还是复杂了些,没有用到更简便的方法。例如以下代码:
1 } 2 /* 3 * 市内 4 * */ 5 class LandPhoneInCityRule extends CallChargeRule { 6 7 @Override 8 public double calCost(UserRecords userRecords) { 9 double sumCost = 0; 10 for (CallRecord call : userRecords.getCallingInCityRecords()) { 11 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 12 if (distanceS < 0) { 13 continue; 14 } 15 double distanceM = (int) distanceS / 60; 16 if (distanceS % 60 != 0) { 17 distanceM += 1; 18 } 19 if (call.getCallType().equals(\"11\")) { 20 sumCost += distanceM * 0.1; 21 } else if (call.getCallType().equals(\"12\")) { 22 sumCost += distanceM * 0.3; 23 } else if (call.getCallType().equals(\"13\")) { 24 sumCost += distanceM * 0.6; 25 } 26 } 27 return sumCost; 28 } 29 30 } 31 /* 32 * 国内 33 * */ 34 class LandPhoneInlandRule extends CallChargeRule { 35 36 @Override 37 public double calCost(UserRecords userRecords) { 38 double sumCost = 0; 39 for (CallRecord call : userRecords.getCallingInLandRecords()) { 40 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 41 if (distanceS < 0) { 42 continue; 43 } 44 double distanceM = (int) distanceS / 60; 45 if (distanceS % 60 != 0) { 46 distanceM += 1; 47 } 48 sumCost += distanceM * 0.6; 49 } 50 return sumCost; 51 } 52 53 } 54 /* 55 * 省内 56 */ 57 class LandPhoneInProvinceRule extends CallChargeRule { 58 59 @Override 60 public double calCost(UserRecords userRecords) { 61 double sumCost = 0; 62 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 63 double distanceS = (call.getEndTime().getTime() - call.getStartTime().getTime()) / 1000; 64 if (distanceS < 0) { 65 continue; 66 } 67 double distanceM = (int) distanceS / 60; 68 if (distanceS % 60 != 0) { 69 distanceM += 1; 70 } 71 sumCost += distanceM * 0.3; 72 } 73 return sumCost; 74 } 75 76 }
这些计算费用方法中有部分代码重复了,手机三个,座机三个,还有一个短信的,相同代码重复太多次了,不太符合java代码复用的原则,增加代码长度,可以单独提炼出一个static方法或类。
还有就是输入格式判断中我用到了一个很长的正则表达式,感觉这个方法不太好,应该还能有其他更简便的方法吧。
五、总结
这三次作业主要让我们练习了抽象类,接口,内部类,以及一些如ArrayList,Date等常用类。算法上相较之前几次的作业来讲更简单了,但是更集中的运用了java写代码的套路,可以感觉到作业更java啦!从这几次作业也可看出多态能减少代码长度,且更能体现代码复用或者说java的便利。不过继承与多态好像常常是同时出现的,都能实现代码复用。除了继承,多态,聚合等类的关系外,还要多去学习一些java中常用的类,java库中已经建好了很多实现方法,可以直接拿来用,会方便很多。
来源:https://www.cnblogs.com/java-036/p/16961766.html
本站部分图文来源于网络,如有侵权请联系删除。