面向对象程序设计第三单元内容总结
前言:
这一单元的学习主要以实践为主,围绕电信计费系统问题,基于给定类图实现功能,并迭代。
设计与分析:
第一次作业:

由于给出了类图,类的设计已完成,使用IDEA自动生成代码大大减少了实际编码量。这样就使得我可以把主要的精力放在了重要方法的实现上。
代码如下:
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static final String regStr1 = "u-0791\\d{7,8}\\s[0-2]"; public static final String regStr = "t-0791\\d{7,8}\\s" + "0\\d{9,11}\\s" + "(((\\d{3}[1-9]|\\d{2}[1-9]\\d|\\d[1-9]\\d{2}|[1-9]\\d{3})\\.(((0?[13578]|1[02])\\.(0?" + "[1-9]|[12]\\d|3[01]))|(([469]|11)\\.([1-9]|[12]\\d|30))|(2\\.([1-9]|1\\d|2[0-8]))))|(((" + "\\d{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + "\\s([0-1]?\\d|2[0-3]):([0-5]\\d):([0-5]\\d)\\s" + "(((\\d{3}[1-9]|\\d{2}[1-9]\\d|\\d[1-9]\\d{2}|[1-9]\\d{3})\\.((([13578]|1[02])\\.(" + "[1-9]|[12]\\d|3[01]))|(([469]|11)\\.([1-9]|[12]\\d|30))|(2\\.([1-9]|1\\d|2[0-8]))))|(((" + "\\d{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + "\\s([0-1]?\\d|2[0-3]):([0-5]\\d):([0-5]\\d)"; public static void main(String[] args) { DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Scanner in = new Scanner(System.in); Pattern pattern = Pattern.compile(regStr1); String line = in.nextLine(); Matcher matcher = pattern.matcher(line); ArrayList<User> users = new ArrayList<>(); String[] userData = line.split(" "); int repeat = 0; while (!line.equals("end")) { if (line.startsWith("t-")){ Pattern pattern1 = Pattern.compile(regStr); Matcher matcher1 = pattern1.matcher(line); if(matcher1.find()) break; } if (matcher.find()) { User newUser = new User(100, new LandlinePhoneCharging(), userData[0].substring(2)); for (User user : users) { if (user.getNumber().equals(newUser.getNumber()) || !user.getNumber().startsWith("0791")) { repeat = 1; break; } } if (repeat == 0) { users.add(newUser); } repeat = 0; } line = in.nextLine(); userData = line.split(" "); matcher = pattern.matcher(line); } pattern = Pattern.compile(regStr); matcher = pattern.matcher(line); String callNumber; String answerNumber; while (!line.equals("end")) { if (matcher.find()) { String[] data = line.split(" "); callNumber = data[0].substring(2); answerNumber = data[1]; try { Date startDate = dateFormat.parse(data[2] + " " + data[3]); Date endDate = dateFormat.parse(data[4] + " " + data[5]); for (User user : users) { if (user.getNumber().equals(callNumber)) { int pos = judgePosition(user.getNumber(), answerNumber); switch (pos) { case 0: user.getUserRecords().addCallingInCityRecords(new CallRecord(callNumber, answerNumber, startDate, endDate)); break; case 1: user.getUserRecords().addCallingInProvinceRecords(new CallRecord(callNumber, answerNumber, startDate, endDate)); break; case 2: user.getUserRecords().addCallingInLandRecords(new CallRecord(callNumber, answerNumber, startDate, endDate)); break; } } if (user.getNumber().equals(answerNumber)) { int pos = judgePosition(user.getNumber(), answerNumber); switch (pos) { case 0: user.getUserRecords().addAnswerInCityRecords(new CallRecord(callNumber, answerNumber, startDate, endDate)); break; case 1: user.getUserRecords().addAnswerInProvinceRecords(new CallRecord(callNumber, answerNumber, startDate, endDate)); break; case 2: user.getUserRecords().addAnswerInLandRecords(new CallRecord(callNumber, answerNumber, startDate, endDate)); break; } } } } catch (Exception e) { line = in.nextLine(); matcher = pattern.matcher(line); continue; } } line = in.nextLine(); matcher = pattern.matcher(line); } Collections.sort(users); for (User user : users) { user.setBalance(user.calBalance()); System.out.printf(user.getNumber() + " " + round(user.calCost()) + " " + round(user.getBalance()) + "\n"); } } public static String round(double val) { BigDecimal bigDecimal = new BigDecimal(val); bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP); bigDecimal = bigDecimal.stripTrailingZeros(); String ret = bigDecimal.toPlainString(); if (!ret.contains(".")) { ret += ".0"; } return ret; } public static int judgePosition(String callNumber, String answerNumber) { if (callNumber.substring(0, 4).equals(answerNumber.substring(0, 4))) { return 0; } else if ((callNumber.startsWith("0790") || callNumber.startsWith("0791") || callNumber.startsWith("0792") || callNumber.startsWith("0793") || callNumber.startsWith("0794") || callNumber.startsWith("0795") || callNumber.startsWith("0796") || callNumber.startsWith("0797") || callNumber.startsWith("0798") || callNumber.startsWith("0799") || callNumber.startsWith("0701")) && ( answerNumber.startsWith("0790") || answerNumber.startsWith("0791") || answerNumber.startsWith("0792") || answerNumber.startsWith("0793") || answerNumber.startsWith("0794") || answerNumber.startsWith("0795") || answerNumber.startsWith("0796") || answerNumber.startsWith("0797") || answerNumber.startsWith("0798") || answerNumber.startsWith("0799") || answerNumber.startsWith("0701")) ) { return 1; } else { return 2; } } public static class MessageRecord extends CommunicationRecord { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } public static class User implements Comparable<User> { private UserRecords userRecords = new UserRecords(); private double balance; private ChargeMode chargeMode; private String number; public User() { } public User(double balance, ChargeMode chargeMode, String number) { this.balance = balance; this.chargeMode = chargeMode; this.number = number; } public double calCost() { return chargeMode.calCost(userRecords); } public double calBalance() { return balance - calCost() - chargeMode.getMonthlyRent(); } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public ChargeMode getChargeMode() { return chargeMode; } public void setChargeMode(ChargeMode chargeMode) { this.chargeMode = chargeMode; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public int compareTo(User user) { int result = this.getNumber().compareTo(user.getNumber()); switch (result) { case 0: return 0; case 1: return 1; default: return -1; } } } public static class UserRecords { private final ArrayList<CallRecord> callingInCityRecords = new ArrayList<>(); private final ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>(); private final ArrayList<CallRecord> callingInLandRecords = new ArrayList<>(); private final ArrayList<CallRecord> answerInCityRecords = new ArrayList<>(); private final ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<>(); private final ArrayList<CallRecord> answerInLandRecords = new ArrayList<>(); private final ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>(); private final ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>(); public void addCallingInCityRecords(CallRecord callRecord) { if (!checkRepeat(callRecord, getCallingInCityRecords())) callingInCityRecords.add(callRecord); } public void addCallingInProvinceRecords(CallRecord callRecord) { if (!checkRepeat(callRecord, getCallingInProvinceRecords())) callingInProvinceRecords.add(callRecord); } public void addCallingInLandRecords(CallRecord callRecord) { if (!checkRepeat(callRecord, getCallingInLandRecords())) callingInLandRecords.add(callRecord); } public void addAnswerInCityRecords(CallRecord answerRecord) { if (!checkRepeat(answerRecord, getAnswerInCityRecords())) answerInCityRecords.add(answerRecord); } public void addAnswerInProvinceRecords(CallRecord answerRecord) { if (!checkRepeat(answerRecord, getAnswerInProvinceRecords())) answerInProvinceRecords.add(answerRecord); } public void addAnswerInLandRecords(CallRecord answerRecord) { if (!checkRepeat(answerRecord, getAnswerInLandRecords())) answerInLandRecords.add(answerRecord); } public void addSendMessageRecords(MessageRecord messageRecord) { sendMessageRecords.add(messageRecord); } public void addReceiveMessageRecords(MessageRecord messageRecord) { receiveMessageRecords.add(messageRecord); } public ArrayList<CallRecord> getCallingInCityRecords() { return callingInCityRecords; } public ArrayList<CallRecord> getCallingInProvinceRecords() { return callingInProvinceRecords; } public ArrayList<CallRecord> getCallingInLandRecords() { return callingInLandRecords; } public ArrayList<CallRecord> getAnswerInCityRecords() { return answerInCityRecords; } public ArrayList<CallRecord> getAnswerInProvinceRecords() { return answerInProvinceRecords; } public ArrayList<CallRecord> getAnswerInLandRecords() { return answerInLandRecords; } public ArrayList<MessageRecord> getSendMessageRecords() { return sendMessageRecords; } public ArrayList<MessageRecord> getReceiveMessageRecords() { return receiveMessageRecords; } public boolean checkRepeat(CallRecord record, ArrayList<CallRecord> records) { if (record.getCallingNumber().equals(record.getAnswerNumber())){ return true; } for (CallRecord rd : records) { if (rd.getStartTime() == record.getStartTime() && rd.getEndTime() == record.getEndTime()) { return true; } if (record.getCallingNumber().equals(record.getAnswerNumber())) { return true; } if (record.getStartTime().getTime() - record.getEndTime().getTime() > 0) { return true; } } return false; } } public static class LandPhoneInProvinceRule extends CallChargeRule { @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord : callRecords) { diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if (second != 0) { minutes++; } result += minutes * 0.3; } return result; } } public static class LandPhoneInlandRule extends CallChargeRule { @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord : callRecords) { diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if (second != 0) { minutes++; } result += minutes * 0.6; } return result; } } public static class LandPhoneInCityRule extends CallChargeRule { @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord : callRecords) { diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if (second != 0) { minutes++; } result += minutes * 0.1; } return result; } } public static class LandlinePhoneCharging extends ChargeMode { private final double monthlyRent = 20; public LandlinePhoneCharging() { getChargeRules().add(new LandPhoneInCityRule()); getChargeRules().add(new LandPhoneInlandRule()); getChargeRules().add(new LandPhoneInProvinceRule()); } @Override public double calCost(UserRecords userRecords) { double cost = 0; cost += getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords()); cost += getChargeRules().get(1).calCost(userRecords.getCallingInLandRecords()); cost += getChargeRules().get(2).calCost(userRecords.getCallingInProvinceRecords()); return cost; } @Override public double getMonthlyRent() { return monthlyRent; } } public abstract static class CommunicationRecord { protected String callingNumber; protected String answerNumber; public String getCallingNumber() { return callingNumber; } public void setCallingNumber(String callingNumber) { this.callingNumber = callingNumber; } public String getAnswerNumber() { return answerNumber; } public void setAnswerNumber(String answerNumber) { this.answerNumber = answerNumber; } } public abstract static class ChargeRule { abstract double calCost(ArrayList<CallRecord> callRecords); } public abstract static class ChargeMode { private ArrayList<ChargeRule> chargeRules = new ArrayList<>(); public ArrayList<ChargeRule> getChargeRules() { return chargeRules; } public void setChargeRules(ArrayList<ChargeRule> chargeRules) { this.chargeRules = chargeRules; } public abstract double calCost(UserRecords userRecords); public abstract double getMonthlyRent(); } public static class CallRecord extends CommunicationRecord { private Date startTime; private Date endTime; private String callingAddressAreaCode; private String answerAddressAreaCode; public CallRecord(String callNumber, String answerNumber, Date startTime, Date endTime) { setCallingNumber(callNumber); setAnswerNumber(answerNumber); this.startTime = startTime; this.endTime = endTime; callingAddressAreaCode = callNumber.substring(0, 4); answerAddressAreaCode = answerNumber.substring(0, 4); } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } } public abstract static class CallChargeRule extends ChargeRule { abstract double calCost(ArrayList<CallRecord> callRecords); } }
在实现方法的过程中主要有以下几个问题:第一,类图中给出的方法不足以满足题目的需求,需要给个别类合理添加方法来实现需求,例如,校验用户重复,校验通话记录重复。第二,在计费算法的实现过程中需要获取时间差,这里我选用了SimpleDateFormat类来获取所需的时间。第三,在设计Main类中需要合理规划IPO,对于输入用户和输入通话记录要有所区分,并且大量使用正则表达式。
在第一次的实现中,并没有考虑仔细输入用户与输入通话记录的分界点,把它们放在两个循环里读入,很难完美选择跳出循环的条件。
第二次作业:
在第一次作业的基础上,新增了手机用户。这一次的迭代中需要我按照座机收费的类编写手机用户所需要的各种类。
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Scanner; public class Main { public static void main(String[] args) throws ParseException { Controller controller = new Controller(); Scanner in = new Scanner(System.in); ArrayList<User> users = new ArrayList<>(); String line = in.nextLine(); // 判断时间输入的正则表达式 String datePatten = "(((\\d{3}[1-9]|\\d{2}[1-9]\\d|\\d[1-9]\\d{2}|[1-9]\\d{3})\\.(((0?[13578]|1[02])\\.(" + "[1-9]|[12]\\d|3[01]))|(([469]|11)\\.([1-9]|[12]\\d|30))|(2\\.([1-9]|1\\d|2[0-8]))))|(((" + "\\d{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" + "\\s([0-1]?\\d|2[0-3]):([0-5]\\d):([0-5]\\d)"; //座机开户 String Account1 = "u-0791\\d{7,8}\\s0"; //手机开户 String Account2 = "u-13\\d{9}\\s1"; //座机打座机 String Mode1 = "t-0791\\d{7,8}\\s" + "0\\d{9,11}\\s" + datePatten + "\\s" + datePatten; //座机打手机 String Mode2 = "t-0791\\d{7,8}\\s" + "1\\d{10}\\s" + "0\\d{2,3}\\s" + datePatten + "\\s" + datePatten; //手机打座机 String Mode3 = "t-1\\d{10}\\s" + "0\\d{2,3}\\s" + "0\\d{10,11}\\s" + datePatten + "\\s" + datePatten; //手机打手机 String Mode4 = "t-1\\d{10}\\s" + "0\\d{2,3}\\s" + "1\\d{10}\\s" + "0\\d{2,3}\\s" + datePatten + "\\s" + datePatten; while (!line.equals("end")) { String[] data = line.split(" +"); if (line.matches(Account1)) { controller.addLandLineUser(users, data); } else if (line.matches(Account2)) { controller.addCellPhoneUser(users, data); } else if (line.matches(Mode1)) { // 座机打座机 controller.addLandLineCallRecord(users, data); } else if (line.matches(Mode2)) { // 座机打手机 controller.addLandLineToCellPhoneRecord(users, data); } else if (line.matches(Mode3)) { controller.addCellPhoneToLandLineRecord(users, data); } else if (line.matches(Mode4)) { controller.addCellPhoneToCellPhoneRecord(users, data); } line = in.nextLine(); } Collections.sort(users); for(User user:users){ user.setBalance(user.calBalance()); System.out.printf(user.getNumber() + " " + round(user.calCost()) + " " + round(user.getBalance()) + "%n"); } } public static String round(double val) { BigDecimal bigDecimal = new BigDecimal(val); bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP); bigDecimal = bigDecimal.stripTrailingZeros(); String ret = bigDecimal.toPlainString(); if (!ret.contains(".")) { ret += ".0"; } return ret; } public static class MessageRecord extends CommunicationRecord{ private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } public static class UserRecords { private ArrayList<CallRecord> callingInCityToProvinceRecords = new ArrayList<>(); private ArrayList<CallRecord> callingInCityToLandRecords = new ArrayList<>(); private ArrayList<CallRecord> callingInCityRecords= new ArrayList<>(); private ArrayList<CallRecord> callingInProvinceRecords= new ArrayList<>(); private ArrayList<CallRecord> callingInLandRecords= new ArrayList<>(); private ArrayList<CallRecord> answerInCityRecords= new ArrayList<>(); private ArrayList<CallRecord> answerInProvinceRecords= new ArrayList<>(); private ArrayList<CallRecord> answerInLandRecords= new ArrayList<>(); private ArrayList<MessageRecord> sendMessageRecords= new ArrayList<>(); private ArrayList<MessageRecord> receiveMessageRecords= new ArrayList<>(); public ArrayList<CallRecord> getCallingInCityToProvinceRecords() { return callingInCityToProvinceRecords; } public void addCallingInCityToProvinceRecords(CallRecord callRecord) { if (!checkRepeat(callRecord, getCallingInCityToProvinceRecords())) callingInCityToProvinceRecords.add(callRecord); } public ArrayList<CallRecord> getCallingInCityToLandRecords() { return callingInCityToLandRecords; } public void addCallingInCityToLandRecords(CallRecord callRecord) { if (!checkRepeat(callRecord, getCallingInCityToLandRecords())){ callingInCityToLandRecords.add(callRecord); } } public void addCallingInCityRecords(CallRecord callRecord){ if (!checkRepeat(callRecord, getCallingInCityRecords())) callingInCityRecords.add(callRecord); } public void addCallingInProvinceRecords(CallRecord callRecord){ if (!checkRepeat(callRecord, getCallingInProvinceRecords())) callingInProvinceRecords.add(callRecord); } public void addCallingInLandRecords(CallRecord callRecord){ if (!checkRepeat(callRecord, getCallingInLandRecords())) callingInLandRecords.add(callRecord); } public void addAnswerInCityRecords(CallRecord answerRecord){ if (!checkRepeat(answerRecord, getAnswerInCityRecords())) answerInCityRecords.add(answerRecord); } public void addAnswerInProvinceRecords(CallRecord answerRecord){ if (!checkRepeat(answerRecord, getAnswerInProvinceRecords())) answerInProvinceRecords.add(answerRecord); } public void addAnswerInLandRecords(CallRecord answerRecord){ if (!checkRepeat(answerRecord, getAnswerInLandRecords())) answerInLandRecords.add(answerRecord); } public void addSendMessageRecords(MessageRecord messageRecord){ sendMessageRecords.add(messageRecord); } public void addReceiveMessageRecords(MessageRecord messageRecord){ receiveMessageRecords.add(messageRecord); } public ArrayList<CallRecord> getCallingInCityRecords() { return callingInCityRecords; } public ArrayList<CallRecord> getCallingInProvinceRecords() { return callingInProvinceRecords; } public ArrayList<CallRecord> getCallingInLandRecords() { return callingInLandRecords; } public ArrayList<CallRecord> getAnswerInCityRecords() { return answerInCityRecords; } public ArrayList<CallRecord> getAnswerInProvinceRecords() { return answerInProvinceRecords; } public ArrayList<CallRecord> getAnswerInLandRecords() { return answerInLandRecords; } public ArrayList<MessageRecord> getSendMessageRecords() { return sendMessageRecords; } public ArrayList<MessageRecord> getReceiveMessageRecords() { return receiveMessageRecords; } public boolean checkRepeat(CallRecord record, ArrayList<CallRecord> records){ for (CallRecord rd:records){ if (rd.getStartTime() == record.getStartTime() && rd.getEndTime() == record.getEndTime()){ return true; } if (record.getCallingNumber().equals(record.getAnswerNumber())){ return true; } } return false; } } public static class User implements Comparable<User>{ private UserRecords userRecords = new UserRecords(); private double balance; private ChargeMode chargeMode; private String number; public User(){} public User(double balance, ChargeMode chargeMode, String number) { this.balance = balance; this.chargeMode = chargeMode; this.number = number; } public double calCost(){ return chargeMode.calCost(userRecords); } public double calBalance(){ return balance - calCost() - chargeMode.getMonthlyRent(); } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public ChargeMode getChargeMode() { return chargeMode; } public void setChargeMode(ChargeMode chargeMode) { this.chargeMode = chargeMode; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public int compareTo(User user) { return getNumber().compareTo(user.getNumber()); } } public static class LandPhoneInProvinceRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getStartTime().getTime() - callRecord.getEndTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes--; } result += - minutes * 0.3; } return result; } } public static class LandPhoneInlandRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getStartTime().getTime() - callRecord.getEndTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes--; } result += - minutes * 0.6; } return result; } } public static class LandPhoneInCityRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getStartTime().getTime() - callRecord.getEndTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes--; } result += - minutes * 0.1; } return result; } } public static class LandlinePhoneCharging extends ChargeMode{ private double monthlyRent = 20; public LandlinePhoneCharging(){ getChargeRules().add(new LandPhoneInCityRule()); getChargeRules().add(new LandPhoneInlandRule()); getChargeRules().add(new LandPhoneInProvinceRule()); } @Override public double calCost(UserRecords userRecords) { double cost = 0; cost += getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords()); cost += getChargeRules().get(1).calCost(userRecords.getCallingInLandRecords()); cost += getChargeRules().get(2).calCost(userRecords.getCallingInProvinceRecords()); return cost; } @Override public double getMonthlyRent() { return monthlyRent; } } public static class Controller { /** * CellPhone to CellPhone * @param users * @param data */ public void addCellPhoneToCellPhoneRecord(ArrayList<User> users, String[] data) throws ParseException{ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Date StartDate; Date EndDate; String callNumber = data[0].substring(2); String answerNumber = data[2]; StartDate = dateFormat.parse(data[4] + " " + data[5]); EndDate = dateFormat.parse(data[6] + " " + data[7]); CallRecord record = new CallRecord(callNumber, answerNumber, StartDate, EndDate); record.setCallingAddressAreaCode(data[1]); record.setAnswerAddressAreaCode(data[3]); for(User user:users){ if (user.getNumber().equals(callNumber)){ int callPos = judgePos(record.getCallingAddressAreaCode()); int answerPos = judgePos(record.getAnswerAddressAreaCode()); if (callPos == 1 && answerPos == 1){ user.getUserRecords().addCallingInCityRecords(record); } else if (callPos == 1 && answerPos == 2){ user.getUserRecords().addCallingInCityToProvinceRecords(record); } else if (callPos == 2){ user.getUserRecords().addCallingInProvinceRecords(record); } else if (callPos == 3) { user.getUserRecords().addCallingInLandRecords(record); } else if (callPos == 1 && answerPos == 3){ user.getUserRecords().addCallingInCityToLandRecords(record); } } if (user.getNumber().equals(answerNumber)){ int pos = judgePos(record.getAnswerAddressAreaCode()); if (pos == 3){ user.getUserRecords().addAnswerInLandRecords(record); } } } } /** * CellPhone to LandLine * @param users * @param data * @throws ParseException */ public void addCellPhoneToLandLineRecord(ArrayList<User> users, String[] data) throws ParseException{ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Date StartDate; Date EndDate; String callNumber = data[0].substring(2); String answerNumber = data[2]; StartDate = dateFormat.parse(data[3] + " " + data[4]); EndDate = dateFormat.parse(data[5] + " " + data[6]); CallRecord record = new CallRecord(callNumber, answerNumber, StartDate, EndDate); record.setCallingAddressAreaCode(data[1]); for (User user:users){ if (user.getNumber().equals(callNumber)){ int answerPos = judgePos(record.getAnswerAddressAreaCode()); int callPos = judgePos(record.getCallingAddressAreaCode()); if (answerPos == 1 && callPos == 1){ user.getUserRecords().addCallingInCityRecords(record); } else if (callPos == 1 && answerPos == 2){ user.getUserRecords().addCallingInCityToProvinceRecords(record); } else if (callPos == 2){ user.getUserRecords().addCallingInProvinceRecords(record); } else if (callPos == 3){ user.getUserRecords().addCallingInLandRecords(record); } else if (callPos == 1 && answerPos == 3){ user.getUserRecords().addCallingInCityToLandRecords(record); } } } } /** * Landline to CellPhone * @param users * @param data * @throws ParseException */ public void addLandLineToCellPhoneRecord(ArrayList<User> users, String[] data) throws ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Date StartDate; Date EndDate; String callNumber = data[0].substring(2); String answerNumber = data[1]; StartDate = dateFormat.parse(data[3] + " " + data[4]); EndDate = dateFormat.parse(data[5] + " " + data[6]); CallRecord record = new CallRecord(callNumber, answerNumber, StartDate, EndDate); record.setAnswerAddressAreaCode(data[2]); for (User user: users){ if (user.getNumber().equals(callNumber)){ int pos = judgePos(record.getAnswerAddressAreaCode()); switch (pos){ case 1:user.getUserRecords().addCallingInCityRecords(record);break; case 2:user.getUserRecords().addCallingInProvinceRecords(record);break; case 3:user.getUserRecords().addCallingInLandRecords(record);break; } } if (user.getNumber().equals(answerNumber)){ int pos = judgePos(record.getAnswerAddressAreaCode(), record.getCallingAddressAreaCode()); switch (pos){ case 1: user.getUserRecords().addAnswerInCityRecords(record);break; case 2: user.getUserRecords().addAnswerInProvinceRecords(record);break; case 3: user.getUserRecords().addAnswerInLandRecords(record);break; } } } } /** * Landline to Landline * @param users * @param data * @throws ParseException */ public void addLandLineCallRecord(ArrayList<User> users, String[] data) throws ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Date StartDate; Date EndDate; String callNumber = data[0].substring(2); String answerNumber = data[1]; StartDate = dateFormat.parse(data[2] + " " + data[3]); EndDate = dateFormat.parse(data[4] + " " + data[5]); CallRecord record = new CallRecord(callNumber, answerNumber, StartDate, EndDate); for (User user:users){ if (user.getNumber().equals(callNumber)){ int pos = judgePos(record.getAnswerAddressAreaCode()); switch (pos){ case 1:user.getUserRecords().addCallingInCityRecords(record);break; case 2:user.getUserRecords().addCallingInProvinceRecords(record);break; case 3:user.getUserRecords().addCallingInLandRecords(record);break; } } } } public void addLandLineUser(ArrayList<User> users, String[] data) { if (!UserRepeat(data[0].substring(2), users)){ User user = new User(100, new LandlinePhoneCharging(), data[0].substring(2)); users.add(user); } } public boolean UserRepeat(String Number, ArrayList<User> users){ for (User user: users){ if (user.getNumber().equals(Number)){ return true; } } return false; } public int judgePos(String AnswerNumber){ if (AnswerNumber.matches("0791")) { return 1; }else if (AnswerNumber.matches("07(9[0|2-9]|01)")) { return 2; }else { return 3; } } public int judgePos(String answerAddressAreaCode, String callingAddressAreaCode){ if (answerAddressAreaCode.matches("0791") && callingAddressAreaCode.matches("0791")){ return 1; } else if (answerAddressAreaCode.matches("07(9[0|1-9]|01)") && callingAddressAreaCode.matches("07(9[0|1-9]|01)")){ return 2; } else { return 3; } } public void addCellPhoneUser(ArrayList<User> users, String[] data) { if (!UserRepeat(data[0].substring(2), users)){ User user = new User(100, new CellPhoneCharging(), data[0].substring(2)); users.add(user); } } } public abstract static class CommunicationRecord { protected String callingNumber; protected String answerNumber; public String getCallingNumber() { return callingNumber; } public void setCallingNumber(String callingNumber) { this.callingNumber = callingNumber; } public String getAnswerNumber() { return answerNumber; } public void setAnswerNumber(String answerNumber) { this.answerNumber = answerNumber; } } public abstract static class ChargeRule { abstract double calCost(ArrayList<CallRecord> callRecords); } public abstract static class ChargeMode { private ArrayList<ChargeRule> chargeRules = new ArrayList<>(); public ArrayList<ChargeRule> getChargeRules() { return chargeRules; } public void setChargeRules(ArrayList<ChargeRule> chargeRules) { this.chargeRules = chargeRules; } public abstract double calCost(UserRecords userRecords); public abstract double getMonthlyRent(); } public static class CellPhoneInProvinceRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes++; } result += minutes * 0.3; } return result; } } public static class CellPhoneInLandRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes++; } result += minutes * 0.6; } return result; } } public static class CellPhoneInCityToProvinceRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes++; } result += minutes * 0.2; } return result; } } public static class CellPhoneInCityToLandRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes++; } result += minutes * 0.3; } return result; } } public static class CellPhoneInCityToCityRule extends CallChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes++; } result += minutes * 0.1; } return result; } } public static class CellPhoneCharging extends ChargeMode { private double MonthlyRent = 15; public CellPhoneCharging(){ getChargeRules().add(new CellPhoneInCityToCityRule()); getChargeRules().add(new CellPhoneInCityToProvinceRule()); getChargeRules().add(new CellPhoneInCityToLandRule()); getChargeRules().add(new CellPhoneInProvinceRule()); getChargeRules().add(new CellPhoneInLandRule()); getChargeRules().add(new AnswerOutOfProvinceRule()); } @Override public double calCost(UserRecords userRecords) { double cost = 0; cost += getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords()); cost += getChargeRules().get(1).calCost(userRecords.getCallingInCityToProvinceRecords()); cost += getChargeRules().get(2).calCost(userRecords.getCallingInCityToLandRecords()); cost += getChargeRules().get(3).calCost(userRecords.getCallingInProvinceRecords()); cost += getChargeRules().get(4).calCost(userRecords.getCallingInLandRecords()); cost += getChargeRules().get(5).calCost(userRecords.getAnswerInLandRecords()); return cost; } @Override public double getMonthlyRent() { return MonthlyRent; } } public static class CallRecord extends CommunicationRecord { private Date startTime; private Date endTime; private String callingAddressAreaCode; private String answerAddressAreaCode; public CallRecord(String callNumber, String answerNumber, Date startTime, Date endTime){ setCallingNumber(callNumber); setAnswerNumber(answerNumber); this.startTime = startTime; this.endTime = endTime; callingAddressAreaCode = callNumber.substring(0, 4); answerAddressAreaCode = answerNumber.substring(0, 4); } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } } public abstract static class CallChargeRule extends ChargeRule { abstract double calCost(ArrayList<CallRecord> callRecords); } public static class AnswerOutOfProvinceRule extends AnswerChargeRule{ @Override double calCost(ArrayList<CallRecord> callRecords) { long diff = 0; long minutes = 0; long second = 0; double result = 0; for (CallRecord callRecord:callRecords){ diff = callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime(); minutes = diff / (1000 * 60); second = (diff - minutes * (1000 * 60)) / (1000); if ( second != 0){ minutes++; } result += minutes * 0.3; } return result; } } public abstract static class AnswerChargeRule extends ChargeRule { abstract double calCost(ArrayList<CallRecord> callRecords); } }
这一次迭代由于初代版本已经做好了相应的拓展性,并没有花费太多的时间。吸取第一次Main类的设计失误,这次对Main类进行了重构,新增了Controller类用作解耦合。main方法中的代码更加简洁。在这次迭代中主要的难点在于对呼叫用户和接听用户的类型进行分类,并对每一种通话类型进行地区分类,再收录进相应的record。最后进行计算。
第三次作业:
第三次作业是对短信的单独计费,难度在于计费算法以及识别合法短信的正则表达式。
1 import java.math.BigDecimal; 2 import java.math.RoundingMode; 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Scanner; 6 7 public class Main { 8 public static void main(String[] args) { 9 Controller controller = new Controller(); 10 Scanner in = new Scanner(System.in); 11 ArrayList<User> users = new ArrayList<>(); 12 13 String Account = "u-1\\d{10}\\s3"; 14 String Message = "^m-1\\d{10} 1\\d{10}\\s[\\w\\d\\s,.]+$"; 15 16 String line = in.nextLine(); 17 18 while (!line.equals("end")){ 19 if (line.matches(Account)){ 20 controller.addCellPhoneUser(users, line); 21 } else if (line.matches(Message)){ 22 controller.addMessage(users, line); 23 } 24 line = in.nextLine(); 25 } 26 Collections.sort(users); 27 for(User user:users){ 28 user.setBalance(user.calBalance()); 29 System.out.printf(user.getNumber() + " " + round(user.calCost()) + " " + round(user.getBalance()) + "%n"); 30 } 31 } 32 33 public static String round(double val) { 34 BigDecimal bigDecimal = new BigDecimal(val); 35 bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP); 36 bigDecimal = bigDecimal.stripTrailingZeros(); 37 String ret = bigDecimal.toPlainString(); 38 if (!ret.contains(".")) { 39 ret += ".0"; 40 } 41 return ret; 42 } 43 44 public static class MessageChargeRule extends ChargeRule{ 45 46 @Override 47 double calCost(ArrayList<MessageRecord> messageRecords) { 48 double cost = 0; 49 double fee = 0; 50 int n = 0; 51 for (MessageRecord record:messageRecords){ 52 if (record.getMessage().length() < 10){ 53 n++; 54 } else { 55 int text = 0; 56 text = record.getMessage().length() / 10; 57 int length = record.getMessage().length(); 58 int mod = record.getMessage().length() % 10; 59 if (record.getMessage().length() % 10 != 0){ 60 text++; 61 } 62 n += text; 63 } 64 } 65 if (n < 3){ 66 fee = 0.1; 67 cost = n * fee; 68 } else if (n < 5){ 69 fee = 0.2; 70 cost = 0.1 * 3 + 0.2 * (n - 3); 71 } else { 72 fee = 0.3; 73 cost = 0.1 * 3 + 0.2 * 2 + 0.3 * (n - 5); 74 } 75 76 return cost; 77 } 78 } 79 80 public static class MessageRecord extends CommunicationRecord{ 81 private String message; 82 83 public String getMessage() { 84 return message; 85 } 86 87 public void setMessage(String message) { 88 this.message = message; 89 } 90 } 91 92 public static class User implements Comparable<User>{ 93 private UserRecords userRecords = new UserRecords(); 94 private double balance; 95 private ChargeMode chargeMode; 96 private String number; 97 98 public User(){} 99 100 public User(double balance, ChargeMode chargeMode, String number) { 101 this.balance = balance; 102 this.chargeMode = chargeMode; 103 this.number = number; 104 } 105 106 public double calCost(){ 107 return chargeMode.calCost(userRecords); 108 } 109 110 public double calBalance(){ 111 return balance - calCost() - chargeMode.getMonthlyRent(); 112 } 113 114 public UserRecords getUserRecords() { 115 return userRecords; 116 } 117 118 public void setUserRecords(UserRecords userRecords) { 119 this.userRecords = userRecords; 120 } 121 122 public double getBalance() { 123 return balance; 124 } 125 126 public void setBalance(double balance) { 127 this.balance = balance; 128 } 129 130 public ChargeMode getChargeMode() { 131 return chargeMode; 132 } 133 134 public void setChargeMode(ChargeMode chargeMode) { 135 this.chargeMode = chargeMode; 136 } 137 138 public String getNumber() { 139 return number; 140 } 141 142 public void setNumber(String number) { 143 this.number = number; 144 } 145 146 public int compareTo(User user) { 147 return getNumber().compareTo(user.getNumber()); 148 } 149 } 150 151 public static class UserRecords { 152 private ArrayList<MessageRecord> sendMessageRecords= new ArrayList<>(); 153 private ArrayList<MessageRecord> receiveMessageRecords= new ArrayList<>(); 154 155 public ArrayList<MessageRecord> getSendMessageRecords() { 156 return sendMessageRecords; 157 } 158 159 public ArrayList<MessageRecord> getReceiveMessageRecords() { 160 return receiveMessageRecords; 161 } 162 163 public void addSendMessageRecords(MessageRecord messageRecord){ 164 sendMessageRecords.add(messageRecord); 165 } 166 167 public void addReceiveMessageRecords(MessageRecord messageRecord){ 168 receiveMessageRecords.add(messageRecord); 169 } 170 } 171 172 public static class Controller { 173 public void addCellPhoneUser(ArrayList<User> users, String line) { 174 String[] data = line.split(" +"); 175 if (!UserRepeat(data[0].substring(2), users)){ 176 User user = new User(100, new CellPhoneMessageCharging(), data[0].substring(2)); 177 users.add(user); 178 } 179 } 180 181 public boolean UserRepeat(String Number, ArrayList<User> users){ 182 for (User user: users){ 183 if (user.getNumber().equals(Number)){ 184 return true; 185 } 186 } 187 return false; 188 } 189 190 public void addMessage(ArrayList<User> users, String line){ 191 String[] data = line.split(" +"); 192 String Sender = data[0].substring(2); 193 String Receiver = data[1]; 194 String text = line.substring(26); 195 MessageRecord messageRecord = new MessageRecord(); 196 messageRecord.setMessage(text); 197 messageRecord.setCallingNumber(Sender); 198 messageRecord.setAnswerNumber(Receiver); 199 for (User user:users){ 200 if (user.getNumber().equals(Sender)){ 201 user.getUserRecords().addSendMessageRecords(messageRecord); 202 } 203 if (user.getNumber().equals(Receiver)){ 204 user.getUserRecords().addReceiveMessageRecords(messageRecord); 205 } 206 } 207 } 208 } 209 210 public abstract static class CommunicationRecord { 211 protected String callingNumber; 212 protected String answerNumber; 213 214 public String getCallingNumber() { 215 return callingNumber; 216 } 217 218 public void setCallingNumber(String callingNumber) { 219 this.callingNumber = callingNumber; 220 } 221 222 public String getAnswerNumber() { 223 return answerNumber; 224 } 225 226 public void setAnswerNumber(String answerNumber) { 227 this.answerNumber = answerNumber; 228 } 229 } 230 231 public abstract static class ChargeRule { 232 abstract double calCost(ArrayList<MessageRecord> messageRecords); 233 } 234 235 public abstract static class ChargeMode { 236 private ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 237 238 public ArrayList<ChargeRule> getChargeRules() { 239 return chargeRules; 240 } 241 242 public void setChargeRules(ArrayList<ChargeRule> chargeRules) { 243 this.chargeRules = chargeRules; 244 } 245 246 public abstract double calCost(UserRecords userRecords); 247 248 public abstract double getMonthlyRent(); 249 } 250 251 public static class CellPhoneMessageCharging extends ChargeMode { 252 private double MonthlyRent = 0; 253 254 public CellPhoneMessageCharging(){ 255 getChargeRules().add(new MessageChargeRule()); 256 } 257 @Override 258 public double calCost(UserRecords userRecords) { 259 double cost = 0; 260 cost += getChargeRules().get(0).calCost(userRecords.getSendMessageRecords()); 261 return cost; 262 } 263 264 @Override 265 public double getMonthlyRent() { 266 return MonthlyRent; 267 } 268 } 269 }
踩坑心得:
没有提前设计好main方法导致的一系列问题,各种问题堆叠在一起后就不得不重构代码,花费大量时间。编写核心代码不能浮躁,各种情况都要考虑到,不然核心代码出现问题后main函数基本要重构。
改进建议:
对于简单的函数可以使用自动生成代码, 对于关联比较复杂的方法就需要自己动手编写,以防自动生成的代码有参数上的不一致。分配好设计与编码的比例,应该以设计为主,编码所需的时间应该适当降低,说不定能起到事半功倍的效果。
总结:
在代码量提升后,面向对象程序设计原则的优越性就体现出来了。符合设计原则的代码能有很高的复用率,也更容易发现问题。在大量代码面前,统一的规范是必须的。这三次的迭代对我来说就是加强了对代码设计自我的要求,更严格的去按照所学的设计原则设计和编写代码,使得代码更加规范和美观。

浙公网安备 33010602011771号