OO第1~3次作業總結

来源:https://www.cnblogs.com/jeffan/archive/2018/04/04/bingoit.html
-Advertisement-
Play Games

面向對象這門課,寫了3次作業,在這裡分享一下自己的設計思路、分析總結等,歡迎一起探討~ ...


作業1——多項式運算

基於度量和類圖分析設計

先看Metrics插件做出的複雜度分析:

p1

乍一看沒有紅色報警,其實是因為選中某一行時會自動將該行改為黑色,無論之前是紅色還是藍色emmm

真正展開第一行時,慘不忍睹:

為什麼圈複雜度這樣大?先看看類圖:

  • 【當時的設計思路】有個poly類,既是poly的數據結構(繫數和冪指數的數組),又是其方法載體(能夠實現加減、列印自身信息);還有一個負責統籌規劃的計算者類,能夠分析輸入的字元串、進行多項式運算、列印錯誤信息。
  • 【如今看來需要做的改動】

  (1)把分析字元串合法性的工作放給poly,他應該知道自己是不是一個合格的poly

  (2)列印錯誤輸出這件事,應該另起一個類,實現功能的劃分。

  (3)不要洋洋灑灑就用數組。

  (4)字元串匹配這事兒,不要用狀態機來做。

  • 【我為什麼當時用狀態機】這是一個令人心酸的故事QAQ

  首先,我花了一上午熟練掌握了正則表達式的通用知識,打算在C程式(作業的另一個要求)中試試手,便去下載C程式所要的相關的頭文件等,結果一直用不了...大神跟我說C最好不要用正則表達式emmm 於是我想起來學姐提示過的有限狀態機,我畫了個大狀態機,反覆分析論證其正確性,然後在C程式實現了。發現時間不多了趕緊跑去乾java,可能是太緊張了吧,java正則表達式教程我看了倆小時沒懂,突然失去自信...那就先穩一點用狀態機寫吧,之後就沒時間改過來了...

  這個故事告訴我們,做事前一定要分輕重。

  後來第一次實驗課時,要求我們會用java使用正則表達式,於是我打開被分配到的互測作業,有例子果然學起來就是快,10分鐘我就懂了...

  所以同樣是緊張,為何效率如此不同...答案或許是,面向例子學習法萬歲!

  • 【PS】狀態機唯一的優點(安慰自己一波),就是能在實現狀態的同時,順帶對錯誤的輸入進行準確的錯誤提示,比如,在第幾個字元處出現了錯誤,用戶輸入了什麼,而本程式期望怎樣的輸入。
  • 【狀態機導致了高複雜度】既然我用了狀態機,那麼swith-case, if-else就暴增了,而McCabe圈複雜度:

認為程式的複雜性很大程度上取決於程式圖的複雜性。

單一的順序結構最為簡單,迴圈和選擇所構成的環路越多,程式就越複雜。
   因此,我的McCabe圈複雜度直接爆表(哭)。嚴格來講,我的這次代碼 屬於 面向對象和麵向過程之間 的過渡類型...  

Bug分析

  • 公測:通過
  • 互測:我方安全,對方正則表達式爆棧
  • 課下自我調試:發現poly列印自己的函數有bug——在考慮 結果多項式 的 某個term 的繫數為0 的情況時,漏掉了一些情況導致的bug,後來對繫數為0的term出現的位置進行了首、中、末的遍歷,來確保自己的列印輸出格式正確。
  • 今晚是個平安夜。

 


 

 作業2——傻瓜電梯

基於度量和類圖分析設計

先看Metrics插件做出的複雜度分析:

 

這次是真的沒有紅色報警~撒花~

