面向对象程序设计第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)    收藏  举报

导航