BLOG-3
Java博客作业(三)
一、前言
<1>第六次大作业
题型总结:电信计费系列1-座机计费、多态测试。
涉及知识点:正则表达式的理解和应用、Java基本的语法和面向对象的一系列操作,对给出类图的阅读能力,父类和子类的关系以及对多态的理解。
题量:适中。
难度:适中。
<2>第七次大作业
题型总结: 电信计费系列2-手机+座机计费,sdut-Collection-sort--C~K的班级(II),阅读程序,按照题目需求修改程序。
涉及知识点:正则表达式的理解和应用、Java基本的语法和面向对象的一系列操作,阅读类图的能力,对动态数组的理解和其自带方法的使用。
题量:适中。
难度:适中。
<3>第八次大作业
题型总结:电信计费系列3-短信计费、编写一个类Shop(商店)、内部类InnerCoupons(内部购物券)、动物发声模拟器(多态)。
涉及知识点:Java基本的语法和面向对象的一系列操作,继承和多态、抽象方法、类的重构、ArrayList的使用、容器的使用。
题量:适中。
难度:适中。
二、设计与分析
1.算法设计以及思路
<1>第六次大作业第一题
实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
输入格式:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码除区号外由是7-8位数字组成。
本题只考虑计费类型0-座机计费,电信系列2、3题会逐步增加计费类型。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
注意:
本题非法输入只做格式非法的判断,不做内容是否合理的判断(时间除外,否则无法计算),比如:
1、输入的所有通讯信息均认为是同一个月的通讯信息,不做日期是否在同一个月还是多个月的判定,直接将通讯费用累加,因此月租只计算一次。
2、记录中如果同一电话号码的多条通话记录时间出现重合,这种情况也不做判断,直接 计算每条记录的费用并累加。
3、用户区号不为南昌市的区号也作为正常用户处理。
输出格式:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,
单位元)。假设每个用户初始余额是100元。
每条通讯信息单独计费后累加,不是将所有时间累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
建议类图:
参见图1、2、3,可根据理解自行调整:
图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是
座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
大概思路:
首先通过给出的类图去理解每个类的内容和类与类之间的关系,理解计算余额,计算消费的方法,比如座机收费模式,短信收费模式,手机收费模式,而在这些收费模式中可以包括一些计费方式比如市内计费方式,省内计费方式,省外计费方式,在用户记录类当中包括市内拨号记录,市内接听记录,短信发送记录,短信接收记录等等,最后根据类图在idea里逐步实现。
代码:

