移动业务资费问题分析与总结
移动业务资费问题分析与总结
前言:移动业务资费问题,主要是涉及座机,手机等不同设备,在不同地域通信的收费问题,
如省内省外通信,或出省漫游通信,不同设备,通信地点不同,收费规则也不同
而本次将对移动业务资费问题的三次作业进行分析,三次作业迭代,主要涉及多态,继承,抽象,SimpleDateFormat类等
题目整体分析
先看看题目


有两种机型,座机,手机,众所周知,座机不能移动,只能在南昌市拨打接听,
而手机则是我们每天带在身边的那种,当然是跟随我们移动的,
也就会出现市内,省内,省外,接听,拨打,3*2=6种情况,而手机还有发送信息的计费情况
1.0第一次
第一次全为对座机的计费

第一次题目笔者认为有以下几点比较重要
1.1确定要使用哪些类,以及它们之间的关系
其中我使用了用户类,通讯记录类,计费规则类,业务类
用户有自己的通讯记录,确定座机或手机后,对应有不同计费规则,体现策略模式

座机下的计费规则

class LandPhoneInCityRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
long difMin = 0;
double sumCost = 0;
for (CallRecord c : callRecords) {
difMin = (c.getEndTime().getTime() - c.getStartTime().getTime())/60/1000;
if ((c.getEndTime().getTime() - c.getStartTime().getTime())/60.0/1000.0 % 1 != 0) {
difMin = difMin + 1;
}
sumCost = sumCost + difMin * 0.1;
}
return sumCost;
}
}
class LandPhoneInProvinceRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
long difMin = 0;
double sumCost = 0;
for (CallRecord c : callRecords) {
difMin = (c.getEndTime().getTime() - c.getStartTime().getTime())/60/1000;
if ((c.getEndTime().getTime() - c.getStartTime().getTime())/60.0/1000.0 % 1 != 0) {
difMin = difMin + 1;
}
sumCost = sumCost + difMin * 0.3;
}
return sumCost;
}
}
class LandPhoneInLandRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
long difMin = 0;
double sumCost = 0;
for (CallRecord c : callRecords) {
difMin = (c.getEndTime().getTime() - c.getStartTime().getTime())/60/1000;
if ((c.getEndTime().getTime() - c.getStartTime().getTime())/60.0/1000.0 % 1 != 0) {
difMin = difMin + 1;
}
sumCost = sumCost + difMin * 0.6;
}
return sumCost;
}
}
通讯记录类将市内,省内,省外的接听拨打,信息的发送接收分开存储

计费规则则是针对市内,省内,省外的接听拨打,信息的发送接收采取不同计费规则
而业务类则负责整个用户群体的信息记录,打印话费,余额
业务类中使用

