? ? ? 最开始看到这类图时并不能马上理解类图想表达的意思,后面经过慢慢的思考明白了这种设计具备的可扩展性,也是后续学习过程中自己需要学习的地方,在用户类User中包含私有属性? 用户记录类 useRecords,浮点型用户余额 balance,计费模式类chargeMode,字符串类型电话号码 number,以及计算余额,计算消费的方法。收费模式类是一个抽象类,包含计费方式的集合,以及计费的抽象方法。在后续的扩展中我们可以添加计费模式,就是继承抽象的计费模式类然后实现这些方法,比如座机收费模式,短信收费模式,手机收费模式,而在这些收费模式中可以包括一些计费方式比如市内计费方式,省内计费方式,省外计费方式,在用户记录类当中包括市内拨号记录,市内接听记录,短信发送记录,短信接收记录等等。本题还是要依赖正则表达式处理字符串,利用正则表达式来过滤不符合格式的输入,在一些测试用例中出现由于正则表达式的误判导致无法通过,采用了菜鸟工具中的正则表达式测试,合理的使用工具可以提高实现代码的效率。
? ? ? SourceMonitor的生成报表内容
? ? ?
? ? ?根据报表内容我们可以看出由于类设计的合理性,代码质量较好,主要是实现是导致函数的最大复杂度较高。
电信计费系列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
图1中User是用户类,包括属性:userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。ChargeMode是计费方式的抽象类:chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。getMonthlyRent()方法用于返回月租(monthlyRent)。UserRecords是用户记录类,保存用户各种通话、短信的记录, 各种计费规则将使用其中的部分或者全部记录。其属性从上到下依次是:市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、市内接听电话、省内(不含市内)接听电话、省外接听电话的记录以及发送短信、接收短信的记录。
?
图2
图2中CommunicationRecord是抽象的通讯记录类:包含callingNumber拨打号码、answerNumber接听号码两个属性。CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。CallRecord(通话记录类)包含属性:通话的起始、结束时间以及拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
?
图3
图3是计费规则的相关类,这些类的核心方法是:calCost(ArrayList CallRecord callRecords)。该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
?
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
输入样例:
在这里给出一组输入。例如:
u-13811111111 1t-13811111111 0791 13811111110 020 2022.1.3 08:00:00 2022.1.3 08:09:20end
?
输出样例:
在这里给出相应的输出。例如:
13811111111 3.0 82.0
show code
import java.util.ArrayList;import java.util.Date;import java.util.Iterator;import java.util.Map;import java.util.Scanner;import java.util.TreeMap;import java.text.ParseException;import java.text.SimpleDateFormat;public class Main { public static void main(String[] args) { // TODO 自动生成的方法存根 Processdata p = new Processdata(); p.work();abstract class AnswerChargeRule extends ChargeRule { public abstract double calCost(ArrayList CallRecord callrecords); class AnswerRoamMobilePhoneInCityRule extends AnswerChargeRule { @Override public double calCost(ArrayList CallRecord callrecords) { // TODO 自动生成的方法存根 double cost = 0; for(CallRecord c : callrecords) { cost+=Math.ceil((c.getEndTime().getTime()-c.getStateTime().getTime())/1000.0/60.0)*0.3; return cost;abstract class CallChargeRule extends ChargeRule { public abstract double calCost(ArrayList CallRecord callrecords);