《原神攻略》2.7版夜蘭全面配裝測試與配置建議
目錄
1.對前三次作業的大體分析
2.設計與分析
3. 踩坑心得
4. 改進建議
5. 總結
一. 對前三次大作業的大體分析
1. 前三次大作業總體是一個體系的題目,主要是關於電信計費的多種計費混合實現。
2. 第一次大作業是基礎,做好了第一次座機計費的基礎,後面兩次的計費方式也就差不多了。
3. 第二次大作業是電話計費,主要複雜的問題就是如何解決對輸入資訊的判定和提取。
4.第三次大作業是最為簡單的,主要就是對資訊計費的資訊提取計算即可。
二. 設計與分析
1.第一個習題集的設計分析
程式碼及其類圖如下
import java.util.ArrayList;import java.util.Date;import java.text.ParseException;import java.text.SimpleDateFormat;import java.text.DecimalFormat;import java.util.Collections;import java.util.Comparator;import java.util.Scanner;abstractclass CallChargeRule extends ChargeRule{publicdouble calCost(ArrayList<CallRecord> callRecords) {return 0;}
}
class CallRecord extends CommunicationRecord{private Date startTime = new Date();private Date endTime = new Date();private String callingAddressAreaCode;private String answerAddressAreaCode;public CallRecord() {}
public Date getStartTime() {returnthis.startTime;}
publicvoid setStartTime(Date startTime) {this.startTime=startTime;}
public Date getEndTime() {returnthis.endTime;}
publicvoid setEndTime(Date endTime) {this.endTime=endTime;}
public String getCallingAddressAreaCode() {returnthis.callingAddressAreaCode;}
publicvoid setCallingAddressAreaCode(String callingAddressAreaCode) {String s
= callingAddressAreaCode.substring(0, 4);this.callingAddressAreaCode=s;}
public String getAnswerAddressAreaCode() {returnthis.answerAddressAreaCode;}
publicvoid setAnswerAddressAreaCode(String answerAddressAreaCode) {String s
= answerAddressAreaCode.substring(0, 4);this.answerAddressAreaCode=s;}
}
abstractclass ChargeMode {private ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();public ArrayList<ChargeRule> getChargeRule(){returnthis.chargeRules;}
publicvoid setChargeRule(ArrayList<ChargeRule> chargeRules) {this.chargeRules=chargeRules;}
publicdouble calCost(UserRecords userRecords) {return 0;}
publicdouble getMonthlyRent() {return 0;}
}
abstractclass ChargeRule {}
abstractclass CommunicationRecord {String callingNumber;
String answerNumber;
public String getCallingNumber(){return callingNumber;}
publicvoid setCallingNumber(String callingNumber) {}
}
class InputHandle {private String input;public InputHandle(String input) {this.input=input;}
publicboolean InputIsQualified(String input) {String[] str
= input.split(" ");if(str.length>1) {String s2
= str[0];String s3
= str[1];if(s2.matches("^u-0791\\d{7,8}$")&&s3.equals("0")) {returntrue;}
else {returnfalse;}
}
else {returnfalse;}
}
publicboolean inputTwoIsQualified(String input) {String[] str
= input.split(" ");if(str.length>2) {if(str[2].matches("[\\d]{4}.((0([1-9]{1}))|(1[1|2])|([1-9])).(([0-2]([1-9]{1}))|(3[0|1])|([1|2]0)|([1-9]))")&&str[3].matches("([0-2][0-9]):([0-5][0-9]):([0-5][0-9])")&&str[4].matches("[\\d]{4}.((0([1-9]{1}))|(1[1|2])|([1-9])).(([0-2]([1-9]{1}))|(3[0|1])|([1|2]0)|([1-9]))")&&str[5].matches("([0-2][0-9]):([0-5][0-9]):([0-5][0-9])")) {if(IsCallingNumber(input)==true&&IsAnswerNumber(input)==true) {returntrue;}
else {returnfalse;}
}
else {returnfalse;}
}
else {returnfalse;}
}
public String getUnumber(String input){String[] s1
= input.split(" ");String[] s2
= s1[0].split("-");return s2[1];}
public String getInputIntoCallingNumber(String input) {String[] s1
= input.split(" ");if(s1[0].matches("t-0\\d{10,11}")) {String[] s2
= s1[0].split("-");return s2[1];}
else {returnnull;}
}
publicboolean IsCallingNumber(String input) {if(getInputIntoCallingNumber(input)!=null) {returntrue;}
else {returnfalse;}
}
publicboolean IsAnswerNumber(String input) {if(getInputIntoAnswerNumber(input)!=null) {returntrue;}
else {returnfalse;}
}
publicint WhereAreTheNumber(String s) {if(s.matches("(0791)(\\d{7,8})")) {//電話為室內電話return 1;
}
elseif(s.matches("(0790)(\\d{7,8})")||s.matches("(0701)(\\d{7,8})")||s.matches("^(079)([2-9]{1})(\\d{7,8})")) {//電話為省內電話
return -1;
}
else {//電話為國內電話
return 0;
}
}
public String getInputIntoAnswerNumber(String input) {
String[] s2 = input.split(" ");
if(s2[1].matches("^0\\d{10,11}")) {
return s2[1];
}
else {
returnnull;
}
}
public Date getInputIntoStartTime(String input) throws ParseException {
String[] s = input.split(" ");
String s2 = s[2]+" "+s[3];
Date d = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
d = sdf1.parse(s2);
return d;
}
public Date getInputIntoEndTime(String input) throws ParseException {
String[] s = input.split(" ");
String s2 = s[4]+" "+s[5];
Date d = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
d = sdf1.parse(s2);
return d;
}
}
class LandlinePhoneCharging extends ChargeMode {
double monthlyRent = 20;
@Override
publicdouble calCost(UserRecords userRecords) {
double s=0;
CallChargeRule c = new LandPhonelnCityRule();
CallChargeRule p = new LandPhonelnProvinceRule();
CallChargeRule l = new LandPhonelnlandRule();
s+=c.calCost(userRecords.getCallingInCityRecords());
s+=p.calCost(userRecords.getCallingInProvinceRecords());
s+=l.calCost(userRecords.getCallingInLandRecords());
return s;
}
@Override
publicdouble getMonthlyRent() {
returnthis.monthlyRent;
}
}
class LandPhonelnCityRule extends CallChargeRule{
@Override
publicdouble calCost(ArrayList<CallRecord> callRecords) {
double s=0;
for(CallRecord k: callRecords) {
long time1 = k.getStartTime().getTime();
long time2 = k.getEndTime().getTime();
long time = Math.abs(time1-time2);
if(time/1000%60==0) {
double minute = (double)(time/1000/60);
s=s+0.1*minute;
}
else {
double minute = (double)(time/1000/60);
s=s+0.1*(minute+1);
}
}
return s;
}
}
class LandPhonelnlandRule extends CallChargeRule{
@Override
publicdouble calCost(ArrayList<CallRecord> callRecords) {
double s=0;
for(CallRecord k: callRecords) {
long time1 = k.getStartTime().getTime();
long time2 = k.getEndTime().getTime();
long time = Math.abs(time1-time2);
if(time/1000%60==0) {
double minute = (double)(time/1000/60);
s=s+0.6*minute;
}
else {
double minute = (double)(time/1000/60);
s=s+0.6*(minute+1);
}
}
return s;
}
}
class LandPhonelnProvinceRule extends CallChargeRule{
@Override
publicdouble calCost(ArrayList<CallRecord> callRecords) {
double s=0;
for(CallRecord k: callRecords) {
long time1 = k.getStartTime().getTime();
long time2 = k.getEndTime().getTime();
long time = Math.abs(time1-time2);
if(time/1000%60==0) {
double minute = (double)(time/1000/60);
s=s+0.3*minute;
}
else {
double minute = (double)(time/1000/60);
s=s+0.3*(minute+1);
}
}
return s;
}
}
publicclass Main {
publicstaticvoid main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
CallRecord c;
UserRecords userRecord;
LandlinePhoneCharging l = new LandlinePhoneCharging();
ArrayList<User> users = new ArrayList<User>();
while (true) {
int t=0;
String s = sc.nextLine();
InputHandle input = new InputHandle(s);
if(input.InputIsQualified(s)) {
t++;
if(users.isEmpty()) {
User u2 = new User();
String[] s1 = s.split(" ");
String s2 = s1[0].substring(2);
u2.setNumber(s2);
u2.setChargeMode(l);
users.add(u2);
userRecord = new UserRecords();
u2.setUserRecords(userRecord);
}
else {
for(User u:users) {
if(u.getNumber().equals(input.getUnumber(s))) {
t++;
}
}
if(t==1) {
User u2 = new User();
String[] s1 = s.split(" ");
String s2 = s1[0].substring(2);
u2.setNumber(s2);
u2.setChargeMode(l);
users.add(u2);
userRecord = new UserRecords();
u2.setUserRecords(userRecord);
}
}
}
elseif(input.inputTwoIsQualified(s)) {
for(User ur : users) {
if(ur.getNumber().equals(input.getInputIntoCallingNumber(s))||ur.getNumber().equals(input.getInputIntoAnswerNumber(s))) {
c = new CallRecord();
c.setAnswerAddressAreaCode(input.getInputIntoAnswerNumber(s));
c.setCallingAddressAreaCode(input.getInputIntoCallingNumber(s));
c.setStartTime(input.getInputIntoStartTime(s));
c.setEndTime(input.getInputIntoEndTime(s));
if(input.WhereAreTheNumber(input.getInputIntoAnswerNumber(s))==0) {
ur.getUserRecords().addCallingInLandRecords(c);
}
if(input.WhereAreTheNumber(input.getInputIntoAnswerNumber(s))==1) {
ur.getUserRecords().addCallingInCityRecords(c);
}
if(input.WhereAreTheNumber(input.getInputIntoAnswerNumber(s))==-1) {
ur.getUserRecords().addCallingInProvinceRecords(c);
}
}
}
}
else {
if(s.equals("end")) {
break;
}
}
}
users=sort(users);
for(User ur2:users) {
System.out.println(ur2.getNumber()+" "+OutFormat.doubleFormat(ur2.calCost())+" "+OutFormat.doubleFormat(ur2.calBalance()));
}
sc.close();
}
publicstatic ArrayList<User> sort(ArrayList<User> us) {
Collections.sort(us,new Comparator<User>() {
@Override
publicint compare(User o1, User o2) {
if(o1.getNumber().compareTo(o2.getNumber())>0)
return 1;
else {
return -1;
}
}
});
return us;
}
}
class MessageRecord extends CommunicationRecord{
String message;
public String getMessage() {
returnthis.message;
}
publicvoid setMessage(String message) {
this.message=message;
}
}
class OutFormat {
publicstatic Double doubleFormat(double b) {
DecimalFormat df = new DecimalFormat("#.0");
Double output = Double.valueOf(df.format(b));
return output;
}
}
class User {
private UserRecords userRecords = new UserRecords();
privatedouble balance = 100;
private ChargeMode chargeMode;
private String number;
public User(InputHandle inputHandle) {
}
public User() {
}
publicdouble calBalance() {
this.balance = this.getBalance()-this.calCost()-this.chargeMode.getMonthlyRent();
returnthis.balance;
}
publicdouble calCost() {
returnthis.chargeMode.calCost(this.userRecords);
}
public UserRecords getUserRecords() {
returnthis.userRecords;
}
publicvoid setUserRecords(UserRecords userRecords) {
this.userRecords=userRecords;
}
publicdouble getBalance() {
returnthis.balance;
}
publicvoid setChargeMode(ChargeMode chargeMode) {
this.chargeMode=chargeMode;
}
public ChargeMode getChargeMode() {
returnthis.chargeMode;
}
publicvoid setNumber(String number) {
this.number=number;
}
public String getNumber() {
returnthis.number;
}
}
class UserRecords {//包括3種撥打記錄和3種接聽記錄和2種簡訊記錄
private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>();
private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>();
private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>();
public UserRecords() {
}
publicvoid addCallingInCityRecords(CallRecord callRecord) {
this.callingInCityRecords.add(callRecord);
}
publicvoid addCallingInProvinceRecords(CallRecord callRecord) {
this.callingInProvinceRecords.add(callRecord);
}
publicvoid addCallingInLandRecords(CallRecord callRecord) {
this.callingInLandRecords.add(callRecord);
}
publicvoid addAnswerInCityRecords(CallRecord callRecord) {
this.answerInCityRecords.add(callRecord);
}
publicvoid addAnswerInProvinceRecords(CallRecord callRecord) {
this.answerInProvinceRecords.add(callRecord);
}
publicvoid addAnswerInLandRecords(CallRecord callRecord) {
this.answerInLandRecords.add(callRecord);
}
publicvoid addSendMessageRecords (MessageRecord messageRecord) {
this.sendMessageRecords.add(messageRecord);
}
publicvoid addReceiveMessageRecords (MessageRecord messageRecord) {
this.receiveMessageRecords.add(messageRecord);
}
public ArrayList<MessageRecord> getSendMessageRecords(){
returnthis.sendMessageRecords;
}
public ArrayList<MessageRecord> getReceiveMessageRecords(){
returnthis.receiveMessageRecords;
}
public ArrayList<CallRecord> getCallingInCityRecords(){
returnthis.callingInCityRecords;
}
public ArrayList<CallRecord> getCallingInProvinceRecords(){
returnthis.callingInProvinceRecords;
}
public ArrayList<CallRecord> getCallingInLandRecords(){
returnthis.callingInLandRecords;
}
public ArrayList<CallRecord> getAnswerInCityRecords(){
returnthis.answerInCityRecords;
}
public ArrayList<CallRecord> getAnswerInProvinceRecords(){
returnthis.answerInProvinceRecords;
}
public ArrayList<CallRecord> getAnswerInLandRecords(){
returnthis.answerInLandRecords;
}
}
下面是我的複雜度分析圖
1. 因為有了已經知道的類圖,所以只需要根據類圖設計就可以了。
2. 在實現user資訊的錄入和判定資訊邏輯有點複雜,需要多次測試去完善判定資訊和條件。
3.在main函式中有太多的if,else判斷,極大的提高了我的類複雜度。
4.在對資料處理的函式中,我對每一個方法都進行了註釋,因為很多方法都差不多,不填上註釋很容易用錯。
2.第二個習題集的分析
設計上:在設計手機的計費方式中,我沿用座機計費的程式碼,並補充對手機計費的方法,同時在main函式中新增手機計費的內容。
elseif(input.inputTwoIsQualified(s)) {//座機打座機for(User ur : users) {
if(ur.getNumber().equals(input.getInputIntoCallingNumber(s))||ur.getNumber().equals(input.getInputIntoAnswerNumber(s))) {
c = new CallRecord();
c.setAnswerAddressAreaCode(input.getInputIntoAnswerNumber(s));
c.setCallingAddressAreaCode(input.getInputIntoCallingNumber(s));
c.setStartTime(input.getInputIntoStartTime(s));
c.setEndTime(input.getInputIntoEndTime(s));
if(!ur.getNumber().equals(input.getInputIntoAnswerNumber(s))||input.getInputIntoCallingNumber(s).equals(input.getInputIntoAnswerNumber(s))) {
if(input.WhereAreTheNumber(input.getInputIntoAnswerNumber(s))==0) {
ur.getUserRecords().addCallingInLandRecords(c);
}
if(input.WhereAreTheNumber(input.getInputIntoAnswerNumber(s))==1) {
ur.getUserRecords().addCallingInCityRecords(c);
}
if(input.WhereAreTheNumber(input.getInputIntoAnswerNumber(s))==-1) {
ur.getUserRecords().addCallingInProvinceRecords(c);
}
}
}
}
}
elseif(input2.IsLandPhoneToSmartPhone(s)) {//座機打手機
for(User ur : users) {
if(ur.getNumber().equals(input2.zuojiCallNumber(s))||ur.getNumber().equals(input2.smartAnswerNumber(s))) {
c = new CallRecord();
c.setCallingAddressAreaCode(input2.zuojiCallCode(s));
c.setAnswerAddressAreaCode(input2.smartAnswerCode(s));
c.setStartTime(input2.getInputIntoStartTime(s));
c.setEndTime(input2.getInputIntoEndTime(s));
if(ur.getNumber().equals(input2.zuojiCallNumber(s))) {//使用者為撥打使用者
if(input2.WhereAreTheSmartPhoneNumber(input2.smartAnswerCode(s))==1) {//為座機市內打電話且手機接聽省內
ur.getUserRecords().addCallingInCityRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.smartAnswerCode(s))==-1) {//為座機省內打電話且手機接聽省內
ur.getUserRecords().addCallingInProvinceRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.smartAnswerCode(s))==0) {//為座機國內打電話且手機接聽省內
ur.getUserRecords().addCallingInLandRecords(c);
}
}
if(ur.getNumber().equals(input2.smartAnswerNumber(s))){//使用者為接聽使用者
if(input2.WhereAreTheSmartPhoneNumber(input2.smartAnswerCode(s))==0) {
ur.getUserRecords().addAnswerInLandRecords(c);
}
}
}
}
}
elseif(input2.IsTheQualitiedInput(s)) {//手機打手機||手機打座機
for(User ur : users) {
if(ur.getNumber().equals(input2.getInputIntoSmartPheoneCallingNumber(s))||ur.getNumber().equals(input2.getInputIntoSmartPheoneAnswerNumber(s))) {
String[] s1 = s.split(" ");
if(s1.length==7) {//手機打座機
c = new CallRecord();
c.setCallingAddressAreaCode(input2.getInputIntoPhoneCallingCode(s));
c.setAnswerAddressAreaCode(input2.getInputIntoLandAnswerCode(s));
c.setStartTime(input2.getInputIntoStartTime(s));
c.setEndTime(input2.getInputIntoEndTime(s));
if(ur.getNumber().equals(input2.getInputIntoSmartPheoneCallingNumber(s))) {
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==1&&input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoLandAnswerCode(s))==1) {
ur.getUserRecords().addCallingInCityRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==1&&input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoLandAnswerCode(s))==-1) {
ur.getUserRecords().addCallingInProvinceRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==1&&input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoLandAnswerCode(s))==0) {
ur.getUserRecords().addCallingInLandRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==-1) {
ur.getUserRecords().addCallingInProvinceRoamingRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==0) {
ur.getUserRecords().addCallingInLandRoamingRecords(c);
}
}
}
else {//手機打手機
c = new CallRecord();
c.setCallingAddressAreaCode(input2.getInputIntoPhoneCallingCode(s));
c.setAnswerAddressAreaCode(input2.getInputIntoSmartAnswerCode(s));
c.setStartTime(input2.getInputIntoStartTime(s));
c.setEndTime(input2.getInputIntoEndTime(s));
if(ur.getNumber().equals(input2.getInputIntoSmartPheoneCallingNumber(s))) {//該使用者為撥打使用者
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==1&&input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoSmartAnswerCode(s))==1) {
ur.getUserRecords().addCallingInCityRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==1&&input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoSmartAnswerCode(s))==-1) {
ur.getUserRecords().addCallingInProvinceRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==1&&input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoSmartAnswerCode(s))==0) {
ur.getUserRecords().addCallingInLandRecords(c);
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==0) {
ur.getUserRecords().addCallingInLandRoamingRecords(c);;
}
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoPhoneCallingCode(s))==-1) {
ur.getUserRecords().addCallingInProvinceRoamingRecords(c);
}
}
if(ur.getNumber().equals(input2.getInputIntoSmartPheoneAnswerNumber(s))) {//該使用者為接聽使用者
if(input2.WhereAreTheSmartPhoneNumber(input2.getInputIntoSmartAnswerCode(s))==0) {
ur.getUserRecords().addAnswerInLandRecords(c);
}
}
}
}
}
}
分析:基本的思路和方法處理第一次習題差不多,就是多了對手機資訊的處理和手機座機混合輸入的處理,
但是由於沿用了第一次習題的main類,所以在其中又加入了手機,手機座機的資訊判斷處理,導致main裡面有更多的if-else判斷,加大了main的圈複雜度。
3.第三個題目集的分析
分析:因為這個題目集的難度偏低,實現起來比較容易,所以在main裡面的判斷少了些許,圈複雜度明顯低與前兩題。
三.踩坑心得
1.第一個習題集在處理字串的判斷時,正則表示式出錯了,對正則表示式的使用還不太熟悉。
2.在儲存user的相關資訊時,需要判斷是否為空的情況,如果為空也得add一個user。
3.第二個習題集中,出現了很多userecord的儲存錯誤,主要是根據提取的資訊號碼和區號去選擇set相應的user和callRecord的相關資訊
4. 在第三個題目集的計算中,需要注意簡訊的長度,根據簡訊的長度計算不同的收費。
四.改進建議
1.將main中的對輸入資訊的if-else判斷放在一個單獨的邏輯判斷類中,以此減少夯餘的if-else判斷。
2.可以考慮採用繼承的方法去實現對手機,座機資訊的提取和判斷,從而減少程式碼的重複。
五.總結
1.學會使用繼承和多型簡化重複的程式碼
2.學會了使用Arrilist操作多個物件,並學會使用其中的各類方法。
3.學習並加強使用了正則表示式,利用正則表示式簡化格式問題。
4.學會了用容器介面和多型的複用。
5.深刻體會了類的設計的單一原則的重要性,避免在一個類中設計多個交叉呼叫的方法。
以上是 《原神攻略》2.7版夜蘭全面配裝測試與配置建議 的全部内容, 来源链接: utcz.com/yxgl/576602.html