Remember的Java-blog3
一、前言
此次blog为电信计费系列的座机,手机,短信大作业总结。相对于前几次的多边形,这次在算法上更简单,但是涉及到的内容很多,比如容器的使用、抛出异常、抽象类、继承与多态、正则表达式、类和对象等知识点。下面我就这三次作业进行分析。
二、设计与分析
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.text.DateFormat; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.ArrayList; 5 import java.util.Date; 6 import java.util.Scanner; 7 import java.util.regex.Matcher; 8 import java.util.regex.Pattern; 9 10 //用户类——完成 11 class User { 12 private UserRecords userRecords = new UserRecords();// 用户记录 13 private float balance = 100;// 余额 14 private ChargeMode chargeMode = new ChargeMode();// 计费方式(地区) 15 private String number;// 号码 16 private String costMode;// 计费方式(座机,手机。。。) 17 18 public float calBalance() {// 返回余额 19 balance = balance - chargeMode.getMonthlyRent() - calCost() ; 20 return (float) balance; 21 } 22 23 public float calCost() {// 返回计费总额 24 return chargeMode.calCost(userRecords); 25 } 26 27 // get,set 28 public UserRecords getUserRecords() { 29 return userRecords; 30 } 31 32 public void setUserRecords(UserRecords userRecords) { 33 this.userRecords = userRecords; 34 } 35 36 public double getBalance() { 37 return balance; 38 } 39 40 public ChargeMode getChargeMode() { 41 return chargeMode; 42 } 43 44 public void setChargeMode(ChargeMode chargeMode) { 45 this.chargeMode = chargeMode; 46 } 47 48 public String getNumber() { 49 return number; 50 } 51 52 public void setNumber(String number) { 53 this.number = number; 54 } 55 56 public void setcostMode(String s) {// 传入计费方式 57 this.costMode = s; 58 } 59 } 60 61 //用户记录类——完成 62 class UserRecords { 63 // 拨打 64 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>();// 市内拨打电话 65 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>();// 省内拨打电话 66 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>();// 省外拨打电话 67 // 接听 68 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>();// 室内接听电话 69 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>();// 省内接听电话 70 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>();// 省外接听电话 71 72 // 添加电话记录 73 // 拨打 74 public void addCallingInCityRecords(CallRecord callRecord) { 75 callingInCityRecords.add(callRecord); 76 } 77 78 public void addCallingInProvinceRecords(CallRecord callRecord) { 79 callingInProvinceRecords.add(callRecord); 80 } 81 82 public void addCallingInLandRecords(CallRecord callRecord) { 83 callingInLandRecords.add(callRecord); 84 } 85 86 // 接听 87 public void addAnswerInCityRecords(CallRecord answerRecord) { 88 answerInCityRecords.add(answerRecord); 89 } 90 91 public void addAnswerInProvinceRecords(CallRecord answerRecord) { 92 answerInProvinceRecords.add(answerRecord); 93 } 94 95 public void addAnswerInLandRecords(CallRecord answerRecord) { 96 answerInLandRecords.add(answerRecord); 97 } 98 99 // 添加短信记录 100 public void addSendMessageRecords(CallRecord answerRecord) { 101 102 } 103 104 public void addReceiveMessageRecords(CallRecord answerRecord) { 105 106 } 107 108 109 // get方法 110 public ArrayList<CallRecord> getCallingInCityRecords() { 111 return callingInCityRecords; 112 } 113 114 public ArrayList<CallRecord> getCallingInProvinceRecords() { 115 return callingInProvinceRecords; 116 } 117 118 public ArrayList<CallRecord> getCallingInLandRecords() { 119 return callingInLandRecords; 120 } 121 122 public ArrayList<CallRecord> getAnswerInCityRecords() { 123 return answerInCityRecords; 124 } 125 126 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 127 return answerInProvinceRecords; 128 } 129 130 public ArrayList<CallRecord> getAnswerInLandRecords() { 131 return answerInLandRecords; 132 } 133 134 } 135 136 //计费方式抽象类(直接计算费用总额)——完成 137 class ChargeMode { 138 private ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>(); 139 private LandPhoneInCityRule cityCal = new LandPhoneInCityRule();// 城市内计费 140 private LandPhoneInProvinceRule provinceCal = new LandPhoneInProvinceRule();// 省内计费 141 private LandPhoneInlandRule landCal = new LandPhoneInlandRule();// 省外计费 142 143 public ArrayList<ChargeRule> getChargeRules() { 144 return chargeRules; 145 } 146 147 public float calCost(UserRecords userRecords) {// 计算费用总额 148 double sumOfcost = 0; 149 if (userRecords.getCallingInCityRecords().size() != 0) {// 如果容器不为空 150 sumOfcost += cityCal.calCost(userRecords.getCallingInCityRecords()); 151 } 152 if (userRecords.getCallingInProvinceRecords().size() != 0) { 153 sumOfcost += provinceCal.calCost(userRecords.getCallingInProvinceRecords()); 154 } 155 if (userRecords.getCallingInLandRecords().size() != 0) { 156 sumOfcost += landCal.calCost(userRecords.getCallingInLandRecords()); 157 } 158 return (float) sumOfcost; 159 } 160 161 public float getMonthlyRent() { 162 return 20;// 月租 163 } 164 } 165 166 //座机月租管理 167 class LandlinePhoneCharging extends ChargeMode { 168 private double monthlyRent = 20;// 月租20 169 170 public float calCost(UserRecords userRecords) {// 放在父类算 171 return 0; 172 } 173 174 public float getMonthlyRent() { 175 return (float) monthlyRent; 176 } 177 } 178 179 //通话记录类——完成 180 class CallRecord extends CommunicationRecord { 181 182 private Date startTime;// 起始时间 183 private Date endTime;// 结束时间 184 private String callingAddressAreaCode;// 拨号地点的区号 185 private String answerAddressAreaCode;// 接听地点的区号 186 187 // get,set 188 public Date getStartTime() { 189 return startTime; 190 } 191 192 public void setStartTime(Date startTime) { 193 this.startTime = startTime; 194 } 195 196 public Date getEndTime() { 197 return endTime; 198 } 199 200 public void setEndTime(Date endTime) { 201 this.endTime = endTime; 202 } 203 204 public String getCallingAddressAreaCode() { 205 return callingAddressAreaCode; 206 } 207 208 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 209 this.callingAddressAreaCode = callingAddressAreaCode; 210 } 211 212 public String getAnswerAddressAreaCode() { 213 return answerAddressAreaCode; 214 } 215 216 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 217 this.answerAddressAreaCode = answerAddressAreaCode; 218 } 219 220 } 221 222 223 //抽象的通讯记录类——完成 224 abstract class CommunicationRecord { 225 protected String callingNumber;// 拨打号码 226 protected String answerNumber;// 接听号码 227 228 // get,set 229 public String getCallingNumber() { 230 return callingNumber; 231 } 232 233 public void setCallingNumber(String callingNumber) { 234 this.callingNumber = callingNumber; 235 } 236 237 public String getAnswerNumber() { 238 return answerNumber; 239 } 240 241 public void setAnswerNumber(String answerNumber) { 242 this.answerNumber = answerNumber; 243 } 244 245 } 246 247 //市内通话(计费)——完成 248 class LandPhoneInCityRule extends CallChargeRule { 249 250 251 @Override 252 public double calCost(ArrayList<CallRecord> callRecords) { 253 // TODO Auto-generated method stub 254 255 double sumofMoney = 0; 256 for (CallRecord e : callRecords) { 257 long second = (e.getEndTime().getTime() - e.getStartTime().getTime()) / 1000;// 毫秒——>秒 258 long minutes = (second + 59) / 60;// 秒——>分钟 259 sumofMoney += 0.1 * minutes; // 0.1元/min 260 261 } 262 return sumofMoney; 263 } 264 265 } 266 267 //省内通话(计费)——完成 268 class LandPhoneInProvinceRule extends CallChargeRule {// forEach 循环将每条记录计算再进行累加 269 270 271 @Override 272 public double calCost(ArrayList<CallRecord> callRecords) { 273 // TODO Auto-generated method stub 274 double sumofMoney = 0; 275 for (CallRecord e : callRecords) { 276 long second = (e.getEndTime().getTime() - e.getStartTime().getTime()) / 1000;// 毫秒——>秒 277 long minutes = (second + 59) / 60;// 秒——>分钟 278 sumofMoney += 0.3 * minutes; // 0.3元/min 279 280 } 281 return sumofMoney; 282 } 283 284 } 285 286 //省外通话(计费)——完成 287 class LandPhoneInlandRule extends CallChargeRule {// forEach 循环将每条记录计算再进行累加 288 289 @Override 290 public double calCost(ArrayList<CallRecord> callRecords) { 291 double sumofMoney = 0; 292 for (CallRecord e : callRecords) { 293 double minute = ((e.getEndTime().getTime() - e.getStartTime().getTime()) / 1000.0 / 60.0);// 毫秒——>秒 294 if (minute > (int) minute) { 295 sumofMoney = sumofMoney + 0.6 * ((int) minute + 1); 296 } else { 297 sumofMoney = sumofMoney + 0.6 * minute;// 0.6元/min 298 } 299 } 300 return sumofMoney; 301 } 302 303 } 304 305 //通话计费规则抽象类(完成) 306 307 abstract class CallChargeRule extends ChargeRule { 308 309 public abstract double calCost(ArrayList<CallRecord> callRecords); 310 311 } 312 313 //收费规则抽象类(完成) 314 abstract class ChargeRule { 315 public abstract double calCost(ArrayList<CallRecord> callRecords); 316 } 317 318 319 320 public class Main {// 主方法( 接受信息——处理信息——返回信息) 321 322 323 // 声明静态类型,便于更替 324 static User user; 325 326 public static void main(String[] args) throws ParseException {// SimpleDateFormat类型转换 327 328 CallRecord callrecord = new CallRecord(); 329 UserRecords userRecord = new UserRecords(); 330 ArrayList<String> dateCumb = new ArrayList<>(); // 存放数据的容器 331 ArrayList<User> listOfuser = new ArrayList<User>();// 存放开户的容器 332 SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");// 标准日期格式 333 334 // 接受信息,处理信息 335 Scanner in = new Scanner(System.in); 336 int sign = 1; // 控制循环进行 337 while (sign == 1) 338 { 339 String date = in.nextLine();// 输入数据 340 // 防止重复数据 341 if (dateCumb.contains(date)) 342 continue; 343 else 344 dateCumb.add(date); 345 // 正则表达式过滤多余数据 346 String judge1 = "u-([0-9]){11,12} 0|t-[0-9]{11,12} [0-9]{10,12}( [0-9]{4}.([1-9]|10|11|12).([0-9]|[1-3][0-9]) ([0-9]|[0-2][0-9]):([0-5][0-9]):([0-5][0-9]))+|end"; 347 if (!Pattern.matches(judge1, date)) 348 continue; 349 Pattern p = Pattern.compile( "[0-9]{10,12}|0|end|[0-9]{4}.([1-9]|10|11|12).([1-9]|[1-3][0-9]) ([0-9]|[0-9][0-9]):([0-9]|[0-5][0-9]):([0-5][0-9])");// 规范格式(分组) 350 Matcher m = p.matcher(date);// 依据正则表达式筛选 351 int guide = 0;// 控制循环导向 352 while (m.find()) {// 提取数据 353 if (m.group(0).equals("end")) 354 sign = 0;// 标志结束,退出循环 355 if (date.charAt(0) == 'u') 356 {// 输入到开户用户 357 if (guide == 0) 358 { 359 user = new User(); 360 user.setNumber(m.group(0));// 传入号码 361 } 362 if (guide == 1) 363 { 364 user.setcostMode(m.group(0));// 传入计费方式 365 } 366 if (guide == 1) 367 {// 传入用户,并进行下一次传入 368 listOfuser.add(user); 369 user = null; 370 } 371 guide++;// 指向下一个用户 372 } 373 else if (date.charAt(0) == 't') 374 {// 输入到通信信息 375 if (guide == 2) 376 {// 所有日期格式 377 if (judge3(m.group(0).length(), m.group(0), "yyyy.MM.dd HH:mm:ss") 378 || judge3(m.group(0).length(), m.group(0), "yyyy.M.dd HH:mm:ss") 379 || judge3(m.group(0).length(), m.group(0), "yyyy.MM.d HH:mm:ss") 380 || judge3(m.group(0).length(), m.group(0), "yyyy.M.d HH:mm:ss")) { 381 callrecord.setStartTime(format.parse(m.group(0)));// 传入开始时间 382 } else 383 { 384 break; 385 } 386 } 387 if (guide == 3) 388 {// 所有日期格式 389 if (judge3(m.group(0).length(), m.group(0), "yyyy.MM.dd HH:mm:ss") 390 || judge3(m.group(0).length(), m.group(0), "yyyy.M.dd HH:mm:ss") 391 || judge3(m.group(0).length(), m.group(0), "yyyy.MM.d HH:mm:ss") 392 || judge3(m.group(0).length(), m.group(0), "yyyy.M.d HH:mm:ss") ) 393 { 394 callrecord.setEndTime(format.parse(m.group(0)));// 传入结束时间 395 } 396 else 397 { 398 break; 399 } 400 } 401 if (guide == 0) 402 { 403 callrecord = new CallRecord();// 刷新 404 callrecord.setCallingNumber(m.group(0));// 传入拨打号码 405 callrecord.setCallingAddressAreaCode(m.group(0).substring(0, 4));// 传入拨打地区 406 } 407 if (guide == 1) 408 { 409 callrecord.setAnswerNumber(m.group(0));// 传入接听号码 410 callrecord.setAnswerAddressAreaCode(m.group(0).substring(0, 4));// 传入接听地区 411 } 412 if (guide == 3) 413 { 414 // forEach循环,对不同座机号匹配相应的通话记录 415 for (User e : listOfuser) 416 { 417 if (e.getNumber().equals(callrecord.getCallingNumber())) 418 {// 号码对应正确 419 String judge2 = "079[0-9]|0701";// 区号判断 420 if (callrecord.getCallingAddressAreaCode().equals("0791") 421 && callrecord.getAnswerAddressAreaCode().equals("0791")) 422 { 423 e.getUserRecords().addCallingInCityRecords(callrecord); 424 } 425 else if (callrecord.getCallingAddressAreaCode().equals("0791") && Pattern.matches(judge2, callrecord.getAnswerAddressAreaCode())) 426 { 427 e.getUserRecords().addCallingInProvinceRecords(callrecord); 428 } 429 else 430 { 431 e.getUserRecords().addCallingInLandRecords(callrecord); 432 } 433 } else 434 { 435 continue; 436 } 437 } 438 } 439 guide++;// 指向下一条记录 440 } 441 } 442 } 443 444 // 返回信息 445 // 声明一个User类的数组,将容器中的对象取出来 446 User[] user = new User[listOfuser.size()]; 447 User temp;// 交换元素 448 for (int i = 0; i < listOfuser.size(); i++) 449 { 450 user[i] = listOfuser.get(i); 451 } 452 453 // 仿造冒泡排序(将号码字符从小到大排序) 454 for (int i = 0; i < user.length - 1; i++) 455 { 456 for (int j = 0; j < user.length - 1 - i; j++) 457 { 458 // 将号码提取出来比较大小 459 double x = Double.parseDouble(user[j + 1].getNumber()); 460 double y = Double.parseDouble(user[j].getNumber()); 461 if (x < y) 462 {// user[j+1]号码比user[j]小 463 temp = user[j + 1]; 464 user[j + 1] = user[j]; 465 user[j] = temp; 466 } 467 } 468 } 469 470 for (int i = 0; i < user.length; i++) 471 { 472 System.out.println(user[i].getNumber() + " " + user[i].calCost() + " " + user[i].calBalance()); 473 } 474 475 } 476 477 public static boolean judge3(int length, String Date, String format) {// 仿造Date类中的代码,判断日期格式是否错误 478 int legalLen = length; 479 if ((Date == null) || (Date.length() != legalLen)) { 480 return false; 481 } 482 DateFormat Format = new SimpleDateFormat(format); 483 try { 484 Date date = Format.parse(Date); 485 return Date.equals(Format.format(date)); 486 } catch (Exception e) { 487 return false; 488 } 489 } 490 }
SourceMonitor的生成报表内容如下:
小结:
看这个报表就知道这道题写的不怎么样,但是但是我还是写完了它,尽管花费了我好多好多时间,还好老师给了类图,不然我会直接放弃的好吗。
7-1 电信计费系列2-手机+座机计费
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
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元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
建议类图:
参见图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的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
我的最终代码如下:
1 import java.util.ArrayList; 2 import java.util.Comparator; 3 import java.util.Scanner; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 import java.math.BigDecimal; 7 import java.text.SimpleDateFormat; 8 import java.util.Date; 9 import java.util.Locale; 10 import java.text.ParseException; 11 12 public class Main { 13 14 public static void main(String[] args) { 15 16 Outputtool outputtool = new Outputtool(); 17 Inputdeal inputdeal = new Inputdeal(); 18 ArrayList<User> users = new ArrayList<>(); 19 Scanner in = new Scanner(System.in); 20 String input = in.nextLine(); 21 22 while (!input.equals("end")) { 23 if (1 == inputdeal.check(input)) { 24 inputdeal.writeUser(users, input); 25 } else if (2 == inputdeal.check(input)) { 26 inputdeal.writeRecord(users, input); 27 } 28 input = in.nextLine(); 29 } 30 31 users.sort(new Comparator<User>() { 32 33 @Override 34 public int compare(User u1, User u2) { 35 if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') 36 return -1; 37 else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') 38 return 1; 39 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) 40 return 1; 41 else 42 return -1; 43 } 44 }); 45 46 for (User u : users) { 47 System.out.print(u.getNumber() + " "); 48 outputtool.output(u.calCost()); 49 System.out.print(" "); 50 outputtool.output(u.calBalance()); 51 System.out.println(); 52 53 } 54 } 55 } 56 57 abstract class ChargeMode { 58 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 59 public abstract double calCost(UserRecords userRecords); 60 public abstract double getMonthlyRent(); 61 public ArrayList<ChargeRule> getChargeRules() { 62 return chargeRules; 63 } 64 65 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 66 this.chargeRules = chargeRules; 67 } 68 } 69 70 class UserRecords { 71 72 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 73 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 74 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 75 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 76 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 77 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 78 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 79 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 80 81 public void addCallingInCityRecords(CallRecord callRecord) { 82 callingInCityRecords.add(callRecord); 83 } 84 85 public void addCallingInProvinceRecords(CallRecord callRecord) { 86 callingInProvinceRecords.add(callRecord); 87 } 88 89 public void addCallingInLandRecords(CallRecord callRecord) { 90 callingInLandRecords.add(callRecord); 91 } 92 93 public void addAnswerInCityRecords(CallRecord callRecord) { 94 answerInCityRecords.add(callRecord); 95 } 96 97 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 98 answerInProvinceRecords.add(callRecord); 99 } 100 101 public void addAnswerInLandRecords(CallRecord callRecord) { 102 answerInLandRecords.add(callRecord); 103 } 104 105 public void addSendMessageRecords(MessageRecord callRecord) { 106 sendMessageRecords.add(callRecord); 107 } 108 109 public void addReceiveMessageRecords(MessageRecord callRecord) { 110 receiveMessageRecords.add(callRecord); 111 } 112 113 public ArrayList<CallRecord> getCallingInCityRecords() { 114 return callingInCityRecords; 115 } 116 117 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 118 this.callingInCityRecords = callingInCityRecords; 119 } 120 121 public ArrayList<CallRecord> getCallingInProvinceRecords() { 122 return callingInProvinceRecords; 123 } 124 125 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 126 this.callingInProvinceRecords = callingInProvinceRecords; 127 } 128 129 public ArrayList<CallRecord> getCallingInLandRecords() { 130 return callingInLandRecords; 131 } 132 133 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 134 this.callingInLandRecords = callingInLandRecords; 135 } 136 137 public ArrayList<CallRecord> getAnswerInCityRecords() { 138 return answerInCityRecords; 139 } 140 141 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 142 this.answerInCityRecords = answerInCityRecords; 143 } 144 145 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 146 return answerInProvinceRecords; 147 } 148 149 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 150 this.answerInProvinceRecords = answerInProvinceRecords; 151 } 152 153 public ArrayList<CallRecord> getAnswerInLandRecords() { 154 return answerInLandRecords; 155 } 156 157 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 158 this.answerInLandRecords = answerInLandRecords; 159 } 160 161 public ArrayList<MessageRecord> getSendMessageRecords() { 162 return sendMessageRecords; 163 } 164 165 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 166 this.sendMessageRecords = sendMessageRecords; 167 } 168 169 public ArrayList<MessageRecord> getReceiveMessageRecords() { 170 return receiveMessageRecords; 171 } 172 173 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 174 this.receiveMessageRecords = receiveMessageRecords; 175 } 176 177 } 178 179 class LandlinePhoneCharging extends ChargeMode { 180 181 private double monthlyRent = 20; 182 public LandlinePhoneCharging() { 183 super(); 184 chargeRules.add(new LandPhoneInCityRule()); 185 chargeRules.add(new LandPhoneInProvinceRule()); 186 chargeRules.add(new LandPhoneInlandRule()); 187 } 188 189 @Override 190 public double calCost(UserRecords userRecords) { 191 double sumCost = 0; 192 for (ChargeRule rule : chargeRules) { 193 sumCost += rule.calCost(userRecords); 194 } 195 return sumCost; 196 } 197 198 @Override 199 public double getMonthlyRent() { 200 return monthlyRent; 201 } 202 203 } 204 205 class MobilePhoneCharging extends ChargeMode { 206 207 private double monthlyRent = 15; 208 public MobilePhoneCharging() { 209 super(); 210 chargeRules.add(new MobilePhoneInCityRule()); 211 chargeRules.add(new MobilePhoneInProvinceRule()); 212 chargeRules.add(new MobilePhoneInlandRule()); 213 } 214 215 @Override 216 public double calCost(UserRecords userRecords) { 217 double sumCost = 0; 218 for (ChargeRule rule : chargeRules) { 219 sumCost += rule.calCost(userRecords); 220 } 221 return sumCost; 222 } 223 224 @Override 225 public double getMonthlyRent() { 226 return monthlyRent; 227 } 228 229 } 230 231 class Inputdeal { 232 233 public int check(String input) { 234 if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[1]")) { 235 return 1; 236 } else if (input.matches("(([t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s)|" 237 + "([t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s)|" 238 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s)|" 239 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s))" 240 241 + "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.(((0?[13578]|1[02])\\.(0?" 242 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 243 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 244 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" 245 + "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.((([13578]|1[02])\\.(" 246 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 247 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 248 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])")) { 249 return 2; 250 } 251 return 0; 252 } 253 254 @SuppressWarnings("unused") 255 private boolean validatet(String string) { 256 if (!string.matches("^([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { 257 return false; 258 } 259 return true; 260 } 261 262 public static boolean validate(String dateString) { 263 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 264 Pattern p = Pattern.compile("\\d{4}+[\\.]\\d{1,2}+[\\.]\\d{1,2}+"); 265 Matcher m = p.matcher(dateString); 266 if (!m.matches()) { 267 return false; 268 } 269 270 // 得到年月日 271 String[] array = dateString.split("\\."); 272 int year = Integer.valueOf(array[0]); 273 int month = Integer.valueOf(array[1]); 274 int day = Integer.valueOf(array[2]); 275 276 if (month < 1 || month > 12) { 277 return false; 278 } 279 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 280 if (isLeapYear(year)) { 281 monthLengths[2] = 29; 282 } else { 283 monthLengths[2] = 28; 284 } 285 int monthLength = monthLengths[month]; 286 if (day < 1 || day > monthLength) { 287 return false; 288 } 289 return true; 290 } 291 292 /** 是否是闰年 */ 293 private static boolean isLeapYear(int year) { 294 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 295 } 296 297 public boolean judge(String input) { 298 299 return false; 300 } 301 302 public void writeUser(ArrayList<User> users, String input) { 303 User usernew = new User(); 304 String[] inputs = input.split(" "); 305 String num = inputs[0].substring(2); 306 for (User i : users) { 307 if (i.getNumber().equals(num)) { 308 return; 309 } 310 } 311 usernew.setNumber(num); 312 int mode = Integer.parseInt(inputs[1]); 313 if (mode == 0) { 314 usernew.setChargeMode(new LandlinePhoneCharging()); 315 } else if (mode == 1) { 316 usernew.setChargeMode(new MobilePhoneCharging()); 317 } 318 users.add(usernew); 319 } 320 321 public void writeRecord(ArrayList<User> users, String input) { 322 String[] inputs = input.split(" "); 323 324 User callu = null, answeru = null; 325 CallRecord callrecord = new CallRecord(inputs); 326 327 if (input.charAt(0) == 't') { 328 String out = inputs[0]; 329 String in = ""; 330 if (inputs.length == 6) { 331 in = inputs[1]; 332 } else if (inputs.length == 7) { 333 in = inputs[1]; 334 } else if (inputs.length == 8) { 335 in = inputs[2]; 336 } 337 338 for (User i : users) { 339 if (i.getNumber().equals(out)) { 340 callu = i; 341 } 342 if (i.getNumber().equals(in)) { 343 answeru = i; 344 } 345 if (callu != null && answeru != null) { 346 break; 347 } 348 } 349 350 if (callu != null) { 351 if (callrecord.getCallType().matches("^1[1-3]$")) { 352 callu.getUserRecords().addCallingInCityRecords(callrecord); 353 } else if (callrecord.getCallType().matches("^2[1-3]$")) { 354 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 355 } else { 356 callu.getUserRecords().addCallingInLandRecords(callrecord); 357 } 358 } 359 360 if (answeru != null) { 361 if (callrecord.getCallType().matches("^[1-3]1$")) { 362 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 363 } else if (callrecord.getCallType().matches("^[1-3]2$")) { 364 answeru.getUserRecords().aaddAnswerInProvinceRecords(callrecord); 365 } else { 366 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 367 } 368 } 369 } else if (input.charAt(0) == 'm') { 370 371 } 372 373 } 374 375 } 376 377 abstract class CommunicationRecord { 378 protected String callingNumber; 379 protected String answerNumbe; 380 381 public String getCallingNumber() { 382 return callingNumber; 383 } 384 385 public void setCallingNumber(String callingNumber) { 386 this.callingNumber = callingNumber; 387 } 388 389 public String getAnswerNumbe() { 390 return answerNumbe; 391 } 392 393 public void setAnswerNumbe(String answerNumbe) { 394 this.answerNumbe = answerNumbe; 395 } 396 397 } 398 399 abstract class ChargeRule { 400 401 abstract public double calCost(UserRecords userRecords); 402 403 } 404 405 class CallRecord extends CommunicationRecord { 406 private Date startTime; 407 private Date endTime; 408 private String callingAddressAreaCode; 409 private String answerAddressAreaCode; 410 411 public String getCallType() { 412 String type = ""; 413 if (callingAddressAreaCode.equals("0791")) { 414 type = type.concat("1"); 415 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 416 type = type.concat("2"); 417 } else { 418 type = type.concat("3"); 419 } 420 421 if (answerAddressAreaCode.equals("0791")) { 422 type = type.concat("1"); 423 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 424 type = type.concat("2"); 425 } else { 426 type = type.concat("3"); 427 } 428 429 return type; 430 } 431 432 public CallRecord(String[] inputs) { 433 super(); 434 435 char type = inputs[0].charAt(0); 436 inputs[0] = inputs[0].substring(2); 437 438 String sd = null, st = null, ed = null, et = null; 439 440 if (type == 't') { 441 if (inputs.length == 6) { 442 sd = inputs[2]; 443 st = inputs[3]; 444 ed = inputs[4]; 445 et = inputs[5]; 446 callingAddressAreaCode = inputs[0].substring(0, 4); 447 answerAddressAreaCode = inputs[1].substring(0, 4); 448 } else if (inputs.length == 7) { 449 sd = inputs[3]; 450 st = inputs[4]; 451 ed = inputs[5]; 452 et = inputs[6]; 453 if (inputs[0].charAt(0) != '0') { 454 if (inputs[2].length() == 10) { 455 answerAddressAreaCode = inputs[2].substring(0, 3); 456 } else { 457 answerAddressAreaCode = inputs[2].substring(0, 4); 458 } 459 callingAddressAreaCode = inputs[1]; 460 } else { 461 if (inputs[0].length() == 10) { 462 callingAddressAreaCode = inputs[0].substring(0, 3); 463 } else { 464 callingAddressAreaCode = inputs[0].substring(0, 4); 465 } 466 answerAddressAreaCode = inputs[2]; 467 } 468 } else if (inputs.length == 8) { 469 sd = inputs[4]; 470 st = inputs[5]; 471 ed = inputs[6]; 472 et = inputs[7]; 473 callingAddressAreaCode = inputs[1]; 474 answerAddressAreaCode = inputs[3]; 475 } 476 } else if (type == 'm') { 477 478 } 479 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 480 try { 481 startTime = simpleDateFormat.parse(sd + " " + st); 482 endTime = simpleDateFormat.parse(ed + " " + et); 483 } catch (ParseException e) { 484 } 485 486 } 487 488 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 489 super(); 490 this.startTime = startTime; 491 this.endTime = endTime; 492 this.callingAddressAreaCode = callingAddressAreaCode; 493 this.answerAddressAreaCode = answerAddressAreaCode; 494 } 495 496 public Date getStartTime() { 497 return startTime; 498 } 499 500 public void setStartTime(Date startTime) { 501 this.startTime = startTime; 502 } 503 504 public Date getEndTime() { 505 return endTime; 506 } 507 508 public void setEndTime(Date endTime) { 509 this.endTime = endTime; 510 } 511 512 public String getCallingAddressAreaCode() { 513 return callingAddressAreaCode; 514 } 515 516 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 517 this.callingAddressAreaCode = callingAddressAreaCode; 518 } 519 520 public String getAnswerAddressAreaCode() { 521 return answerAddressAreaCode; 522 } 523 524 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 525 this.answerAddressAreaCode = answerAddressAreaCode; 526 } 527 } 528 529 abstract class CallChargeRule extends ChargeRule { 530 531 } 532 533 class LandPhoneInCityRule extends CallChargeRule { 534 535 @Override 536 public double calCost(UserRecords userRecords) { 537 double sumCost = 0; 538 for (CallRecord call : userRecords.getCallingInCityRecords()) { 539 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 540 if (distanceS < 0) { 541 continue; 542 } 543 double distanceM = (int) distanceS / 60; 544 if (distanceS % 60 != 0) { 545 distanceM += 1; 546 } 547 if (call.getCallType().equals("11")) { 548 sumCost += distanceM * 0.1; 549 } else if (call.getCallType().equals("12")) { 550 sumCost += distanceM * 0.3; 551 } else if (call.getCallType().equals("13")) { 552 sumCost += distanceM * 0.6; 553 } 554 } 555 return sumCost; 556 } 557 } 558 559 class LandPhoneInlandRule extends CallChargeRule { 560 561 @Override 562 public double calCost(UserRecords userRecords) { 563 double sumCost = 0; 564 for (CallRecord call : userRecords.getCallingInLandRecords()) { 565 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 566 if (distanceS < 0) { 567 continue; 568 } 569 double distanceM = (int) distanceS / 60; 570 if (distanceS % 60 != 0) { 571 distanceM += 1; 572 } 573 sumCost += distanceM * 0.6; 574 } 575 return sumCost; 576 } 577 578 } 579 580 class LandPhoneInProvinceRule extends CallChargeRule { 581 582 @Override 583 public double calCost(UserRecords userRecords) { 584 double sumCost = 0; 585 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 586 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 587 if (distanceS < 0) { 588 continue; 589 } 590 double distanceM = (int) distanceS / 60; 591 if (distanceS % 60 != 0) { 592 distanceM += 1; 593 } 594 sumCost += distanceM * 0.3; 595 } 596 return sumCost; 597 } 598 599 } 600 601 class MobilePhoneInCityRule extends CallChargeRule { 602 603 @Override 604 public double calCost(UserRecords userRecords) { 605 double sumCost = 0; 606 for (CallRecord call : userRecords.getCallingInCityRecords()) { 607 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 608 if (distanceS < 0) { 609 continue; 610 } 611 double distanceM = (int) distanceS / 60; 612 if (distanceS % 60 != 0) { 613 distanceM += 1; 614 } 615 if (call.getCallType().equals("11")) { 616 sumCost += distanceM * 0.1; 617 } else if (call.getCallType().equals("12")) { 618 sumCost += distanceM * 0.2; 619 } else if (call.getCallType().equals("13")) { 620 sumCost += distanceM * 0.3; 621 } 622 } 623 return sumCost; 624 } 625 626 } 627 628 class MobilePhoneInlandRule extends CallChargeRule { 629 630 @Override 631 public double calCost(UserRecords userRecords) { 632 double sumCost = 0; 633 for (CallRecord call : userRecords.getCallingInLandRecords()) { 634 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 635 if (distanceS < 0) { 636 continue; 637 } 638 double distanceM = (int) distanceS / 60; 639 if (distanceS % 60 != 0) { 640 distanceM += 1; 641 } 642 sumCost += distanceM * 0.6; 643 } 644 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 645 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 646 if (distanceS < 0) { 647 continue; 648 } 649 double distanceM = (int) distanceS / 60; 650 if (distanceS % 60 != 0) { 651 distanceM += 1; 652 } 653 sumCost += distanceM * 0.3; 654 } 655 return sumCost; 656 } 657 658 } 659 660 class MobilePhoneInProvinceRule extends CallChargeRule { 661 662 @Override 663 public double calCost(UserRecords userRecords) { 664 double sumCost = 0; 665 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 666 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 667 if (distanceS < 0) { 668 continue; 669 } 670 double distanceM = (int) distanceS / 60; 671 if (distanceS % 60 != 0) { 672 distanceM += 1; 673 } 674 if (call.getCallType().equals("21")) { 675 sumCost += distanceM * 0.3; 676 } else if (call.getCallType().equals("22")) { 677 sumCost += distanceM * 0.3; 678 } else if (call.getCallType().equals("23")) { 679 sumCost += distanceM * 0.3; 680 } 681 } 682 return sumCost; 683 } 684 685 } 686 687 class MessageRecord extends CommunicationRecord { 688 689 private String message; 690 691 public String getMessage() { 692 return message; 693 } 694 695 public void setMessage(String message) { 696 this.message = message; 697 } 698 } 699 700 class User { 701 702 private UserRecords userRecords = new UserRecords(); 703 private double balance = 100; 704 private ChargeMode chargeMode; 705 private String number; 706 707 public double calCost() { 708 return chargeMode.calCost(userRecords); 709 } 710 711 public double calBalance() { 712 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 713 } 714 715 public UserRecords getUserRecords() { 716 return userRecords; 717 } 718 719 public void setUserRecords(UserRecords userRecords) { 720 this.userRecords = userRecords; 721 } 722 723 public ChargeMode getChargeMode() { 724 return chargeMode; 725 } 726 727 public void setChargeMode(ChargeMode chargeMode) { 728 this.chargeMode = chargeMode; 729 } 730 731 public String getNumber() { 732 return number; 733 } 734 735 public void setNumber(String number) { 736 this.number = number; 737 } 738 739 } 740 741 class Outputtool { 742 743 @SuppressWarnings("deprecation") 744 public void output(double out) { 745 BigDecimal numb = new BigDecimal(out); 746 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 747 System.out.print(out); 748 } 749 }
SourceMonitor的生成报表内容如下:
小结:
有了第一题的铺垫,第二题写起来就顺利多了!有了多边形的打击还怕写不出别的吗?哦一步一步拿到满分真是太舒服了!!!
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”结束。
输出:
根据输入的详细短信信息,计算所有已开户的用户的当月短信费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码、自己给自己打电话等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
本题只考虑短信计费,不考虑通信费用以及月租费。
建议类图:
参见图1、2、3:
图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
我的最终代码如下:
1 import java.util.ArrayList; 2 import java.util.Comparator; 3 import java.util.Scanner; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 import java.math.BigDecimal; 7 import java.text.SimpleDateFormat; 8 import java.util.Date; 9 import java.util.Locale; 10 import java.text.ParseException; 11 12 public class Main { 13 14 public static void main(String[] args) { 15 16 Outputtool outputtool = new Outputtool(); 17 Inputdeal inputdeal = new Inputdeal(); 18 ArrayList<User> users = new ArrayList<>(); 19 Scanner in = new Scanner(System.in); 20 21 String input = in.nextLine(); 22 23 while (!input.equals("end")) { 24 if (1 == inputdeal.check(input)) { 25 inputdeal.writeUser(users, input); 26 } else if (2 == inputdeal.check(input)) { 27 inputdeal.writeRecord(users, input); 28 } 29 input = in.nextLine(); 30 } 31 32 users.sort(new Comparator<User>() { 33 34 @Override 35 public int compare(User u1, User u2) { 36 if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') { 37 return -1; 38 } else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') { 39 return 1; 40 } 41 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 42 return 1; 43 } else { 44 return -1; 45 } 46 } 47 }); 48 49 for (User u : users) { 50 System.out.print(u.getNumber() + " "); 51 outputtool.output(u.calCost()); 52 System.out.print(" "); 53 outputtool.output(u.calBalance()); 54 System.out.println(); 55 56 } 57 58 } 59 60 } 61 62 abstract class ChargeMode { 63 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 64 65 public abstract double calCost(UserRecords userRecords); 66 67 public abstract double getMonthlyRent(); 68 69 public ArrayList<ChargeRule> getChargeRules() { 70 return chargeRules; 71 } 72 73 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 74 this.chargeRules = chargeRules; 75 } 76 } 77 78 class UserRecords { 79 80 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 81 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 82 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 83 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 84 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 85 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 86 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 87 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 88 89 public void addCallingInCityRecords(CallRecord callRecord) { 90 callingInCityRecords.add(callRecord); 91 } 92 93 public void addCallingInProvinceRecords(CallRecord callRecord) { 94 callingInProvinceRecords.add(callRecord); 95 } 96 97 public void addCallingInLandRecords(CallRecord callRecord) { 98 callingInLandRecords.add(callRecord); 99 } 100 101 public void addAnswerInCityRecords(CallRecord callRecord) { 102 answerInCityRecords.add(callRecord); 103 } 104 105 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 106 answerInProvinceRecords.add(callRecord); 107 } 108 109 public void addAnswerInLandRecords(CallRecord callRecord) { 110 answerInLandRecords.add(callRecord); 111 } 112 113 public void addSendMessageRecords(MessageRecord callRecord) { 114 sendMessageRecords.add(callRecord); 115 } 116 117 public void addReceiveMessageRecords(MessageRecord callRecord) { 118 receiveMessageRecords.add(callRecord); 119 } 120 121 public ArrayList<CallRecord> getCallingInCityRecords() { 122 return callingInCityRecords; 123 } 124 125 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 126 this.callingInCityRecords = callingInCityRecords; 127 } 128 129 public ArrayList<CallRecord> getCallingInProvinceRecords() { 130 return callingInProvinceRecords; 131 } 132 133 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 134 this.callingInProvinceRecords = callingInProvinceRecords; 135 } 136 137 public ArrayList<CallRecord> getCallingInLandRecords() { 138 return callingInLandRecords; 139 } 140 141 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 142 this.callingInLandRecords = callingInLandRecords; 143 } 144 145 public ArrayList<CallRecord> getAnswerInCityRecords() { 146 return answerInCityRecords; 147 } 148 149 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 150 this.answerInCityRecords = answerInCityRecords; 151 } 152 153 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 154 return answerInProvinceRecords; 155 } 156 157 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 158 this.answerInProvinceRecords = answerInProvinceRecords; 159 } 160 161 public ArrayList<CallRecord> getAnswerInLandRecords() { 162 return answerInLandRecords; 163 } 164 165 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 166 this.answerInLandRecords = answerInLandRecords; 167 } 168 169 public ArrayList<MessageRecord> getSendMessageRecords() { 170 return sendMessageRecords; 171 } 172 173 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 174 this.sendMessageRecords = sendMessageRecords; 175 } 176 177 public ArrayList<MessageRecord> getReceiveMessageRecords() { 178 return receiveMessageRecords; 179 } 180 181 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 182 this.receiveMessageRecords = receiveMessageRecords; 183 } 184 185 } 186 187 class LandlinePhoneCharging extends ChargeMode { 188 189 private double monthlyRent = 20; 190 191 public LandlinePhoneCharging() { 192 super(); 193 chargeRules.add(new LandPhoneInCityRule()); 194 chargeRules.add(new LandPhoneInProvinceRule()); 195 chargeRules.add(new LandPhoneInlandRule()); 196 } 197 198 @Override 199 public double calCost(UserRecords userRecords) { 200 double sumCost = 0; 201 for (ChargeRule rule : chargeRules) { 202 sumCost += rule.calCost(userRecords); 203 } 204 return sumCost; 205 } 206 207 @Override 208 public double getMonthlyRent() { 209 return monthlyRent; 210 } 211 212 } 213 214 class MobilePhoneCharging extends ChargeMode { 215 216 private double monthlyRent = 15; 217 218 public MobilePhoneCharging() { 219 super(); 220 chargeRules.add(new MobilePhoneInCityRule()); 221 chargeRules.add(new MobilePhoneInProvinceRule()); 222 chargeRules.add(new MobilePhoneInlandRule()); 223 } 224 225 @Override 226 public double calCost(UserRecords userRecords) { 227 double sumCost = 0; 228 for (ChargeRule rule : chargeRules) { 229 sumCost += rule.calCost(userRecords); 230 } 231 return sumCost; 232 } 233 234 @Override 235 public double getMonthlyRent() { 236 return monthlyRent; 237 } 238 239 } 240 241 class MobilePhoneMassageCharging extends ChargeMode { 242 243 private double monthlyRent = 0; 244 245 public MobilePhoneMassageCharging() { 246 super(); 247 chargeRules.add(new MobilePhoneMessageRule()); 248 } 249 250 @Override 251 public double calCost(UserRecords userRecords) { 252 double sumCost = 0; 253 for (ChargeRule rule : chargeRules) { 254 sumCost += rule.calCost(userRecords); 255 } 256 return sumCost; 257 } 258 259 @Override 260 public double getMonthlyRent() { 261 return monthlyRent; 262 } 263 264 } 265 266 class Inputdeal { 267 268 public int check(String input) { 269 if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[13]")) { 270 return 1; 271 } else if (input.matches("[m]-1[0-9]{10}\\s" + "1[0-9]{10}\\s" + "[0-9a-zA-Z\\s\\.,]+")) { 272 return 2; 273 } 274 return 0; 275 } 276 277 public void writeUser(ArrayList<User> users, String input) { 278 User usernew = new User(); 279 String[] inputs = input.split(" "); 280 String num = inputs[0].substring(2); 281 for (User i : users) { 282 if (i.getNumber().equals(num)) { 283 return; 284 } 285 } 286 usernew.setNumber(num); 287 int mode = Integer.parseInt(inputs[1]); 288 if (mode == 0) { 289 usernew.setChargeMode(new LandlinePhoneCharging()); 290 } else if (mode == 1) { 291 usernew.setChargeMode(new MobilePhoneCharging()); 292 } else if (mode == 3) { 293 usernew.setChargeMode(new MobilePhoneMassageCharging()); 294 } 295 users.add(usernew); 296 } 297 298 public void writeRecord(ArrayList<User> users, String input) { 299 String[] inputs = input.split(" "); 300 inputs[0] = inputs[0].substring(2); 301 302 User callu = null, answeru = null; 303 304 String out = inputs[0]; 305 String in = ""; 306 if (inputs.length == 6) { 307 in = inputs[1]; 308 } else if (inputs.length == 7) { 309 in = inputs[1]; 310 } else if (inputs.length == 8) { 311 in = inputs[2]; 312 } else { 313 in = inputs[1]; 314 } 315 316 for (User i : users) { 317 if (i.getNumber().equals(out)) { 318 callu = i; 319 } 320 if (i.getNumber().equals(in)) { 321 answeru = i; 322 } 323 if (callu != null && answeru != null) { 324 break; 325 } 326 } 327 328 if (input.charAt(0) == 'm') { 329 MessageRecord messageRecord = new MessageRecord(input); 330 if (callu != null) { 331 callu.getUserRecords().addSendMessageRecords(messageRecord); 332 ; 333 } 334 if (answeru != null) { 335 callu.getUserRecords().addReceiveMessageRecords(messageRecord); 336 } 337 } 338 339 } 340 341 } 342 343 abstract class CommunicationRecord { 344 protected String callingNumber; 345 protected String answerNumbe; 346 347 public String getCallingNumber() { 348 return callingNumber; 349 } 350 351 public void setCallingNumber(String callingNumber) { 352 this.callingNumber = callingNumber; 353 } 354 355 public String getAnswerNumbe() { 356 return answerNumbe; 357 } 358 359 public void setAnswerNumbe(String answerNumbe) { 360 this.answerNumbe = answerNumbe; 361 } 362 363 } 364 365 abstract class ChargeRule { 366 367 abstract public double calCost(UserRecords userRecords); 368 369 } 370 371 class CallRecord extends CommunicationRecord { 372 private Date startTime; 373 private Date endTime; 374 private String callingAddressAreaCode; 375 private String answerAddressAreaCode; 376 377 public String getCallType() { 378 String type = ""; 379 if (callingAddressAreaCode.equals("0791")) { 380 type = type.concat("1"); 381 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 382 type = type.concat("2"); 383 } else { 384 type = type.concat("3"); 385 } 386 387 if (answerAddressAreaCode.equals("0791")) { 388 type = type.concat("1"); 389 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 390 type = type.concat("2"); 391 } else { 392 type = type.concat("3"); 393 } 394 395 return type; 396 } 397 398 public CallRecord(String[] inputs) { 399 super(); 400 401 char type = inputs[0].charAt(0); 402 403 String sd = null, st = null, ed = null, et = null; 404 405 if (type == 't') { 406 if (inputs.length == 6) { 407 sd = inputs[2]; 408 st = inputs[3]; 409 ed = inputs[4]; 410 et = inputs[5]; 411 callingAddressAreaCode = inputs[0].substring(0, 4); 412 answerAddressAreaCode = inputs[1].substring(0, 4); 413 } else if (inputs.length == 7) { 414 sd = inputs[3]; 415 st = inputs[4]; 416 ed = inputs[5]; 417 et = inputs[6]; 418 if (inputs[0].charAt(0) != '0') { 419 if (inputs[2].length() == 10) { 420 answerAddressAreaCode = inputs[2].substring(0, 3); 421 } else { 422 answerAddressAreaCode = inputs[2].substring(0, 4); 423 } 424 callingAddressAreaCode = inputs[1]; 425 } else { 426 if (inputs[0].length() == 10) { 427 callingAddressAreaCode = inputs[0].substring(0, 3); 428 } else { 429 callingAddressAreaCode = inputs[0].substring(0, 4); 430 } 431 answerAddressAreaCode = inputs[2]; 432 } 433 } else if (inputs.length == 8) { 434 sd = inputs[4]; 435 st = inputs[5]; 436 ed = inputs[6]; 437 et = inputs[7]; 438 callingAddressAreaCode = inputs[1]; 439 answerAddressAreaCode = inputs[3]; 440 } 441 } else if (type == 'm') { 442 443 } 444 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 445 try { 446 startTime = simpleDateFormat.parse(sd + " " + st); 447 endTime = simpleDateFormat.parse(ed + " " + et); 448 } catch (ParseException e) { 449 } 450 451 } 452 453 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 454 super(); 455 this.startTime = startTime; 456 this.endTime = endTime; 457 this.callingAddressAreaCode = callingAddressAreaCode; 458 this.answerAddressAreaCode = answerAddressAreaCode; 459 } 460 461 public Date getStartTime() { 462 return startTime; 463 } 464 465 public void setStartTime(Date startTime) { 466 this.startTime = startTime; 467 } 468 469 public Date getEndTime() { 470 return endTime; 471 } 472 473 public void setEndTime(Date endTime) { 474 this.endTime = endTime; 475 } 476 477 public String getCallingAddressAreaCode() { 478 return callingAddressAreaCode; 479 } 480 481 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 482 this.callingAddressAreaCode = callingAddressAreaCode; 483 } 484 485 public String getAnswerAddressAreaCode() { 486 return answerAddressAreaCode; 487 } 488 489 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 490 this.answerAddressAreaCode = answerAddressAreaCode; 491 } 492 } 493 494 abstract class CallChargeRule extends ChargeRule { 495 496 } 497 498 class LandPhoneInCityRule extends CallChargeRule { 499 500 @Override 501 public double calCost(UserRecords userRecords) { 502 double sumCost = 0; 503 for (CallRecord call : userRecords.getCallingInCityRecords()) { 504 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 505 if (distanceS < 0) { 506 continue; 507 } 508 double distanceM = (int) distanceS / 60; 509 if (distanceS % 60 != 0) { 510 distanceM += 1; 511 } 512 if (call.getCallType().equals("11")) { 513 sumCost += distanceM * 0.1; 514 } else if (call.getCallType().equals("12")) { 515 sumCost += distanceM * 0.3; 516 } else if (call.getCallType().equals("13")) { 517 sumCost += distanceM * 0.6; 518 } 519 } 520 return sumCost; 521 } 522 523 } 524 525 class LandPhoneInlandRule extends CallChargeRule { 526 527 @Override 528 public double calCost(UserRecords userRecords) { 529 double sumCost = 0; 530 for (CallRecord call : userRecords.getCallingInLandRecords()) { 531 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 532 if (distanceS < 0) { 533 continue; 534 } 535 double distanceM = (int) distanceS / 60; 536 if (distanceS % 60 != 0) { 537 distanceM += 1; 538 } 539 sumCost += distanceM * 0.6; 540 } 541 return sumCost; 542 } 543 544 } 545 546 class LandPhoneInProvinceRule extends CallChargeRule { 547 548 @Override 549 public double calCost(UserRecords userRecords) { 550 double sumCost = 0; 551 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 552 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 553 if (distanceS < 0) { 554 continue; 555 } 556 double distanceM = (int) distanceS / 60; 557 if (distanceS % 60 != 0) { 558 distanceM += 1; 559 } 560 sumCost += distanceM * 0.3; 561 } 562 return sumCost; 563 } 564 565 } 566 567 class MobilePhoneInCityRule extends CallChargeRule { 568 569 @Override 570 public double calCost(UserRecords userRecords) { 571 double sumCost = 0; 572 for (CallRecord call : userRecords.getCallingInCityRecords()) { 573 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 574 if (distanceS < 0) { 575 continue; 576 } 577 double distanceM = (int) distanceS / 60; 578 if (distanceS % 60 != 0) { 579 distanceM += 1; 580 } 581 if (call.getCallType().equals("11")) { 582 sumCost += distanceM * 0.1; 583 } else if (call.getCallType().equals("12")) { 584 sumCost += distanceM * 0.2; 585 } else if (call.getCallType().equals("13")) { 586 sumCost += distanceM * 0.3; 587 } 588 589 } 590 return sumCost; 591 } 592 593 } 594 595 class MobilePhoneInlandRule extends CallChargeRule { 596 597 @Override 598 public double calCost(UserRecords userRecords) { 599 double sumCost = 0; 600 for (CallRecord call : userRecords.getCallingInLandRecords()) { 601 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 602 if (distanceS < 0) { 603 continue; 604 } 605 double distanceM = (int) distanceS / 60; 606 if (distanceS % 60 != 0) { 607 distanceM += 1; 608 } 609 sumCost += distanceM * 0.6; 610 } 611 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 612 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 613 if (distanceS < 0) { 614 continue; 615 } 616 double distanceM = (int) distanceS / 60; 617 if (distanceS % 60 != 0) { 618 distanceM += 1; 619 } 620 sumCost += distanceM * 0.3; 621 } 622 return sumCost; 623 } 624 625 } 626 627 class MobilePhoneInProvinceRule extends CallChargeRule { 628 629 @Override 630 public double calCost(UserRecords userRecords) { 631 double sumCost = 0; 632 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 633 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().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 if (call.getCallType().equals("21")) { 642 sumCost += distanceM * 0.3; 643 } else if (call.getCallType().equals("22")) { 644 sumCost += distanceM * 0.3; 645 } else if (call.getCallType().equals("23")) { 646 sumCost += distanceM * 0.3; 647 } 648 } 649 return sumCost; 650 } 651 652 } 653 654 class MobilePhoneMessageRule extends CallChargeRule { 655 656 @Override 657 public double calCost(UserRecords userRecords) { 658 double sumCost = 0; 659 int number = 0; 660 for (MessageRecord m : userRecords.getSendMessageRecords()) { 661 int length = m.getMessage().length(); 662 if (length <= 10) { 663 number++; 664 } else { 665 number += length / 10; 666 if (length % 10 != 0) { 667 number++; 668 } 669 } 670 } 671 if (number <= 3) { 672 sumCost = number * 0.1; 673 } else if (number <= 5) { 674 sumCost = 0.3 + 0.2 * (number - 3); 675 } else { 676 sumCost = 0.7 + 0.3 * (number - 5); 677 } 678 return sumCost; 679 } 680 681 } 682 683 class MessageRecord extends CommunicationRecord { 684 685 private String message; 686 687 public MessageRecord(String input) { 688 super(); 689 this.message = input.substring(26); 690 } 691 692 public String getMessage() { 693 return message; 694 } 695 696 public void setMessage(String message) { 697 this.message = message; 698 } 699 } 700 701 class User { 702 703 private UserRecords userRecords = new UserRecords(); 704 private double balance = 100; 705 private ChargeMode chargeMode; 706 private String number; 707 708 public double calCost() { 709 return chargeMode.calCost(userRecords); 710 } 711 712 public double calBalance() { 713 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 714 } 715 716 public UserRecords getUserRecords() { 717 return userRecords; 718 } 719 720 public void setUserRecords(UserRecords userRecords) { 721 this.userRecords = userRecords; 722 } 723 724 public ChargeMode getChargeMode() { 725 return chargeMode; 726 } 727 728 public void setChargeMode(ChargeMode chargeMode) { 729 this.chargeMode = chargeMode; 730 } 731 732 public String getNumber() { 733 return number; 734 } 735 736 public void setNumber(String number) { 737 this.number = number; 738 } 739 740 } 741 742 class Outputtool { 743 744 @SuppressWarnings("deprecation") 745 public void output(double out) { 746 BigDecimal numb = new BigDecimal(out); 747 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 748 System.out.print(out); 749 } 750 }
SourceMonitor的生成报表内容如下:
小结:
第三次时间紧迫,写的匆匆忙忙,但是在同学的帮助下,还是顺利的写完啦~~~
三、踩坑心得以及改进建议
1.当类和对象非常多时,导致我对之间的关系有些混乱,这说明我还需要多加练习,应用需要更加熟练。
2.对包装类中的方法不够清楚,导致使用时常常报错,在之后需要多次使用其中的方法来增加印象。
3.对SimpleDateFormat类的不了解也导致第一题使用了错误的方法判断的时间,对其余部分的格式判断也简单判断,没有使用正则表达式判断,导致座机计费格式判断并不全面。在学会使用SimpleDateFormat类进行时间判断后,使用正则表达式进行了前面的号码的判断。
四、总结
这次的pta的作业让我知道了如何面向对象去设计实验,面向对象的好处,它的思路更清晰,修改起来更简单,代码耦合度小,代码复杂度低的优点。当我掌握这种方法后可以使代码复用度更高,可以使后面需要加什么代码直接可以加上去,不用再去另外写新的代码了。这三次连续的大作业老师都给了类图,在设计上少走了很多弯路,但是在之后的题目完成过程中,学会设计更为重要!java还有很多很多工具功能没学,在今后尽量学习更多。