1 package 电信计费1; 2 3 4 import java.math.RoundingMode; 5 import java.util.ArrayList; 6 import java.util.Comparator; 7 import java.util.Scanner; 8 import java.util.regex.Matcher; 9 import java.util.regex.Pattern; 10 import java.math.BigDecimal; 11 import java.text.SimpleDateFormat; 12 import java.util.Date; 13 import java.util.Locale; 14 import java.text.ParseException; 15 16 public class Main { 17 public static Double output(Double data) 18 { 19 double a = data; 20 BigDecimal bigDecimal = new BigDecimal(a); 21 double res = bigDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue(); 22 return res; 23 } 24 public static void main(String[] args) { 25 Inputdeal inputdeal = new Inputdeal(); 26 ArrayList<User> users = new ArrayList<>(); 27 Scanner in = new Scanner(System.in); 28 String input = in.nextLine(); 29 while (!input.equals("end")) { 30 if (inputdeal.check(input) == 1) { 31 inputdeal.writeUser(users, input); 32 } else if (inputdeal.check(input) == 2) { 33 inputdeal.writeRecord(users, input); 34 } 35 input = in.nextLine(); 36 } 37 users.sort(new Comparator<User>() { 38 @Override 39 public int compare(User u1, User u2) { 40 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 41 return 1; 42 } else { 43 return -1; 44 } 45 } 46 }); 47 for (User u : users) { 48 System.out.println(u.getNumber() + " "+output(u.calCost())+" "+u.calBalance()); 49 } 50 } 51 } 52 53 abstract class ChargeMode { 54 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 55 public abstract double calCost(UserRecords userRecords); 56 public abstract double getMonthlyRent(); 57 public ArrayList<ChargeRule> getChargeRules() { 58 return chargeRules; 59 } 60 } 61 62 class UserRecords { 63 64 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<>(); 65 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>(); 66 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<>(); 67 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<>(); 68 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<>(); 69 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<>(); 70 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>(); 71 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>(); 72 73 public void addCallingInCityRecords(CallRecord callRecord) { 74 callingInCityRecords.add(callRecord); 75 } 76 77 public void addCallingInProvinceRecords(CallRecord callRecord) { 78 callingInProvinceRecords.add(callRecord); 79 } 80 public void addCallingInLandRecords(CallRecord callRecord) { 81 callingInLandRecords.add(callRecord); 82 } 83 public void addAnswerInCityRecords(CallRecord callRecord) { 84 answerInCityRecords.add(callRecord); 85 } 86 public void addAnswerInProvinceRecords(CallRecord callRecord) { 87 answerInProvinceRecords.add(callRecord); 88 } 89 public void addAnswerInLandRecords(CallRecord callRecord) { 90 answerInLandRecords.add(callRecord); 91 } 92 public ArrayList<CallRecord> getCallingInCityRecords() { 93 return callingInCityRecords; 94 } 95 96 public ArrayList<CallRecord> getCallingInProvinceRecords() { 97 return callingInProvinceRecords; 98 } 99 public ArrayList<CallRecord> getCallingInLandRecords() { 100 return callingInLandRecords; 101 } 102 } 103 104 class LandlinePhoneCharging extends ChargeMode { 105 private double monthlyRent = 20; 106 public LandlinePhoneCharging() { 107 super(); 108 chargeRules.add(new LandPhoneInCityRule()); 109 chargeRules.add(new LandPhoneInProvinceRule()); 110 chargeRules.add(new LandPhoneInlandRule()); 111 } 112 113 @Override 114 public double calCost(UserRecords userRecords) { 115 double sumCost = 0; 116 for (ChargeRule rule : chargeRules) { 117 sumCost += rule.calCost(userRecords); 118 } 119 return sumCost; 120 } 121 122 @Override 123 public double getMonthlyRent() { 124 return monthlyRent; 125 } 126 127 } 128 129 class Inputdeal { 130 131 public int check(String input) { 132 String[] inputs = input.split(" "); 133 if (inputs.length == 2) { 134 if (inputs[0].matches("^u-[0-9]{11,13}$")) { 135 if (Integer.parseInt(inputs[1]) >= 0) { 136 if (Integer.parseInt(inputs[1]) <= 2) { 137 return 1; 138 } 139 } 140 } 141 } else if (inputs.length == 6) { 142 if (validate(inputs[2])) 143 if (validate(inputs[4])) 144 if (validatet(inputs[3])) 145 if (validatet(inputs[5])) 146 // if (inputs[0].matches("^t\\-[0-9]{10,12}$")) { 147 if (inputs[0].matches("[t]-0791[0-9]{7,8}")) { 148 if (inputs[1].matches(".[0-9]{9,11}")) 149 return 2; 150 } 151 } 152 return 0; 153 } 154 private boolean validatet(String string) { 155 String[] split = string.split(":"); 156 if (!string.matches("^([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { 157 return false; 158 } 159 return true; 160 } 161 public static boolean validate(String dateString) { 162 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 163 Pattern p = Pattern.compile("\\d{4}+[\\.]\\d{1,2}+[\\.]\\d{1,2}+"); 164 Matcher m = p.matcher(dateString); 165 if (!m.matches()) { 166 return false; 167 } 168 169 // 得到年月日 170 String[] array = dateString.split("\\."); 171 int year = Integer.parseInt(array[0]); 172 int month = Integer.parseInt(array[1]); 173 int day = Integer.parseInt(array[2]); 174 if (month < 1 || month > 12) { 175 return false; 176 } 177 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 178 if (isLeapYear(year)) { 179 monthLengths[2] = 29; 180 } else { 181 monthLengths[2] = 28; 182 } 183 int monthLength = monthLengths[month]; 184 if (day < 1 || day > monthLength) { 185 return false; 186 } 187 return true; 188 } 189 190 /** 是否是闰年 */ 191 private static boolean isLeapYear(int year) { 192 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 193 } 194 195 public boolean judge(String input) { 196 197 return false; 198 } 199 200 /** 是否是闰年 */ 201 202 public void writeUser(ArrayList<User> users, String input) { 203 User newuser = new User(); 204 String[] inputs = input.split(" "); 205 String num = inputs[0].substring(2); 206 for (User i : users) { 207 if (i.getNumber().equals(num)) { 208 return; 209 } 210 } 211 newuser.setNumber(num); 212 int mode = Integer.parseInt(inputs[1]); 213 if (mode == 0) { 214 newuser.setChargeMode(new LandlinePhoneCharging()); 215 } 216 users.add(newuser); 217 } 218 219 public void writeRecord(ArrayList<User> users, String input) { 220 String[] inputs = input.split(" "); 221 inputs[0] = inputs[0].replace("t-", ""); 222 223 User callu = null, answeru = null; 224 CallRecord callrecord = new CallRecord(inputs); 225 226 for (User i : users) { 227 if (i.getNumber().equals(inputs[0])) { 228 callu = i; 229 } 230 if (i.getNumber().equals(inputs[1])) { 231 answeru = i; 232 } 233 if (callu != null && answeru != null) { 234 break; 235 } 236 } 237 238 if (callu != null) { 239 if (callrecord.getCallType() == 1) { 240 callu.getUserRecords().addCallingInCityRecords(callrecord); 241 } else if (callrecord.getCallType() == 2) { 242 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 243 } else { 244 callu.getUserRecords().addCallingInLandRecords(callrecord); 245 } 246 } 247 248 if (answeru != null) { 249 if (callrecord.getCallType() == 1) { 250 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 251 } else if (callrecord.getCallType() == 2) { 252 answeru.getUserRecords().addAnswerInProvinceRecords(callrecord); 253 } else { 254 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 255 } 256 } 257 258 } 259 260 } 261 262 abstract class CommunicationRecord { 263 protected String callingNumber; 264 protected String answerNumber; 265 public String getCallingNumber() { 266 return callingNumber; 267 } 268 public void setCallingNumber(String callingNumber) { 269 this.callingNumber = callingNumber; 270 } 271 public String getAnswerNumber() { 272 return answerNumber; 273 } 274 public void setAnswerNumber(String answerNumber) { 275 this.answerNumber = answerNumber; 276 } 277 } 278 279 abstract class ChargeRule { 280 abstract public double calCost(UserRecords userRecords); 281 } 282 283 class CallRecord extends CommunicationRecord { 284 private Date startTime; 285 private Date endTime; 286 private String callingAddressAreaCode; 287 private String answerAddressAreaCode; 288 289 public int getCallType() { 290 if (callingAddressAreaCode.equals(answerAddressAreaCode)) { 291 return 1; 292 } 293 if (callingAddressAreaCode.matches("^079[0-9]$") || callingAddressAreaCode.equals("0701")) { 294 if (answerAddressAreaCode.matches("^079[0-9]$") || answerAddressAreaCode.equals("0701")) { 295 return 2; 296 } 297 } 298 return 3; 299 } 300 301 public CallRecord(String[] inputs) { 302 super(); 303 if (inputs[0].length() == 10) { 304 callingAddressAreaCode = inputs[0].substring(0, 3); 305 } else { 306 callingAddressAreaCode = inputs[0].substring(0, 4); 307 } 308 if (inputs[1].length() == 10) { 309 answerAddressAreaCode = inputs[1].substring(0, 3); 310 } else { 311 answerAddressAreaCode = inputs[1].substring(0, 4); 312 } 313 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 314 try { 315 startTime = simpleDateFormat.parse(inputs[2] + " " + inputs[3]); 316 endTime = simpleDateFormat.parse(inputs[4] + " " + inputs[5]); 317 } catch (ParseException e) { 318 } 319 } 320 public Date getStartTime() { 321 return startTime; 322 } 323 public void setStartTime(Date startTime) { 324 this.startTime = startTime; 325 } 326 public Date getEndTime() { 327 return endTime; 328 } 329 public void setEndTime(Date endTime) { 330 this.endTime = endTime; 331 } 332 333 public String getCallingAddressAreaCode() { 334 return callingAddressAreaCode; 335 } 336 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 337 this.callingAddressAreaCode = callingAddressAreaCode; 338 } 339 public String getAnswerAddressAreaCode() { 340 return answerAddressAreaCode; 341 } 342 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 343 this.answerAddressAreaCode = answerAddressAreaCode; 344 } 345 } 346 abstract class CallChargeRule extends ChargeRule { 347 348 } 349 350 class LandPhoneInCityRule extends CallChargeRule { 351 352 @Override 353 public double calCost(UserRecords userRecords) { 354 double sumCost = 0; 355 for (CallRecord call : userRecords.getCallingInCityRecords()) { 356 double distanceS = (call.getEndTime().getTime()-call.getStartTime().getTime()) / 1000; 357 if (distanceS < 0) { 358 continue; 359 } 360 double distanceM = (int) distanceS / 60; 361 if (distanceS % 60 != 0) { 362 distanceM += 1; 363 } 364 sumCost += distanceM * 0.1; 365 } 366 return sumCost; 367 } 368 369 } 370 371 class LandPhoneInlandRule extends CallChargeRule { 372 373 @Override 374 public double calCost(UserRecords userRecords) { 375 double sumCost = 0; 376 for (CallRecord call : userRecords.getCallingInLandRecords()) { 377 double distanceS = (call.getEndTime().getTime()-call.getStartTime().getTime()) / 1000; 378 if (distanceS < 0) { 379 continue; 380 } 381 double distanceM = (int) distanceS / 60; 382 if (distanceS % 60 != 0) { 383 distanceM += 1; 384 } 385 sumCost += distanceM * 0.6; 386 } 387 return sumCost; 388 } 389 390 } 391 392 class LandPhoneInProvinceRule extends CallChargeRule { 393 394 @Override 395 public double calCost(UserRecords userRecords) { 396 double sumCost = 0; 397 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 398 double distanceS = (call.getEndTime().getTime()-call.getStartTime().getTime()) / 1000; 399 if (distanceS < 0) { 400 continue; 401 } 402 double distanceM = (int) distanceS / 60; 403 if (distanceS % 60 != 0) { 404 distanceM += 1; 405 } 406 sumCost += distanceM * 0.3; 407 } 408 return sumCost; 409 } 410 411 } 412 413 class MessageRecord extends CommunicationRecord { 414 415 private String message; 416 417 public String getMessage() { 418 return message; 419 } 420 421 public void setMessage(String message) { 422 this.message = message; 423 } 424 } 425 426 class User { 427 428 private UserRecords userRecords = new UserRecords(); 429 private double balance = 100; 430 private ChargeMode chargeMode; 431 private String number; 432 433 public double calCost() { 434 return chargeMode.calCost(userRecords); 435 } 436 public double calBalance() { 437 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 438 } 439 440 public UserRecords getUserRecords() { 441 return userRecords; 442 } 443 444 public void setUserRecords(UserRecords userRecords) { 445 this.userRecords = userRecords; 446 } 447 448 public ChargeMode getChargeMode() { 449 return chargeMode; 450 } 451 452 public void setChargeMode(ChargeMode chargeMode) { 453 this.chargeMode = chargeMode; 454 } 455 456 public String getNumber() { 457 return number; 458 } 459 public void setNumber(String number) { 460 this.number = number; 461 } 462 }
<2>第七次大作业第一题
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费:
u-13307912264 1
t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
输入:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,含手机和座机用户
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题在电信计费系列1基础上增加类型1-手机实时计费。
手机设置0或者座机设置成1,此种错误可不做判断。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
输入格式增加手机接打电话以及收发短信的格式,手机接打电话的信息除了号码之外需要额外记录拨打/接听的地点的区号,比如:
座机打手机:
t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:
t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
建议类图:
参见图1、2、3:
图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
大概思路:
本次在第一次座机计费的基础上添加了手机用户的计费方式,在手机用户的计费方式中添加了漫游的计费方式,漫游指的是在南昌市的用户,在外地拨打电话或者接听电话等,在处理这种的通讯机录主要是区号,根据区号来判断位置,其他的与座机的收费模式类似,对第一次座机计费的代码进行相应的添加和修改。

1 package 电信计费2; 2 3 import java.util.Scanner; 4 import java.util.ArrayList; 5 import java.util.Comparator; 6 import java.util.Date; 7 import java.util.Locale; 8 import java.text.ParseException; 9 import java.util.regex.Matcher; 10 import java.util.regex.Pattern; 11 import java.math.BigDecimal; 12 import java.text.SimpleDateFormat; 13 14 15 public class Main { 16 17 public static void main(String[] args) { 18 19 Output output = new Output(); 20 21 Inputdeal inputdeal = new Inputdeal(); 22 23 ArrayList<User> users = new ArrayList<>(); 24 25 Scanner in = new Scanner(System.in); 26 27 String input = in.nextLine(); 28 29 while (!input.equals("end")) { 30 if (1 == inputdeal.check(input)) { 31 inputdeal.writeUser(users, input); 32 } else if (2 == inputdeal.check(input)) { 33 inputdeal.writeRecord(users, input); 34 } 35 input = in.nextLine(); 36 } 37 38 users.sort(new Comparator<User>() { 39 40 @Override 41 public int compare(User u1, User u2) { 42 if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') { 43 return -1; 44 } else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') { 45 return 1; 46 } 47 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 48 return 1; 49 } else { 50 return -1; 51 } 52 } 53 }); 54 55 for (User u : users) { 56 System.out.print(u.getNumber() + " "); 57 output.output(u.calCost()); 58 System.out.print(" "); 59 output.output(u.calBalance()); 60 System.out.println(); 61 62 } 63 64 } 65 66 } 67 class Output { 68 69 @SuppressWarnings("deprecation") 70 public void output(double out) { 71 BigDecimal numb = new BigDecimal(out); 72 out = numb.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 73 System.out.print(out); 74 } 75 } 76 77 abstract class ChargeMode { 78 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 79 80 public abstract double calCost(UserRecords userRecords); 81 82 public abstract double getMonthlyRent(); 83 84 } 85 86 class UserRecords { 87 88 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<>(); 89 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>(); 90 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<>(); 91 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<>(); 92 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<>(); 93 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<>(); 94 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>(); 95 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>(); 96 97 public void addCallingInCityRecords(CallRecord callRecord) { 98 callingInCityRecords.add(callRecord); 99 } 100 101 public void addCallingInProvinceRecords(CallRecord callRecord) { 102 callingInProvinceRecords.add(callRecord); 103 } 104 105 public void addCallingInLandRecords(CallRecord callRecord) { 106 callingInLandRecords.add(callRecord); 107 } 108 109 public void addAnswerInCityRecords(CallRecord callRecord) { 110 answerInCityRecords.add(callRecord); 111 } 112 113 public void aaddAnswerInProvinceRecords(CallRecord callRecord) { 114 answerInProvinceRecords.add(callRecord); 115 } 116 117 public void addAnswerInLandRecords(CallRecord callRecord) { 118 answerInLandRecords.add(callRecord); 119 } 120 121 122 public ArrayList<CallRecord> getCallingInCityRecords() { 123 return callingInCityRecords; 124 } 125 126 127 public ArrayList<CallRecord> getCallingInProvinceRecords() { 128 return callingInProvinceRecords; 129 } 130 131 132 public ArrayList<CallRecord> getCallingInLandRecords() { 133 return callingInLandRecords; 134 } 135 136 137 public ArrayList<CallRecord> getAnswerInLandRecords() { 138 return answerInLandRecords; 139 } 140 141 142 } 143 144 class LandlinePhoneCharging extends ChargeMode { 145 146 private final double monthlyRent = 20; 147 148 public LandlinePhoneCharging() { 149 super(); 150 chargeRules.add(new LandPhoneInCityRule()); 151 chargeRules.add(new LandPhoneInProvinceRule()); 152 chargeRules.add(new LandPhoneInlandRule()); 153 } 154 155 @Override 156 public double calCost(UserRecords userRecords) { 157 double sumCost = 0; 158 for (ChargeRule rule : chargeRules) { 159 sumCost += rule.calCost(userRecords); 160 } 161 return sumCost; 162 } 163 164 @Override 165 public double getMonthlyRent() { 166 return monthlyRent; 167 } 168 169 } 170 171 class MobilePhoneCharging extends ChargeMode { 172 173 private final double monthlyRent = 15; 174 175 public MobilePhoneCharging() { 176 super(); 177 chargeRules.add(new MobilePhoneInCityRule()); 178 chargeRules.add(new MobilePhoneInProvinceRule()); 179 chargeRules.add(new MobilePhoneInlandRule()); 180 } 181 182 @Override 183 public double calCost(UserRecords userRecords) { 184 double sumCost = 0; 185 for (ChargeRule rule : chargeRules) { 186 sumCost += rule.calCost(userRecords); 187 } 188 return sumCost; 189 } 190 191 @Override 192 public double getMonthlyRent() { 193 return monthlyRent; 194 } 195 196 } 197 198 class Inputdeal { 199 200 public int check(String input) { 201 if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[1]")) { 202 return 1; 203 } else if (input.matches("(([t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s)|" 204 + "([t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s)|" 205 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s)|" 206 + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s))" 207 208 + "((([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?" 209 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 210 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 211 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" 212 + "((([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])\\.(" 213 + "[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" 214 + "[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" 215 + "\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])")) { 216 return 2; 217 } 218 return 0; 219 } 220 221 @SuppressWarnings("unused") 222 private boolean validatet(String string) { 223 if (!string.matches("^([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { 224 return false; 225 } 226 return true; 227 } 228 229 public static boolean validate(String dateString) { 230 // 使用正则表达式 测试 字符 符合 dddd.dd.dd 的格式(d表示数字) 231 Pattern p = Pattern.compile("\\d{4}+[\\.]\\d{1,2}+[\\.]\\d{1,2}+"); 232 Matcher m = p.matcher(dateString); 233 if (!m.matches()) { 234 return false; 235 } 236 237 // 得到年月日 238 String[] array = dateString.split("\\."); 239 int year = Integer.valueOf(array[0]); 240 int month = Integer.valueOf(array[1]); 241 int day = Integer.valueOf(array[2]); 242 243 if (month < 1 || month > 12) { 244 return false; 245 } 246 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 247 if (isLeapYear(year)) { 248 monthLengths[2] = 29; 249 } else { 250 monthLengths[2] = 28; 251 } 252 int monthLength = monthLengths[month]; 253 if (day < 1 || day > monthLength) { 254 return false; 255 } 256 return true; 257 } 258 259 /** 是否是闰年 */ 260 private static boolean isLeapYear(int year) { 261 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 262 } 263 264 public boolean judge(String input) { 265 266 return false; 267 } 268 269 public void writeUser(ArrayList<User> users, String input) { 270 User usernew = new User(); 271 String[] inputs = input.split(" "); 272 String num = inputs[0].substring(2); 273 for (User i : users) { 274 if (i.getNumber().equals(num)) { 275 return; 276 } 277 } 278 usernew.setNumber(num); 279 int mode = Integer.parseInt(inputs[1]); 280 if (mode == 0) { 281 usernew.setChargeMode(new LandlinePhoneCharging()); 282 } else if (mode == 1) { 283 usernew.setChargeMode(new MobilePhoneCharging()); 284 } 285 users.add(usernew); 286 } 287 288 public void writeRecord(ArrayList<User> users, String input) { 289 String[] inputs = input.split(" "); 290 291 User callu = null, answeru = null; 292 CallRecord callrecord = new CallRecord(inputs); 293 294 if (input.charAt(0) == 't') { 295 String out = inputs[0]; 296 String in = ""; 297 if (inputs.length == 6) { 298 in = inputs[1]; 299 } else if (inputs.length == 7) { 300 in = inputs[1]; 301 } else if (inputs.length == 8) { 302 in = inputs[2]; 303 } 304 305 for (User i : users) { 306 if (i.getNumber().equals(out)) { 307 callu = i; 308 } 309 if (i.getNumber().equals(in)) { 310 answeru = i; 311 } 312 if (callu != null && answeru != null) { 313 break; 314 } 315 } 316 317 if (callu != null) { 318 if (callrecord.getCallType().matches("^1[1-3]$")) { 319 callu.getUserRecords().addCallingInCityRecords(callrecord); 320 } else if (callrecord.getCallType().matches("^2[1-3]$")) { 321 callu.getUserRecords().addCallingInProvinceRecords(callrecord); 322 } else { 323 callu.getUserRecords().addCallingInLandRecords(callrecord); 324 } 325 } 326 327 if (answeru != null) { 328 if (callrecord.getCallType().matches("^[1-3]1$")) { 329 answeru.getUserRecords().addAnswerInCityRecords(callrecord); 330 } else if (callrecord.getCallType().matches("^[1-3]2$")) { 331 answeru.getUserRecords().aaddAnswerInProvinceRecords(callrecord); 332 } else { 333 answeru.getUserRecords().addAnswerInLandRecords(callrecord); 334 } 335 } 336 } else if (input.charAt(0) == 'm') { 337 338 } 339 340 } 341 342 } 343 344 abstract class CommunicationRecord { 345 protected String callingNumber; 346 protected String answerNumbe; 347 348 } 349 350 abstract class ChargeRule { 351 352 abstract public double calCost(UserRecords userRecords); 353 354 } 355 356 class CallRecord extends CommunicationRecord { 357 private Date startTime; 358 private Date endTime; 359 private String callingAddressAreaCode; 360 private String answerAddressAreaCode; 361 362 public String getCallType() { 363 String type = ""; 364 if (callingAddressAreaCode.equals("0791")) { 365 type = type.concat("1"); 366 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 367 type = type.concat("2"); 368 } else { 369 type = type.concat("3"); 370 } 371 372 if (answerAddressAreaCode.equals("0791")) { 373 type = type.concat("1"); 374 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 375 type = type.concat("2"); 376 } else { 377 type = type.concat("3"); 378 } 379 380 return type; 381 } 382 383 public CallRecord(String[] inputs) { 384 super(); 385 386 char type = inputs[0].charAt(0); 387 inputs[0] = inputs[0].substring(2); 388 389 String sd = null, st = null, ed = null, et = null; 390 391 if (type == 't') { 392 if (inputs.length == 6) { 393 sd = inputs[2]; 394 st = inputs[3]; 395 ed = inputs[4]; 396 et = inputs[5]; 397 callingAddressAreaCode = inputs[0].substring(0, 4); 398 answerAddressAreaCode = inputs[1].substring(0, 4); 399 } else if (inputs.length == 7) { 400 sd = inputs[3]; 401 st = inputs[4]; 402 ed = inputs[5]; 403 et = inputs[6]; 404 if (inputs[0].charAt(0) != '0') { 405 if (inputs[2].length() == 10) { 406 answerAddressAreaCode = inputs[2].substring(0, 3); 407 } else { 408 answerAddressAreaCode = inputs[2].substring(0, 4); 409 } 410 callingAddressAreaCode = inputs[1]; 411 } else { 412 if (inputs[0].length() == 10) { 413 callingAddressAreaCode = inputs[0].substring(0, 3); 414 } else { 415 callingAddressAreaCode = inputs[0].substring(0, 4); 416 } 417 answerAddressAreaCode = inputs[2]; 418 } 419 } else if (inputs.length == 8) { 420 sd = inputs[4]; 421 st = inputs[5]; 422 ed = inputs[6]; 423 et = inputs[7]; 424 callingAddressAreaCode = inputs[1]; 425 answerAddressAreaCode = inputs[3]; 426 } 427 } else if (type == 'm') { 428 429 } 430 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 431 try { 432 startTime = simpleDateFormat.parse(sd + " " + st); 433 endTime = simpleDateFormat.parse(ed + " " + et); 434 } catch (ParseException e) { 435 } 436 437 } 438 439 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 440 super(); 441 this.startTime = startTime; 442 this.endTime = endTime; 443 this.callingAddressAreaCode = callingAddressAreaCode; 444 this.answerAddressAreaCode = answerAddressAreaCode; 445 } 446 447 public Date getStartTime() { 448 return startTime; 449 } 450 451 452 453 public Date getEndTime() { 454 return endTime; 455 } 456 457 } 458 459 abstract class CallChargeRule extends ChargeRule { 460 461 } 462 463 class LandPhoneInCityRule extends CallChargeRule { 464 465 @Override 466 public double calCost(UserRecords userRecords) { 467 double sumCost = 0; 468 for (CallRecord call : userRecords.getCallingInCityRecords()) { 469 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 470 if (distanceS < 0) { 471 continue; 472 } 473 double distanceM = (int) distanceS / 60; 474 if (distanceS % 60 != 0) { 475 distanceM += 1; 476 } 477 if (call.getCallType().equals("11")) { 478 sumCost += distanceM * 0.1; 479 } else if (call.getCallType().equals("12")) { 480 sumCost += distanceM * 0.3; 481 } else if (call.getCallType().equals("13")) { 482 sumCost += distanceM * 0.6; 483 } 484 } 485 return sumCost; 486 } 487 488 } 489 490 class LandPhoneInlandRule extends CallChargeRule { 491 492 @Override 493 public double calCost(UserRecords userRecords) { 494 double sumCost = 0; 495 for (CallRecord call : userRecords.getCallingInLandRecords()) { 496 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 497 if (distanceS < 0) { 498 continue; 499 } 500 double distanceM = (int) distanceS / 60; 501 if (distanceS % 60 != 0) { 502 distanceM += 1; 503 } 504 sumCost += distanceM * 0.6; 505 } 506 return sumCost; 507 } 508 509 } 510 511 class LandPhoneInProvinceRule extends CallChargeRule { 512 513 @Override 514 public double calCost(UserRecords userRecords) { 515 double sumCost = 0; 516 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 517 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 518 if (distanceS < 0) { 519 continue; 520 } 521 double distanceM = (int) distanceS / 60; 522 if (distanceS % 60 != 0) { 523 distanceM += 1; 524 } 525 sumCost += distanceM * 0.3; 526 } 527 return sumCost; 528 } 529 530 } 531 532 class MobilePhoneInCityRule extends CallChargeRule { 533 534 @Override 535 public double calCost(UserRecords userRecords) { 536 double sumCost = 0; 537 for (CallRecord call : userRecords.getCallingInCityRecords()) { 538 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 539 if (distanceS < 0) { 540 continue; 541 } 542 double distanceM = (int) distanceS / 60; 543 if (distanceS % 60 != 0) { 544 distanceM += 1; 545 } 546 if (call.getCallType().equals("11")) { 547 sumCost += distanceM * 0.1; 548 } else if (call.getCallType().equals("12")) { 549 sumCost += distanceM * 0.2; 550 } else if (call.getCallType().equals("13")) { 551 sumCost += distanceM * 0.3; 552 } 553 554 } 555 return sumCost; 556 } 557 558 } 559 560 class MobilePhoneInlandRule extends CallChargeRule { 561 562 @Override 563 public double calCost(UserRecords userRecords) { 564 double sumCost = 0; 565 for (CallRecord call : userRecords.getCallingInLandRecords()) { 566 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 567 if (distanceS < 0) { 568 continue; 569 } 570 double distanceM = (int) distanceS / 60; 571 if (distanceS % 60 != 0) { 572 distanceM += 1; 573 } 574 sumCost += distanceM * 0.6; 575 } 576 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 577 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 578 if (distanceS < 0) { 579 continue; 580 } 581 double distanceM = (int) distanceS / 60; 582 if (distanceS % 60 != 0) { 583 distanceM += 1; 584 } 585 sumCost += distanceM * 0.3; 586 } 587 return sumCost; 588 } 589 590 } 591 592 class MobilePhoneInProvinceRule extends CallChargeRule { 593 594 @Override 595 public double calCost(UserRecords userRecords) { 596 double sumCost = 0; 597 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 598 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 599 if (distanceS < 0) { 600 continue; 601 } 602 double distanceM = (int) distanceS / 60; 603 if (distanceS % 60 != 0) { 604 distanceM += 1; 605 } 606 if (call.getCallType().equals("21")) { 607 sumCost += distanceM * 0.3; 608 } else if (call.getCallType().equals("22")) { 609 sumCost += distanceM * 0.3; 610 } else if (call.getCallType().equals("23")) { 611 sumCost += distanceM * 0.3; 612 } 613 } 614 return sumCost; 615 } 616 617 } 618 619 class MessageRecord extends CommunicationRecord { 620 621 private String message; 622 623 } 624 625 class User { 626 627 private UserRecords userRecords = new UserRecords(); 628 private double balance = 100; 629 private ChargeMode chargeMode; 630 private String number; 631 632 public double calCost() { 633 return chargeMode.calCost(userRecords); 634 } 635 636 public double calBalance() { 637 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 638 } 639 640 public UserRecords getUserRecords() { 641 return userRecords; 642 } 643 644 645 public void setChargeMode(ChargeMode chargeMode) { 646 this.chargeMode = chargeMode; 647 } 648 649 public String getNumber() { 650 return number; 651 } 652 653 public void setNumber(String number) { 654 this.number = number; 655 } 656 657 }
<3>第八次大作业第一题
7-1 电信计费系列3-短信计费
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。
输入:
输入信息包括两种类型
1、逐行输入南昌市手机用户开户的信息,每行一个用户。
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐 3-手机短信计费)
例如:u-13305862264 3
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题只针对类型3-手机短信计费。
2、逐行输入本月某些用户的短信信息,短信的格式:
m-主叫号码,接收号码,短信内容 (短信内容只能由数字、字母、空格、英文逗号、英文句号组成)
m-18907910010 13305862264 welcome to jiangxi.
m-13305862264 18907910010 thank you.
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细短信信息,计算所有已开户的用户的当月短信费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码、自己给自己打电话等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
本题只考虑短信计费,不考虑通信费用以及月租费。
建议类图:
参见图1、2、3:
图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。
图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
大概思路:
本系列中添加短信计费模式较简单,在上次的基础上容易实现。

1 package 电信计费3; 2 3 import java.math.RoundingMode; 4 import java.util.Scanner; 5 import java.util.ArrayList; 6 import java.util.Comparator; 7 import java.util.Date; 8 import java.math.BigDecimal; 9 import java.text.SimpleDateFormat; 10 import java.text.ParseException; 11 import java.util.Locale; 12 13 public class Main { 14 15 public static void main(String[] args) { 16 17 Output output = new Output(); 18 19 Inputdeal inputdeal = new Inputdeal(); 20 21 ArrayList<User> users = new ArrayList<>(); 22 23 Scanner in = new Scanner(System.in); 24 25 String input = in.nextLine(); 26 27 while (!input.equals("end")) { 28 if (1 == inputdeal.check(input)) { 29 inputdeal.writeUser(users, input); 30 } else if (2 == inputdeal.check(input)) { 31 inputdeal.writeRecord(users, input); 32 } 33 input = in.nextLine(); 34 } 35 36 users.sort((u1, u2) -> { 37 if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') { 38 return -1; 39 } else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') { 40 return 1; 41 } 42 if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) { 43 return 1; 44 } else { 45 return -1; 46 } 47 }); 48 49 for (User u : users) { 50 System.out.print(u.getNumber() + " "); 51 output.output(u.calCost()); 52 System.out.print(" "); 53 output.output(u.calBalance()); 54 System.out.println(); 55 56 } 57 58 } 59 60 } 61 class Output { 62 public void output(double out) { 63 BigDecimal numb = new BigDecimal(out); 64 out = numb.setScale(2, RoundingMode.HALF_UP).doubleValue(); 65 System.out.print(out); 66 } 67 } 68 abstract class ChargeMode { 69 protected ArrayList<ChargeRule> chargeRules = new ArrayList<>(); 70 71 public abstract double calCost(UserRecords userRecords); 72 73 public abstract double getMonthlyRent(); 74 75 76 } 77 78 class UserRecords { 79 80 private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>(); 81 private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>(); 82 private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>(); 83 private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>(); 84 private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>(); 85 private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>(); 86 private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>(); 87 private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>(); 88 89 public void addCallingInCityRecords(CallRecord callRecord) { 90 callingInCityRecords.add(callRecord); 91 } 92 93 public void addCallingInProvinceRecords(CallRecord callRecord) { 94 callingInProvinceRecords.add(callRecord); 95 } 96 97 public void addCallingInLandRecords(CallRecord callRecord) { 98 callingInLandRecords.add(callRecord); 99 } 100 101 public void addAnswerInCityRecords(CallRecord callRecord) { 102 answerInCityRecords.add(callRecord); 103 } 104 105 106 107 public void addSendMessageRecords(MessageRecord callRecord) { 108 sendMessageRecords.add(callRecord); 109 } 110 111 public void addReceiveMessageRecords(MessageRecord callRecord) { 112 receiveMessageRecords.add(callRecord); 113 } 114 115 public ArrayList<CallRecord> getCallingInCityRecords() { 116 return callingInCityRecords; 117 } 118 119 public void setCallingInCityRecords(ArrayList<CallRecord> callingInCityRecords) { 120 this.callingInCityRecords = callingInCityRecords; 121 } 122 123 public ArrayList<CallRecord> getCallingInProvinceRecords() { 124 return callingInProvinceRecords; 125 } 126 127 128 129 public ArrayList<CallRecord> getCallingInLandRecords() { 130 return callingInLandRecords; 131 } 132 133 134 135 136 137 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 138 return answerInProvinceRecords; 139 } 140 141 public void setAnswerInProvinceRecords(ArrayList<CallRecord> answerInProvinceRecords) { 142 this.answerInProvinceRecords = answerInProvinceRecords; 143 } 144 145 public ArrayList<CallRecord> getAnswerInLandRecords() { 146 return answerInLandRecords; 147 } 148 149 public void setAnswerInLandRecords(ArrayList<CallRecord> answerInLandRecords) { 150 this.answerInLandRecords = answerInLandRecords; 151 } 152 153 public ArrayList<MessageRecord> getSendMessageRecords() { 154 return sendMessageRecords; 155 } 156 157 public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) { 158 this.sendMessageRecords = sendMessageRecords; 159 } 160 161 public ArrayList<MessageRecord> getReceiveMessageRecords() { 162 return receiveMessageRecords; 163 } 164 165 public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) { 166 this.receiveMessageRecords = receiveMessageRecords; 167 } 168 169 } 170 171 class LandlinePhoneCharging extends ChargeMode { 172 173 private final double monthlyRent = 20; 174 175 public LandlinePhoneCharging() { 176 super(); 177 chargeRules.add(new LandPhoneInCityRule()); 178 chargeRules.add(new LandPhoneInProvinceRule()); 179 chargeRules.add(new LandPhoneInlandRule()); 180 } 181 182 @Override 183 public double calCost(UserRecords userRecords) { 184 double sumCost = 0; 185 for (ChargeRule rule : chargeRules) { 186 sumCost += rule.calCost(userRecords); 187 } 188 return sumCost; 189 } 190 191 @Override 192 public double getMonthlyRent() { 193 return monthlyRent; 194 } 195 196 } 197 198 class MobilePhoneCharging extends ChargeMode { 199 200 private final double monthlyRent = 15; 201 202 public MobilePhoneCharging() { 203 super(); 204 chargeRules.add(new MobilePhoneInCityRule()); 205 chargeRules.add(new MobilePhoneInProvinceRule()); 206 chargeRules.add(new MobilePhoneInlandRule()); 207 } 208 209 @Override 210 public double calCost(UserRecords userRecords) { 211 double sumCost = 0; 212 for (ChargeRule rule : chargeRules) { 213 sumCost += rule.calCost(userRecords); 214 } 215 return sumCost; 216 } 217 218 @Override 219 public double getMonthlyRent() { 220 return monthlyRent; 221 } 222 223 } 224 225 class MobilePhoneMassageCharging extends ChargeMode { 226 227 private final double monthlyRent = 0; 228 229 public MobilePhoneMassageCharging() { 230 super(); 231 chargeRules.add(new MobilePhoneMessageRule()); 232 } 233 234 @Override 235 public double calCost(UserRecords userRecords) { 236 double sumCost = 0; 237 for (ChargeRule rule : chargeRules) { 238 sumCost += rule.calCost(userRecords); 239 } 240 return sumCost; 241 } 242 243 @Override 244 public double getMonthlyRent() { 245 return monthlyRent; 246 } 247 248 } 249 250 class Inputdeal { 251 252 public int check(String input) { 253 if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[13]")) { 254 return 1; 255 } else if (input.matches("[m]-1[0-9]{10}\\s" + "1[0-9]{10}\\s" + "[0-9a-zA-Z\\s\\.,]+")) { 256 return 2; 257 } 258 return 0; 259 } 260 261 public void writeUser(ArrayList<User> users, String input) { 262 User usernew = new User(); 263 String[] inputs = input.split(" "); 264 String num = inputs[0].substring(2); 265 for (User i : users) { 266 if (i.getNumber().equals(num)) { 267 return; 268 } 269 } 270 usernew.setNumber(num); 271 int mode = Integer.parseInt(inputs[1]); 272 if (mode == 0) { 273 usernew.setChargeMode(new LandlinePhoneCharging()); 274 } else if (mode == 1) { 275 usernew.setChargeMode(new MobilePhoneCharging()); 276 } else if (mode == 3) { 277 usernew.setChargeMode(new MobilePhoneMassageCharging()); 278 } 279 users.add(usernew); 280 } 281 282 public void writeRecord(ArrayList<User> users, String input) { 283 String[] inputs = input.split(" "); 284 inputs[0] = inputs[0].substring(2); 285 286 User callu = null, answeru = null; 287 288 String out = inputs[0]; 289 String in = ""; 290 if (inputs.length == 6) { 291 in = inputs[1]; 292 } else if (inputs.length == 7) { 293 in = inputs[1]; 294 } else if (inputs.length == 8) { 295 in = inputs[2]; 296 } else { 297 in = inputs[1]; 298 } 299 300 for (User i : users) { 301 if (i.getNumber().equals(out)) { 302 callu = i; 303 } 304 if (i.getNumber().equals(in)) { 305 answeru = i; 306 } 307 if (callu != null && answeru != null) { 308 break; 309 } 310 } 311 312 if (input.charAt(0) == 'm') { 313 MessageRecord messageRecord = new MessageRecord(input); 314 if (callu != null) { 315 callu.getUserRecords().addSendMessageRecords(messageRecord); 316 ; 317 } 318 if (answeru != null) { 319 callu.getUserRecords().addReceiveMessageRecords(messageRecord); 320 } 321 } 322 323 } 324 325 } 326 327 abstract class CommunicationRecord { 328 protected String callingNumber; 329 protected String answerNumbe; 330 331 public String getCallingNumber() { 332 return callingNumber; 333 } 334 335 public void setCallingNumber(String callingNumber) { 336 this.callingNumber = callingNumber; 337 } 338 339 public String getAnswerNumbe() { 340 return answerNumbe; 341 } 342 343 public void setAnswerNumbe(String answerNumbe) { 344 this.answerNumbe = answerNumbe; 345 } 346 347 } 348 349 abstract class ChargeRule { 350 351 abstract public double calCost(UserRecords userRecords); 352 353 } 354 355 class CallRecord extends CommunicationRecord { 356 private Date startTime; 357 private Date endTime; 358 private String callingAddressAreaCode; 359 private String answerAddressAreaCode; 360 361 public String getCallType() { 362 String type = ""; 363 if (callingAddressAreaCode.equals("0791")) { 364 type = type.concat("1"); 365 } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) { 366 type = type.concat("2"); 367 } else { 368 type = type.concat("3"); 369 } 370 371 if (answerAddressAreaCode.equals("0791")) { 372 type = type.concat("1"); 373 } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) { 374 type = type.concat("2"); 375 } else { 376 type = type.concat("3"); 377 } 378 379 return type; 380 } 381 382 public CallRecord(String[] inputs) { 383 super(); 384 385 char type = inputs[0].charAt(0); 386 387 String sd = null, st = null, ed = null, et = null; 388 389 if (type == 't') { 390 if (inputs.length == 6) { 391 sd = inputs[2]; 392 st = inputs[3]; 393 ed = inputs[4]; 394 et = inputs[5]; 395 callingAddressAreaCode = inputs[0].substring(0, 4); 396 answerAddressAreaCode = inputs[1].substring(0, 4); 397 } else if (inputs.length == 7) { 398 sd = inputs[3]; 399 st = inputs[4]; 400 ed = inputs[5]; 401 et = inputs[6]; 402 if (inputs[0].charAt(0) != '0') { 403 if (inputs[2].length() == 10) { 404 answerAddressAreaCode = inputs[2].substring(0, 3); 405 } else { 406 answerAddressAreaCode = inputs[2].substring(0, 4); 407 } 408 callingAddressAreaCode = inputs[1]; 409 } else { 410 if (inputs[0].length() == 10) { 411 callingAddressAreaCode = inputs[0].substring(0, 3); 412 } else { 413 callingAddressAreaCode = inputs[0].substring(0, 4); 414 } 415 answerAddressAreaCode = inputs[2]; 416 } 417 } else if (inputs.length == 8) { 418 sd = inputs[4]; 419 st = inputs[5]; 420 ed = inputs[6]; 421 et = inputs[7]; 422 callingAddressAreaCode = inputs[1]; 423 answerAddressAreaCode = inputs[3]; 424 } 425 } else if (type == 'm') { 426 427 } 428 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()); 429 try { 430 startTime = simpleDateFormat.parse(sd + " " + st); 431 endTime = simpleDateFormat.parse(ed + " " + et); 432 } catch (ParseException e) { 433 } 434 435 } 436 437 public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { 438 super(); 439 this.startTime = startTime; 440 this.endTime = endTime; 441 this.callingAddressAreaCode = callingAddressAreaCode; 442 this.answerAddressAreaCode = answerAddressAreaCode; 443 } 444 445 public Date getStartTime() { 446 return startTime; 447 } 448 449 public void setStartTime(Date startTime) { 450 this.startTime = startTime; 451 } 452 453 public Date getEndTime() { 454 return endTime; 455 } 456 457 458 } 459 460 abstract class CallChargeRule extends ChargeRule { 461 462 } 463 464 class LandPhoneInCityRule extends CallChargeRule { 465 466 @Override 467 public double calCost(UserRecords userRecords) { 468 double sumCost = 0; 469 for (CallRecord call : userRecords.getCallingInCityRecords()) { 470 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 471 if (distanceS < 0) { 472 continue; 473 } 474 double distanceM = (int) distanceS / 60; 475 if (distanceS % 60 != 0) { 476 distanceM += 1; 477 } 478 if (call.getCallType().equals("11")) { 479 sumCost += distanceM * 0.1; 480 } else if (call.getCallType().equals("12")) { 481 sumCost += distanceM * 0.3; 482 } else if (call.getCallType().equals("13")) { 483 sumCost += distanceM * 0.6; 484 } 485 } 486 return sumCost; 487 } 488 489 } 490 491 class LandPhoneInlandRule extends CallChargeRule { 492 493 @Override 494 public double calCost(UserRecords userRecords) { 495 double sumCost = 0; 496 for (CallRecord call : userRecords.getCallingInLandRecords()) { 497 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 498 if (distanceS < 0) { 499 continue; 500 } 501 double distanceM = (int) distanceS / 60; 502 if (distanceS % 60 != 0) { 503 distanceM += 1; 504 } 505 sumCost += distanceM * 0.6; 506 } 507 return sumCost; 508 } 509 510 } 511 512 class LandPhoneInProvinceRule extends CallChargeRule { 513 514 @Override 515 public double calCost(UserRecords userRecords) { 516 double sumCost = 0; 517 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 518 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 519 if (distanceS < 0) { 520 continue; 521 } 522 double distanceM = (int) distanceS / 60; 523 if (distanceS % 60 != 0) { 524 distanceM += 1; 525 } 526 sumCost += distanceM * 0.3; 527 } 528 return sumCost; 529 } 530 531 } 532 533 class MobilePhoneInCityRule extends CallChargeRule { 534 535 @Override 536 public double calCost(UserRecords userRecords) { 537 double sumCost = 0; 538 for (CallRecord call : userRecords.getCallingInCityRecords()) { 539 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 540 if (distanceS < 0) { 541 continue; 542 } 543 double distanceM = (int) distanceS / 60; 544 if (distanceS % 60 != 0) { 545 distanceM += 1; 546 } 547 if (call.getCallType().equals("11")) { 548 sumCost += distanceM * 0.1; 549 } else if (call.getCallType().equals("12")) { 550 sumCost += distanceM * 0.2; 551 } else if (call.getCallType().equals("13")) { 552 sumCost += distanceM * 0.3; 553 } 554 555 } 556 return sumCost; 557 } 558 559 } 560 561 class MobilePhoneInlandRule extends CallChargeRule { 562 563 @Override 564 public double calCost(UserRecords userRecords) { 565 double sumCost = 0; 566 for (CallRecord call : userRecords.getCallingInLandRecords()) { 567 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 568 if (distanceS < 0) { 569 continue; 570 } 571 double distanceM = (int) distanceS / 60; 572 if (distanceS % 60 != 0) { 573 distanceM += 1; 574 } 575 sumCost += distanceM * 0.6; 576 } 577 for (CallRecord call : userRecords.getAnswerInLandRecords()) { 578 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 579 if (distanceS < 0) { 580 continue; 581 } 582 double distanceM = (int) distanceS / 60; 583 if (distanceS % 60 != 0) { 584 distanceM += 1; 585 } 586 sumCost += distanceM * 0.3; 587 } 588 return sumCost; 589 } 590 591 } 592 593 class MobilePhoneInProvinceRule extends CallChargeRule { 594 595 @Override 596 public double calCost(UserRecords userRecords) { 597 double sumCost = 0; 598 for (CallRecord call : userRecords.getCallingInProvinceRecords()) { 599 double distanceS = (-call.getStartTime().getTime() + call.getEndTime().getTime()) / 1000; 600 if (distanceS < 0) { 601 continue; 602 } 603 double distanceM = (int) distanceS / 60; 604 if (distanceS % 60 != 0) { 605 distanceM += 1; 606 } 607 if (call.getCallType().equals("21")) { 608 sumCost += distanceM * 0.3; 609 } else if (call.getCallType().equals("22")) { 610 sumCost += distanceM * 0.3; 611 } else if (call.getCallType().equals("23")) { 612 sumCost += distanceM * 0.3; 613 } 614 } 615 return sumCost; 616 } 617 618 } 619 620 class MobilePhoneMessageRule extends CallChargeRule { 621 622 @Override 623 public double calCost(UserRecords userRecords) { 624 double sumCost = 0; 625 int number = 0; 626 for (MessageRecord m : userRecords.getSendMessageRecords()) { 627 int length = m.getMessage().length(); 628 if (length <= 10) { 629 number++; 630 } else { 631 number += length / 10; 632 if (length % 10 != 0) { 633 number++; 634 } 635 } 636 } 637 if (number <= 3) { 638 sumCost = number * 0.1; 639 } else if (number <= 5) { 640 sumCost = 0.3 + 0.2 * (number - 3); 641 } else { 642 sumCost = 0.7 + 0.3 * (number - 5); 643 } 644 return sumCost; 645 } 646 647 } 648 649 class MessageRecord extends CommunicationRecord { 650 651 private String message; 652 653 public MessageRecord(String input) { 654 super(); 655 this.message = input.substring(26); 656 } 657 658 public String getMessage() { 659 return message; 660 } 661 662 663 } 664 665 class User { 666 667 private UserRecords userRecords = new UserRecords(); 668 private final double balance = 100; 669 private ChargeMode chargeMode; 670 private String number; 671 672 public double calCost() { 673 return chargeMode.calCost(userRecords); 674 } 675 676 public double calBalance() { 677 return balance - chargeMode.getMonthlyRent() - chargeMode.calCost(userRecords); 678 } 679 680 public UserRecords getUserRecords() { 681 return userRecords; 682 } 683 684 public void setUserRecords(UserRecords userRecords) { 685 this.userRecords = userRecords; 686 } 687 688 public ChargeMode getChargeMode() { 689 return chargeMode; 690 } 691 692 public void setChargeMode(ChargeMode chargeMode) { 693 this.chargeMode = chargeMode; 694 } 695 696 public String getNumber() { 697 return number; 698 } 699 700 public void setNumber(String number) { 701 this.number = number; 702 } 703 704 }
三、踩坑心得
1. 最开始看到这类图时并不能马上理解类图想表达的意思,后面经过慢慢的思考明白了这种设计具备的可扩展性,也是后续学习过程中自己需要学习的地方,在用户类User
中包含私有属性 用户记录类 useRecords
,浮点型用户余额 balance
,计费模式类chargeMode
,字符串类型电话号码 number
,以及计算余额,计算消费的方法。收费模式类是一个抽象类,包含计费方式的集合,以及计费的抽象方法。在后续的扩展中我们可以添加计费模式,就是继承抽象的计费模式类然后实现这些方法,比如座机收费模式,短信收费模式,手机收费模式,而在这些收费模式中可以包括一些计费方式比如市内计费方式,省内计费方式,省外计费方式,在用户记录类当中包括市内拨号记录,市内接听记录,短信发送记录,短信接收记录等等。本题还是要依赖正则表达式处理字符串,利用正则表达式来过滤不符合格式的输入。
2.开始未考虑到未开户的用户产生的通讯记录,导致后面计算的时候出现错误,解决方案就是添加判断条件(若用户集合中不含拨号号码则跳过)。
3.未考虑到一些特殊地区的区号为三位数导致正则表达式出现误判。
4.抽象类可以有构造方法,接口中不能有构造方法。抽象类中可以有普通成员变量,接口中没有普通成员变量。抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。抽象类中可以包含静态方法,接口中不能包含静态方法。
5.抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。一个类可以实现多个接口,但只能继承一个抽象类。
四、改进建议
1.添加判断条件(若用户集合中不含拨号号码则跳过)。
2.减少代码的嵌套,将具体功能和判断写成详细的方法,包装起来,不要一个函数写一长串。
3.尽量将子类里相同的方法集合起来写在父类里面。
五、总结
对于本阶段的学习,收获还是挺大的,较之前的题目也更加贴近生活。了解了许多设计模式,也明白了设计模式的重要性, 设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件代码的基石,如同大厦的一块块砖石一样。
这阶段的学习也对JavaFX有了更深入的理解。场景scene、布局layout、UI控件是javaFX的基本组成部分。控件可以放到布局中,布局可以放到布局中,也可以放到场景中,这里要注意,每个场景里只能放一个布局,多个布局的话只会默认识别最后一个布局。如果添加多个布局,虽然页面可以显示完整,但是所添加的事件驱动可能不会做出反应。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义