哈工大軟體構造Lab2
2021年春季學期
計算學部《軟體構造》課程
Lab 2實驗報告
姓名 |
李金宣 |
學號 |
1181910201 |
班號 |
1903002 |
電子郵件 |
|
手機號碼 |
13274539391 |
1實驗目標概述
本次實驗訓練抽象資料型別(ADT)的設計、規約、測試,並使用面向物件程式設計(OOP)技術實現ADT。具體來說:
l針對給定的應用問題,從問題描述中識別所需的ADT;
l設計ADT規約(pre-condition、post-condition)並評估規約的質量;
l根據ADT
lADT的泛型化;
l根據規約設計ADT的多種不同的實現;針對每種實現,設計其表示(representation)、表示不變性(rep invariant)、抽象過程(abstraction function)
l使用OOP實現ADT,並判定表示不變性是否違反、各實現是否存在表示洩露(rep exposure);
l測試ADT的實現並評估測試的覆蓋度;
l使用ADT及其實現,為應用問題開發程式;
l在測試程式碼中,能夠寫出testing strategy並據此設計測試用例。
2實驗環境配置
簡要陳述你配置本次實驗所需環境的過程,必要時可以給出螢幕截圖。
特別是要記錄配置過程中遇到的問題和困難,以及如何解決的。
Eclipse選單→“幫助”→安裝新軟體;
“安裝”對話方塊中,在“工作日期”中輸入http://update.eclemma.org/
根據指示正常安裝即可
在這裡給出你的GitHub Lab2倉庫的URL地址(Lab2-學號)。
https://github.com/ComputerScienceHIT/HIT-Lab2-1181910201
3實驗過程
請仔細對照實驗手冊,針對三個問題中的每一項任務,在下面各節中記錄你的實驗過程、闡述你的設計思路和問題求解思路,可輔之以示意圖或關鍵原始碼加以說明(但千萬不要把你的原始碼全部貼上過來!)。
3.1Poetic Walks
實現一個圖graph的模組,基於此模組,根據語義庫進行詩歌創作
1.實現Graph的String型別介面類,之後將String拓展為泛型L類;
2.建立Graph類的add、set、remove、vertices、sources、targets等方法;
3.基於建立好的Graph類,實現GraphPoet類,將語義庫存入graph圖中,然後利用GraphPoet類,根據graph中語義庫的資訊,對輸入文字進行處理,若輸入文字的兩個單詞之間存在橋接詞,則插入橋接詞;若存在多個單一橋接詞,則選取邊權重較大者。最終得到由輸入文字創作的詩歌,
3.1.1Get the code and prepare Git repository
建立本地倉庫
git init
下載實驗程式碼
git clone
https://github.com/rainywang/Spring2020_HITCS_SC_Lab2/tree/master/P1
連線遠端倉庫
git remote
https://github.com/ComputerScienceHIT/HIT-Lab2-1181910201
新增到本地倉庫
git add .
提交到本地倉庫
git commit -m
初次上傳到遠端倉庫
git push -u origin master
之後
git push origin master
3.1.2Problem 1: TestGraph <String>
針對每個方法進行等價類劃分的測試
覆蓋率:
3.1.3Problem 2: ImplementGraph <String>
以下各部分,請按照MIT頁面上相應部分的要求,逐項列出你的設計和實現思路/過程/結果。
3.1.3.1ImplementConcreteEdgesGraph
1.實現Edge類
資料段-邊的權值weight,邊的起點source,終點target
Edge中的方法
Edge |
構造方法,初始化邊的權值weight,起點source,終點target |
checkRep |
檢查不變性,邊不為空且權值非負 |
getSource |
get方法返回起點source |
getTarget |
get方法返回終點targe |
getWeight |
get方法返回權值weight |
toString |
" Source:"+this.source+",Target:"+this.target+",Weight:"+this.weight |
2.實現ConcreteEdgesGraph類
資料段:頂點集vertices和動態連結串列edges
ConcreteEdgesGraph中的方法:
ConcreteEdgesGraph |
構造方法 |
checkRep |
檢查不變性,edges中邊的source與target在vertices中,權值weight大於0 |
add |
引數為新頂點,點不在原圖,新增成功-true否則-false |
set |
引數為邊的起點source邊的終點target邊的權重weight,列表edges中新增一條邊,若起點終點相同或權值為負,新增失敗返回;若是新邊,權值為正,將兩點新增至vertices,邊新增到edges.若是已存在的邊,權值為正,更新邊的權值,返回上一條邊的權值,權值為0,刪除此邊 |
remove |
引數為需移除的頂點,刪除頂點,與此點相連的邊也一併刪除,原圖有此頂點返回true,若無則返回false |
vertices |
返回得到圖中所有頂點的HashSet集 |
sources |
引數為目標頂點,返回得到所有以該點為終點的邊的起點及權值,儲存到Map |
targets |
引數為目標頂點,返回得到所有以該點為起點的邊的終點及權值,儲存到Map |
toString |
返回字串,包含頂點數,邊數,各邊及其權重 |
3.測試,增加testToString部分即可
覆蓋率
3.1.3.2ImplementConcreteVerticesGraph
1.實現Vertex類:
資料段-V表示頂點,Sources表示以該頂點為終點的邊的起點表,Targets表示以該頂點為起點的邊的終點表,Map中String為頂點的對點,Integer為邊的權值
Vertex中的方法
Vertex |
初始化構造方法,引數為頂點 |
checkRep |
檢查不變性,頂點不空,權值為正 |
getV |
返回頂點V |
sources |
返回所有以該點為終點的邊,Map中為邊的起點及權值 |
targets |
返回所有以該點為終點的邊,Map中為邊的起點及權值 |
setSource |
引數為待加入的起點與權值,該點為終點時,將邊的起點和權值加入到Map Sources中,若權值小於等於0,返回0,若權值為正,當起點已存在時,更新權值,返回原來的權值,起點不存在則新增新點 |
setTarget |
引數為待加入的終點與權值,該點為起點時,將邊的終點和權值加入到Map Target中,若權值小於等於0,返回0,若權值為正,當終點已存在時,更新權值,返回原來的權值,終點不存在則新增新點 |
removeEdge |
引數為對點,在Sources或Targets表中,刪除與頂點相連某條邊的對點,返回原來的邊長 |
toString |
this.V.toString()+"-Sources:"+this.Sources.toString()+" Targets:"+this.Targets.toString()+"\n" |
2.實現ConcreteVerticesGraph類
資料段-Vertex構成的列表vertices
ConcreteVerticesGraph中的方法:
ConcreteVerticesGraph |
構造方法 |
checkRep |
檢查不變性,權值為正,頂點非空,起點終點數相同 |
add |
引數為頂點,在圖中新增一個頂點,若圖中存在該點,新增失敗return false;若新增成功,return true |
set |
引數為邊的起點,邊的終點,邊的權值,新增一條邊(在起點終點各自的vertex類裡新增各自的對點)若起點終點相同或權值為負,新增失敗返回,若是新邊,權值為正,將兩點新增至vertices,各自類中新增邊,權值為0,只將兩點新增至vertices,若是已存在的邊,權值為正,更新邊的權值,返回上一條邊的權值,權值為0,刪除此邊 |
remove |
引數為需移除的頂點,刪除頂點,與此點相連的邊也一併刪除,原圖有此頂點返回true,若無則返回false |
vertices |
返回得到圖中所有頂點的點集 |
sources |
引數為目標頂點,返回得到所有以該點為終點的邊的起點及權值,儲存到Map |
targets |
引數為目標頂點,返回得到所有以該點為起點的邊的終點及權值,儲存到Map |
toString |
各頂點的邊對點及其權重 |
3.測試,增加testToString部分即可
覆蓋率
3.1.4Problem 3: Implement genericGraph<L>
3.1.4.1Make the implementations generic
將型別更改為
publicclass ConcreteEdgesGraph<L> implements Graph<L>{ ... }class Edge<L>{ ... }
和:
publicclass ConcreteVerticesGraph<L> implements Graph<L>{ ... }class Vertex<L>{ ... }
已經聲明瞭型別為Edge或 的變數List<Edge>,成為Edge<L>和List<Edge<L>>
只需按以上規則對Graph<String>進行重構即可,程式碼整體邏輯框架不變。
重構後測試結果
3.1.4.2 ImplementGraph.empty()
public static Graph<String> empty() {
return new ConcreteEdgesGraph();
}
返回空的例項
3.1.5Problem 4: Poetic walks
基於建立好的Graph類,實現GraphPoet類,將語義庫存入graph圖中,然後利用GraphPoet類,根據graph中語義庫的資訊,對輸入文字進行處理,若輸入文字的兩個單詞之間存在橋接詞,則插入橋接詞;若存在多個單一橋接詞,則選取邊權重較大者。最終得到由輸入文字創作的詩歌
3.1.5.1TestGraphPoet
新增一段測試,生成詩歌是否與預期相同即可
覆蓋率
3.1.5.2ImplementGraphPoet
資料段-新的空表
GraphPoet,按行讀入文字檔案,String.split()分割為陣列String.toLowerCase()小寫。構建圖,相鄰的單詞加邊。首先要在加邊前通過Graph.add()加點,加邊時要判斷是否存在:由於Graph.set()能返回之前加的邊的值,以此來判斷是否存在,存在則在之前的值加一(之前的邊的值儲存為temp_weight)。
poem當相鄰兩個單詞任意一個不在之前建立的圖裡,則將後者單詞加入,當存在時,Bridge長度只能為2,分別求兩個單詞的sources和targets,將該Map轉換為Set求交集;若交集為空,則無橋,若交集不空,則在交集中找最短的橋(可以在Map的value中查詢weight)。
3.1.5.3Graph poetry slam
測試
3.1.6使用Eclemma檢查測試的程式碼覆蓋度
3.1.7Before you’re done
請按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的說明,檢查你的程式。
如何通過Git提交當前版本到GitHub上你的Lab2倉庫。
在這裡給出你的專案的目錄結構樹狀示意圖。
3.2Re-implement the Social Network in Lab1
同Lab1類似,用Person和FriendshipGraph兩個類模擬社交網路圖,Person模擬圖的頂點,FriendshipGraph模擬關係,getDistance能夠計算出每兩個Person之間的最短路徑,但要用3.1中的Graph ADT中的方法來實現
3.2.1FriendshipGraph類
資料段:
一個由Person類組成的Graph型別圖,初始為空
方法:
addVertex():呼叫graph.add()新增點。
addEdge():呼叫graph.set()兩次,新增雙向邊,權值為1,返回舊邊的權值。
int getDistance():判斷起止點是否相等。再新建Map<Person, Integer> disance儲存從起始點開始到該Person的距離,Map<Person, Boolean> visited表示該Person是否訪問過。將兩個Map初始化後,把起點標記為已經訪問。然後開始BFS搜尋,找到終點為止,返回最短距離。
3.2.2Person類
資料段name,構造方法Person賦值,get方法getName返回資料段name
3.2.3客戶端main()
Lab1中的main複製過來即可
3.2.4測試用例
覆蓋率
3.2.5提交至Git倉庫
在這裡給出你的專案的目錄結構樹狀示意圖。
4實驗進度記錄
請使用表格方式記錄你的進度情況,以超過半小時的連續程式設計時間為一行。
每次結束程式設計時,請向該表格中增加一行。不要事後胡亂填寫。
不要嫌煩,該表格可幫助你彙總你在每個任務上付出的時間和精力,發現自己不擅長的任務,後續有意識的彌補。
日期 |
時間段 |
計劃任務 |
實際完成情況 |
2021.6.10 |
18.00-22.00 |
完成Graph<String>部分 |
對實驗要求有了初步認識,細節未完成 |
2021.6.11 |
18.00-23.00 |
完成poet之前的部分 |
完成 |
2021.6.12 |
12.00-15.00 |
完成poet部分 |
完成 |
2021.6.13 |
12.00-15.00 |
完成Person部分 |
完成 |
5實驗過程中遇到的困難與解決途徑
遇到的難點 |
解決途徑 |
MIT的實驗要求不明確,英文難懂
|
翻譯軟體初步翻譯後,仍有許多細節模糊,每一句再具體翻譯 |
對javadoc要求的完善方法具體實現需要的資料結構不清楚
|
上網,翻閱教材查閱相關資料結構 |
|
|
6實驗過程中收穫的經驗、教訓、感想
6.1實驗過程中收穫的經驗和教訓
1.java程式設計經驗少,對相關資料結構不熟悉,javadoc格式的註釋不規範
2.對ADT與OOP有了更深刻的理解
3.對相關資料結構,有了更深的理解。
6.2針對以下方面的感受
(1)面向ADT的程式設計和直接面嚮應用場景程式設計,你體會到二者有何差異?
面向物件以抽象,類,繼承,物件等方法為基礎,就像製造汽車時,先將汽車分成多個部分,然後具體生產每一部分的零件再組裝,而面向過程像是從零件直接組裝。
(2)使用泛型和不使用泛型的程式設計,對你來說有何差異?
泛型能適應更多的情況,更加靈活多變。
(3)在給出ADT的規約後就開始編寫測試用例,優勢是什麼?你是否能夠適應這種測試方式?
可以及時修改,保證程式碼正確性與規範性,能
(4)P1設計的ADT在多個應用場景下使用,這種複用帶來什麼好處?
增加程式碼利用率,避免重複造輪子
(5)P3要求你從0開始設計ADT並使用它們完成一個具體應用,你是否已適應從具體應用場景到ADT的“抽象對映”?相比起P1給出了ADT非常明確的rep和方法、ADT之間的邏輯關係,P3要求你自主設計這些內容,你的感受如何?
體會到了面向物件程式設計的優點,有輪子時很容易實現,造輪子很困難。
(6)為ADT撰寫specification, invariants, RI, AF,時刻注意ADT是否有rep exposure,這些工作的意義是什麼?你是否願意在以後程式設計中堅持這麼做?
防止內部資料被外部修改,願意
(7)關於本實驗的工作量、難度、deadline。
大,難,緊
(8)《軟體構造》課程進展到目前,你對該課程有何體會和建議?
上課內容太過寬泛,課後輔導較少,難度較大,實驗和課堂結合不好。
2021年春季學期
計算學部《軟體構造》課程
Lab
1實驗報告
姓名 |
李金宣 |
學號 |
1181910201 |
班號 |
1903002 |
電子郵件 |
|
手機號碼 |
|
1 實驗目標概述
本次實驗通過求解三個問題,訓練基本Java程式設計技能,能夠利用Java OO開發基本的功能模組,能夠閱讀理解已有程式碼框架並根據功能需求補全程式碼,能夠為所開發的程式碼編寫基本的測試程式並完成測試,初步保證所開發程式碼的正確性。另一方面,利用Git作為程式碼配置管理的工具,學會Git的基本使用方法。
l 基本的Java OO程式設計
l 基於Eclipse IDE進行Java程式設計
l 基於JUnit的測試
l 基於Git的程式碼配置管理
2 實驗環境配置
JDK環境,大一學習Javaee課程時配置的jdk8環境,環境變數等配置時遇到一些問題,通過網路搜尋自學解決。
配置Eclipse環境時,一開始按照指導手冊的教程一步步安裝,中間匯入URL等環節出現許多問題,於是直接放棄指導手冊,自己一路點選next與finish進行安裝,所幸成功安裝eclipse。由於對全英文開發環境不太熟悉,網上搜索了eclipse簡體中文環境的配置方法,具體參考
https://blog.csdn.net/qq_43015730/article/details/89225747
下載的eclipse自帶Junit環境,但需要在eclipse設定中自行呼叫,一開始並不太懂應該怎麼呼叫Junit,在執行P2的turtle的test檔案時,因未配置Junit環境導致出錯,在報錯的行ctrl+1進行修改,成功配置Junit4環境。
在使用git的過程中遇到了非常多的問題,前後花了很長時間才將git環境配置好,一開始按照實驗指導手冊的Git指導書學習,但指導書內容過於繁雜,重點不突出,很多細節問題都沒有解答,於是直接放棄指導書,同學間交流和網路上自行搜尋成功配置好Git環境。
參考過非常多網站,如
https://www.cnblogs.com/dfsxh/articles/10959383.html
在這裡給出你的GitHub Lab1倉庫的URL地址。
https://github.com/ComputerScienceHIT/HIT-Lab1-1181910201
3 實驗過程
請仔細對照實驗手冊,針對四個問題中的每一項任務,在下面各節中記錄你的實驗過程、闡述你的設計思路和問題求解思路,可輔之以示意圖或關鍵原始碼加以說明(但無需把你的原始碼全部貼上過來!)。
為了條理清晰,可根據需要在各節增加三級標題。
3.1 Magic Squares
要求1:在 main()函式中呼叫五次 isLegalMagicSquare()函式,將 5 個文字檔名作為引數輸入,讀入文字資料,判斷輸入的資料能否構成一個MagicSquare,若是則返回true,若不是或格式錯誤,則返回false且說明原因。
要求2:對給出的generateMagicSquare函式擴充套件,根據引數n生成一個MagicSquare並寫入文字6.txt中,然後判斷其是否為MagicSquare。輸入為奇數能生成MagicSquare返回true,輸入偶數或者負數會返回false。
3.1.1 isLegalMagicSquare()
設計思路:首先讀入txt文字檔案,然後進行判斷題目要求的三個條件:
1. 行列數不相等,並非矩陣:每讀入一行row++,計算總行數,將每一行按照\t分隔存入陣列,判斷每一行的列數是否與行數相等,若存在不相等,返回false。
2. 矩陣中的某些數字並非正整數:每一行按照\t分隔存入陣列後,判斷陣列元素有無”-”或”.”,有則說明有負數或小數,返回false
3. 數字之間並非使用\t分割:對Integer.valueOf使用try catch方法,若不是以 \t作為分隔符則丟擲異常資訊,返回false。
對錯誤型別進行判斷輸出錯誤型別並返回false,當判斷完畢沒 格式錯誤時,將讀入的資料存入到矩陣中,判斷每一行,每一列,對角線的和是否相等,滿足MagicSquare 則返回true,若有不相等則返回false
測試結果:
3.1.2 generatelMagicSquare()
流程圖
合法輸入判斷
測試樣例
3.2 Turtle Graphics
要求:1.完善drawSquare函式,畫出一個正方形
2.完善calculateRegularPolygonAngle函式計算正多邊形內角
3.完善calculatePolygonSidesFromAngle函式,由正多邊形內角 得到邊數
4.完善drawRegularPolygon函式,畫正多邊形
5.完善calculateBearingToPoint計算從一個點到另一個點所轉過的角度,
6.完善calculateBearings函式,給定一組點,計算每次轉過的角度並返回集合,
7.完善convexHull函式計算一系列點中的凸包,使用junit進行單元測試。
8.呼叫函式繪製自己的圖形
3.2.1 Problem 1: Clone and import
從實驗手冊的網站git clone下載P2的包,解壓匯入eclipse專案中。
1.獲取祕鑰:
2.找到祕鑰並複製新增到github上;
本地Git提交,push到GitHub:
1. git add;
2. git commit -m " ";
3. gitpush
參考https://www.cnblogs.com/dfsxh/articles/10959383.html
3.2.2 Problem 3: Turtle graphics and drawSquare
行進四次,每次轉90度
測試結果
3.2.3 Problem 5: Drawing polygons
正多邊形內角=(邊數-2)*180/邊數
畫多邊形時每次前進偏轉外角度數即可
3.2.4 Problem 6: Calculating Bearings
呼叫atan2函式得到兩點間偏轉弧度,toDegree轉換成角度,減去當前偏角即為偏轉角度,計算一組點,反覆呼叫兩點的函式即可
3.2.5 Problem 7: Convex Hulls
利用Gift wrapping演算法計算凸包,先找到最左下角的點作為初始點加入集合,然後比較剩餘點到此點的偏轉角,找到偏轉角最小的加入集合,當偏轉角相同時,找到最長的一條邊的點加入集合,直到返回初始點最後得到凸包的點集。
//這部分原始碼過長貼不下,請看原始檔
3.2.6 Problem 8: Personal art
3.2.7 Submitting
Junit測試
3.3Social Network
用Person和FriendshipGraph兩個類模擬社交網路圖,Person模擬圖的頂點,FriendshipGraph模擬關係,getDistance能夠計算出每兩個Person之間的最短路徑。
3.3.1設計/實現FriendshipGraph類
定義Person陣列來儲存所有的頂點,構造方法
addVertex新增物件,若新物件名字與已有名字重複,列印錯誤,退出
addEdge新增邊(頂點間的關係),在Person a物件陣列friend的裡新增b,單向
因為邊權重為1,可以使用廣度優先搜尋求兩點間最短路徑,呼叫類HashMap,用temp臨時儲存a1到各個點的最短距離,呼叫佇列,將a1入隊後按廣度優先搜尋的方法不斷入隊出隊,更新temp中各頂點當前最短路徑,直到有到a2的路徑為止,返回最短距離
3.3.2設計/實現Person類
3.3.3設計/實現客戶端程式碼main()
3.3.4設計/實現測試用例
給出你的設計和實現思路/過程/結果。
對於addVertex,設計用例,建立四個Person物件,執行addVertex,判斷vertex裡面這些物件。
對於addEdge,設計test用例,建立四個Person物件,執行addVertex後,執行addEdge然後判斷每個物件的friend中是否包含即可。
對於getDistance,設計test用例t,建立四個Person物件,執行addVertex後,執行addEdge後,最短距離正確即可。
4 實驗進度記錄
請使用表格方式記錄你的進度情況,以超過半小時的連續程式設計時間為一行。
每次結束程式設計時,請向該表格中增加一行。不要事後胡亂填寫。
不要嫌煩,該表格可幫助你彙總你在每個任務上付出的時間和精力,發現自己不擅長的任務,後續有意識的彌補。
日期 |
時間段 |
任務 |
實際完成情況 |
2021-05-19 |
晚 |
配置環境 |
Git配置未完成 |
2021-05-20 |
18.:00- |
配置環境 |
完成 |
2021-05-21 |
10:00-13:00 |
編寫P1的isLegalMagicSquare函式 |
完成 |
2021-05-21 |
15:00-16:00 |
編寫P1的generateMagicSquare函式 |
完成 |
2021-05-22 |
10:00-14:00 |
完成P2 |
完成 |
2021-05-22 |
17:00-21:00 |
完成P3 |
完成 |
|
|
|
|
5 實驗過程中遇到的困難與解決途徑
遇到的困難 |
解決途徑 |
Git配置出現問題
|
網上自己搜,與同學交流學習 |
P2測試類時出現問題
|
Eclipse的junit環境未設定,在報錯的行ctrl+1進行修改,成功配置Junit4環境。 |
P2對禮物包裝演算法不熟悉
|
網路上搜索演算法詳細介紹,參考演算法的相關程式碼編寫 |
P3對Java的廣度優先演算法編寫不太熟悉 |
查閱Java中佇列,雜湊表等相關類的介紹和用法,成功使用並優化了程式碼 |
6 實驗過程中收穫的經驗、教訓、感想
6.1 實驗過程中收穫的經驗和教訓
1.使用java次數少,對java語法不熟悉,許多地方程式碼優化不好
2.對Git配置不熟悉,出現許多問題
3.對java語言有了更深的理解。
6.2 針對以下方面的感受
(1) Java程式語言是否對你的口味?還好,有一定java基礎但不熟練,Java可使用的類與庫非常多,相比c語言可以使程式碼的編寫更加容易,程式碼更加簡潔。
(2) 關於Eclipse IDE;以前用過,使用者介面也比較良好,上手也容易,暫時未遇到太多問題
(3) 關於Git和GitHub;環境配置非常麻煩,實驗手冊的指導完全沒有重點,不知道從哪學起,全依靠自己上網搜尋和同學交流,希望這門課以後能把Git環境的配置詳細地指導給大家,而不是直接照搬MIT的指導手冊。
(4) 關於CMU和MIT的作業;雖然有一定難度,但層層遞進,鍛鍊程式設計能力,Java程式設計的收穫很大。
(5) 關於本實驗的工作量、難度、deadline;有一定難度,工作量大,雖然兩週時間實驗其實還算充裕,但課程時間與其他課程ddl衝突,開課第一週恰逢自動機期末考試和csapp實驗ddl,導致實際上的實驗時間被大大縮短,希望教務處能平衡好這幾門課ddl的衝突.
(6) 關於初接觸“軟體構造”課程;
實驗收穫還是很大的,但個人覺得平時上課講的東西太抽象寬泛,缺乏實際聯絡,很難理解什麼意思,很多同學也聽得不知所云,應對考試也就是背知識點做題,很難有實際收穫,然而這些部分卻佔了成績的大頭,希望課程考核和教學方式能有所改革,能更多側重於實驗部分或者提升平日課程內容的質量。