编程语言
首页 > 编程语言> > 面向对象程序设计第12-15周内容总结

面向对象程序设计第12-15周内容总结

作者:互联网

(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