一、前言
對這兩次題目集的總結:
這兩次題目集相較於上次迭代作業來説,在題目量和難度上都做了下調。但要求我們在理解題目意思、設計好程序結構、掌握並運用知識這三方面有一定的要求。涉及到類的繼承與多態,抽象類的設計和抽象方法的靈活運用。以及面向對象的幾種程序設計的原則(單一職責原則、里氏代換原則、開閉原則、合成複用原則)。鍛鍊我們面向接口編程的能力。需要我們不斷規範自己的類設計、優化代碼結構、降低代碼的耦合性,提高程序的可擴展性。
二、設計與分析
因為題目集的前面幾題都比較基礎,所以該部分重點對航空貨物管理系統迭代題做分析。
第一次電梯題目的設計與分析
題目要求:編程實現一個航空貨物管理系統,對於訂單信息的一些基本數據的輸入(客户信息,收件人、發件人、貨物信息、航班信息、支付方式等)。還有空運貨物的重量計算,以及按照不同的重量區間具有不同的費率。最後一訂單表的形式輸出。並且本次題目重點考核面向對象設計原則中的單一職責原則、里氏代換原則、開閉原則以及合成複用原則。
類圖設計:
考慮到此次的題目是按照面向對象設計原則來進行打分的,所以類設計的比較多。
類的總體設計
- Main類: 正確的將數據儲存並且由這些數據構建具體實現類,並且能處理貨物是否超載的邏輯判斷。
- People類: 作為一個抽象的父類,裏面有用户的名字,電話號碼,地址的信息,以及Getter、Setter抽象的展示信息方法。
- Sender類: 該類繼承與People類作為一個具體實現類,繼承了父類的屬性並且實現了父類當中的展示信息方法。
- Recipient類: 該類繼承與People類作為一個具體實現類,繼承了父類的屬性並且實現了父類當中的展示信息方法。
- Customer類: 該類繼承與People類作為一個具體實現類,繼承了父類的屬性,同時還有自己的特有的編號屬性並且實現了父類當中的展示信息方法。
- Flight類: 屬性有航班的基本信息如始發地、終點和航班的編號。然後有按格式展示航班的基本信息的方法。
- Freight類: 這個類主要就是用來表示航空貨物的一些信息,同時裏面還有計算並獲取用於計算貨物真實重量的方法,並且與下面的貨物鏈表類相關聯。
- FreightList類: 作為貨物的容器,主要就是用來計算貨物的總重量,以及用於支付類的計算金額。
- PayMethod接口 主要就是做一個接口來放支付方式的抽象方法,用來展示支付方式。提高代碼的可擴展性。
- RateStrategy接口 接口來放不同費率計算方式的抽象方法,用來確定用哪種費率計算方式。提高代碼的可擴展性。
- PayMent類 組合貨物鏈表和支付方式和費率策略類,用於計算支付訂單所需要的總金額,並具有按訂單的形式的輸出的方法。
- Order類 具有訂單的編號和日期,同樣也有按訂單信息形式輸出的方法。
- ShowOrder類 組合上面有按訂單行動展示自身信息的類,主要控制訂單格式的輸出的順序邏輯。
Source Monitor分析結果:
點此處看方法具體複雜度
分析與心得
由上面的Source Monitor分析的結果來看不難發現,這次題目集提交的代碼雖然類的設計有很多,但是依舊有不合理的地方,還是有可以改進的地方。
- 類的職責不夠單一 有些具體信息類有展示的方法,並沒有完全的做到類的單一職責,應該將這種展示信息的方法分離出來,降低耦合度,提高系統的可擴展性。
- 代碼註釋量過少,可讀性差:代碼的註釋量依舊沒有達到規範的範圍。説明當時在完成這個題目集的時候沒有考慮到以後代碼還需要不斷地改進和維護。
心得:通過深刻剖析第一次的代碼,以及使用特定工具來檢查代碼不難發現這次的代碼在設計合理的類間關係、優化代碼結構和增強代碼的可讀性上面還有很大的改進和提升的空間。
第二次電梯題目的設計與分析
題目要求: 相較於上一次新增了不同的客户類型,不同的貨物,不同的支付方式。具體如下折扣率是指不同的用户類型針對每個訂單的運費可以享受相應的折扣,在本題中,用户分為個人用户和集團用户,其中個人用户可享受訂單運費的 9折優惠,集團用户可享受訂單運費的 8折優惠。本次作業費率與貨物類型有關,貨物類型分為普通貨物、危險貨物和加急貨物三種。支付方式(支付寶支付、微信支付、現金支付)
由於這次有不同的客户類型,不同的貨物,不同的支付方式。所以我採用了接口的形式來應對這些不同的情況。
類圖:
設計
將上一次的代碼的類設計做出以下的改變,下面是設計的每個類的功能:- Main類: 正確的將數據儲存並且由這些數據構建具體實現類,並且能處理貨物是否超載的邏輯判斷。然後新增按照不同的輸入類型創建相對應的接口,能夠應對此次題目新增的功能。
- People類: 作為一個抽象的父類,裏面有用户的名字,電話號碼,地址的信息,以及Getter、Setter。將第一次題目集展示信息的方法剝離出去。
- Sender類: 該類繼承與People類作為一個具體實現類,繼承了父類的屬性。
- Recipient類: 該類繼承與People類作為一個具體實現類,繼承了父類的屬性。
- Customer類: 該類繼承與People類作為一個具體實現類,繼承了父類的屬性,同時還有自己的特有的編號屬性。
- Flight類: 屬性有航班的基本信息如始發地、終點和航班的編號。
- Freight類: 這個類主要就是用來表示航空貨物的一些信息,同時裏面還有計算並獲取用於計算貨物真實重量的方法,並且與下面的貨物鏈表類相關聯。
- FreightList類: 作為貨物的容器,主要就是用來計算貨物的總重量,以及用於支付類的計算金額。
- PayMethod接口 主要就是做一個接口來放支付方式的抽象方法,用來展示支付方式。提高代碼的可擴展性。
- RateStrategy接口 該接口來放不同費率計算方式的抽象方法,用來確定用哪種費率計算方式。提高代碼的可擴展性。
- DiscountStrategy接口 該接口來放不同客户類型的折扣計算方式的抽象方法,用來確定用哪種折扣計算方式。提高代碼的可擴展性。
- PayMent類 組合貨物鏈表和支付方式和費率策略類,用於計算支付訂單所需要的總金額。
- Order類 對比上次題目的類該類具有訂單的編號和日期,還組合了客户,收件人,發件人,航班信息。將這些信息的展示方式放在這個類當中來展示。做好類的單一職責(SPR)。
- OrderDetais類 新增訂單明細類,組合支付類,和貨物鏈表類。主要就是用來展示一些有關於訂單金額信息的類。進一步解耦,提高擴展性。
- ShowOrder類 組合上面訂單類和訂單明細類,展示訂單信息的類,主要控制訂單格式的輸出的順序邏輯。
Source Monitor分析結果:
點此處看方法具體複雜度
分析與心得
由上面的Source Monitor分析的結果來看,第二次提交的通過代碼在新增了不同類型的處理情況後,代碼行數從 510 增至 670,設計多個接口和做到展示信息的和訂單信息職責拆分後新增OrderDetails類,符合接口編程的設計預期。質量明顯要比第一次的好的多,但是還是存在一些問題的:
- 代碼的註釋還是太少:註釋量站的百分比下降,可能是因為在重新設計類後,代碼行數的增多,導致第二次的邏輯部分即使增加了代碼註釋,註釋的量依舊沒有達到Java規範的量。
- 代碼的最大複雜度增加: 代碼的最大複雜度比上次提高了,説明在某個方法的調用或者計算的方式依舊有可以提升的空間。
心得:雖然這次的代碼仍有兩個方面沒有達到要求的範圍,但相比上次題目集已經有了很大的改進了,不過還是要養寫代碼註釋的習慣,尤其是邏輯部分和調用方法部分。使代碼邏輯容易理解和調試,符合Java編程原則規範了。
三、踩坑心得
本部分對每次題目集提交代碼出現的問題和心得進行總結
-
1.不能正確的構建具體類:在主方法裏使用nextLine來解析輸入的數據時,總是忘記把String類型的數據轉換為對應的數據類型。還有就是傳入的構造數據的順序老是弄錯。導致了不能正確的構建具體實現類,進而浪費了一些時間。
-
2.無法獲取父類的屬性 在編寫代碼的時候,把父類的屬性設置為了private的,然後又沒設計get方法導致無法獲取屬性。
-
3.超載信息提示的格式錯誤 第一次提交的時候回答詳情裏面超載信息的那部分顯示格式錯誤,一開始我以為是航班號的信息有問題,浪費了一些時間在檢查航班類的構建和信息輸出上面。後面才發現,我是在main方法裏面運用println輸出超載信息的時候“”裏面忘記加一個空格導致的格式錯誤。
四、改進建議
點擊查看可改進的代碼
static public void main(String[]args){
Scanner sc = new Scanner(System.in);
// 讀取客户信息
String customerNumber = sc.nextLine();
String customerName = sc.nextLine();
String customerTel = sc.nextLine();
String customerAddress = sc.nextLine();
//創建客户
Customer customer = new Customer(customerNumber, customerName, customerAddress, customerTel);
// 讀取貨物數量
int freightCount = Integer.parseInt(sc.nextLine());
FreightList freightList = new FreightList();
// 讀取每個貨物信息
for (int i = 0; i < freightCount; i++) {
Freight freight = new Freight(
sc.nextLine(),//number
sc.nextLine(), // name
Double.parseDouble( sc.nextLine()), // width
Double.parseDouble( sc.nextLine()), // length
Double.parseDouble( sc.nextLine()), // height
Double.parseDouble( sc.nextLine())//weight
);
freightList.addFreight(freight);
}
// 讀取航班信息
Flight flight = new Flight(
sc.nextLine(), // flightNumber
sc.nextLine(), // departure
sc.nextLine(), // arrival
sc.nextLine(), // date
Double.parseDouble(sc.nextLine()) // maxcapacity
);
//判斷重量是否滿足該航班的最大容量
if(freightList.calculateTotalWeight()>flight.getMaxcapacity()){
System.out.println("The flight with flight number:"+flight.getFlightNumber()+" has exceeded its load capacity and cannot carry the order.");
return;
}
// 讀取訂單信息
Order order = new Order(
sc.nextLine(), // number
sc.nextLine() // date
);
// 讀取發件人信息
String senderAddress = sc.nextLine();
String senderName = sc.nextLine();
String senderTel = sc.nextLine();
Sender sender = new Sender(senderName, senderAddress, senderTel);
// 讀取收件人信息
String recipientAddress = sc.nextLine();
String recipientName = sc.nextLine();
String recipientTel = sc.nextLine();
Recipient recipient = new Recipient(recipientName, recipientAddress, recipientTel);
//創建費率
Rate rate=new Rate();
// 創建支付類
Payment payment = new Payment(new WeChatPay(),freightList,rate);
// 創建Show實例並顯示
ShowOrder show = new ShowOrder(customer, freightList, flight, payment, sender, recipient, order);
show.showOrderInformation();
sc.close();
做好類的單一職責,降低耦合度
在這段Main類的的main方法裏面有超載的邏輯判斷和輸出沒有很好的做到類的職責單一原則,可以將這個邏輯判斷單拎出來。
添加合適的註釋,增強代碼可讀性
一些複雜的構造和調用方法並沒有註釋。這就會導致,當自己再次閲讀代碼或者別人查看代碼時,會變得很吃力,所以需要給出合適的代碼註釋,增強代碼的可讀性。
五、總結
收穫和建議:
收穫
在完成航空貨物管理系統的過程中,最大的收穫在於對面向對象設計原則的具象化理解與應用。通過兩次迭代題目,我逐步體會到單一職責原則(SRP)如何通過拆分 “展示邏輯” 與 “業務邏輯”(如將訂單信息輸出從Order類剝離至ShowOrder類)降低類的複雜度;里氏代換原則(LSP)要求子類完全替代父類的場景(如Sender/Recipient繼承People並實現統一接口),避免因子類行為差異導致的程序崩潰;開閉原則(OCP)則通過引入RateStrategy/DiscountStrategy接口,在新增貨物類型或客户折扣時僅需擴展實現類而非修改原有代碼,顯著提升系統可維護性。
此外,這次的航空貨物管理系統也讓我對 “接口編程” 思維有了一個具體化的瞭解。例如,將支付方式抽象為PayMethod接口,使支付寶、微信支付等具體實現可動態替換,這種 “面向抽象而非實現” 的設計極大減少了模塊間的耦合。同時,通過FreightList類封裝貨物集合的操作,實現了數據存儲與業務邏輯的分離,符合合成複用原則(CRP),避免了繼承帶來的緊耦合問題。
最後雖然這次的題目讓我收穫頗豐,但還是有一些方面需要進一步的學習和研究的。比如:深入去了解,什麼時候將方法抽象出來好,什麼時候不要把方法抽象出來。跟深入的去了解這些不同設計所帶來的優勢和不同。在今後的編程當中更加主動去重視面向對象程序設計原則,規範自己的代碼結構!
建議
最後根據這次迭代作業,給面向對象程序設計課題組的一些建議:
可以在迭代的題目集完全結束後給出規範合理的類設計結構給同學們學習、改進最終提升自己的編程能力
你在完成航空貨物系統時遇到了哪些挑戰?歡迎在評論區分享你的解決方案!感謝您的閲讀!