标签:12 15 String callRecord public 面向对象 源码 each strings
(1)前言:总结之前所涉及到的知识点、题量、难度等情况
(2)设计与分析:重点对题目的提交源码进行分析,可参考SourceMonitor的生成报表内容以及PowerDesigner的相应类图,要有相应的解释和心得(做到有图有真相),本次Blog必须分析PTA中的三个资费题目
(3)采坑心得:对源码的提交过程中出现的问题及心得进行总结,务必做到详实,拿数据、源码及测试结果说话,切忌假大空
(4)改进建议:对相应题目的编码改进给出自己的见解,做到可持续改进
(5)总结:对本阶段(12-15周)综合性总结,学到了什么,哪些地方需要进一步学习及研究,对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见。
还没写完,持续更新ing。。。
前言
本次PTA题目集09-11主要围绕电信计费系统展开,涉及到的知识点包括继承与多态、对象容器、正则表达式等多方面的内容。每个题目集均以1+N的模式,即1道电信计费系统+N道基础题型,题量适中,其中电信计费系统难度较高,基础题型难度较低。
设计与分析
题目集09
如下是题目集09中我设计的电信计费系统的powerDesigner类图,关于整个系统的设计,我将其分为Main、用户端、计费方式、通讯记录四个板块。
1.Main
我将信息输入工作放在Main函数中完成,以下是我的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 }
如源码第32-33行所示,我在Main中先一行行读入输入数据,当数据读入成功时,我通过split函数将接收到的数据分割,这样可以更方便的提取需要的信息;
如源码第34、39、76行所示,我将每次读到的行数据进行格式比对,如果遇到格式错误就直接跳过后续步骤,开始读入下一行数据;
如源码第34-38行所示,此时如果模式为u(开通),则程序会在用户库中检索号码是否已被开通,如果没开通,程序将会通过分割后所得的数据实例化一个带参的User对象,并将之写入到用户库中;如果未被开通,则会直接跳过后续步骤,开始读入下一行数据;
如源码第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>中的计费方式对其进行资费计算并累加后传回。
标签:12,15,String,callRecord,public,面向对象,源码,each,strings 来源: https://www.cnblogs.com/3110321341chg/p/16380372.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。
