面向对象程序设计第12-15周内容总结
前言
本次PTA题目集09-11主要围绕电信计费系统展开,涉及到的知识点包括继承与多态、对象容器、正则表达式等多方面的内容。每个题目集均以1+N的模式,即1道电信计费系统+N道基础题型,题量适中,其中电信计费系统难度较高,基础题型难度较低。
设计与分析
题目集09
关于整个系统的设计,我将其分为Main、用户端、计费方式、通讯记录四个板块。
1.Main
1 import java.util.Date; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.Comparator; 7 import java.util.Scanner; 8 9 public class Main { 10 11 public static Scanner input = new Scanner(System.in); 12 public static String uPattern = "[u]-0791[0-9]{7,8}\\s[0-2]"; 13 public static String tPattern = "[t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s" + 14 "((([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?" + 15 "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" + 16 "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + 17 "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" + 18 "((([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])\\.(" + 19 "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" + 20 "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + 21 "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; 22 23 public static String exitPattern = "end"; 24 public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); 25 26 public static void main(String[] args) { 27 28 ArrayList<User> users = new ArrayList<User>(); 29 boolean isT = false; 30 31 while(true) { 32 String string = input.nextLine(); 33 String[] strings = string.split(" "); 34 if (string.matches(uPattern) && !isT) { 35 User user = new User(strings); 36 if (!users.contains(user)) { 37 users.add(user); 38 } 39 } else if (string.matches(tPattern)) { 40 String userNumber = strings[0].substring(2); 41 for (User each:users) { 42 if (each.getNumber().equals(userNumber)) { 43 CallRecord callRecord = new CallRecord(); 44 String startDateString = strings[2] + " " + strings[3]; 45 String endDateString = strings[4] + " " + strings[5]; 46 Date startDate; 47 Date endDate; 48 try { 49 startDate = sdf.parse(startDateString); 50 } catch (ParseException e) { 51 continue; 52 } 53 try { 54 endDate = sdf.parse(endDateString); 55 } catch (ParseException e) { 56 continue; 57 } 58 callRecord.setCallingNumber(strings[0].substring(2)); 59 callRecord.setAnswerNumber(strings[1]); 60 callRecord.setStartTime(startDate); 61 callRecord.setEndTime(endDate); 62 callRecord.setCallingAddressAreaCode("0791"); 63 if (strings[1].substring(0, 4).matches("0791")) { 64 callRecord.setAnswerAddressAreaCode("0791"); 65 each.getUserRecords().addCallingInCityRecords(callRecord); 66 } else if (strings[1].substring(0, 4).matches("07(9[0-9]{1}|01)")) { 67 callRecord.setAnswerAddressAreaCode(strings[1].substring(0, 4)); 68 each.getUserRecords().addCallingInProvinceRecords(callRecord); 69 } else { 70 callRecord.setAnswerAddressAreaCode(strings[1].substring(0, 4)); 71 each.getUserRecords().addCallingInLandRecords(callRecord); 72 } 73 isT = true; 74 } 75 } 76 } else if (string.matches(exitPattern)) { 77 break; 78 } 79 } 80 Collections.sort(users, new Comparator<User>() { 81 public int compare(User user1, User user2) { 82 return user1.getNumber().compareTo(user2.getNumber()); 83 } 84 }); 85 for (User each:users) { 86 System.out.println(each.getNumber() + " " + String.format("%.1f", each.calCost()) + " " + String.format("%.1f", each.calBalance())); 87 } 88 89 } 90 91 }
我选择将信息输入工作放在Main函数中完成;
如源码第32-33行所示,我在Main中先一行行读入输入数据,当数据读入成功时,我通过split函数将接收到的数据分割,这样可以更方便的提取需要的信息;
如源码第34、39、76行所示,我将每次读到的行数据进行格式比对,如果遇到格式错误就直接跳过后续步骤,开始读入下一行数据;
如源码第34-38行所示,此时如果模式为u(开通),则程序会在用户库中检索号码是否已被开通,如果没开通,程序将会通过分割后所得的数据实例化一个带参的User对象,并将之写入到用户库中;如果未被开通,则会直接跳过后续步骤,开始读入下一行数据;
附:User的有参构造函数:
1 public User(String[] strings) { 2 number = strings[0].substring(2); 3 if (strings[1].equals("0")) { 4 chargeMode = new LandlinePhoneCharging(); 5 } 6 balance = 100; 7 }
如源码第39-75行所示,此时如果模式为t(通讯),程序会在用户库中检索主叫号码是否已被开通;
如源码第42-72行所示,如果已开通,程序会实例化一个带参的CallRecord对象,根据分割后所得的数据完善这个对象的所有信息,并通过if判断,将它写入主叫号码的对应通话记录中,然后将输入模式修改为t输入模式(源码第73行),此后若读入u模式数据也会被判定为格式错误;如果未被开通,则会直接跳过后续步骤,开始读入下一行数据;
如源码第80-87行所示,当信息完全录入完毕后,程序通过Collection.sort()函数将用户库中的用户按照号码大小排序,然后依次计算当月资费信息并输出。
2.通讯记录
通讯记录类的作用仅为保存通讯信息,故只需要完成数据的写入和输出,即完成getters与setters方法便可,不多做赘述。
3.计费方式
计费方式的核心便是calCost()函数,其中CallChargeRule类与其下属类的calCost()均是对ChargeRule中的复写;
我对于calCost()函数的设计为,传入一个泛型为通讯记录类的容器,然后分别计算容器中所有通讯记录的资费并累加后传回,对于不同的计费类型(如LandPhoneInlandRule、LandPhoneInProvinceRule等),计算资费的方式会有所不同;
以下是LandPhoneInCityRule类的源码,仅供参考:
1 import java.util.ArrayList; 2 3 public class LandPhoneInCityRule extends CallChargeRule{ 4 5 public LandPhoneInCityRule() { 6 // TODO Auto-generated constructor stub 7 } 8 9 @Override 10 public double calCost(ArrayList<CallRecord> callRecords) { 11 double cost = 0; 12 for (CallRecord each:callRecords) { 13 long startTime = each.getStartTime().getTime(); 14 long endTime = each.getEndTime().getTime(); 15 int minute = (int)(endTime - startTime) / 60000; 16 int Second = (int)(endTime - startTime) % 60000 / 1000; 17 if (Second > 0) { 18 minute ++; 19 } 20 cost += minute * 0.1; 21 } 22 return cost; 23 } 24 25 }
4.用户端
用户端的主要作用为储存通讯数据,统计并输出资费信息,其中最为关键的内容为ChargeMode类;
关于chargeMode类,我的设计为:
其私有属性ArrayList<ChargeRule>用于存储相关的具体计费模式,这一步我将它放在实例化时实现;
其calCost()方法需要传入一个UserRecord对象,然后对于该对象中的不同类型的通话记录采用对应的ChargeRule进行资费计算;
以LandlinePhoneCharging为例,以下是其源码与相应说明:
1 public class LandlinePhoneCharging extends ChargeMode { 2 3 private double monthlyRent = 20; 4 5 public LandlinePhoneCharging() { 6 super.getChargeRules().add(new LandPhoneInCityRule()); 7 super.getChargeRules().add(new LandPhoneInProvinceRule()); 8 super.getChargeRules().add(new LandPhoneInlandRule()); 9 } 10 11 @Override 12 public double calCost(UserRecords userRecords) { 13 double cost = 0; 14 cost += super.getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords()); 15 cost += super.getChargeRules().get(1).calCost(userRecords.getCallingInProvinceRecords()); 16 cost += super.getChargeRules().get(2).calCost(userRecords.getCallingInLandRecords()); 17 return cost; 18 } 19 20 @Override 21 public double getMonthlyRent() { 22 return monthlyRent; 23 } 24 25 }
如源码第5-9行,当LandlinePhoneCharging类实例化时,程序将会将LandPhoneInCityRule等计费方式写入父类中的ArrayList<ChargeRule>;
如源码第12-18行,程序提取出userRecords中的通讯记录,并调用ArrayList<ChargeRule>中的计费方式对其进行资费计算并累加后传回。
题目集10
题目集10中的电信计费问题相比于题目集9新增了手机号码开通与手机主叫功能,对此我仅在题目集9中代码的基础上修改了Main,同时新增了与手机相关的几种计费方式,因此本部分对于题目集9中已有的内容不再赘述。
1.Main
1 import java.util.Date; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.Comparator; 7 import java.util.Scanner; 8 9 public class Main { 10 11 public static Scanner input = new Scanner(System.in); 12 public static String uPattern0 = "[u]-0791[0-9]{7,8}\\s[0]"; 13 public static String uPattern1 = "[u]-1[0-9]{10}\\s[1]"; 14 public static String tPattern00 = "[t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s"; 15 public static String tPattern01 = "[t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s"; 16 public static String tPattern10 = "[t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s"; 17 public static String tPattern11 = "[t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s"; 18 public static String timePattern = "" + 19 "((([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?" + 20 "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" + 21 "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + 22 "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" + 23 "((([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])\\.(" + 24 "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" + 25 "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + 26 "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; 27 28 public static String exitPattern = "end"; 29 public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); 30 31 public static void main(String[] args) { 32 33 ArrayList<User> users = new ArrayList<User>(); 34 boolean isT = false; 35 36 while(true) { 37 String string = input.nextLine(); 38 String[] strings = string.split(" "); 39 if ((string.matches(uPattern0) || string.matches(uPattern1)) && !isT) { 40 User user = new User(string); 41 if (!users.contains(user)) { 42 users.add(user); 43 } 44 } else if (string.matches(tPattern00 + timePattern)) { 45 String userNumber = strings[0].substring(2); 46 for (User each:users) { 47 if (each.getNumber().equals(userNumber)) { 48 CallRecord callRecord = new CallRecord(); 49 String startDateString = strings[2] + " " + strings[3]; 50 String endDateString = strings[4] + " " + strings[5]; 51 Date startDate; 52 Date endDate; 53 try { 54 startDate = sdf.parse(startDateString); 55 } catch (ParseException e) { 56 continue; 57 } 58 try { 59 endDate = sdf.parse(endDateString); 60 } catch (ParseException e) { 61 continue; 62 } 63 callRecord.setCallingNumber(strings[0].substring(2)); 64 callRecord.setAnswerNumber(strings[2]); 65 callRecord.setStartTime(startDate); 66 callRecord.setEndTime(endDate); 67 callRecord.setCallingAddressAreaCode("0791"); 68 if (strings[1].substring(0, 4).matches("0791")) { 69 callRecord.setAnswerAddressAreaCode("0791"); 70 each.getUserRecords().addCallToCityRecords(callRecord); 71 } else if (strings[1].substring(0, 4).matches("07(9[0-9]{1}|01)")) { 72 callRecord.setAnswerAddressAreaCode(strings[1].substring(0, 4)); 73 each.getUserRecords().addCallToProvinceRecords(callRecord); 74 } else { 75 callRecord.setAnswerAddressAreaCode(strings[1].substring(0, 4)); 76 each.getUserRecords().addCallToLandRecords(callRecord); 77 } 78 isT = true; 79 } 80 } 81 } else if (string.matches(tPattern01 + timePattern)) { 82 String userNumber = strings[0].substring(2); 83 String answerNumber = strings[1]; 84 for (User each:users) { 85 if (each.getNumber().equals(userNumber)) { 86 CallRecord callRecord = new CallRecord(); 87 String startDateString = strings[3] + " " + strings[4]; 88 String endDateString = strings[5] + " " + strings[6]; 89 Date startDate; 90 Date endDate; 91 try { 92 startDate = sdf.parse(startDateString); 93 } catch (ParseException e) { 94 continue; 95 } 96 try { 97 endDate = sdf.parse(endDateString); 98 } catch (ParseException e) { 99 continue; 100 } 101 callRecord.setCallingNumber(strings[0].substring(2)); 102 callRecord.setAnswerNumber(answerNumber); 103 callRecord.setStartTime(startDate); 104 callRecord.setEndTime(endDate); 105 callRecord.setCallingAddressAreaCode("0791"); 106 callRecord.setAnswerAddressAreaCode(strings[2]); 107 if (callRecord.getAnswerAddressAreaCode().matches("0791")) { 108 each.getUserRecords().addCallToCityRecords(callRecord); 109 } else if (callRecord.getAnswerAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 110 each.getUserRecords().addCallToProvinceRecords(callRecord); 111 } else { 112 each.getUserRecords().addCallToLandRecords(callRecord); 113 } 114 isT = true; 115 } 116 if (each.getNumber().equals(answerNumber)) { 117 CallRecord callRecord = new CallRecord(); 118 String startDateString = strings[3] + " " + strings[4]; 119 String endDateString = strings[5] + " " + strings[6]; 120 Date startDate; 121 Date endDate; 122 try { 123 startDate = sdf.parse(startDateString); 124 } catch (ParseException e) { 125 continue; 126 } 127 try { 128 endDate = sdf.parse(endDateString); 129 } catch (ParseException e) { 130 continue; 131 } 132 callRecord.setCallingNumber(strings[0].substring(2)); 133 callRecord.setAnswerNumber(answerNumber); 134 callRecord.setStartTime(startDate); 135 callRecord.setEndTime(endDate); 136 callRecord.setCallingAddressAreaCode("0791"); 137 callRecord.setAnswerAddressAreaCode(strings[2]); 138 if (!callRecord.getAnswerAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 139 each.getUserRecords().addAnswerOutOfProvinceRecords(callRecord); 140 } 141 isT = true; 142 } 143 } 144 } else if (string.matches(tPattern10 + timePattern)) { 145 String userNumber = strings[0].substring(2); 146 String answerNumber = strings[1]; 147 for (User each:users) { 148 if (each.getNumber().equals(userNumber)) { 149 CallRecord callRecord = new CallRecord(); 150 String startDateString = strings[3] + " " + strings[4]; 151 String endDateString = strings[5] + " " + strings[6]; 152 Date startDate; 153 Date endDate; 154 try { 155 startDate = sdf.parse(startDateString); 156 } catch (ParseException e) { 157 continue; 158 } 159 try { 160 endDate = sdf.parse(endDateString); 161 } catch (ParseException e) { 162 continue; 163 } 164 callRecord.setCallingNumber(strings[0].substring(2)); 165 callRecord.setAnswerNumber(answerNumber); 166 callRecord.setStartTime(startDate); 167 callRecord.setEndTime(endDate); 168 callRecord.setCallingAddressAreaCode(strings[1]); 169 callRecord.setAnswerAddressAreaCode(strings[2].substring(0, 4)); 170 if (callRecord.getCallingAddressAreaCode().matches("0791")) { 171 if (callRecord.getAnswerAddressAreaCode().matches("0791")) { 172 each.getUserRecords().addCallToCityRecords(callRecord); 173 } else if (callRecord.getAnswerAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 174 each.getUserRecords().addCallToProvinceRecords(callRecord); 175 } else { 176 each.getUserRecords().addCallToLandRecords(callRecord); 177 } 178 } else if (callRecord.getCallingAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 179 each.getUserRecords().addCallOutOfCityRecords(callRecord); 180 } else { 181 each.getUserRecords().addCallOutOfProvinceRecords(callRecord); 182 } 183 isT = true; 184 } 185 } 186 } else if (string.matches(tPattern11 + timePattern)) { 187 String userNumber = strings[0].substring(2); 188 String answerNumber = strings[2]; 189 for (User each:users) { 190 if (each.getNumber().equals(userNumber)) { 191 CallRecord callRecord = new CallRecord(); 192 String startDateString = strings[4] + " " + strings[5]; 193 String endDateString = strings[6] + " " + strings[7]; 194 Date startDate; 195 Date endDate; 196 try { 197 startDate = sdf.parse(startDateString); 198 } catch (ParseException e) { 199 continue; 200 } 201 try { 202 endDate = sdf.parse(endDateString); 203 } catch (ParseException e) { 204 continue; 205 } 206 callRecord.setCallingNumber(strings[0].substring(2)); 207 callRecord.setAnswerNumber(answerNumber); 208 callRecord.setStartTime(startDate); 209 callRecord.setEndTime(endDate); 210 callRecord.setCallingAddressAreaCode(strings[1]); 211 callRecord.setAnswerAddressAreaCode(strings[3]); 212 if (callRecord.getCallingAddressAreaCode().matches("0791")) { 213 if (callRecord.getAnswerAddressAreaCode().matches("0791")) { 214 each.getUserRecords().addCallToCityRecords(callRecord); 215 } else if (callRecord.getAnswerAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 216 each.getUserRecords().addCallToProvinceRecords(callRecord); 217 } else { 218 each.getUserRecords().addCallToLandRecords(callRecord); 219 } 220 } else if (callRecord.getCallingAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 221 each.getUserRecords().addCallOutOfCityRecords(callRecord); 222 } else { 223 each.getUserRecords().addCallOutOfProvinceRecords(callRecord); 224 } 225 isT = true; 226 } 227 if (each.getNumber().equals(answerNumber)) { 228 CallRecord callRecord = new CallRecord(); 229 String startDateString = strings[4] + " " + strings[5]; 230 String endDateString = strings[6] + " " + strings[7]; 231 Date startDate; 232 Date endDate; 233 try { 234 startDate = sdf.parse(startDateString); 235 } catch (ParseException e) { 236 continue; 237 } 238 try { 239 endDate = sdf.parse(endDateString); 240 } catch (ParseException e) { 241 continue; 242 } 243 callRecord.setCallingNumber(strings[0].substring(2)); 244 callRecord.setAnswerNumber(answerNumber); 245 callRecord.setStartTime(startDate); 246 callRecord.setEndTime(endDate); 247 callRecord.setCallingAddressAreaCode(strings[1]); 248 callRecord.setAnswerAddressAreaCode(strings[3]); 249 if (!callRecord.getAnswerAddressAreaCode().matches("0791") && !callRecord.getAnswerAddressAreaCode().matches("07(9[0-9]{1}|01)")) { 250 each.getUserRecords().addAnswerOutOfProvinceRecords(callRecord); 251 } 252 isT = true; 253 } 254 } 255 } else if (string.matches(exitPattern)) { 256 break; 257 } 258 } 259 Collections.sort(users, new Comparator<User>() { 260 public int compare(User user1, User user2) { 261 return user1.getNumber().compareTo(user2.getNumber()); 262 } 263 }); 264 for (User each:users) { 265 System.out.println(each.getNumber() + " " + String.format("%.1f", each.calCost()) + " " + String.format("%.1f", each.calBalance())); 266 } 267 268 } 269 270 }
如源码12-17行所示,本次迭代后的Main的输入模式在原有的座机开通、座机主叫的基础上新增了手机开通、手机主叫,同时座机主叫和手机主叫又被细分为了座机呼叫座机(tPattern00)、座机呼叫手机(tPattern01)、手机呼叫座机(tPattern10)和手机呼叫手机(tPattern11);
在不同的模式下,程序会采用不同的方式处理输入数据(座机呼叫座机(44-80行)、座机呼叫手机(81-143行)、手机呼叫座机(144-185行)和手机呼叫手机(185-251行)),使之能正确地构造出User类,同时构造CallRecord的方式也会略有改变。
附:User的新的有参构造函数:
1 public User(String string) { 2 if (string.matches(Main.uPattern0)) { 3 String[] strings = string.split("\\s"); 4 number = strings[0].substring(2); 5 chargeMode = new LandLinePhoneCharging(); 6 } else if (string.matches(Main.uPattern1)) { 7 number = string.substring(2, 13); 8 if (string.charAt(14) == '1') { 9 chargeMode = new MobilePhoneCharging(); 10 } 11 } 12 }
2.计费方式
本次迭代新增了上图中与“MobilePhone”相关的类,同时重命名了LandPhoneInCityRule等原有类;
MobilePhoneCallOutOfCityRule等类的格式与内容与先前的LandPhoneInCityRule等类区别不大,故不多做展示;
calCost()函数新增了计算省外被叫资费的功能(其实就是多加了两行代码);
题目集11
本题中的电信计费系统省略了原有的内容,仅保留了新增的短信功能其实现方式与原来并无不同,故此处仅展示改动后的Main与短信计费模式示例SendMessageRule的源码
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.Comparator; 4 import java.util.Scanner; 5 6 public class Main { 7 8 public static Scanner input = new Scanner(System.in); 9 public static String uPattern = "[u]-1[0-9]{10}\\s[3]"; 10 public static String tPattern = "[m]-1[0-9]{10}\\s" + "1[0-9]{10}\\s" + "(\\d|\\s|[a-z]|[A-Z]|,|.){1,}"; 11 12 public static String exitPattern = "end"; 13 14 public static void main(String[] args) { 15 16 ArrayList<User> users = new ArrayList<User>(); 17 boolean isT = false; 18 19 while(true) { 20 String string = input.nextLine(); 21 if (string.matches(uPattern) && !isT) { 22 User user = new User(string); 23 if (!users.contains(user)) { 24 users.add(user); 25 } 26 } else if (string.matches(tPattern)) { 27 String userNumber = string.substring(2, 13); 28 String answerNumber = string.substring(14, 25); 29 for (User each:users) { 30 if (each.getNumber().equals(userNumber)) { 31 MessageRecord messageRecord = new MessageRecord(); 32 messageRecord.setCallingNumber(userNumber); 33 messageRecord.setAnswerNumber(answerNumber); 34 messageRecord.setMessage(string.substring(26)); 35 each.getUserRecords().addSendMessageRecords(messageRecord); 36 isT = true; 37 } 38 } 39 } else if (string.matches(exitPattern)) { 40 break; 41 } 42 } 43 Collections.sort(users, new Comparator<User>() { 44 public int compare(User user1, User user2) { 45 return user1.getNumber().compareTo(user2.getNumber()); 46 } 47 }); 48 for (User each:users) { 49 System.out.println(each.getNumber() + " " + String.format("%.1f", each.calCost()) + " " + String.format("%.1f", each.calBalance())); 50 } 51 52 } 53 54 }
1 import java.util.ArrayList; 2 3 public class SendMessageRule extends MessageChargeRule{ 4 5 public SendMessageRule() { 6 // TODO Auto-generated constructor stub 7 } 8 9 @Override 10 public double calCost(ArrayList<MessageRecord> messageRecords) { 11 double cost = 0; 12 int num = 0; 13 for (MessageRecord each:messageRecords) { 14 int length = each.getMessage().length(); 15 num += length / 10; 16 if (length / 10.0 != 0) { 17 num += 1; 18 } 19 } 20 if (num <= 3) { 21 cost = num * 0.1; 22 } else if (num <= 5) { 23 cost = num * 0.2 - 0.3; 24 } else { 25 cost = num * 0.3 - 0.8; 26 } 27 return cost; 28 } 29 30 }
注:我设计的短信计费方式为先计算所有短信经过换算后的实际条数,然后再按照总信息条数所在区间计算资费。
采坑心得
由于我的设计风格为先在脑中构建出整个程序的架构,并且设计较为严谨,故我的程序大多为一遍过,所能分享的坑点不多;
1.正则表达式对于程序运行结果的影响可以说是决定性的,绝对不能出错;
2.程序设计需要贴合实际,如电信计费系统在开通号码时需要检测号码是否已存在,这类附加功能往往会在PTA评分时占有多个测点;
3.题目集9和题目集10中的电信通讯系统有1个大坑:固话区号可能为3或4位,算上号码也就是11或12位。为了方便从输入流中提取各项数据,我们需要对输入数据进行分割,但由于String.substract()需要通过下标号精准切割,而固话号码位数不定,所以我使用split(" ")的方式直接切割字符串,这样便不用考虑固话号码的位数问题。
改进建议
测试样例太少,建议增加一些困难测点的测试样例
总结
1.作为一个合格的程序员需要熟练掌握正则表达式。正则的使用率在程序设计工作中非常高,熟练掌握后可以大大减轻一些格式判定方面的工作量;
2.在进行代码的编写之前做好预设计工作。预设计工作是程序编写过程中非常重要的一环,就像建房子前先画图纸一样,在打开IDE前预先构想好各种类之间的关联关系,可以帮助减少可能出现的逻辑问题,同时在编写时事半功倍。
posted on 2022-06-15 23:51 ILoveFishC 阅读(37) 评论(0) 收藏 举报
浙公网安备 33010602011771号