OO第三次博客作业
目录
- 作业总结
- 设计与分析
- 采坑心得
- 改进建议
- 心得体会
一、作业总结
本次的电信计费系列题目可以说真正体现了Java面向对象编程的特点:类的数量多、种类多、类之间的关系错综复杂又充满联系。之前的多边形系列的类由同学们自己创建,大多较为单一,没有这么复杂的继承关系,而这次的电信计费系列题目已经给了类图,十分考验同学们阅读类图,理解类之间的关系的能力。
作业六:作为电信计费系列的“开篇”,本题能否准确理解类图、完美解决问题很大程度影响了后续两次作业能否顺利完成,后面两次作业都会在作业六上面进行修改并添加内容。题目难度上较为简单,情况比较单一,难点在于正确创建类。
作业七:作业七在作业六的基础上多了一些情况,只要作业六顺利完成的话,作业七难度就不会太大。
作业八: 作业八的测试点只有新的“短信计费”,和之前的没有关系,且有代码总长度限制,所以相对比较独立,继承了前两次的代码结构,但实现更为简单
二、设计与分析
要想顺利完成该题,要先读懂类图含义:

User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。

CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。

以上是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是
座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
首先按题目意思创建出User类,包含属性:userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码):
1 class User { 2 private UserRecords userRecords = new UserRecords(); 3 private double balance = 100; 4 private ChargeMode chargeMode; 5 private String number; 6 7 public double calCost() { 8 return chargeMode.calCost(userRecords); 9 } 10 11 public double calBalance() { 12 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 13 } 14 15 public UserRecords getUserRecords() { 16 return userRecords; 17 } 18 19 public void setUserRecords(UserRecords userRecords) { 20 this.userRecords = userRecords; 21 } 22 23 public ChargeMode getChargeMode() { 24 return chargeMode; 25 } 26 27 public void setChargeMode(ChargeMode chargeMode) { 28 this.chargeMode = chargeMode; 29 } 30 31 public String getNumber() { 32 return number; 33 } 34 35 public void setNumber(String number) { 36 this.number = number; 37 } 38 39 }
紧接着开始创建ChargeMode抽象类,里面包含了计费规则和返回花费的方法:
1 abstract class ChargeMode { 2 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 3 4 public abstract double calCost(UserRecords userRecords); 5 6 public abstract double getMonthlyRent(); 7 8 public ArrayList<ChargeRule> getChargeRules() { 9 return chargeRules; 10 } 11 12 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 13 this.chargeRules = chargeRules; 14 } 15 }
创建LandlinePhoneCharging座机收费模式类和 MobilePhoneCharging手机收费模式类以及MobilePhoneMassageCharging手机短信收费模式类,表示了某一收费类型的月租情况,并调用收费规则的相关方法获得总花费
1 class LandlinePhoneCharging extends ChargeMode { 2 3 private double monthlyRent = 20; 4 5 public LandlinePhoneCharging() { 6 super(); 7 chargeRules.add(new LandPhoneInCityRule()); 8 chargeRules.add(new LandPhoneInProvinceRule()); 9 chargeRules.add(new LandPhoneInlandRule()); 10 } 11 12 @Override 13 public double calCost(UserRecords userRecords) { 14 double sumCost = 0; 15 for (ChargeRule rule : chargeRules) { 16 sumCost += rule.calCost(userRecords); 17 } 18 return sumCost; 19 } 20 21 @Override 22 public double getMonthlyRent() { 23 return monthlyRent; 24 } 25 26 } 27 28 class MobilePhoneCharging extends ChargeMode { 29 30 private double monthlyRent = 15; 31 32 public MobilePhoneCharging() { 33 super(); 34 chargeRules.add(new MobilePhoneInCityRule()); 35 chargeRules.add(new MobilePhoneInProvinceRule()); 36 chargeRules.add(new MobilePhoneInlandRule()); 37 } 38 39 @Override 40 public double calCost(UserRecords userRecords) { 41 double sumCost = 0; 42 for (ChargeRule rule : chargeRules) { 43 sumCost += rule.calCost(userRecords); 44 } 45 return sumCost; 46 } 47 48 @Override 49 public double getMonthlyRent() { 50 return monthlyRent; 51 } 52 53 } 54 55 class MobilePhoneMassageCharging extends ChargeMode { 56 57 private double monthlyRent = 0; 58 59 public MobilePhoneMassageCharging() { 60 super(); 61 chargeRules.add(new MobilePhoneMessageRule()); 62 } 63 64 @Override 65 public double calCost(UserRecords userRecords) { 66 double sumCost = 0; 67 for (ChargeRule rule : chargeRules) { 68 sumCost += rule.calCost(userRecords); 69 } 70 return sumCost; 71 } 72 73 @Override 74 public double getMonthlyRent() { 75 return monthlyRent; 76 } 77 78 }
创建收费规则抽象类ChargeRule:
1 abstract class ChargeRule { 2 3 abstract public double calCost(UserRecords userRecords); 4 5 }
1) 座机收费规则:
创建座机市内、省内和国内三种情况下的计费规则,按照题目市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟的规则重写其calCost方法获得该种通话的总花销。
1 class LandPhoneInCityRule extends CallChargeRule { 2 3 @Override 4 public double calCost(UserRecords userRecords) { 5 double sumCost = 0; 6 for (CallRecord call : userRecords.getCallingInCityRecords()) { 7 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 8 if (distanceS < 0) { 9 continue; 10 } 11 double distanceM = (int) distanceS / 60; 12 if (distanceS % 60 != 0) { 13 distanceM += 1; 14 } 15 if (call.getCallType().equals("11")) { 16 sumCost += distanceM * 0.1; 17 } else if (call.getCallType().equals("12")) { 18 sumCost += distanceM * 0.3; 19 } else if (call.getCallType().equals("13")) { 20 sumCost += distanceM * 0.6; 21 } 22 } 23 return sumCost; 24 } 25 26 } 27 28 class LandPhoneInlandRule extends CallChargeRule { 29 30 @Override 31 public double calCost(UserRecords userRecords) { 32 double sumCost = 0; 33 for (CallRecord call : userRecords.getCallingInLandRecords()) { 34 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 35 if (distanceS < 0) { 36 continue; 37 } 38 double distanceM = (int) distanceS / 60; 39 if (distanceS % 60 != 0) { 40 distanceM += 1; 41 } 42 sumCost += distanceM * 0.6; 43 } 44 return sumCost; 45 } 46 47 } 48 49 class LandPhoneInProvinceRule extends CallChargeRule { 50 51 @Override 52 public double calCost(UserRecords userRecords) { 53 double sumCost = 0; 54 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 55 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 56 if (distanceS < 0) { 57 continue; 58 } 59 double distanceM = (int) distanceS / 60; 60 if (distanceS % 60 != 0) { 61 distanceM += 1; 62 } 63 sumCost += distanceM * 0.3; 64 } 65 return sumCost; 66 } 67 68 }
2) 手机通信收费规则:
创建手机通信市内、省内和国内三种情况下的计费规则,按照题目月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟的规则重写其calCost方法获得该种通话的总花销。
1 class MobilePhoneInCityRule extends CallChargeRule { 2 3 @Override 4 public double calCost(UserRecords userRecords) { 5 double sumCost = 0; 6 for (CallRecord call : userRecords.getCallingInCityRecords()) { 7 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 8 if (distanceS < 0) { 9 continue; 10 } 11 double distanceM = (int) distanceS / 60; 12 if (distanceS % 60 != 0) { 13 distanceM += 1; 14 } 15 if (call.getCallType().equals("11")) { 16 sumCost += distanceM * 0.1; 17 } else if (call.getCallType().equals("12")) { 18 sumCost += distanceM * 0.2; 19 } else if (call.getCallType().equals("13")) { 20 sumCost += distanceM * 0.3; 21 } 22 23 } 24 return sumCost; 25 } 26 27 } 28 29 class MobilePhoneInlandRule extends CallChargeRule { 30 31 @Override 32 public double calCost(UserRecords userRecords) { 33 double sumCost = 0; 34 for (CallRecord call : userRecords.getCallingInLandRecords()) { 35 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 36 if (distanceS < 0) { 37 continue; 38 } 39 double distanceM = (int) distanceS / 60; 40 if (distanceS % 60 != 0) { 41 distanceM += 1; 42 } 43 sumCost += distanceM * 0.6; 44 } 45 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 46 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 47 if (distanceS < 0) { 48 continue; 49 } 50 double distanceM = (int) distanceS / 60; 51 if (distanceS % 60 != 0) { 52 distanceM += 1; 53 } 54 sumCost += distanceM * 0.3; 55 } 56 return sumCost; 57 } 58 59 } 60 61 class MobilePhoneInProvinceRule extends CallChargeRule { 62 63 @Override 64 public double calCost(UserRecords userRecords) { 65 double sumCost = 0; 66 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 67 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 68 if (distanceS < 0) { 69 continue; 70 } 71 double distanceM = (int) distanceS / 60; 72 if (distanceS % 60 != 0) { 73 distanceM += 1; 74 } 75 if (call.getCallType().equals("21")) { 76 sumCost += distanceM * 0.3; 77 } else if (call.getCallType().equals("22")) { 78 sumCost += distanceM * 0.3; 79 } else if (call.getCallType().equals("23")) { 80 sumCost += distanceM * 0.3; 81 } 82 } 83 return sumCost; 84 } 85 86 }
3) 手机短信收费规则:
创建手机短信的计费规则,按照题目1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。的规则重写其calCost方法获得该种通话的总花销。
1 class MobilePhoneMessageRule extends CallChargeRule { 2 3 @Override 4 public double calCost(UserRecords userRecords) { 5 double sumCost = 0; 6 int number = 0; 7 for (MessageRecord m : userRecords.getSendMessageRecords()) { 8 int length = m.getMessage().length(); 9 if (length <= 10) { 10 number++; 11 } else { 12 number += length / 10; 13 if (length % 10 != 0) { 14 number++; 15 } 16 } 17 } 18 if (number <= 3) { 19 sumCost = number * 0.1; 20 } else if (number <= 5) { 21 sumCost = 0.3 + 0.2 * (number - 3); 22 } else { 23 sumCost = 0.7 + 0.3 * (number - 5); 24 } 25 return sumCost; 26 } 27 28 }
最后再来创建通话记录类UserRecords,包含了该用户的市内、省内和国内以及是作为拨打方还是接听方的六种通话记录
1 class UserRecords { 2 3 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 4 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 5 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 6 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 7 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 8 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 9 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 10 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 11 12 public void addCallingInCityRecords(CallRecord callRecord) { 13 callingInCityRecords.add(callRecord); 14 } 15 16 public void addCallingInProvinceRecords(CallRecord callRecord) { 17 callingInProvinceRecords.add(callRecord); 18 } 19 20 public void addCallingInLandRecords(CallRecord callRecord) { 21 callingInLandRecords.add(callRecord); 22 } 23 24 public void addAnswerInCityRecords(CallRecord callRecord) { 25 answerInCityRecords.add(callRecord); 26 } 27 28 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 29 answerInProvinceRecords.add(callRecord); 30 } 31 32 public void addAnswerInLandRecords(CallRecord callRecord) { 33 answerInLandRecords.add(callRecord); 34 } 35 36 public void addSendMessageRecords(MessageRecord callRecord) { 37 sendMessageRecords.add(callRecord); 38 } 39 40 public void addReceiveMessageRecords(MessageRecord callRecord) { 41 receiveMessageRecords.add(callRecord); 42 } 43 44 public ArrayList<CallRecord> getCallingInCityRecords() { 45 return callingInCityRecords; 46 } 47 48 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 49 this.callingInCityRecords = callingInCityRecords; 50 } 51 52 public ArrayList<CallRecord> getCallingInProvinceRecords() { 53 return callingInProvinceRecords; 54 } 55 56 public void setCallingInProvinceRecords(ArrayList<CallRecord> callingInProvinceRecords) { 57 this.callingInProvinceRecords = callingInProvinceRecords; 58 } 59 60 public ArrayList<CallRecord> getCallingInLandRecords() { 61 return callingInLandRecords; 62 } 63 64 public void setCallingInLandRecords(ArrayList<CallRecord> callingInLandRecords) { 65 this.callingInLandRecords = callingInLandRecords; 66 } 67 68 public ArrayList<CallRecord> getAnswerInCityRecords() { 69 return answerInCityRecords; 70 } 71 72 public void setAnswerInCityRecords(ArrayList<CallRecord> answerInCityRecords) { 73 this.answerInCityRecords = answerInCityRecords; 74 } 75 76 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 77 return answerInProvinceRecords; 78 } 79 80 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 81 this.answerInProvinceRecords = answerInProvinceRecords; 82 } 83 84 public ArrayList<CallRecord> getAnswerInLandRecords() { 85 return answerInLandRecords; 86 } 87 88 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 89 this.answerInLandRecords = answerInLandRecords; 90 } 91 92 public ArrayList<MessageRecord> getSendMessageRecords() { 93 return sendMessageRecords; 94 } 95 96 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 97 this.sendMessageRecords = sendMessageRecords; 98 } 99 100 public ArrayList<MessageRecord> getReceiveMessageRecords() { 101 return receiveMessageRecords; 102 } 103 104 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 105 this.receiveMessageRecords = receiveMessageRecords; 106 } 107 108 }
创建CommunicationRecord抽象类代表一次通信,记录了拨打方号码和接听方号码
1 abstract class CommunicationRecord { 2 protected String callingNumber; 3 protected String answerNumbe; 4 5 public String getCallingNumber() { 6 return callingNumber; 7 } 8 9 public void setCallingNumber(String callingNumber) { 10 this.callingNumber = callingNumber; 11 } 12 13 public String getAnswerNumbe() { 14 return answerNumbe; 15 } 16 17 public void setAnswerNumbe(String answerNumbe) { 18 this.answerNumbe = answerNumbe; 19 } 20 21 }
创建手机或座机通话类CallRecord 实现CommunicationRecord
1 class CallRecord extends CommunicationRecord { 2 private Date startTime; 3 private Date endTime; 4 private String callingAddressAreaCode; 5 private String answerAddressAreaCode; 6 7 public String getCallType() { 8 String type = ""; 9 if (callingAddressAreaCode.equals("0791")) { 10 type = type.concat("1"); 11 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 12 type = type.concat("2"); 13 } else { 14 type = type.concat("3"); 15 } 16 17 if (answerAddressAreaCode.equals("0791")) { 18 type = type.concat("1"); 19 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 20 type = type.concat("2"); 21 } else { 22 type = type.concat("3"); 23 } 24 25 return type; 26 } 27 28 public CallRecord(String[] inputs) { 29 super(); 30 31 char type = inputs[0].charAt(0); 32 33 String sd = null, st = null, ed = null, et = null; 34 35 if (type == 't') { 36 if (inputs.length == 6) { 37 sd = inputs[2]; 38 st = inputs[3]; 39 ed = inputs[4]; 40 et = inputs[5]; 41 callingAddressAreaCode = inputs[0].substring(0, 4); 42 answerAddressAreaCode = inputs[1].substring(0, 4); 43 } else if (inputs.length == 7) { 44 sd = inputs[3]; 45 st = inputs[4]; 46 ed = inputs[5]; 47 et = inputs[6]; 48 if (inputs[0].charAt(0) != '0') { 49 if (inputs[2].length() == 10) { 50 answerAddressAreaCode = inputs[2].substring(0, 3); 51 } else { 52 answerAddressAreaCode = inputs[2].substring(0, 4); 53 } 54 callingAddressAreaCode = inputs[1]; 55 } else { 56 if (inputs[0].length() == 10) { 57 callingAddressAreaCode = inputs[0].substring(0, 3); 58 } else { 59 callingAddressAreaCode = inputs[0].substring(0, 4); 60 } 61 answerAddressAreaCode = inputs[2]; 62 } 63 } else if (inputs.length == 8) { 64 sd = inputs[4]; 65 st = inputs[5]; 66 ed = inputs[6]; 67 et = inputs[7]; 68 callingAddressAreaCode = inputs[1]; 69 answerAddressAreaCode = inputs[3]; 70 } 71 } else if (type == 'm') { 72 73 } 74 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 75 try { 76 startTime = simpleDateFormat.parse(sd + " " + st); 77 endTime = simpleDateFormat.parse(ed + " " + et); 78 } catch (ParseException e) { 79 } 80 81 } 82 83 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 84 super(); 85 this.startTime = startTime; 86 this.endTime = endTime; 87 this.callingAddressAreaCode = callingAddressAreaCode; 88 this.answerAddressAreaCode = answerAddressAreaCode; 89 } 90 91 public Date getStartTime() { 92 return startTime; 93 } 94 95 public void setStartTime(Date startTime) { 96 this.startTime = startTime; 97 } 98 99 public Date getEndTime() { 100 return endTime; 101 } 102 103 public void setEndTime(Date endTime) { 104 this.endTime = endTime; 105 } 106 107 public String getCallingAddressAreaCode() { 108 return callingAddressAreaCode; 109 } 110 111 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 112 this.callingAddressAreaCode = callingAddressAreaCode; 113 } 114 115 public String getAnswerAddressAreaCode() { 116 return answerAddressAreaCode; 117 } 118 119 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 120 this.answerAddressAreaCode = answerAddressAreaCode; 121 } 122 }
至此完成了所有类的创建,同时为了方便我们编程,我们还可以创建一个Tool工具类,其中定义一些静态方法:
1 to(double d) -- 将一个浮点数d保留两位小数转化为字符串返回 2 public static String to(double d) { 3 return new DecimalFormat("0.0#").format(d); 4 } 5 print(ArrayList<User> arrayList) -- 打印一个ArrayList集合 6 public static void print(ArrayList<User> arrayList) { 7 for (int i = 0; i < arrayList.size(); i++) { 8 System.out.print(arrayList.get(i).getNumber() + " " + Tool.to(arrayList.get(i).calCost()) + " " + Tool.to(arrayList.get(i).calBalance())); 9 System.out.println(); 10 } 11 } 12 work(String str) -- 判断一行字符串是开户还是通话记录,1代表是开户,2代表通话记录 13 public static int work(String str) { 14 if (str.matches("[u]-0791[0-9]{7,8}\\s[0]") || str.matches("[u]-1[0-9]{10}\\s[13]")) { 15 return 1; 16 } else if (str.matches("[m]-1[0-9]{10}\\s" + "1[0-9]{10}\\s" + "[0-9a-zA-Z\\s\\.,]+")) { 17 return 3; 18 } else if (str.matches("(([t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s)|" 19 + "([t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s)|" 20 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s)|" 21 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s))" 22 23 + "((([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?" 24 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 25 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 26 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" 27 + "((([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])\\.(" 28 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 29 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 30 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])")) { 31 return 2; 32 } 33 return 0; 34 } 35 addUser(ArrayList<User> users, String input) -- 根据input字符串信息向用户对象集合users中添加一个用户,如果已经存在该用户则不进行任何操作 36 public static void addUser(ArrayList<User> users, String input) { 37 User usernew = new User(); 38 String[] inputs = input.split(" "); 39 String num = inputs[0].substring(2); 40 for (User i : users) { 41 if (i.getNumber().equals(num)) { 42 return; 43 } 44 } 45 usernew.setNumber(num); 46 int mode = Integer.parseInt(inputs[1]); 47 if (mode == 0) { 48 usernew.setChargeMode(new LandlinePhoneCharging()); 49 } else if (mode == 1) { 50 usernew.setChargeMode(new MobilePhoneCharging()); 51 } else if (mode == 3) { 52 usernew.setChargeMode(new MobilePhoneMassageCharging()); 53 } 54 users.add(usernew); 55 } 56 57 addRecord2(ArrayList<User> arrayList, String str) -- 根据str字符串信息向用户对象集合users中的某个用户类中添加一条通话记录 58 59 public static void addRecord2(ArrayList<User> arrayList, String str) { 60 String[] inputs = str.split(" "); 61 inputs[0] = inputs[0].substring(2); 62 63 User callu = null, answeru = null; 64 65 String out = inputs[0]; 66 String in = ""; 67 if (inputs.length == 6) { 68 in = inputs[1]; 69 } else if (inputs.length == 7) { 70 in = inputs[1]; 71 } else if (inputs.length == 8) { 72 in = inputs[2]; 73 } else { 74 in = inputs[1]; 75 } 76 77 for (User i : arrayList) { 78 if (i.getNumber().equals(out)) { 79 callu = i; 80 } 81 if (i.getNumber().equals(in)) { 82 answeru = i; 83 } 84 if (callu != null && answeru != null) { 85 break; 86 } 87 } 88 89 if (str.charAt(0) == 'm') { 90 MessageRecord messageRecord = new MessageRecord(str); 91 if (callu != null) { 92 callu.getUserRecords().addSendMessageRecords(messageRecord); 93 ; 94 } 95 if (answeru != null) { 96 callu.getUserRecords().addReceiveMessageRecords(messageRecord); 97 } 98 } 99 100 }
到这里,我们就把所有的类以及一些基本的功能都实现了,接下来只需要在主函数里面调用即可:
public static void main(String[] args) { ArrayList<User> arrayList = new ArrayList<>(); Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); while (!str.equals("end")) { if (Tool.work(str) == 1) { Tool.addUser(arrayList, str); } else if (Tool.work(str) == 3) { Tool.addRecord2(arrayList, str); } else if (Tool.work(str) == 2){ Tool.addRecord(arrayList,str); } str = scanner.nextLine(); } Tool.sort(arrayList); Tool.print(arrayList); }
类图如下:


三、采坑心得
本次的电信计费系列题目只是类图难以理解消化,题目本身的陷阱倒不多,只要看懂了类图,能够创建出题目要求的各个类,实现其中的主要方法,题目难度就会骤减。但难点也在这里,相信对于大部分同学来说,很缺乏这样的编程经历,不过不需要担心,希望同学们可以真正深刻理解本次系列题目,做到下次在做这种类型的题目时可以有经验一点。
系列题目还有一个难点就是正则表达式的应用,判断输入的字符串是否符合规范,我之前不太了解正则表达式,是这学期的Java系列PTA作业才慢慢熟练的,每次使用都觉得很麻烦,还需要多加使用。除了正则表达式的正确使用外,还有怎么样的字符串才算正确输入也要很清楚,比如开户信息“string.matches("u-0791\\d{7,8}\\s[012]")”,必须是u-0791,第一次做时确实把这个忽略了导致出错。
四、改进建议
由于三次作业是分批次完成的,中间间隔也有些长,每次都要回忆题意,看懂上一次写的代码结构在进行编写,而且第三次作业由于代码长度受限且测试点无前两次的情况只能删除了很多和前两次相关的代码,导致没有系统性的写出完成的实现三次作业的代码,而对于没有这种编程经历的我们来说,重构一次电信计费系列会带来很多收获和感悟,所以有必要进行一次重构代码,进一步感悟Java面向对象编程的特点和魅力。
五、心得体会
1.通过本次电信计费系列作业,深刻感受到了Java面向对象编程的思路以及封装、继承和多态这面向对象三大特征的好处和优点,相较于C语言这种面向过程语言侧重于如何实现功能的语言,“如何去做”来说,确实能使得代码结构十分清晰,尤其是做越复杂的项目时,Java更多的是考虑“让谁来做”,理解类之间的关系才是Java的重中之重,相信本次经历会使以后的编程更加轻松!
2.如果题目需要设计多个类来解决问题的时候,一定要对每一个类多次测试验证,把错误率降到最低,循序渐进,这样也能尽量避免盲目找寻bug的情况。
3.通过本学期的Java学习,很大的感受就是个人的能力是有限的,有时候自己实在找不到自己漏考虑了什么情况或者哪个思路有一些问题的时候,一定要找同学帮忙,多互相看对方的实现思路,看看自己的算法是不是复杂度太高,或者实现思路太冗杂等等,相互学习才能最大化效率!

浙公网安备 33010602011771号