那麼再看類圖:(自己手動調整了位置看起來 局部對稱、思路清晰,建議全屏看大圖)

  • 【類設計思路】

  首先明確指導書的要求:需要實現的類 包括但不限於Elevator, Floor, Request, RequestQueue, Scheduler 這5個類(我承認 命名的時候去搜過翻譯...)

  是否要加其他類:為了讓兩種請求有所區別,我設計了RequestER, RequestFR 兩個請求類的子類; 為了讓main函數不要放在某個其他類里導致沒有邏輯關係,我加了Main類; 我吸取第一次作業的教訓,將列印錯誤輸出抽出來作為一個Err類。

  • 程式開始了,字元串輸入進來,誰來處理呢?為了讓Floor類有事乾(哭),我把parseStr分別放在了Floor類以及和它對應的Elevator類裡面,也就是說樓層和電梯都能夠判斷自己接收的請求是不是合格的,同時也能夠根據 合格與否 的判斷結果,來構造FR或ER類型的請求並返回這個請求。
  • 【那麼問題1來了】 

  判斷是否為”合法請求“這件事,所需要的條件不僅僅是內部信息(即輸入的一行字元串),還需要外部信息(即:1. 這條請求是否是第一條請求,如果是需要滿足請求時間為零   2. 這條請求的時間輸入順序是否正確,因為我們要求這堆請求的請求時間應該是非遞減的)。  

  當一個面試者知道自己能力和顏值已經合格的時候,面試官還會把這個面試者和其它面試者進行比較,”比較“這件事就是外部條件吧,那麼我們可以有兩種方式來判斷這個面試者是否內外兼修地合格:

  A. 面試官勤奮些,把 自我判定內部條件為合格 的面試者拿出來,做做比較。

  B. 面試者的工作全面些,也就是把 其他面試者的信息等 也交給 這位面試者,讓面試者自己去判斷 自己是否同時滿足內、外部條件。

  脫離這次作業,從更加抽象的角度來講,我覺得這兩種方法各有利弊。  A似乎更貼合現實,使得上層面試官看起來更加統籌規劃、更有權力的樣子。  B似乎把 “判定合格”這件事包裝得更好,不用把“內、外條件判定”這件事 進行分離(可是這樣的話,總覺得面試官是不是沒有存在的意義了...)

  我無法做出判斷,不過根據本次作業的實際考慮,我選擇了A。

  • 程式繼續,把合格的請求挑出來放到隊列裡面去,然後應該做什麼呢? 讓調度器去 刪除同質請求 得到真正的請求隊列、然後讓電梯運動
  • 【那麼問題2來了】

  調度演算法如何實現?根據我後來的瞭解,大體上有這麼2類思路:

  A. “先知”式的,只面向請求隊列,對請求隊列進行一定的掃描,得出真正要執行的請求隊列 以及 其中每個請求 的開始執行時間和執行結束時間,然後跟傻瓜電梯說,你就按著我這個計劃來動就行。(為什麼叫先知?先看看生活現實:隨著時間的推進,一方面電梯在運動,同時,請求也在不斷地到來。而“先知”式調度, 是 坐了時間穿梭機去未來,把所有請求都拿來分析,然後穿梭回過去,跟電梯說你應該怎麼怎麼動。總的來說,就是交互性不強。)

  B. “模擬”式的,從現實生活得到啟發,模擬時間推進 或 模擬電梯爬樓. 

  筆者寫第2次作業時,只想到了A,然後就動手了,效果還不錯。而且我很懶,覺得電梯既然那麼傻,乾脆不給他運動的方法了,直接讓調度器跟他說:你就把我傳給你的參數按照某個格式列印出來就行,都不用動的...

  • 【問題3和問題1有點像】

  刪除同質請求這件事,我放給了Request類及其子類,但是又遇到內外部條件的問題。

  如果 r2 是 r1 的同質請求,那麼首先需要滿足這個時間條件: r1的請求時間 <= r2的請求時間 <= r1的執行結束時間。一開始我把這個時間條件當成外部條件,由Scheduler判斷 r2  r1是否滿足時間條件,再由 r1 判斷 r2 是否滿足 請求類型、目標樓層、請求方向 等內部條件,這樣就把 “判斷同質” 這事兒拆分成了兩部分,當時就是感覺心裡有點小疙瘩,忍一忍就過去了...

  後來我做第三次作業的時候,受到一些同學的啟發,覺得完全可以把時間條件做成內部條件,也就是請求類增加一些屬性,這樣就可以實現功能的包裝了。

  反過來去思考問題1,如果要實現這樣的功能包裝,或許要把請求隊列傳進來給Request,這樣Request才能知道自己在隊列中的位置 以及 隊列中其它請求的情況,也才能判斷自己是不是一個真正合格的請求,但是顯然我們不應該讓  碗里的豆豆 直接知道 這個碗的信息以及碗里裝的其它豆豆的信息 。而且如果真的實現了這樣的功能包裝,RequestQueue就真的成為 傻瓜式純容器 了(哭)。

  【PS】聰明的你或許已經發現,我的設計 可擴展性 有點弱,到第三次作業就不得不大換血了...