记录用户,为什么选择TreeMap呢,
一是可以解决用户重复的问题,达到去重的效果
二则是对用户类实现了Comparable接口中的compareTo方法后可以自动依据用户号码对用户排序,
三便是将用户号码与用户对应,便于解决对应输入查找相应用户的问题
一举三得
1.2对输入信息格式的判定
输入格式可以说是房门钥匙,若输入不能准确判断,之后的运行过程中也会再出错
使用正则表达式,来排除错误的输入格式,使用SimpleDateFormat类来读取通话的日期
SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
String messageFormat = "t-0791\\d{7,8} \\d{10,12} " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
String userFormat = "u-0791\\d{7,8} [0-2]";
1.3正确地创建用户,记录不同通话类型(市内,省内,省外的接听拨打)
public void addUser() {
Scanner in = new Scanner(System.in);
Date startDate = null;
Date endDate = null;
String userNumber;
String otherNumber;
String message;
SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
String messageFormat = "t-0791\\d{7,8} \\d{10,12} " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
String userFormat = "u-0791\\d{7,8} [0-2]";
String userAccount;
do {
userAccount = in.nextLine();
if (userAccount.matches(userFormat)) {
User user = new User(userAccount.split(" ")[0].split("-")[1]);
switch (Integer.parseInt(userAccount.split(" ")[1])) {
case 0:
user.setChargeMode(new LandlinePhoneCharging());
break;
}
users.put(user.getNumber(), user);
}
} while (userAccount.matches(userFormat));
message = userAccount;
do {
if (message.matches(messageFormat)) {
userNumber = message.split(" ")[0].split("-")[1];
otherNumber = message.split(" ")[1];
if (users.get(userNumber) != null) {
try {
startDate = timeFormat.parse(message.split(" ")[message.split(" ").length-4] + " "
+ message.split(" ")[message.split(" ").length-3]);
endDate = timeFormat.parse(message.split(" ")[message.split(" ").length-2] + " "
+ message.split(" ")[message.split(" ").length-1]);
} catch (ParseException e) {
e.printStackTrace();
}
if (otherNumber.substring(0,4).matches("0791")) {
users.get(userNumber).getUserRecords().
addCallingInCityRecords(new CallRecord(startDate,endDate));
} else if (otherNumber.substring(0,4).matches("(079\\d|0701)")) {
users.get(userNumber).getUserRecords().
addCallingInProvinceRecords(new CallRecord(startDate,endDate));
} else {
users.get(userNumber).getUserRecords().
addCallingInLandRecords(new CallRecord(startDate,endDate));
}
}
}
message = in.nextLine();
} while (!message.equals("end"));
}
程序类图如下:
运行结果如下:

2.0第二次
在第一次基础上新增了对手机的计费

