前言:
在上一个月的课程学习中,我吸收掌握了很多具有拓展性、延申性的知识,其中包含类与对象的构造、组成,以及在封装、继承、多态三原则优化后的代码结构基础上,进行抽象类、抽象方法的联系与应用。同时,也在课堂上和平时的大作业里着重锻炼了自己对程序类图结构的拆分和理解,并从中编写出成功案例的能力。在第六次至第八次PTA大作业中,我们接触并实现了以类与对象为基础的电信计费系列的编程,三次的题目分别从座机计费、手机座机计费、短信计费出发,对我们关于构造类知识的掌握、类图的分析与理解做出了考察。除开三次大作业里难度适中的普通题目,电信计费系列的题目难度偏大,但主要原因在于代码量大、涉及的类与继承关系复杂。不过只要我们能够读懂类图,分析清楚题目的要求,加之对不同信息格式的严格判断,写出符合要求的代码是完全可行的。本文将重点分析三次大作业中电信计费系列的题目,并用IDEA生成类图、SourceMonitor生成圈图进行辅助解析。
设计与分析:
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中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
图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
输入样例:
在这里给出一组输入。例如:
u-079186300001 0
t-079186300001 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:25
end
输出样例:
在这里给出相应的输出。例如:
079186300001 3.0 77.0
其余参考样例详见附件,未尽事宜以附件样例为准:
我的答案:
首先先给出关键部分的实现细节:
用户记录类UserRecords:
1 class UserRecords { 2 3 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 4 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 5 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 6 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 7 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 8 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 9 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 10 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 11 12 public void addCallingInCityRecords(CallRecord callRecord) { 13 callingInCityRecords.add(callRecord); 14 } 15 16 public void addCallingInProvinceRecords(CallRecord callRecord) { 17 callingInProvinceRecords.add(callRecord); 18 } 19 20 public void addCallingInLandRecords(CallRecord callRecord) { 21 callingInLandRecords.add(callRecord); 22 } 23 24 public void addAnswerInCityRecords(CallRecord callRecord) { 25 answerInCityRecords.add(callRecord); 26 } 27 28 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 29 answerInProvinceRecords.add(callRecord); 30 } 31 32 public void addAnswerInLandRecords(CallRecord callRecord) { 33 answerInLandRecords.add(callRecord); 34 } 35 36 public void addSendMessageRecords(MessageRecord callRecord) { 37 sendMessageRecords.add(callRecord); 38 } 39 40 public void addReceiveMessageRecords(MessageRecord callRecord) { 41 receiveMessageRecords.add(callRecord); 42 } 43 44 public ArrayList<CallRecord> getCallingInCityRecords() { 45 return callingInCityRecords; 46 } 47 48 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 49 this.callingInCityRecords = callingInCityRecords; 50 } 51 52 public ArrayList<CallRecord> getCallingInProvinceRecords() { 53 return callingInProvinceRecords; 54 } 55 56 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 57 this.callingInProvinceRecords = callingInProvinceRecords; 58 } 59 60 public ArrayList<CallRecord> getCallingInLandRecords() { 61 return callingInLandRecords; 62 } 63 64 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 65 this.callingInLandRecords = callingInLandRecords; 66 } 67 68 public ArrayList<CallRecord> getAnswerInCityRecords() { 69 return answerInCityRecords; 70 } 71 72 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 73 this.answerInCityRecords = answerInCityRecords; 74 } 75 76 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 77 return answerInProvinceRecords; 78 } 79 80 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 81 this.answerInProvinceRecords = answerInProvinceRecords; 82 } 83 84 public ArrayList<CallRecord> getAnswerInLandRecords() { 85 return answerInLandRecords; 86 } 87 88 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 89 this.answerInLandRecords = answerInLandRecords; 90 } 91 92 public ArrayList<MessageRecord> getSendMessageRecords() { 93 return sendMessageRecords; 94 } 95 96 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 97 this.sendMessageRecords = sendMessageRecords; 98 } 99 100 public ArrayList<MessageRecord> getReceiveMessageRecords() { 101 return receiveMessageRecords; 102 } 103 104 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 105 this.receiveMessageRecords = receiveMessageRecords; 106 } 107 108 }View Code
通话记录类CallRecord:
1 class CallRecord extends CommunicationRecord { 2 private Date startTime; 3 private Date endTime; 4 private String callingAddressAreaCode; 5 private String answerAddressAreaCode; 6 7 public int getCallType() { 8 if (callingAddressAreaCode.equals(answerAddressAreaCode)) { 9 return 1; 10 } 11 if (callingAddressAreaCode.matches("^079[0-9]$") || callingAddressAreaCode.equals("0701")) { 12 if (answerAddressAreaCode.matches("^079[0-9]$") || answerAddressAreaCode.equals("0701")) { 13 return 2; 14 } 15 } 16 return 3; 17 } 18 19 public CallRecord(String[] inputs) { 20 super(); 21 if (inputs[0].length() == 10) { 22 callingAddressAreaCode = inputs[0].substring(0, 3); 23 } else { 24 callingAddressAreaCode = inputs[0].substring(0, 4); 25 } 26 if (inputs[1].length() == 10) { 27 answerAddressAreaCode = inputs[1].substring(0, 3); 28 } else { 29 answerAddressAreaCode = inputs[1].substring(0, 4); 30 } 31 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 32 try { 33 startTime = simpleDateFormat.parse(inputs[2] + " " + inputs[3]); 34 endTime = simpleDateFormat.parse(inputs[4] + " " + inputs[5]); 35 } catch (ParseException e) { 36 } 37 38 } 39 40 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 41 super(); 42 this.startTime = startTime; 43 this.endTime = endTime; 44 this.callingAddressAreaCode = callingAddressAreaCode; 45 this.answerAddressAreaCode = answerAddressAreaCode; 46 } 47 48 public Date getStartTime() { 49 return startTime; 50 } 51 52 public void setStartTime(Date startTime) { 53 this.startTime = startTime; 54 } 55 56 public Date getEndTime() { 57 return endTime; 58 } 59 60 public void setEndTime(Date endTime) { 61 this.endTime = endTime; 62 } 63 64 public String getCallingAddressAreaCode() { 65 return callingAddressAreaCode; 66 } 67 68 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 69 this.callingAddressAreaCode = callingAddressAreaCode; 70 } 71 72 public String getAnswerAddressAreaCode() { 73 return answerAddressAreaCode; 74 } 75 76 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 77 this.answerAddressAreaCode = answerAddressAreaCode; 78 } 79 }View Code
全码展示:
1 package 电信计费系列1; 2 3 import java.util.ArrayList; 4 import java.util.Comparator; 5 import java.util.Scanner; 6 import java.util.regex.Matcher; 7 import java.util.regex.Pattern; 8 import java.math.BigDecimal; 9 import java.text.SimpleDateFormat; 10 import java.util.Date; 11 import java.util.Locale; 12 import java.text.ParseException; 13 14 public class 座机计费 { 15 16 public static void main(String[] args) { 17 18 Outputtool outputtool = new Outputtool(); 19 20 Inputdeal inputdeal = new Inputdeal(); 21 22 ArrayList<User> users = new ArrayList<>(); 23 24 Scanner in = new Scanner(System.in); 25 26 String input = in.nextLine(); 27 28 while (!input.equals("end")) { 29 if (1 == inputdeal.check(input)) { 30 inputdeal.writeUser(users, input); 31 } else if (2 == inputdeal.check(input)) { 32 inputdeal.writeRecord(users, input); 33 } 34 input = in.nextLine(); 35 } 36 37 users.sort(new Comparator<User>() { 38 39 @Override 40 public int compare(User u1, User u2) { 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 Inputdeal { 215 216 public int check(String input) { 217 String[] inputs = input.split(" "); 218 if (inputs.length == 2) { 219 if (inputs[0].matches("^u-[0-9]{11,13}$")) { 220 if (Integer.parseInt(inputs[1]) >= 0) { 221 if (Integer.parseInt(inputs[1]) <= 2) { 222 return 1; 223 } 224 } 225 } 226 } else if (inputs.length == 6) { 227 if (validate(inputs[2])) 228 if (validate(inputs[4])) 229 if (validatet(inputs[3])) 230 if (validatet(inputs[5])) 231 if (inputs[0].matches("[t]-0791[0-9]{7,8}")) { 232 if (inputs[1].matches(".[0-9]{9,11}")) 233 return 2; 234 } 235 } 236 return 0; 237 } 238 239 private boolean validatet(String string) { 240 String[] split = string.split(":"); 241 if (!string.matches("^([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { 242 return false; 243 } 244 return true; 245 } 246 247 public static boolean validate(String dateString) { 248 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 249 Pattern p = Pattern.compile("\\d{4}+[\\.]\\d{1,2}+[\\.]\\d{1,2}+"); 250 Matcher m = p.matcher(dateString); 251 if (!m.matches()) { 252 return false; 253 } 254 255 // 得到年月日 256 String[] array = dateString.split("\\."); 257 int year = Integer.valueOf(array[0]); 258 int month = Integer.valueOf(array[1]); 259 int day = Integer.valueOf(array[2]); 260 261 if (month < 1 || month > 12) { 262 return false; 263 } 264 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 265 if (isLeapYear(year)) { 266 monthLengths[2] = 29; 267 } else { 268 monthLengths[2] = 28; 269 } 270 int monthLength = monthLengths[month]; 271 if (day < 1 || day > monthLength) { 272 return false; 273 } 274 return true; 275 } 276 277 /** 是否是闰年 */ 278 private static boolean isLeapYear(int year) { 279 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 280 } 281 282 public boolean judge(String input) { 283 284 return false; 285 } 286 287 public void writeUser(ArrayList<User> users, String input) { 288 User usernew = new User(); 289 String[] inputs = input.split(" "); 290 String num = inputs[0].substring(2); 291 for (User i : users) { 292 if (i.getNumber().equals(num)) { 293 return; 294 } 295 } 296 usernew.setNumber(num); 297 int mode = Integer.parseInt(inputs[1]); 298 if (mode == 0) { 299 usernew.setChargeMode(new LandlinePhoneCharging()); 300 } 301 users.add(usernew); 302 } 303 304 public void writeRecord(ArrayList<User> users, String input) { 305 String[] inputs = input.split(" "); 306 inputs[0] = inputs[0].replace("t-", ""); 307 308 User callu = null, answeru = null; 309 CallRecord callrecord = new CallRecord(inputs); 310 311 for (User i : users) { 312 if (i.getNumber().equals(inputs[0])) { 313 callu = i; 314 } 315 if (i.getNumber().equals(inputs[1])) { 316 answeru = i; 317 } 318 if (callu != null && answeru != null) { 319 break; 320 } 321 } 322 323 if (callu != null) { 324 if (callrecord.getCallType() == 1) { 325 callu.getUserRecords().addCallingInCityRecords(callrecord); 326 } else if (callrecord.getCallType() == 2) { 327 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 328 } else { 329 callu.getUserRecords().addCallingInLandRecords(callrecord); 330 } 331 } 332 333 if (answeru != null) { 334 if (callrecord.getCallType() == 1) { 335 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 336 } else if (callrecord.getCallType() == 2) { 337 338 answeru.getUserRecords().aaddAnswerInProvinceRecords(callrecord); 339 } else { 340 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 341 } 342 } 343 344 } 345 346 } 347 348 abstract class CommunicationRecord { 349 protected String callingNumber; 350 protected String answerNumbe; 351 352 public String getCallingNumber() { 353 return callingNumber; 354 } 355 356 public void setCallingNumber(String callingNumber) { 357 this.callingNumber = callingNumber; 358 } 359 360 public String getAnswerNumbe() { 361 return answerNumbe; 362 } 363 364 public void setAnswerNumbe(String answerNumbe) { 365 this.answerNumbe = answerNumbe; 366 } 367 368 } 369 370 abstract class ChargeRule { 371 372 abstract public double calCost(UserRecords userRecords); 373 374 } 375 376 class CallRecord extends CommunicationRecord { 377 private Date startTime; 378 private Date endTime; 379 private String callingAddressAreaCode; 380 private String answerAddressAreaCode; 381 382 public int getCallType() { 383 if (callingAddressAreaCode.equals(answerAddressAreaCode)) { 384 return 1; 385 } 386 if (callingAddressAreaCode.matches("^079[0-9]$") || callingAddressAreaCode.equals("0701")) { 387 if (answerAddressAreaCode.matches("^079[0-9]$") || answerAddressAreaCode.equals("0701")) { 388 return 2; 389 } 390 } 391 return 3; 392 } 393 394 public CallRecord(String[] inputs) { 395 super(); 396 if (inputs[0].length() == 10) { 397 callingAddressAreaCode = inputs[0].substring(0, 3); 398 } else { 399 callingAddressAreaCode = inputs[0].substring(0, 4); 400 } 401 if (inputs[1].length() == 10) { 402 answerAddressAreaCode = inputs[1].substring(0, 3); 403 } else { 404 answerAddressAreaCode = inputs[1].substring(0, 4); 405 } 406 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 407 try { 408 startTime = simpleDateFormat.parse(inputs[2] + " " + inputs[3]); 409 endTime = simpleDateFormat.parse(inputs[4] + " " + inputs[5]); 410 } catch (ParseException e) { 411 } 412 413 } 414 415 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 416 super(); 417 this.startTime = startTime; 418 this.endTime = endTime; 419 this.callingAddressAreaCode = callingAddressAreaCode; 420 this.answerAddressAreaCode = answerAddressAreaCode; 421 } 422 423 public Date getStartTime() { 424 return startTime; 425 } 426 427 public void setStartTime(Date startTime) { 428 this.startTime = startTime; 429 } 430 431 public Date getEndTime() { 432 return endTime; 433 } 434 435 public void setEndTime(Date endTime) { 436 this.endTime = endTime; 437 } 438 439 public String getCallingAddressAreaCode() { 440 return callingAddressAreaCode; 441 } 442 443 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 444 this.callingAddressAreaCode = callingAddressAreaCode; 445 } 446 447 public String getAnswerAddressAreaCode() { 448 return answerAddressAreaCode; 449 } 450 451 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 452 this.answerAddressAreaCode = answerAddressAreaCode; 453 } 454 } 455 456 abstract class CallChargeRule extends ChargeRule { 457 458 } 459 460 class LandPhoneInCityRule extends CallChargeRule { 461 462 @Override 463 public double calCost(UserRecords userRecords) { 464 double sumCost = 0; 465 for (CallRecord call : userRecords.getCallingInCityRecords()) { 466 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 467 if (distanceS < 0) { 468 continue; 469 } 470 double distanceM = (int) distanceS / 60; 471 if (distanceS % 60 != 0) { 472 distanceM += 1; 473 } 474 sumCost += distanceM * 0.1; 475 } 476 return sumCost; 477 } 478 479 } 480 481 class LandPhoneInlandRule extends CallChargeRule { 482 483 @Override 484 public double calCost(UserRecords userRecords) { 485 double sumCost = 0; 486 for (CallRecord call : userRecords.getCallingInLandRecords()) { 487 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 488 if (distanceS < 0) { 489 continue; 490 } 491 double distanceM = (int) distanceS / 60; 492 if (distanceS % 60 != 0) { 493 distanceM += 1; 494 } 495 sumCost += distanceM * 0.6; 496 } 497 return sumCost; 498 } 499 500 } 501 502 class LandPhoneInProvinceRule extends CallChargeRule { 503 504 @Override 505 public double calCost(UserRecords userRecords) { 506 double sumCost = 0; 507 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 508 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 509 if (distanceS < 0) { 510 continue; 511 } 512 double distanceM = (int) distanceS / 60; 513 if (distanceS % 60 != 0) { 514 distanceM += 1; 515 } 516 sumCost += distanceM * 0.3; 517 } 518 return sumCost; 519 } 520 521 } 522 523 class MessageRecord extends CommunicationRecord { 524 525 private String message; 526 527 public String getMessage() { 528 return message; 529 } 530 531 public void setMessage(String message) { 532 this.message = message; 533 } 534 } 535 536 class User { 537 538 private UserRecords userRecords = new UserRecords(); 539 private double balance = 100; 540 private ChargeMode chargeMode; 541 private String number; 542 543 public double calCost() { 544 return chargeMode.calCost(userRecords); 545 } 546 547 public double calBalance() { 548 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 549 } 550 551 public UserRecords getUserRecords() { 552 return userRecords; 553 } 554 555 public void setUserRecords(UserRecords userRecords) { 556 this.userRecords = userRecords; 557 } 558 559 public ChargeMode getChargeMode() { 560 return chargeMode; 561 } 562 563 public void setChargeMode(ChargeMode chargeMode) { 564 this.chargeMode = chargeMode; 565 } 566 567 public String getNumber() { 568 return number; 569 } 570 571 public void setNumber(String number) { 572 this.number = number; 573 } 574 575 } 576 577 class Outputtool { 578 579 public void output(double out) { 580 BigDecimal numb = new BigDecimal(out); 581 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 582 System.out.print(out); 583 } 584 }View Code
SourceMonitor分析图:
IDEA生成程序类图:
总结:
本题作为电信计费系列的第一道题,需要我们将题干中给出的类图进行详细的分析,从中提取关键信息组成完成的可运行代码。对于本题我的思路和解题步骤可总结如下:首先构造出电信计费系列的基本框架,即弄清楚都有些什么具体的类,类与类之间的继承关系是怎样的。比如通过第一张类图,我们可以认为它是用来讲用户的,其讲清楚了三个类:用户类User,用户记录类UserRecords,以及计费方式ChargeMode。其中ChargeMode是抽象类,我们可以同时确定继承ChargeMode的是哪些类,以及三种类之间的联系。按照同样的方式分析类图2与类图3,我们可以认为它们分别是通讯记录类和计费规则相关类,之再后向类中填入方法,同时注意抽象类的抽象方法,以及继承时对方法的引用做出相应的改变。另外,本题除了对类与对象以及抽象类、抽象方法,类图分析的考察,由于题目所处的现实环境,对ArryList集合的考察也非常突出。本题构建的结构(此处仅添加了座机计费的功能)对后续功能的继续添加(本系列的第二题需要添加手机计费)十分重要,值得花费较长时间去好好琢磨。
7-2 电信计费系列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中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
输入样例:
在这里给出一组输入。例如:
u-13811111111 1
t-13811111111 0791 13811111110 020 2022.1.3 08:00:00 2022.1.3 08:09:20
end
输出样例:
在这里给出相应的输出。例如:
13811111111 3.0 82.0
更多内容详见附件:
我的答案:
上一题我们已经确定好了仅含有座机计费的体系结构,现在我们把手机计费体系添加的部分类展示如下:
1 class LandlinePhoneCharging extends ChargeMode { 2 3 private double monthlyRent = 20; 4 5 public LandlinePhoneCharging() { 6 super(); 7 chargeRules.add(new LandPhoneInCityRule()); 8 chargeRules.add(new LandPhoneInProvinceRule()); 9 chargeRules.add(new LandPhoneInlandRule()); 10 } 11 12 @Override 13 public double calCost(UserRecords userRecords) { 14 double sumCost = 0; 15 for (ChargeRule rule : chargeRules) { 16 sumCost += rule.calCost(userRecords); 17 } 18 return sumCost; 19 } 20 21 @Override 22 public double getMonthlyRent() { 23 return monthlyRent; 24 } 25 26 } 27 28 class MobilePhoneCharging extends ChargeMode { 29 30 private double monthlyRent = 15; 31 32 public MobilePhoneCharging() { 33 super(); 34 chargeRules.add(new MobilePhoneInCityRule()); 35 chargeRules.add(new MobilePhoneInProvinceRule()); 36 chargeRules.add(new MobilePhoneInlandRule()); 37 } 38 39 @Override 40 public double calCost(UserRecords userRecords) { 41 double sumCost = 0; 42 for (ChargeRule rule : chargeRules) { 43 sumCost += rule.calCost(userRecords); 44 } 45 return sumCost; 46 } 47 48 @Override 49 public double getMonthlyRent() { 50 return monthlyRent; 51 } 52 53 }View Code
全码如下:
1 package 电信计费系列2; 2 3 import java.math.RoundingMode; 4 import java.util.ArrayList; 5 import java.util.Comparator; 6 import java.util.Scanner; 7 import java.util.regex.Matcher; 8 import java.util.regex.Pattern; 9 import java.math.BigDecimal; 10 import java.text.SimpleDateFormat; 11 import java.util.Date; 12 import java.util.Locale; 13 import java.text.ParseException; 14 15 public class 手机座机计费 { 16 17 public static void main(String[] args) { 18 19 Outputtool outputtool = new Outputtool(); 20 21 Inputdeal inputdeal = new Inputdeal(); 22 23 ArrayList<User> users = new ArrayList<>(); 24 25 Scanner in = new Scanner(System.in); 26 27 String input = in.nextLine(); 28 29 while (!input.equals("end")) { 30 if (1 == inputdeal.check(input)) { 31 inputdeal.writeUser(users, input); 32 } else if (2 == inputdeal.check(input)) { 33 inputdeal.writeRecord(users, input); 34 } 35 input = in.nextLine(); 36 } 37 38 users.sort(new Comparator<User>() { 39 40 @Override 41 public int compare(User u1, User u2) { 42 if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') { 43 return -1; 44 } else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') { 45 return 1; 46 } 47 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 48 return 1; 49 } else { 50 return -1; 51 } 52 } 53 }); 54 55 for (User u : users) { 56 System.out.print(u.getNumber() + " "); 57 outputtool.output(u.calCost()); 58 System.out.print(" "); 59 outputtool.output(u.calBalance()); 60 System.out.println(); 61 62 } 63 64 } 65 66 } 67 68 abstract class ChargeMode { 69 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 70 71 public abstract double calCost(UserRecords userRecords); 72 73 public abstract double getMonthlyRent(); 74 75 } 76 77 class UserRecords { 78 79 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 80 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 81 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 82 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 83 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 84 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 85 86 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 87 88 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 89 90 public void addCallingInCityRecords(CallRecord callRecord) { 91 callingInCityRecords.add(callRecord); 92 } 93 94 public void addCallingInProvinceRecords(CallRecord callRecord) { 95 callingInProvinceRecords.add(callRecord); 96 } 97 98 public void addCallingInLandRecords(CallRecord callRecord) { 99 callingInLandRecords.add(callRecord); 100 } 101 102 public void addAnswerInCityRecords(CallRecord callRecord) { 103 answerInCityRecords.add(callRecord); 104 } 105 106 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 107 answerInProvinceRecords.add(callRecord); 108 } 109 110 public void addAnswerInLandRecords(CallRecord callRecord) { 111 answerInLandRecords.add(callRecord); 112 } 113 114 public ArrayList<CallRecord> getCallingInCityRecords() { 115 return callingInCityRecords; 116 } 117 118 public ArrayList<CallRecord> getCallingInProvinceRecords() { 119 return callingInProvinceRecords; 120 } 121 122 public ArrayList<CallRecord> getCallingInLandRecords() { 123 return callingInLandRecords; 124 } 125 126 public ArrayList<CallRecord> getAnswerInLandRecords() { 127 return answerInLandRecords; 128 } 129 130 } 131 132 class LandlinePhoneCharging extends ChargeMode { 133 134 private double monthlyRent = 20; 135 136 public LandlinePhoneCharging() { 137 super(); 138 chargeRules.add(new LandPhoneInCityRule()); 139 chargeRules.add(new LandPhoneInProvinceRule()); 140 chargeRules.add(new LandPhoneInlandRule()); 141 } 142 143 @Override 144 public double calCost(UserRecords userRecords) { 145 double sumCost = 0; 146 for (ChargeRule rule : chargeRules) { 147 sumCost += rule.calCost(userRecords); 148 } 149 return sumCost; 150 } 151 152 @Override 153 public double getMonthlyRent() { 154 return monthlyRent; 155 } 156 157 } 158 159 class MobilePhoneCharging extends ChargeMode { 160 161 private double monthlyRent = 15; 162 163 public MobilePhoneCharging() { 164 super(); 165 chargeRules.add(new MobilePhoneInCityRule()); 166 chargeRules.add(new MobilePhoneInProvinceRule()); 167 chargeRules.add(new MobilePhoneInlandRule()); 168 } 169 170 @Override 171 public double calCost(UserRecords userRecords) { 172 double sumCost = 0; 173 for (ChargeRule rule : chargeRules) { 174 sumCost += rule.calCost(userRecords); 175 } 176 return sumCost; 177 } 178 179 @Override 180 public double getMonthlyRent() { 181 return monthlyRent; 182 } 183 184 } 185 186 class Inputdeal { 187 188 public int check(String input) { 189 if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[1]")) { 190 return 1; 191 // } else if (input.charAt(0) == 'm') { 192 // return 2; 193 } else if (input.matches("(([t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s)|" 194 + "([t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s)|" 195 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s)|" 196 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s))" 197 198 + "((([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?" 199 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 200 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 201 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" 202 + "((([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])\\.(" 203 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 204 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 205 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])")) { 206 return 2; 207 } 208 return 0; 209 } 210 211 @SuppressWarnings("unused") 212 private boolean validatet(String string) { 213 return string.matches("^([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"); 214 } 215 216 public static boolean validate(String dateString) { 217 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 218 Pattern p = Pattern.compile("\\d{4}+[\\.]\\d{1,2}+[\\.]\\d{1,2}+"); 219 Matcher m = p.matcher(dateString); 220 if (!m.matches()) { 221 return false; 222 } 223 224 // 得到年月日 225 String[] array = dateString.split("\\."); 226 int year = Integer.parseInt(array[0]); 227 int month = Integer.parseInt(array[1]); 228 int day = Integer.parseInt(array[2]); 229 230 if (month < 1 || month > 12) { 231 return false; 232 } 233 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 234 if (isLeapYear(year)) { 235 monthLengths[2] = 29; 236 } else { 237 monthLengths[2] = 28; 238 } 239 int monthLength = monthLengths[month]; 240 if (day < 1 || day > monthLength) { 241 return false; 242 } 243 return true; 244 } 245 246 /** 是否是闰年 */ 247 private static boolean isLeapYear(int year) { 248 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 249 } 250 251 public boolean judge(String input) { 252 253 return false; 254 } 255 256 public void writeUser(ArrayList<User> users, String input) { 257 User usernew = new User(); 258 String[] inputs = input.split(" "); 259 String num = inputs[0].substring(2); 260 for (User i : users) { 261 if (i.getNumber().equals(num)) { 262 return; 263 } 264 } 265 usernew.setNumber(num); 266 int mode = Integer.parseInt(inputs[1]); 267 if (mode == 0) { 268 usernew.setChargeMode(new LandlinePhoneCharging()); 269 } else if (mode == 1) { 270 usernew.setChargeMode(new MobilePhoneCharging()); 271 } 272 users.add(usernew); 273 } 274 275 public void writeRecord(ArrayList<User> users, String input) { 276 String[] inputs = input.split(" "); 277 278 User callu = null, answeru = null; 279 CallRecord callrecord = new CallRecord(inputs); 280 281 if (input.charAt(0) == 't') { 282 String out = inputs[0]; 283 String in = ""; 284 if (inputs.length == 6) { 285 in = inputs[1]; 286 } else if (inputs.length == 7) { 287 in = inputs[1]; 288 } else if (inputs.length == 8) { 289 in = inputs[2]; 290 } 291 292 for (User i : users) { 293 if (i.getNumber().equals(out)) { 294 callu = i; 295 } 296 if (i.getNumber().equals(in)) { 297 answeru = i; 298 } 299 if (callu != null && answeru != null) { 300 break; 301 } 302 } 303 304 if (callu != null) { 305 if (callrecord.getCallType().matches("^1[1-3]$")) { 306 callu.getUserRecords().addCallingInCityRecords(callrecord); 307 } else if (callrecord.getCallType().matches("^2[1-3]$")) { 308 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 309 } else { 310 callu.getUserRecords().addCallingInLandRecords(callrecord); 311 } 312 } 313 314 if (answeru != null) { 315 if (callrecord.getCallType().matches("^[1-3]1$")) { 316 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 317 } else if (callrecord.getCallType().matches("^[1-3]2$")) { 318 answeru.getUserRecords().aaddAnswerInProvinceRecords(callrecord); 319 } else { 320 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 321 } 322 } 323 } else if (input.charAt(0) == 'm') { 324 325 } 326 327 } 328 329 } 330 331 abstract class CommunicationRecord { 332 protected String callingNumber; 333 protected String answerNumbe; 334 335 public String getCallingNumber() { 336 return callingNumber; 337 } 338 339 public void setCallingNumber(String callingNumber) { 340 this.callingNumber = callingNumber; 341 } 342 343 public String getAnswerNumbe() { 344 return answerNumbe; 345 } 346 347 public void setAnswerNumbe(String answerNumbe) { 348 this.answerNumbe = answerNumbe; 349 } 350 351 } 352 353 abstract class ChargeRule { 354 355 abstract public double calCost(UserRecords userRecords); 356 357 } 358 359 class CallRecord extends CommunicationRecord { 360 private Date startTime; 361 private Date endTime; 362 private String callingAddressAreaCode; 363 private String answerAddressAreaCode; 364 365 public String getCallType() { 366 String type = ""; 367 if (callingAddressAreaCode.equals("0791")) { 368 type = type.concat("1"); 369 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 370 type = type.concat("2"); 371 } else { 372 type = type.concat("3"); 373 } 374 375 if (answerAddressAreaCode.equals("0791")) { 376 type = type.concat("1"); 377 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 378 type = type.concat("2"); 379 } else { 380 type = type.concat("3"); 381 } 382 383 return type; 384 } 385 386 public CallRecord(String[] inputs) { 387 super(); 388 389 char type = inputs[0].charAt(0); 390 inputs[0] = inputs[0].substring(2); 391 392 String sd = null, st = null, ed = null, et = null; 393 394 if (type == 't') { 395 if (inputs.length == 6) { 396 sd = inputs[2]; 397 st = inputs[3]; 398 ed = inputs[4]; 399 et = inputs[5]; 400 callingAddressAreaCode = inputs[0].substring(0, 4); 401 answerAddressAreaCode = inputs[1].substring(0, 4); 402 } else if (inputs.length == 7) { 403 sd = inputs[3]; 404 st = inputs[4]; 405 ed = inputs[5]; 406 et = inputs[6]; 407 if (inputs[0].charAt(0) != '0') { 408 if (inputs[2].length() == 10) { 409 answerAddressAreaCode = inputs[2].substring(0, 3); 410 } else { 411 answerAddressAreaCode = inputs[2].substring(0, 4); 412 } 413 callingAddressAreaCode = inputs[1]; 414 } else { 415 if (inputs[0].length() == 10) { 416 callingAddressAreaCode = inputs[0].substring(0, 3); 417 } else { 418 callingAddressAreaCode = inputs[0].substring(0, 4); 419 } 420 answerAddressAreaCode = inputs[2]; 421 } 422 } else if (inputs.length == 8) { 423 sd = inputs[4]; 424 st = inputs[5]; 425 ed = inputs[6]; 426 et = inputs[7]; 427 callingAddressAreaCode = inputs[1]; 428 answerAddressAreaCode = inputs[3]; 429 } 430 } else if (type == 'm') { 431 432 } 433 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 434 try { 435 startTime = simpleDateFormat.parse(sd + " " + st); 436 endTime = simpleDateFormat.parse(ed + " " + et); 437 } catch (ParseException ignored) { 438 } 439 440 } 441 442 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 443 super(); 444 this.startTime = startTime; 445 this.endTime = endTime; 446 this.callingAddressAreaCode = callingAddressAreaCode; 447 this.answerAddressAreaCode = answerAddressAreaCode; 448 } 449 450 public Date getStartTime() { 451 return startTime; 452 } 453 454 public Date getEndTime() { 455 return endTime; 456 } 457 } 458 459 abstract class CallChargeRule extends ChargeRule { 460 461 } 462 463 class LandPhoneInCityRule extends CallChargeRule { 464 public double calCost(UserRecords userRecords) { 465 double sumCost = 0; 466 for (CallRecord call : userRecords.getCallingInCityRecords()) { 467 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 468 if (distanceS < 0) { 469 continue; 470 } 471 double distanceM = (int) distanceS / 60; 472 if (distanceS % 60 != 0) { 473 distanceM += 1; 474 } 475 if (call.getCallType().equals("11")) { 476 sumCost += distanceM * 0.1; 477 } else if (call.getCallType().equals("12")) { 478 sumCost += distanceM * 0.3; 479 } else if (call.getCallType().equals("13")) { 480 sumCost += distanceM * 0.6; 481 } 482 } 483 return sumCost; 484 } 485 486 } 487 488 class LandPhoneInlandRule extends CallChargeRule { 489 public double calCost(UserRecords userRecords) { 490 double sumCost = 0; 491 for (CallRecord call : userRecords.getCallingInLandRecords()) { 492 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 493 if (distanceS < 0) { 494 continue; 495 } 496 double distanceM = (int) distanceS / 60; 497 if (distanceS % 60 != 0) { 498 distanceM += 1; 499 } 500 sumCost += distanceM * 0.6; 501 } 502 return sumCost; 503 } 504 505 } 506 507 class LandPhoneInProvinceRule extends CallChargeRule { 508 public double calCost(UserRecords userRecords) { 509 double sumCost = 0; 510 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 511 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 512 if (distanceS < 0) { 513 continue; 514 } 515 double distanceM = (int) distanceS / 60; 516 if (distanceS % 60 != 0) { 517 distanceM += 1; 518 } 519 sumCost += distanceM * 0.3; 520 } 521 return sumCost; 522 } 523 524 } 525 526 class MobilePhoneInCityRule extends CallChargeRule { 527 public double calCost(UserRecords userRecords) { 528 double sumCost = 0; 529 for (CallRecord call : userRecords.getCallingInCityRecords()) { 530 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 531 if (distanceS < 0) { 532 continue; 533 } 534 double distanceM = (int) distanceS / 60; 535 if (distanceS % 60 != 0) { 536 distanceM += 1; 537 } 538 if (call.getCallType().equals("11")) { 539 sumCost += distanceM * 0.1; 540 } else if (call.getCallType().equals("12")) { 541 sumCost += distanceM * 0.2; 542 } else if (call.getCallType().equals("13")) { 543 sumCost += distanceM * 0.3; 544 } 545 546 } 547 return sumCost; 548 } 549 550 } 551 552 class MobilePhoneInlandRule extends CallChargeRule { 553 public double calCost(UserRecords userRecords) { 554 double sumCost = 0; 555 for (CallRecord call : userRecords.getCallingInLandRecords()) { 556 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 557 if (distanceS < 0) { 558 continue; 559 } 560 double distanceM = (int) distanceS / 60; 561 if (distanceS % 60 != 0) { 562 distanceM += 1; 563 } 564 sumCost += distanceM * 0.6; 565 } 566 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 567 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 568 if (distanceS < 0) { 569 continue; 570 } 571 double distanceM = (int) distanceS / 60; 572 if (distanceS % 60 != 0) { 573 distanceM += 1; 574 } 575 sumCost += distanceM * 0.3; 576 } 577 return sumCost; 578 } 579 580 } 581 582 class MobilePhoneInProvinceRule extends CallChargeRule { 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) continue; 588 double distanceM = (int) distanceS / 60; 589 if (distanceS % 60 != 0) distanceM += 1; 590 if (call.getCallType().equals("21")) sumCost += distanceM * 0.3; 591 else if (call.getCallType().equals("22")) { 592 sumCost += distanceM * 0.3; 593 } else if (call.getCallType().equals("23")) { 594 sumCost += distanceM * 0.3; 595 } 596 } 597 return sumCost; 598 } 599 600 } 601 602 class MessageRecord extends CommunicationRecord { 603 604 private String message; 605 606 public String getMessage() { 607 return message; 608 } 609 610 } 611 612 class User { 613 614 private UserRecords userRecords = new UserRecords(); 615 private double balance = 100; 616 private ChargeMode chargeMode; 617 private String number; 618 619 public double calCost() { 620 return chargeMode.calCost(userRecords); 621 } 622 623 public double calBalance() { 624 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 625 } 626 627 public UserRecords getUserRecords() { 628 return userRecords; 629 } 630 631 632 public void setChargeMode(ChargeMode chargeMode) { 633 this.chargeMode = chargeMode; 634 } 635 636 public String getNumber() { 637 return number; 638 } 639 640 public void setNumber(String number) { 641 this.number = number; 642 } 643 644 } 645 646 class Outputtool { 647 public void output(double out) { 648 BigDecimal numb = new BigDecimal(out); 649 out = numb.setScale(2, RoundingMode.HALF_UP).doubleValue(); 650 System.out.print(out); 651 } 652 }View Code
SourceMonitor分析图:
IDEA生成程序类图:
总结:
本题是电信计费系列的第二题,在上一题座机计费的基础上添加了手机计费的功能和计费准则,本题关键点在于添加新继承在原抽象类下的子类。举个例子,CallChargeRule是电信计费的抽象规则类,我们在原来的座机计费中定义了如下三个子类去继承:LandPhoneInlandRule、LandPhoneInlandRule和LandPhoneInCityRule,但是在手机座机并列计费的情况下,对于抽象规则类我们要添加继承在它之下的子类,例如:MobilePhoneInCityRule、MobilePhoneInlandRule、MobilePhoneInProvinceRule。本题中还加入了更多非常复杂的格式判定,对正则表达式的理解和掌握程度有非常大的考察力度。不过我第一步首先还是抄类图,题干中的类图会因为手机类的加入发生变化,我们在第一题的基础上按照同样的方式加入手机通信的付费规则等需要增添的类即可(用户类那些都可以不变的)。
7-3 电信计费系列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中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
输入样例:
在这里给出一组输入。例如:
u-18907910010 3
m-18907910010 13305862264 aaaaaaaaaaaaaaaaaaaaaaa
end
输出样例:
在这里给出相应的输出。例如:
18907910010 0.3 99.7
在这里给出一组输入。例如:
u-18907910010 3
m-18907910010 13305862264 aaaaaaaaaaaa
m-18907910010 13305862264 aaaaaaa.
m-18907910010 13305862264 bb,bbbb
end
输出样例1:
在这里给出相应的输出。例如:
18907910010 0.5 99.5
我的答案:
这道题的测试点居然只有短信计费哈哈哈哈哈,直接上全码:
1 package 电信计费系列3; 2 3 4 5 import java.util.ArrayList; 6 import java.util.Comparator; 7 import java.util.Scanner; 8 import java.util.regex.Matcher; 9 import java.util.regex.Pattern; 10 import java.math.BigDecimal; 11 import java.text.SimpleDateFormat; 12 import java.util.Date; 13 import java.util.Locale; 14 import java.text.ParseException; 15 16 public class 短信计费 { 17 18 public static void main(String[] args) { 19 20 Outputtool outputtool = new Outputtool(); 21 22 Inputdeal inputdeal = new Inputdeal(); 23 24 ArrayList<User> users = new ArrayList<>(); 25 26 Scanner in = new Scanner(System.in); 27 28 String input = in.nextLine(); 29 30 while (!input.equals("end")) { 31 if (1 == inputdeal.check(input)) { 32 inputdeal.writeUser(users, input); 33 } else if (2 == inputdeal.check(input)) { 34 inputdeal.writeRecord(users, input); 35 } 36 input = in.nextLine(); 37 } 38 39 users.sort(new Comparator<User>() { 40 41 @Override 42 public int compare(User u1, User u2) { 43 if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') { 44 return -1; 45 } else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') { 46 return 1; 47 } 48 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 49 return 1; 50 } else { 51 return -1; 52 } 53 } 54 }); 55 56 for (User u : users) { 57 System.out.print(u.getNumber() + " "); 58 outputtool.output(u.calCost()); 59 System.out.print(" "); 60 outputtool.output(u.calBalance()); 61 System.out.println(); 62 63 } 64 65 } 66 67 } 68 69 abstract class ChargeMode { 70 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 71 72 public abstract double calCost(UserRecords userRecords); 73 74 public abstract double getMonthlyRent(); 75 76 public ArrayList<ChargeRule> getChargeRules() { 77 return chargeRules; 78 } 79 80 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 81 this.chargeRules = chargeRules; 82 } 83 } 84 85 class UserRecords { 86 87 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 88 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 89 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 90 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 91 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 92 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 93 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 94 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 95 96 public void addCallingInCityRecords(CallRecord callRecord) { 97 callingInCityRecords.add(callRecord); 98 } 99 100 public void addCallingInProvinceRecords(CallRecord callRecord) { 101 callingInProvinceRecords.add(callRecord); 102 } 103 104 public void addCallingInLandRecords(CallRecord callRecord) { 105 callingInLandRecords.add(callRecord); 106 } 107 108 public void addAnswerInCityRecords(CallRecord callRecord) { 109 answerInCityRecords.add(callRecord); 110 } 111 112 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 113 answerInProvinceRecords.add(callRecord); 114 } 115 116 public void addAnswerInLandRecords(CallRecord callRecord) { 117 answerInLandRecords.add(callRecord); 118 } 119 120 public void addSendMessageRecords(MessageRecord callRecord) { 121 sendMessageRecords.add(callRecord); 122 } 123 124 public void addReceiveMessageRecords(MessageRecord callRecord) { 125 receiveMessageRecords.add(callRecord); 126 } 127 128 public ArrayList<CallRecord> getCallingInCityRecords() { 129 return callingInCityRecords; 130 } 131 132 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 133 this.callingInCityRecords = callingInCityRecords; 134 } 135 136 public ArrayList<CallRecord> getCallingInProvinceRecords() { 137 return callingInProvinceRecords; 138 } 139 140 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 141 this.callingInProvinceRecords = callingInProvinceRecords; 142 } 143 144 public ArrayList<CallRecord> getCallingInLandRecords() { 145 return callingInLandRecords; 146 } 147 148 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 149 this.callingInLandRecords = callingInLandRecords; 150 } 151 152 public ArrayList<CallRecord> getAnswerInCityRecords() { 153 return answerInCityRecords; 154 } 155 156 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 157 this.answerInCityRecords = answerInCityRecords; 158 } 159 160 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 161 return answerInProvinceRecords; 162 } 163 164 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 165 this.answerInProvinceRecords = answerInProvinceRecords; 166 } 167 168 public ArrayList<CallRecord> getAnswerInLandRecords() { 169 return answerInLandRecords; 170 } 171 172 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 173 this.answerInLandRecords = answerInLandRecords; 174 } 175 176 public ArrayList<MessageRecord> getSendMessageRecords() { 177 return sendMessageRecords; 178 } 179 180 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 181 this.sendMessageRecords = sendMessageRecords; 182 } 183 184 public ArrayList<MessageRecord> getReceiveMessageRecords() { 185 return receiveMessageRecords; 186 } 187 188 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 189 this.receiveMessageRecords = receiveMessageRecords; 190 } 191 192 } 193 194 class LandlinePhoneCharging extends ChargeMode { 195 196 private double monthlyRent = 20; 197 198 public LandlinePhoneCharging() { 199 super(); 200 chargeRules.add(new LandPhoneInCityRule()); 201 chargeRules.add(new LandPhoneInProvinceRule()); 202 chargeRules.add(new LandPhoneInlandRule()); 203 } 204 205 @Override 206 public double calCost(UserRecords userRecords) { 207 double sumCost = 0; 208 for (ChargeRule rule : chargeRules) { 209 sumCost += rule.calCost(userRecords); 210 } 211 return sumCost; 212 } 213 214 @Override 215 public double getMonthlyRent() { 216 return monthlyRent; 217 } 218 219 } 220 221 class MobilePhoneCharging extends ChargeMode { 222 223 private double monthlyRent = 15; 224 225 public MobilePhoneCharging() { 226 super(); 227 chargeRules.add(new MobilePhoneInCityRule()); 228 chargeRules.add(new MobilePhoneInProvinceRule()); 229 chargeRules.add(new MobilePhoneInlandRule()); 230 } 231 232 @Override 233 public double calCost(UserRecords userRecords) { 234 double sumCost = 0; 235 for (ChargeRule rule : chargeRules) { 236 sumCost += rule.calCost(userRecords); 237 } 238 return sumCost; 239 } 240 241 @Override 242 public double getMonthlyRent() { 243 return monthlyRent; 244 } 245 246 } 247 248 class MobilePhoneMassageCharging extends ChargeMode { 249 250 private double monthlyRent = 0; 251 252 public MobilePhoneMassageCharging() { 253 super(); 254 chargeRules.add(new MobilePhoneMessageRule()); 255 } 256 257 @Override 258 public double calCost(UserRecords userRecords) { 259 double sumCost = 0; 260 for (ChargeRule rule : chargeRules) { 261 sumCost += rule.calCost(userRecords); 262 } 263 return sumCost; 264 } 265 266 @Override 267 public double getMonthlyRent() { 268 return monthlyRent; 269 } 270 271 } 272 273 class Inputdeal { 274 275 public int check(String input) { 276 if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[13]")) { 277 return 1; 278 } else if (input.matches("[m]-1[0-9]{10}\\s" + "1[0-9]{10}\\s" + "[0-9a-zA-Z\\s\\.,]+")) { 279 return 2; 280 } 281 return 0; 282 } 283 284 public void writeUser(ArrayList<User> users, String input) { 285 User usernew = new User(); 286 String[] inputs = input.split(" "); 287 String num = inputs[0].substring(2); 288 for (User i : users) { 289 if (i.getNumber().equals(num)) { 290 return; 291 } 292 } 293 usernew.setNumber(num); 294 int mode = Integer.parseInt(inputs[1]); 295 if (mode == 0) { 296 usernew.setChargeMode(new LandlinePhoneCharging()); 297 } else if (mode == 1) { 298 usernew.setChargeMode(new MobilePhoneCharging()); 299 } else if (mode == 3) { 300 usernew.setChargeMode(new MobilePhoneMassageCharging()); 301 } 302 users.add(usernew); 303 } 304 305 public void writeRecord(ArrayList<User> users, String input) { 306 String[] inputs = input.split(" "); 307 inputs[0] = inputs[0].substring(2); 308 309 User callu = null, answeru = null; 310 311 String out = inputs[0]; 312 String in = ""; 313 if (inputs.length == 6) { 314 in = inputs[1]; 315 } else if (inputs.length == 7) { 316 in = inputs[1]; 317 } else if (inputs.length == 8) { 318 in = inputs[2]; 319 } else { 320 in = inputs[1]; 321 } 322 323 for (User i : users) { 324 if (i.getNumber().equals(out)) { 325 callu = i; 326 } 327 if (i.getNumber().equals(in)) { 328 answeru = i; 329 } 330 if (callu != null && answeru != null) { 331 break; 332 } 333 } 334 335 if (input.charAt(0) == 'm') { 336 MessageRecord messageRecord = new MessageRecord(input); 337 if (callu != null) { 338 callu.getUserRecords().addSendMessageRecords(messageRecord); 339 ; 340 } 341 if (answeru != null) { 342 callu.getUserRecords().addReceiveMessageRecords(messageRecord); 343 } 344 } 345 346 } 347 348 } 349 350 abstract class CommunicationRecord { 351 protected String callingNumber; 352 protected String answerNumbe; 353 354 public String getCallingNumber() { 355 return callingNumber; 356 } 357 358 public void setCallingNumber(String callingNumber) { 359 this.callingNumber = callingNumber; 360 } 361 362 public String getAnswerNumbe() { 363 return answerNumbe; 364 } 365 366 public void setAnswerNumbe(String answerNumbe) { 367 this.answerNumbe = answerNumbe; 368 } 369 370 } 371 372 abstract class ChargeRule { 373 374 abstract public double calCost(UserRecords userRecords); 375 376 } 377 378 class CallRecord extends CommunicationRecord { 379 private Date startTime; 380 private Date endTime; 381 private String callingAddressAreaCode; 382 private String answerAddressAreaCode; 383 384 public String getCallType() { 385 String type = ""; 386 if (callingAddressAreaCode.equals("0791")) { 387 type = type.concat("1"); 388 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 389 type = type.concat("2"); 390 } else { 391 type = type.concat("3"); 392 } 393 394 if (answerAddressAreaCode.equals("0791")) { 395 type = type.concat("1"); 396 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 397 type = type.concat("2"); 398 } else { 399 type = type.concat("3"); 400 } 401 402 return type; 403 } 404 405 public CallRecord(String[] inputs) { 406 super(); 407 408 char type = inputs[0].charAt(0); 409 410 String sd = null, st = null, ed = null, et = null; 411 412 if (type == 't') { 413 if (inputs.length == 6) { 414 sd = inputs[2]; 415 st = inputs[3]; 416 ed = inputs[4]; 417 et = inputs[5]; 418 callingAddressAreaCode = inputs[0].substring(0, 4); 419 answerAddressAreaCode = inputs[1].substring(0, 4); 420 } else if (inputs.length == 7) { 421 sd = inputs[3]; 422 st = inputs[4]; 423 ed = inputs[5]; 424 et = inputs[6]; 425 if (inputs[0].charAt(0) != '0') { 426 if (inputs[2].length() == 10) { 427 answerAddressAreaCode = inputs[2].substring(0, 3); 428 } else { 429 answerAddressAreaCode = inputs[2].substring(0, 4); 430 } 431 callingAddressAreaCode = inputs[1]; 432 } else { 433 if (inputs[0].length() == 10) { 434 callingAddressAreaCode = inputs[0].substring(0, 3); 435 } else { 436 callingAddressAreaCode = inputs[0].substring(0, 4); 437 } 438 answerAddressAreaCode = inputs[2]; 439 } 440 } else if (inputs.length == 8) { 441 sd = inputs[4]; 442 st = inputs[5]; 443 ed = inputs[6]; 444 et = inputs[7]; 445 callingAddressAreaCode = inputs[1]; 446 answerAddressAreaCode = inputs[3]; 447 } 448 } else if (type == 'm') { 449 450 } 451 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 452 try { 453 startTime = simpleDateFormat.parse(sd + " " + st); 454 endTime = simpleDateFormat.parse(ed + " " + et); 455 } catch (ParseException e) { 456 } 457 458 } 459 460 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 461 super(); 462 this.startTime = startTime; 463 this.endTime = endTime; 464 this.callingAddressAreaCode = callingAddressAreaCode; 465 this.answerAddressAreaCode = answerAddressAreaCode; 466 } 467 468 public Date getStartTime() { 469 return startTime; 470 } 471 472 public void setStartTime(Date startTime) { 473 this.startTime = startTime; 474 } 475 476 public Date getEndTime() { 477 return endTime; 478 } 479 480 public void setEndTime(Date endTime) { 481 this.endTime = endTime; 482 } 483 484 public String getCallingAddressAreaCode() { 485 return callingAddressAreaCode; 486 } 487 488 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 489 this.callingAddressAreaCode = callingAddressAreaCode; 490 } 491 492 public String getAnswerAddressAreaCode() { 493 return answerAddressAreaCode; 494 } 495 496 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 497 this.answerAddressAreaCode = answerAddressAreaCode; 498 } 499 } 500 501 abstract class CallChargeRule extends ChargeRule { 502 503 } 504 505 class LandPhoneInCityRule extends CallChargeRule { 506 507 @Override 508 public double calCost(UserRecords userRecords) { 509 double sumCost = 0; 510 for (CallRecord call : userRecords.getCallingInCityRecords()) { 511 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 512 if (distanceS < 0) { 513 continue; 514 } 515 double distanceM = (int) distanceS / 60; 516 if (distanceS % 60 != 0) { 517 distanceM += 1; 518 } 519 if (call.getCallType().equals("11")) { 520 sumCost += distanceM * 0.1; 521 } else if (call.getCallType().equals("12")) { 522 sumCost += distanceM * 0.3; 523 } else if (call.getCallType().equals("13")) { 524 sumCost += distanceM * 0.6; 525 } 526 } 527 return sumCost; 528 } 529 530 } 531 532 class LandPhoneInlandRule extends CallChargeRule { 533 534 @Override 535 public double calCost(UserRecords userRecords) { 536 double sumCost = 0; 537 for (CallRecord call : userRecords.getCallingInLandRecords()) { 538 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 539 if (distanceS < 0) { 540 continue; 541 } 542 double distanceM = (int) distanceS / 60; 543 if (distanceS % 60 != 0) { 544 distanceM += 1; 545 } 546 sumCost += distanceM * 0.6; 547 } 548 return sumCost; 549 } 550 551 } 552 553 class LandPhoneInProvinceRule extends CallChargeRule { 554 555 @Override 556 public double calCost(UserRecords userRecords) { 557 double sumCost = 0; 558 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 559 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 560 if (distanceS < 0) { 561 continue; 562 } 563 double distanceM = (int) distanceS / 60; 564 if (distanceS % 60 != 0) { 565 distanceM += 1; 566 } 567 sumCost += distanceM * 0.3; 568 } 569 return sumCost; 570 } 571 572 } 573 574 class MobilePhoneInCityRule extends CallChargeRule { 575 576 @Override 577 public double calCost(UserRecords userRecords) { 578 double sumCost = 0; 579 for (CallRecord call : userRecords.getCallingInCityRecords()) { 580 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 581 if (distanceS < 0) { 582 continue; 583 } 584 double distanceM = (int) distanceS / 60; 585 if (distanceS % 60 != 0) { 586 distanceM += 1; 587 } 588 if (call.getCallType().equals("11")) { 589 sumCost += distanceM * 0.1; 590 } else if (call.getCallType().equals("12")) { 591 sumCost += distanceM * 0.2; 592 } else if (call.getCallType().equals("13")) { 593 sumCost += distanceM * 0.3; 594 } 595 596 } 597 return sumCost; 598 } 599 600 } 601 602 class MobilePhoneInlandRule extends CallChargeRule { 603 604 @Override 605 public double calCost(UserRecords userRecords) { 606 double sumCost = 0; 607 for (CallRecord call : userRecords.getCallingInLandRecords()) { 608 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 609 if (distanceS < 0) { 610 continue; 611 } 612 double distanceM = (int) distanceS / 60; 613 if (distanceS % 60 != 0) { 614 distanceM += 1; 615 } 616 sumCost += distanceM * 0.6; 617 } 618 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 619 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 620 if (distanceS < 0) { 621 continue; 622 } 623 double distanceM = (int) distanceS / 60; 624 if (distanceS % 60 != 0) { 625 distanceM += 1; 626 } 627 sumCost += distanceM * 0.3; 628 } 629 return sumCost; 630 } 631 632 } 633 634 class MobilePhoneInProvinceRule extends CallChargeRule { 635 636 @Override 637 public double calCost(UserRecords userRecords) { 638 double sumCost = 0; 639 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 640 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 641 if (distanceS < 0) { 642 continue; 643 } 644 double distanceM = (int) distanceS / 60; 645 if (distanceS % 60 != 0) { 646 distanceM += 1; 647 } 648 if (call.getCallType().equals("21")) { 649 sumCost += distanceM * 0.3; 650 } else if (call.getCallType().equals("22")) { 651 sumCost += distanceM * 0.3; 652 } else if (call.getCallType().equals("23")) { 653 sumCost += distanceM * 0.3; 654 } 655 } 656 return sumCost; 657 } 658 659 } 660 661 class MobilePhoneMessageRule extends CallChargeRule { 662 663 @Override 664 public double calCost(UserRecords userRecords) { 665 double sumCost = 0; 666 int number = 0; 667 for (MessageRecord m : userRecords.getSendMessageRecords()) { 668 int length = m.getMessage().length(); 669 if (length <= 10) { 670 number++; 671 } else { 672 number += length / 10; 673 if (length % 10 != 0) { 674 number++; 675 } 676 } 677 } 678 if (number <= 3) { 679 sumCost = number * 0.1; 680 } else if (number <= 5) { 681 sumCost = 0.3 + 0.2 * (number - 3); 682 } else { 683 sumCost = 0.7 + 0.3 * (number - 5); 684 } 685 return sumCost; 686 } 687 688 } 689 690 class MessageRecord extends CommunicationRecord { 691 692 private String message; 693 694 public MessageRecord(String input) { 695 super(); 696 this.message = input.substring(26); 697 } 698 699 public String getMessage() { 700 return message; 701 } 702 703 public void setMessage(String message) { 704 this.message = message; 705 } 706 } 707 708 class User { 709 710 private UserRecords userRecords = new UserRecords(); 711 private double balance = 100; 712 private ChargeMode chargeMode; 713 private String number; 714 715 public double calCost() { 716 return chargeMode.calCost(userRecords); 717 } 718 719 public double calBalance() { 720 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 721 } 722 723 public UserRecords getUserRecords() { 724 return userRecords; 725 } 726 727 public void setUserRecords(UserRecords userRecords) { 728 this.userRecords = userRecords; 729 } 730 731 public ChargeMode getChargeMode() { 732 return chargeMode; 733 } 734 735 public void setChargeMode(ChargeMode chargeMode) { 736 this.chargeMode = chargeMode; 737 } 738 739 public String getNumber() { 740 return number; 741 } 742 743 public void setNumber(String number) { 744 this.number = number; 745 } 746 747 } 748 749 class Outputtool { 750 751 @SuppressWarnings("deprecation") 752 public void output(double out) { 753 // java.text.DecimalFormat df=new java.text.DecimalFormat("#.##"); 754 // String a=df.format(out); 755 // System.out.print(a); 756 BigDecimal numb = new BigDecimal(out); 757 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 758 System.out.print(out); 759 } 760 }View Code
SourceMonitor分析图:
IDEA生成程序类图:
总结:
这题其实可以偷大懒。本题的测试点仅有短信计费,和手机计费不同,我们可以像考虑座机计费的构成那样去思考,而无需进一步完善先前的体系。根据类图,我们依次建立对应的类及其继承方法,再增添短信计费需要新增的类:如MobilePhoneMassageCharging、MobilePhoneMessageRule等等。本题使用的方法和结构与前两题类似,按照同样的思路去做就行,对此我们不做过多讨论。
踩坑心得
在过去一个月的学习中,我再次总结了如下几个自己容易犯的错误:
1、设计类的时候忘记添加构造函数。一般题目中其实很少用到构造函数,但作为学习的过程,添加构造函数也是创建一个完整类的一部分。
2、类中和方法漏写和判断情况缺失,就算是有类图进行参考,这种情况还是出现了。电信计费需要判断的东西非常多,容易漏掉导致测试点报错.
3、对正则表达式的理解匮乏。正则表达式是经常应用在function(我一般用它来判断输入格式的正误)的一种判断方法,正则表达式的外围一定要添加“ ”。
4、对新知识的掌握尚未完全。在这个阶段的学习中,我们在类与对象、方法基本构建、继承、多态的使用的基础上,新学习并着重强化了对抽象类、抽象方法的构造,接口的加入(这个在实验里比较多),还有javaFX的使用。新知较多,使用起来不够熟练。
5、相关经验较少,对电信计费的实际生活体系不够了解,导致做题思维较慢。
改进意见
在看到题目时,首先要分析题目中蕴含的结构。比如电信计费都给了类图,相当于已经告知了基本结构,那我们就要分析都有哪些类,创建什么对象,继承关系是怎样的,子类的方法哪些可以直接继承抽象父类使用,哪些是自己独有的方法。其次,要扎实自己的基本功。思路清晰的同时,要学会根据不同的题干环境进行变通。比如第一题,建立了用户方面,还需要建立通讯记录,既然是电信计费,那就要建立对应的计费准则。第一题仅考虑电信计费中的座机,第二题就要学会在其基础上加入对手机的操作,第三题由于出题的原因可以简略很多。
总结
通过SourceMontior检测发现,自己写的部分代码各项数值的测量值和规定的范围相差甚远,证明自己还可以有很多的提升空间。Java是一门以面向对象为主的编程语言,所以对类和对象及其方法的要求十分看重。在今后课程的学习中,我们要学会三步走分析法:着重分析题目需求、弄懂类中包含的内容以及方法的编写,最后搞清各个功能代码块之间的联系。通过第三阶段java课程的学习,我对java这一门编程语言有了本质上的了解,明白了类与对象作为java语言内核的原因。在不断吸收新知的同时,也发现了自己的代码有很多的漏洞,未来一定会进行改正,变得越来越好。老师上课质量很高,希望老师能将上课讲解得部分代码传到群内方便我们课后复习就更好啦!
标签:inputs,return,String,double,ArrayList,BLOG,public From: https://www.cnblogs.com/aolibugei/p/16952869.html