Bug分析

  • 公測:通過
  • 互測:我方安全,對方沒有交readme被我報了2個bug
  • 課下自我調試:沒有什麼可說的bug
  • 今晚是我的平安夜。

 

 作業3——“耍點小聰明”的電梯

基於度量和類圖分析設計

先看Metrics插件做出的複雜度分析:

 

一共紅了兩處,分別是 McCabe圈複雜度 和 嵌套塊深度,摘錄出來,發現是 A Little Smart Scheduler 出了問題: 

  作業1的分析中,我對McCabe圈複雜度進行了一定的說明,回顧一下:

它認為程式的複雜性很大程度上取決於程式圖的複雜性。

單一的順序結構最為簡單,迴圈和選擇所構成的環路越多,程式就越複雜。

  那麼這個 A 圈複雜度 和 B 嵌套塊深度 的區別,我覺得是,前者兼顧了廣度和深度兩方面的複雜檢測,後者專註於 深度的複雜檢測。有點像B能推出A,A不能推出B的關係。

  那為什麼這兩個度量值會報警呢——耍點小聰明的ALS_Scheduler類裡面,由於具有 掃描隊列來取出主請求、掃描隊列來得到能夠被捎帶的請求、掃描隊列來刪除被捎帶的請求的同質請求、掃描隊列來刪除主請求的同質請求 這4個掃描遍歷,以及 配套的許多判斷條件,所以這兩個度量值 直接爆表。(儘管我在課下de完bug之後,嘗試著把其中一些塊抽取出來包裝成方法)

  類圖如下:(筆者將類的位置進行了調整,方便和作業2的類圖進行很好的對比)

 

 

  •  【思想大換血】

  一開始,我打算沿襲第二次作業的“先知”式調度,但是卻發現,在遍歷請求隊列的時候,主請求的執行結束時間是動態變化的(如果有請求會被它捎帶的話),{ 每次一發現可以被捎帶的請求R,就必須刪除掉R的同質請求,更新 主請求的執行結束時間,然後再次從頭遍歷請求隊列 },然後重覆執行上述{ }的內容,直至沒有可以被捎帶的請求了。

  這麼一聽,好像不過是稍微複雜了些而已。但是有個問題,當電梯處於STILL狀態時,被捎帶的條件就變得不大一樣了,所以必須記錄電梯在 什麼時候 在 哪個樓層 為了捎帶而停下來開關門,然後我就懵了,這個信息要如何記錄,怎樣記錄才能方便我查詢。突然失去信心。

  於是我便和學霸交流了下,發現學霸模擬電梯爬樓,意識到其中的幾個大優點:

  1. 和模擬時間相比,不會出現 “由於輸入的請求時間過大 而導致程式運行時間變大” 的現象。(這個現象其實可以通過某種辦法消除掉)
  2. 沒有 “先知”式調度 的 “一找到被捎帶請求就要再次從頭遍歷” 的問題,以及由此帶來的輸出順序問題。
  3. 在處理STILL狀態時的捎帶判斷時,十分方便,不需要什麼數據結構來記錄。
  4. 模擬電梯爬樓,每次執行完一條請求,就讓電梯運動並列印運動狀態,十分方便,不用再拿數據結構去存這條請求的執行結束時間等,而且方便調整輸出順序。
  • 【類設計變更】聽了我的設計思路變化,對比於作業2的類設計圖,聰明的你應該已經知道我的類設計變化了:
  1. 電梯沒有那麼傻了,給它增加了 幾個運動的方法 以及 一個時間屬性。
  2. 耍小聰明調度器 繼承了 直男癌調度器,但是並沒有用到 start[] end[] 數組,這兩個數組在第二次作業中記錄的是 每個真正有效請求 的 開始執行時間 和 執行結束時間;現在,由於電梯裡面記錄了時間,而且程式是在每次處理完一條請求後,就列印輸出,所以這兩個數組就沒有存在的意義了。
  3. 其它適應性的小變化。

Bug分析

  • 公測:通過
  • 互測:我方安全,對方公測過了但被我另找出了3個bug
  • 課下自測:輸出順序有問題,這也是大家最容易忽略的一個問題吧。
  • 今晚還是我的平安夜~