手机相比于座机要复杂得多
因为手机可以移动也就产生了多种情况
市内拨打市内电话
市内拨打省内电话
市内拨打省外电话
省内漫游打电话
省外漫游接听
省外漫游拨打
这些情况下计费方式各不相同,还多了对接听的记录
需要对不同情况细致分类
2.1不同情况使用不同正则表达式
String messageFormatLL = "t-0791\\d{7,8} 0\\d{9,11} " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
String messageFormatLP = "t-0791\\d{7,8} 1\\d{10} 0\\d{2,3} " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
String messageFormatPL = "t-1\\d{10} 0\\d{2,3} 0791\\d{7,8} " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
String messageFormatPP = "t-1\\d{10} 0\\d{2,3} 1\\d{10} 0\\d{2,3} " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d " +
"[1-9]\\d*.([1-9]|10|11|12).([1-9]|[1-2]\\d|30|31) " +
"(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
2.2分析不同情况,正确记录通信
对于不同情况的分析主要是对区号进行比较,
通过不同区号逐一,层层判断是否在市内,省内,是否是漫游状态
其中需要注意区号也存在三位区号的情况
不同情况下的判断如下代码中作不同注释
do {
if (message.matches(messageFormatLL) || message.matches(messageFormatLP)
|| message.matches(messageFormatPL)|| message.matches(messageFormatPP)) {
userNumber = message.split(" ")[0].split("-")[1];
if (message.matches(messageFormatLL) || message.matches(messageFormatLP)) {
otherNumber = message.split(" ")[1];
} else {
otherNumber = message.split(" ")[2];
}
if (users.containsKey(userNumber) || users.containsKey(otherNumber)) {
try {
startDate = timeFormat.parse(message.split(" ")[message.split(" ").length - 4] + " "
+ message.split(" ")[message.split(" ").length - 3]);
endDate = timeFormat.parse(message.split(" ")[message.split(" ").length - 2] + " "
+ message.split(" ")[message.split(" ").length - 1]);
} catch (ParseException e) {
e.printStackTrace();
}
//座机打座机
if (message.matches(messageFormatLL)) {
if (otherNumber.substring(0,4).matches("0791")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInCityRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),otherNumber.substring(0,4)));
}
} else if (otherNumber.substring(0,4).matches("(079\\d|0701)")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInProvinceRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),otherNumber.substring(0,4)));
}
} else {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInLandRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),otherNumber.substring(0,4)));
}
}
//座机打手机
} else if(message.matches(messageFormatLP)) {
if (message.split(" ")[2].matches("0791")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInCityRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),message.split(" ")[2]));
}
} else if (message.split(" ")[2].matches("(079\\d|0701)")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInProvinceRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),message.split(" ")[2]));
}
} else {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInLandRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),message.split(" ")[2]));
}
if (users.containsKey(otherNumber)) {
users.get(otherNumber).getUserRecords().
addAnswerInLandRecords(new CallRecord(startDate,endDate,
userNumber.substring(0,4),message.split(" ")[2]));
}
}
//手机打座机
} else if (message.matches(messageFormatPL)) {
if (message.split(" ")[1].matches("0791")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInCityRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],otherNumber.substring(0,4)));
}
} else if (message.split(" ")[1].matches("(079\\d|0701)")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInProvinceRoamRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],otherNumber.substring(0,4)));
}
} else {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInLandRoamRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
}
//手机打手机
} else {
if (message.split(" ")[1].matches("0791")
&& message.split(" ")[3].matches("0791")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInCityRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
} else if (message.split(" ")[1].matches("0791")
&& message.split(" ")[3].matches("(079\\d|0701)")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInProvinceRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
} else if (message.split(" ")[1].matches("0791")
&& !message.split(" ")[3].matches("(079\\d|0701)")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInLandRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
if (users.containsKey(otherNumber)) {
users.get(otherNumber).getUserRecords().
addAnswerInLandRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
} else if (message.split(" ")[1].matches("(079\\d|0701)")
&& !message.split(" ")[1].matches("0791")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInProvinceRoamRecords(new CallRecord(startDate, endDate,
message.split(" ")[1], message.split(" ")[3]));
}
if (!message.split(" ")[3].matches("(079\\d|0701)")) {
if (users.containsKey(otherNumber)) {
users.get(otherNumber).getUserRecords().
addAnswerInLandRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
}
} else if (!message.split(" ")[1].matches("(079\\d|0701)")) {
if (users.containsKey(userNumber)) {
users.get(userNumber).getUserRecords().
addCallingInLandRoamRecords(new CallRecord(startDate, endDate,
message.split(" ")[1], message.split(" ")[3]));
}
if (!message.split(" ")[3].matches("(079\\d|0701)")) {
if (users.containsKey(otherNumber)) {
users.get(otherNumber).getUserRecords().
addAnswerInLandRecords(new CallRecord(startDate,endDate,
message.split(" ")[1],message.split(" ")[3]));
}
}
}
}
}
}
message = in.nextLine();
} while (!message.equals("end"));
类图如下:
运行结果如下:

3.0第三次
第三次相比第一次和第二次的计费,只计算手机间消息发送,接收的收费情况,较为简单

3.1也仅有3.1,对信息条数的正确判断
短信内容只能由数字、字母、空格、英文逗号、英文句号组成
短信内容中包含空格,也就直接导致不能使用空格分隔来确定短信条数
因为前端用户信息的字符个数已经确定,使用
就可以截取短信内容
之后通过

便可计算出短信条数
最后根据短信的条数分类
只有一条则直接添加一条记录,完毕

而存在多条短信,则使用循环,不断添加记录,并对最后一条短信单独添加
以免截取过多短信内容

如此便成功添加了所有短信
类图如下:
运行结果如下:

总结:
写代码之前理解类之间的关系,理解需求很重要,类之间的关系可以从上往下开始分析,
即先从Main开始,了解类之间整体的架构,他们之间是怎样联系起来的。
也可以从下往上分析,即先找到代码中最小的类,此时一般看类名也能了解它的具体用处,
再看看它是如何实现的,之后向上找它的父类,不断重复到Main

浙公网安备 33010602011771号