电信计费任务系列工作总结
一,前言
前几次的作业分别是电信计费系列1-座机计费,电信计费系列2-手机+座机计费,电信计费系列3-短信计费三种计费方式,早在第一次座机计费的时候题目就已经暗示后续还会有手机计费手机短信计费功能需要我们去实现。题目算法难度不大,但是类图比较复杂,关系比较多容易摸不着头脑。这次作业是类图最多的一次作业,也是第一次通过题目所给的类图去写。做电信计费1的时候很不适应感觉题目给的类图很绕,我只知道写的时候花了不少时间去理解每一个类图之间的联系。
二,设计与分析
作业代码,点击展开
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
import java.util.Date;
public class Main {
static ArrayList<User> u = new ArrayList<>();
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
String s = new String();
String regx1 = "u-\\d{11,12} [0-3]";
String regx2 = "t-\\d{10,12} (0\\d{2,3} )?\\d{10,12} (0\\d{2,3} )?((20\\d{2}\\.([1-9]|1[0-2])\\.(([1-9]|10)|(2[0-9]|3[0-1])) ([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9])( )?){2}";
String regx3="m-1[0-9]{10} 1[0-9]{10} [ 0-9a-z,.A-Z]+";
s = sc.nextLine();
while (!s.equals("end")) {
if (s.matches(regx1)) {
creatUser(s);
} else if (s.matches(regx2)) {
records(s);
}else if(s.matches(regx3))
messageRecord(s);
s = sc.nextLine();
}
u.sort(Comparator.comparing(User::getNumber));
for (User user : u) {
user.calBalance();
System.out.print(user.getNumber() + " " + (float) (user.calCost()) + " " + (float) (user.getBalance()));
System.out.println();
}
}
public static void creatUser(String s) {
String[] temp = s.split(" ");
User user = new User();
user.setNumber(temp[0].substring(2));
if (temp[1].matches("0")) user.setChargeMode(new LandLinePhoneCharging());
else if(temp[1].matches("1")) user.setChargeMode(new SmartPhoneCharging());
else if(temp[1].matches("3")) user.setChargeMode(new SendMessageCharging());
if (!repeat(user))
u.add(user);
}
public static void records(String s) throws ParseException {
String[] temp = s.split(" ");
CallRecord callRecord = new CallRecord();
String startTime;
String endTime;
callRecord.setCallingNumber(temp[0].substring(2));
if(temp.length==8) {
callRecord.setCallingAddressAreaCode(temp[1]);
callRecord.setAnswerAddressAreaCode(temp[3]);
callRecord.setAnswerNumber(temp[2]);
startTime = temp[4] + " " + temp[5];
endTime = temp[6] + " " + temp[7];
}
else if(temp.length==6){
callRecord.setCallingAddressAreaCode(temp[0].substring(2, 6));
callRecord.setAnswerAddressAreaCode(temp[1].substring(0, 4));
callRecord.setAnswerNumber(temp[1]);
startTime = temp[2] + " " + temp[3];
endTime = temp[4] + " " + temp[5];
}
else{
startTime = temp[3] + " " + temp[4];
endTime = temp[5] + " " + temp[6];
if(temp[0].charAt(2) == '1'){
callRecord.setCallingAddressAreaCode(temp[1]);
callRecord.setAnswerAddressAreaCode(temp[2].substring(0, 4));
callRecord.setAnswerNumber(temp[2]);
}
else{
callRecord.setCallingAddressAreaCode(temp[0].substring(2,6));
callRecord.setAnswerAddressAreaCode(temp[2]);
callRecord.setAnswerNumber(temp[1]);
}
}
callRecord.setStartTime(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(startTime));
callRecord.setEndTime(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(endTime));
for (User user : u) {
if (temp[0].substring(2).matches(user.getNumber())&&temp[0].substring(2,3).matches("0")) {
if (callRecord.getAnswerAddressAreaCode().matches("0791"))
user.getUserRecords().addCallingInCityRecords(callRecord);
else if (callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)"))
user.getUserRecords().addCallingInProvinceRecords(callRecord);
else user.getUserRecords().addCallingInLandRecords(callRecord);
}
else if(temp[0].substring(2).matches(user.getNumber())&&temp[0].substring(2,3).matches("1")){
if((callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791"))||
callRecord.getCallingAddressAreaCode().matches("(0790|079[2-9])|(0701)"))
user.getUserRecords().addCallingInProvinceRecords(callRecord);
else if(((!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")))||
!callRecord.callingAddressAreaCode.matches("(079[0-9])|(0701)"))
user.getUserRecords().addCallingInLandRecords(callRecord);
else if(callRecord.callingAddressAreaCode.matches("0791")&&callRecord.answerAddressAreaCode.matches("0791"))
user.getUserRecords().addCallingInCityRecords(callRecord);
}
else if (user.getNumber().matches(callRecord.answerNumber)) {
if (!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)"))
user.getUserRecords().addAnswerInLandRecords(callRecord);
}
}
}
public static void messageRecord(String s){
String[] temp = s.split(" ");
MessageRecord messageRecord=new MessageRecord();
String sent=temp[0].substring(2);
String accepter=temp[1];
messageRecord.message=s.substring(26);
for (User user : u) {
if (user.number.matches(sent))
user.userRecords.addSentMessageRecords(messageRecord);
}
}
public static boolean repeat(User user) {
for (User value : u) {
if (user.getNumber().matches(value.getNumber()))
return true;
}
return false;
}
}
abstract class CallChargeRule extends ChargeRule{
abstract double calCallCost(ArrayList<CallRecord> callRecords);
}
class CallRecord extends CommunicationRecord{
Date startTime;
Date endTime;
String callingAddressAreaCode;
String answerAddressAreaCode;
Date getStartTime(){
return this.startTime;
}
void setStartTime(Date startTime){
this.startTime=startTime;
}
Date getEndTime(){
return this.endTime;
}
void setEndTime(Date endTime){
this.endTime=endTime;
}
String getCallingAddressAreaCode(){
return callingAddressAreaCode;
}
void setCallingAddressAreaCode(String callingAddressAreaCode){
this.callingAddressAreaCode=callingAddressAreaCode;
}
String getAnswerAddressAreaCode(){
return answerAddressAreaCode;
}
void setAnswerAddressAreaCode(String answerAddressAreaCode){
this.answerAddressAreaCode=answerAddressAreaCode;
}
}
abstract class ChargeMode {
ArrayList<ChargeRule> chargeRules=new ArrayList<>();
ArrayList<ChargeRule> getChargeRules(){
return this.chargeRules;
}
void setChargeRules(ArrayList<ChargeRule> chargeRules){
this.chargeRules=chargeRules;
}
abstract double calCost(UserRecords userRecords);
abstract double getMonthlyRent();
}
abstract class ChargeRule {
abstract double calCallCost(ArrayList<CallRecord> callRecords);
abstract double calMessageCost(ArrayList<MessageRecord> messageRecords);
}
abstract class CommunicationRecord {
String callingNumber;
String answerNumber;
String getCallingNumber(){
return callingNumber;
}
void setCallingNumber(String callingNumber){
this.callingNumber=callingNumber;
}
String getAnswerNumber(){
return answerNumber;
}
void setAnswerNumber(String answerNumber){
this.answerNumber=answerNumber;
}
}
class LandLinePhoneCharging extends ChargeMode {
double monthlyRent = 20;
public LandLinePhoneCharging(){
getChargeRules().add(new LandPhoneCityRule());
getChargeRules().add(new LandPhoneInProvinceRule());
getChargeRules().add(new LandPhoneInLandRule());
}
@Override
double calCost(UserRecords userRecords) {
double cost = 0;
cost += getChargeRules().get(0).calCallCost(userRecords.getCallingInCityRecords());
cost += getChargeRules().get(1).calCallCost(userRecords.getCallingInProvinceRecords());
cost += getChargeRules().get(2).calCallCost(userRecords.getCallingInLandRecords());
return cost;
}
@Override
double getMonthlyRent() {
return monthlyRent;
}
}
class LandPhoneCityRule extends CallChargeRule{
@Override
public double calCallCost(ArrayList<CallRecord> callRecords){
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.answerAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.1 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
class LandPhoneInLandRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
String regx="((079[0-9])|(0701))";
for (CallRecord callRecord : callRecords) {
int time = 0;
if (!callRecord.answerAddressAreaCode.matches(regx)) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.6 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
class LandPhoneInProvinceRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
String regx="(0790|079[2-9])|(0701)";
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.answerAddressAreaCode.matches(regx)) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
abstract class MessageChargeRule extends ChargeRule{
@Override
abstract double calMessageCost(ArrayList<MessageRecord> messageRecords);
}
class MessageRecord extends CommunicationRecord{
String message;
String getMessage(){
return message;
}
void setMessage(String message){
this.message=message;
};
}
class SendMessageCharging extends ChargeMode{
public SendMessageCharging(){
getChargeRules().add(new SendMessageRule());
}
@Override
double calCost(UserRecords userRecords) {
double cost=0;
cost+=getChargeRules().get(0).calMessageCost(userRecords.getSendMessageRecords());
return cost;
}
@Override
double getMonthlyRent() {
return 0;
}
}
class SendMessageRule extends MessageChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
return 0;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
double cost=0;
int num=0;
for (MessageRecord messageRecord : messageRecords) {
if (messageRecord.message.length() % 10 == 0)
num += (int)messageRecord.message.length() / 10;
else num += (int)messageRecord.message.length() / 10 + 1;
}
if(num>5)
cost+=(num-5)*0.3+0.7;
else if(num>3)
cost+=(num-3)*0.2+0.3;
else cost+=num*0.1;
return cost;
}
}
class SmartPhoneCharging extends ChargeMode{
double monthlyRent = 15;
public SmartPhoneCharging() {
getChargeRules().add(new SmartPhoneInCityRule());
getChargeRules().add(new SmartPhoneInProvinceRule());
getChargeRules().add(new SmartPhoneInLandRule());
getChargeRules().add(new 省外漫游接电话());
}
@Override
double calCost(UserRecords userRecords) {
double cost=0;
cost += getChargeRules().get(0).calCallCost(userRecords.getCallingInCityRecords());
cost += getChargeRules().get(1).calCallCost(userRecords.getCallingInProvinceRecords());
cost += getChargeRules().get(2).calCallCost(userRecords.getCallingInLandRecords());
cost+=getChargeRules().get(3).calCallCost(userRecords.getAnswerInLandRecords());
return cost;
}
@Override
double getMonthlyRent() {
return this.monthlyRent;
}
}
class SmartPhoneInCityRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.callingAddressAreaCode.matches("0791")&&callRecord.answerAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.1 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
class SmartPhoneInLandRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
else if (!callRecord.callingAddressAreaCode.matches("079[0-9]|0701")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.6 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
class SmartPhoneInProvinceRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.2 * minute;
}
else if (callRecord.getCallingAddressAreaCode().matches("(0790|079[2-9])|(0701)")){
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
class User {
public UserRecords userRecords=new UserRecords();//用户记录
public double balance=100;//余额
public ChargeMode chargeMode;//计费模式
public String number;//号码
double calBalance(){
return balance-calCost()-chargeMode.getMonthlyRent();
}
double calCost(){
return chargeMode.calCost(userRecords);
}
UserRecords getUserRecords(){
return userRecords;
}
void setUserRecords(UserRecords userRecords) {
this.userRecords = userRecords;
}
double getBalance(){
return calBalance() ;
}
ChargeMode getChargeMode(){
return chargeMode;
}
void setChargeMode(ChargeMode chargeMode){
this.chargeMode=chargeMode;
}
String getNumber(){
return this.number;
}
void setNumber(String number){
this.number=number;
}
}
class UserRecords{
ArrayList<CallRecord> callingInCityRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> callingInProvinceRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> callingInLandRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInCityRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInProvinceRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInLandRecords=new ArrayList<CallRecord>();
ArrayList<MessageRecord> sendMessageRecords=new ArrayList<MessageRecord>();
ArrayList<MessageRecord> receiveMessageRecords=new ArrayList<MessageRecord>();
void addCallingInCityRecords(CallRecord callRecord){
callingInCityRecords.add(callRecord);
}
void addCallingInProvinceRecords(CallRecord callRecord){
callingInProvinceRecords.add(callRecord);
}
void addCallingInLandRecords(CallRecord callRecord){
callingInLandRecords.add(callRecord);
}
void addAnswerInCityRecords(CallRecord answerRecord){
answerInCityRecords.add(answerRecord);
}
void addAnswerInProvinceRecords(CallRecord answerRecord){
answerInProvinceRecords.add(answerRecord);
}
void addAnswerInLandRecords(CallRecord answerRecord){
answerInLandRecords.add(answerRecord);
}
void addSentMessageRecords(MessageRecord sendMessageRecords){
this.sendMessageRecords.add(sendMessageRecords);
}
void addReceiveMessageRecords(MessageRecord receiveMessageRecords){
this.receiveMessageRecords.add(receiveMessageRecords);
}
ArrayList<MessageRecord> getSendMessageRecords(){return this.sendMessageRecords;}
ArrayList<MessageRecord> getReceiveMessageRecords(){return this.receiveMessageRecords;}
ArrayList<CallRecord> getCallingInCityRecords(){
return this.callingInCityRecords;
}
ArrayList<CallRecord> getCallingInProvinceRecords(){
return this.callingInProvinceRecords;
}
ArrayList<CallRecord> getCallingInLandRecords(){
return this.callingInLandRecords;
}
ArrayList<CallRecord> getAnswerInCityRecords(){return this.answerInCityRecords;}
ArrayList<CallRecord> getAnswerInProvinceRecords(){return this.answerInProvinceRecords;}
ArrayList<CallRecord> getAnswerInLandRecords(){return this.answerInLandRecords;}
}
class 省外漫游接电话 extends CallChargeRule{
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
String regx="(0790|079[2-9])|(0701)";
for (CallRecord callRecord : callRecords) {
int time = 0;
if (!callRecord.answerAddressAreaCode.matches("079[1-9]|0701")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
1.电信计费系列1-座机计费题目分析
题目针对的座机仅限于南昌市的而南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。座机的号码由区号加上7-8位数字组成,这时候座机的范围已经可以确定了,考虑到题目会对座机号码进行非法判断所以需要使用正则表达式去检验输入的座机号码是否正确。正则表达式写完后就需要考虑是如何计费了。
南昌市电信分公司针对市内座机用户采用的计费方式:
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
座机计费方式有三种,分别是省内拨打,省内长途拨打,国内长途拨打,每一种的计费方式每分钟收费不同。最终的消费由所消费内容的消费方式对应的时间决定,因此我们还需要去对通话记录的时间进行处理,这里涉及到一个知识点关于SimpleDateFormat类,通过导入该类然后如下创建两个对象去对输入的字符串处理,把对应的时间分别存入到通话记录的开始时间和结束时间中去。
callRecord.setStartTime(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(startTime));
callRecord.setEndTime(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(endTime));
当得到了每条通话记录的起始时间和结束时间后我们就可以计算出相应的消费额了,分析题目类图发现题目提供了座机的三种计费方式类分别是LandPhoneCityRule类,LandPhoneInLandRule类,LandPhoneInProvinceRule类这几个类先暂且不谈,先分析一下类图中的用户User类我们需要先将输入的用户存储下来存储所有的开户用户我定义了一个ArrayList集合去存当通过了座机号码的正则表达式就存到用户中去,通过了通话记录的正则表达式存就到通话记录。主要实现代码如下:
while (!s.equals("end")) {
if (s.matches(regx1)) {
creatUser(s);
} else if (s.matches(regx2)) {
if(isRightRegx(s))
records(s);
}else if(s.matches(regx3))
messageRecord(s);
s = sc.nextLine();
}
createUser函数如下:
public static void creatUser(String s) {
String[] temp = s.split(" ");
User user = new User();
user.setNumber(temp[0].substring(2));
if (temp[1].matches("0")) user.setChargeMode(new LandLinePhoneCharging());
else if(temp[1].matches("1")) user.setChargeMode(new SmartPhoneCharging());
else if(temp[1].matches("3")) user.setChargeMode(new SendMessageCharging());
if (!repeat(user))
u.add(user);
}
record函数如下:
public static void records(String s) throws ParseException {
String[] temp = s.split(" ");
CallRecord callRecord = new CallRecord();
String startTime;
String endTime;
callRecord.setCallingNumber(temp[0].substring(2));
if(temp.length==8) {
callRecord.setCallingAddressAreaCode(temp[1]);
callRecord.setAnswerAddressAreaCode(temp[3]);
callRecord.setAnswerNumber(temp[2]);
startTime = temp[4] + " " + temp[5];
endTime = temp[6] + " " + temp[7];
}
else if(temp.length==6){
callRecord.setCallingAddressAreaCode(temp[0].substring(2, 6));
callRecord.setAnswerAddressAreaCode(temp[1].substring(0, 4));
callRecord.setAnswerNumber(temp[1]);
startTime = temp[2] + " " + temp[3];
endTime = temp[4] + " " + temp[5];
}
else{
startTime = temp[3] + " " + temp[4];
endTime = temp[5] + " " + temp[6];
if(temp[0].charAt(2) == '1'){
callRecord.setCallingAddressAreaCode(temp[1]);
callRecord.setAnswerAddressAreaCode(temp[2].substring(0, 4));
callRecord.setAnswerNumber(temp[2]);
}
else{
callRecord.setCallingAddressAreaCode(temp[0].substring(2,6));
callRecord.setAnswerAddressAreaCode(temp[2]);
callRecord.setAnswerNumber(temp[1]);
}
}
callRecord.setStartTime(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(startTime));
callRecord.setEndTime(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(endTime));
for (User user : u) {
if (temp[0].substring(2).matches(user.getNumber())&&temp[0].substring(2,3).matches("0")) {
if (callRecord.getAnswerAddressAreaCode().matches("0791"))
user.getUserRecords().addCallingInCityRecords(callRecord);
else if (callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)"))
user.getUserRecords().addCallingInProvinceRecords(callRecord);
else user.getUserRecords().addCallingInLandRecords(callRecord);
}
else if(temp[0].substring(2).matches(user.getNumber())&&temp[0].substring(2,3).matches("1")){
if((callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791"))||
callRecord.getCallingAddressAreaCode().matches("(0790|079[2-9])|(0701)"))
user.getUserRecords().addCallingInProvinceRecords(callRecord);
else if(((!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")))||
!callRecord.callingAddressAreaCode.matches("(079[0-9])|(0701)"))
user.getUserRecords().addCallingInLandRecords(callRecord);
else if(callRecord.callingAddressAreaCode.matches("0791")&&callRecord.answerAddressAreaCode.matches("0791"))
user.getUserRecords().addCallingInCityRecords(callRecord);
}
else if (user.getNumber().matches(callRecord.answerNumber)) {
if (!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)"))
user.getUserRecords().addAnswerInLandRecords(callRecord);
}
}
}
观察类图发现User类有个UserRecords的成员变量,该变量中存的就是我们后续要用来遍历计算消费的通话记录。观察UserRecords类可以发现我们输入的聊天记录是以ArrayList集合存储的,通话记录里面又细分为如下记录:
ArrayList<CallRecord> callingInCityRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> callingInProvinceRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> callingInLandRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInCityRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInProvinceRecords=new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInLandRecords=new ArrayList<CallRecord>();
ArrayList<MessageRecord> sendMessageRecords=new ArrayList<MessageRecord>();
ArrayList<MessageRecord> receiveMessageRecords=new ArrayList<MessageRecord>();
这些记录的存储应当在Main函数中实现,通过判断输入的字符串去进行分割处理把对应的部分存入到CallRecord类中对应的变量中去最后通过判断区号存入到对应的记录中去主要实现代码如下:
for (User user : u) {
if (temp[0].substring(2).matches(user.getNumber())&&temp[0].substring(2,3).matches("0")) {
if (callRecord.getAnswerAddressAreaCode().matches("0791"))
user.getUserRecords().addCallingInCityRecords(callRecord);
else if (callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)"))
user.getUserRecords().addCallingInProvinceRecords(callRecord);
else user.getUserRecords().addCallingInLandRecords(callRecord);
}
}
遍历所有用户和当前正在处理的通话记录的拨打电话的号码比对,如果通话记录中的拨打电话人和当前用户匹配则判断通话记录的区号,如果接电话的号码是属于“0791”说明是南昌的用户此条通话记录属于市内拨打电话,如果接电话的号码区号是"(0790|079[2-9])|(0701)"即在江西省内不在南昌市则归为省内长途拨打电话,剩下的一个else就是国内长途拨打电话了。有了这些记录就可以去对应的类实现计算消费额的功能了,消费额计算的核心代码如下:
LandPhoneCityRule类(市内拨打电话):
public class LandPhoneCityRule extends CallChargeRule{
@Override
public double calCallCost(ArrayList<CallRecord> callRecords){
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.answerAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.1 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
LandPhoneInLandRule(省内拨打电话):
public class LandPhoneInProvinceRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
String regx="(0790|079[2-9])|(0701)";
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.answerAddressAreaCode.matches(regx)) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
LandPhoneInProvinceRule(国内长途拨打电话):
public class LandPhoneInLandRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
String regx="((079[0-9])|(0701))";
for (CallRecord callRecord : callRecords) {
int time = 0;
if (!callRecord.answerAddressAreaCode.matches(regx)) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.6 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
因为同一个用户可以有多条通话记录而且产生的通话记录可以是不同计费方式产生的,因此还需要将用户所有的消费记录进行相加该操作在LandLinePhoneCharging(座机计费)类中去实现,实现代码如下:
public class LandLinePhoneCharging extends ChargeMode {
double monthlyRent = 20;
public LandLinePhoneCharging(){
getChargeRules().add(new LandPhoneCityRule());
getChargeRules().add(new LandPhoneInProvinceRule());
getChargeRules().add(new LandPhoneInLandRule());
}
@Override
double calCost(UserRecords userRecords) {
double cost = 0;
cost += getChargeRules().get(0).calCallCost(userRecords.getCallingInCityRecords());
cost += getChargeRules().get(1).calCallCost(userRecords.getCallingInProvinceRecords());
cost += getChargeRules().get(2).calCallCost(userRecords.getCallingInLandRecords());
return cost;
}
@Override
double getMonthlyRent() {
return monthlyRent;
}
}
座机的计费方式月租是20元,手机的是15元。观察类图可知LandLinePhoneCharging类继承了ChargeMode类,而ChargeMode类中又定义了存储Rule的集合,所有在LandLinePhoneCharging需要将市内,省内,国内长途计费方式加入到Rule集合中去。最后重写ChargeMode里的calCost抽象方法把三种计费规则下产生的消费相加就可以得出用户的总消费额了。
题目所给类图如下:
2. 电信计费系列2-手机+座机计费题目分析
这次的作业多加了一个手机计费,座机计费还是用原来的不用做任何修改,多了几个手机计费就意味着又多了一种计费模式,因此我仿照座机计费模式多加了几个用于计算手机费用的类。而且手机的号码格式和座机的又不一样手机是11位号码,而且首位是1,所以需要对正则表达式修改改后变为:
String regx2 = "t-\\d{10,12} (0\\d{2,3} )?\\d{10,12} (0\\d{2,3} )?((20\\d{2}\\.([1-9]|1[0-2])\\.(([1-9]|10)|(2[0-9]|3[0-1])) ([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9])( )?){2}";
手机计费方式为:
针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费。
简要分析可知手机计费规则有市内拨打省内电话,市内拨打省外,市内拨打省外电话,省内漫游打电话,省外漫游接听,省外漫游拨打这几种Rule,这几种方式的判别是通过通话记录中拨打号码区号和接听电话区号决定的主要代码如下:
else if(temp[0].substring(2).matches(user.getNumber())&&temp[0].substring(2,3).matches("1")){
if((callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791"))||
callRecord.getCallingAddressAreaCode().matches("(0790|079[2-9])|(0701)"))
user.getUserRecords().addCallingInProvinceRecords(callRecord);
else if(((!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")))||
!callRecord.callingAddressAreaCode.matches("(079[0-9])|(0701)"))
user.getUserRecords().addCallingInLandRecords(callRecord);
else if(callRecord.callingAddressAreaCode.matches("0791")&&callRecord.answerAddressAreaCode.matches("0791"))
user.getUserRecords().addCallingInCityRecords(callRecord);
}
else if (user.getNumber().matches(callRecord.answerNumber)) {
if (!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)"))
user.getUserRecords().addAnswerInLandRecords(callRecord);
}
如果接听号码的区号是"(0790|079[2-9])|(0701)"并且拨打号码的区号是“0791”或者拨打电话的区号是"(0790|079[2-9])|(0701)"则属于市内拨打省内电话 ,同理市内拨打省外,市内拨打省外电话,省内漫游打电话,省外漫游接听,省外漫游拨打都是通过区号来判断的。这几种规则我用了四个类去实现,主要代码如下:
SmartPhoneInCityRule类
public class SmartPhoneInCityRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.callingAddressAreaCode.matches("0791")&&callRecord.answerAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.1 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
SmartPhoneInProvinceRule类
public class SmartPhoneInProvinceRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.getAnswerAddressAreaCode().matches("(0790|079[2-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.2 * minute;
}
else if (callRecord.getCallingAddressAreaCode().matches("(0790|079[2-9])|(0701)")){
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
SmartPhoneInLandRule类
public class SmartPhoneInLandRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (!callRecord.answerAddressAreaCode.matches("(079[0-9])|(0701)")&&callRecord.callingAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.3 * minute;
}
else if (!callRecord.callingAddressAreaCode.matches("079[0-9]|0701")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.6 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
3.电信计费系列3-短信计费题目分析
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。
第三次的作业又是在前面的基础上加了一个短信计费功能,所以仿照之前的作业我添加了两个类,一个短信费用计算类,一个短信计费规则类,短信计费类同样继承ChargeMode类,在计算费用的时候需要将SendMessageRule添加进Rule的集合中去。短信计费的是最简单的只需要添加这两个类即可。主要实现代码如下:
public class SmartPhoneCharging extends ChargeMode{
double monthlyRent = 15;
public SmartPhoneCharging() {
getChargeRules().add(new SmartPhoneInCityRule());
getChargeRules().add(new SmartPhoneInProvinceRule());
getChargeRules().add(new SmartPhoneInLandRule());
getChargeRules().add(new 省外漫游接电话());
}
@Override
double calCost(UserRecords userRecords) {
double cost=0;
cost += getChargeRules().get(0).calCallCost(userRecords.getCallingInCityRecords());
cost += getChargeRules().get(1).calCallCost(userRecords.getCallingInProvinceRecords());
cost += getChargeRules().get(2).calCallCost(userRecords.getCallingInLandRecords());
cost+=getChargeRules().get(3).calCallCost(userRecords.getAnswerInLandRecords());
return cost;
}
@Override
double getMonthlyRent() {
return this.monthlyRent;
}
}
public class SmartPhoneInCityRule extends CallChargeRule{
@Override
double calCallCost(ArrayList<CallRecord> callRecords) {
double cost=0;
for (CallRecord callRecord : callRecords) {
int time = 0;
if (callRecord.callingAddressAreaCode.matches("0791")&&callRecord.answerAddressAreaCode.matches("0791")) {
time = (int) (callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime());
int minute = (int)(time / 60000);
int s=(int)(time/1000%60);
if (s > 0) minute++;
cost += 0.1 * minute;
}
}
return cost;
}
@Override
double calMessageCost(ArrayList<MessageRecord> messageRecords) {
return 0;
}
}
到这里所有的作业分析完毕,题目算法不难,难得是怎么去理解看懂类图做完第一题后,再去写第二题和第三题就会觉得很简单不用花很多时间就可以写完。最后看一下最终的类图:
SourceMonitor代码分析
本来以为按照题目给的类图构造的代码圈复杂度会很小,结果和我之前写多边形的圈复杂度没啥区别,这是我没想到的,可能代码量到了一定的程度复杂度也就会跟着上来吧。
三,踩坑心得
这三次作业中让我印象最深的一个坑就是手机计费的规则划分了,一开始我下意识的以为手机和座机一样都是固定在南昌拨打的。所以判断区号去划分计费规则的时候只需要判断拨打电话的号码的区号即可,结果提交答案的时候,测试点都没过之后 我才看到题目说手机是可以跨省的最后我才反应过来自己想当然的理解错了。其次还有个小问题就是计费的规则没理解出错,超过的部分只算超出部分的钱,未超出的时间按照原定的费用计算,这是个小问题随便用一个测试点测一下我就找到了。除了这两个错误基本就没啥错了。
四,改进建议
虽然是按照题目给的类图所写的,但是还是存在需要我去改进的地方,我的计费规则中是通过重新遍历判断UserRecord的拔打电话区号和接听电话的区号去做判断,而我的主函数中已经对所有情况做出了判断,并且存入了对应的Record中,列如我的LandPhoneCityRule就无需再去判断区号了,而是直接遍历CallingInCityRecords的通话记录去做计费操作。
五,总结
通过这几周的学习,我对java的了解越来越深入了,java的一下基本概念也潜移默化的印在我的脑海里。还记得刚开始写java的时候使用面向对象硬是觉得很抽象,写起来浑身难受很不自然,到现在用起来行云流水,悠然自得。这一切都离不离开这段时间的锻炼,电信计费的这一套题目让我对类与类之间的关系理解更加深刻,知道了类的强大之处。实验中我们做的农夫过河小游戏同样让我收获了学多新知识,在经过不断的重构代码最终得到一份相对理想的代码使得我对java的学习自信心更强,听完老师讲的javafx之后我结合农夫过河实验也把这个游戏的图形化实现了出来,当做出图形化界面游戏的那一刻,我想这是对我这段时间以来努力的最好回报,虽然期中考试和期末考试没有做的很好,但是我真的学到了很多。
上一篇: Java计费系统的设计结构和计费准则
推荐阅读