其它總結

發現bug的策略

  1. 解剖指導書。我遍歷了幾遍指導書,而且自己用筆把一條條規定都簡單列了出來,用紅筆標記不同條列之間的關係以及易忽略的點。然後進行一些深入思考,比如指導書說到電梯可能的幾個狀態的時候,我就畫了個狀態機出來。深入瞭解指導書是前提。
  2. 給自己程式打過的補丁,也可能是別人容易漏掉的。
  3. 不同的設計方式會有不同的易錯點,如果你抽到的代碼的設計方式和你不同,可以找找其他使用這個設計方法的同學,問問他們課下de出來了什麼bug。
  4. 討論區和微信群里大家的討論也都一條條列出來了,並和3合併。
  5. 與你親愛的同學交換測試樣例。
  6. 把問題抽象到一定層次,以更加巨集觀的視角去看待,就更容易發現問題所在。比如我第三次作業的時候,就畫了個時間軸,以最複雜的捎帶情況為基準來分析,然後遍歷所有可能出現的情況。同時,這個時間軸也很方便我構造測試樣例。(在這裡表示羡慕大佬 只需要動動腦子 就可以模擬出電梯運動情況,反正對我來說,每看到一個測試樣例,我基本都要畫個時間軸,不過越畫越快了嘿嘿嘿)

還可以改進的地方

  1. 加入枚舉的使用。
  2. 通過讓方法 拋出異常 來更好地包裝方法。比如,如果傳入的A滿足條件,請返回關於A的某個具體的內容,如果傳入的A不滿足條件,就拋出異常。

  總之,我現在的設計狀態是,必須把設計的大體思路、以及某些實現細節,都想清楚了,偽代碼也寫得比較細緻了,我才會開始碼代碼,而且想清楚之後 寫代碼賊快,也便於debug。而且,在設計和思考的時候,腦子處於及其活躍的狀態,這個時候容易想到各種你之後可能想不到的細節,儘管這個過程比較痛苦。另外,我會請給我指點迷津的大佬次飯的,再次感謝~

  預祝大家 習得OO,策馬歸來~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 項目中用到的一個功能是要通過點擊地址來實現打開地圖app實現地址導航。 如下圖: 實現思路就是在H5頁面內通過點擊marker圖標然後進行當前位置與頁面上地址的路程規劃與導航。 由於項目中用到的是高德地圖,所以這裡用到的是調起高德地圖APP來實現該功能。 首先肯定要去高德開放平臺去申請KEY,拿到這 ...
  • css2.0文檔查閱下載 網址:http://soft.hao123.com/soft/appid/9517.html <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content=" ...
  • 錯誤: Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’ 原因: html代碼中出現類似這樣的<input type=“text” [(ngModel)]=“username”>語句,其中使用了[(ngModel)] ...
  • 因為換了個工作,所以博客停了一段時間。 這是上個月留下來的坑,webpack的源碼已經不太想看了,又臭又長,噁心的要死,想去看node的源碼……總之先補完這個 上一節完成了babel-loader對JS文件字元串的轉換,最後返回後進入如下代碼: 在看這個parse方法之前,需要過一下參數,首先是這個 ...
  • <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>引入外部樣式</title><link rel=" ...
  • 模板方法模式使用繼承來實現模式的功能,在基類使用一個方法來定義演算法的各個步驟,這些步驟(方法)的具體實現會放到子類中,通過這樣來實現不同演算法對象的演算法拼合,完成該對象整體演算法的實現。 作用 模板方法中定義了具體操作中所使用演算法的各個步驟,並將其實現交由子類完成,從而實現多種不同的功能; 類視圖 實現 ...
  • 一、前言 BIM:Building Information Modeling 建築信息模型,就是將建築的相關信息附著於模型中,以管理該建築在設計、算量、施工、運維全生命周期的情況。創建模型的主要主流軟體有Autodesk(歐特克)的Revit、Bentley的microstation、達索的CATI ...
  • 策略模式將不同演算法的邏輯抽象介面封裝到一個類中,通過組合和多態結合的方式來進行不同演算法具體的實現。 作用 策略模式是一種定義一系列演算法的方法,Strategy類層次為Context定義了一系列的可重用的演算法或行為, 所有的演算法以相同的方式進行調用,減少了演算法類之間的耦合 類視圖 實現 Strateg ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...