結對程式設計專案-最長英語單詞鏈
專案 | 內容 |
---|---|
這個作業屬於哪個課程 | 軟體工程 |
這個作業的要求在哪裡 | 結對程式設計專案-最長英語單詞鏈 |
我在這個課程的目標是 | 增加開發專案具體經驗,提高團隊協作能力 |
這個作業在哪個具體方面幫助我實現目標 | 體驗結對程式設計,進行工程實踐 |
- 1.在文章開頭給出教學班級和可克隆的 Github 專案地址(例子如下)。(1')
- 2.在開始實現程式之前,在下述 PSP 表格記錄下你估計將在程式的 各個模組的開發上耗費的時間。(0.5')
- 3.看教科書和其它資料中關於 Information Hiding,Interface Design,Loose Coupling 的章節,說明你們在結對程式設計中是如何利用這些方法對介面進行設計的。(5')
- 4.計算模組介面的設計與實現過程。
- 5.閱讀有關 UML 的內容,畫出 UML 圖顯示計算模組部分各個實體之間的關係(畫一個圖即可)。(2’)
- 6.計算模組介面部分的效能改進。
- 7.看 Design by Contract,Code Contract 的內容,並描述這些做法的優缺點,說明你是如何把它們融入結對作業中的。(5')
- 8.計算模組部分單元測試展示。
- 9.計算模組部分異常處理說明。
- 10.介面模組的詳細設計過程。
- 11.介面模組與計算模組的對接。
- 12.描述結對的過程
- 13.說明結對程式設計的優點和缺點。同時描述結對的每一個人的優點和缺點在哪裡(要列出至少三個優點和一個缺點)。(5')
1.在文章開頭給出教學班級和可克隆的 Github 專案地址(例子如下)。(1')
- 教學班級:週五班
- 專案地址:專案地址
2.在開始實現程式之前,在下述 PSP 表格記錄下你估計將在程式的 各個模組的開發上耗費的時間。(0.5')
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 30 | 30 |
· Estimate | · 估計這個任務需要多少時間 | 30 | 30 |
Development | 開發 | 1040 | 1190 |
· Analysis | · 需求分析 (包括學習新技術) | 90 | 150 |
· Design Spec | · 生成設計文件 | 60 | 50 |
· Design Review | · 設計複審 (和同事稽核設計文件) | 30 | 60 |
· Coding Standard | · 程式碼規範 (為目前的開發制定合適的規範) | 30 | 20 |
· Design | · 具體設計 | 90 | 70 |
· Coding | · 具體編碼 | 450 | 540 |
· Code Review | · 程式碼複審 | 90 | 120 |
· Test | · 測試(自我測試,修改程式碼,提交修改) | 150 | 180 |
Reporting | 報告 | 180 | 160 |
· Test Report | · 測試報告 | 90 | 70 |
· Size Measurement | · 計算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 60 | 60 |
合計 | 1250 | 1380 |
3.看教科書和其它資料中關於 Information Hiding,Interface Design,Loose Coupling 的章節,說明你們在結對程式設計中是如何利用這些方法對介面進行設計的。(5')
資訊隱藏:資訊隱藏是面向物件的基礎,該思想將某些功能的具體實現方法封裝在函式裡,外界使用該功能只需要呼叫函式便可以獲得想要的結果,保證了資料的安全性、程式的簡潔性。我們將介面設計的儘量簡潔,使一個函式可以獨立完成一個功能,而接口裡的屬性應是private,不被外界影響的。
介面設計:介面設計應該滿足可以提供功能所需的所有引數的基礎上儘可能簡潔,且不同需求的介面要分開。我們嚴格遵守課程組提供的介面,介面中包含原始提供資料,控制引數,以及儲存結果的容器。
鬆耦合:鬆耦合可以使該模組和其他程式通過介面組合,由於都是採用老師的介面,比較容易鬆耦合,但我們在之前處理了大小寫部分,直接傳輸不合規範的資料時會存在問題。
4.計算模組介面的設計與實現過程。
設計包括程式碼如何組織,比如會有幾個類,幾個函式,他們之間關係如何,關鍵函式是否需要畫出流程圖?說明你的演算法的關鍵(不必列出原始碼),以及獨到之處。(7')
在命令列處理中,需要先處理文字,統一大小寫,處理引數異常。獲取引數後將源單詞和約束引數傳給getWordLinks獲取全部單詞鏈,再按照不同的輸出函式處理輸出。
在core模組中,我們的計算模組介面實現了五個函式,分別是四個實現需求功能的介面函式(-n,-w,-m,-c四個需求)以及一個底層的具體實現計算的函式(根據單詞陣列和引數獲得符合要求的單詞鏈陣列的函式)。四個介面函式供其他模組呼叫。每個介面函式都會呼叫底層函式來得到單詞鏈陣列,並根據自身需求加以處理返回。
這次的程式設計題目可以用有向有環圖來表示,將一個字母視為一個結點,將單詞視為邊,一共有26*26個邊,建立鄰接矩陣,在每個邊中儲存相應的單詞。如apple這個詞,存在從a到e的邊中。
尋找單詞鏈時,從首字母開始,尋找在矩陣中是否存在由該字母開始的單詞,若有,則將該單詞標記為已用,並將該單詞首字母設為首字母進行遞迴,直到某首字母沒有可連線的單詞。其中呼叫了一個getOneLink的函式來進行遞迴。若此時單詞鏈中包含至少2個單詞,則輸出進單詞鏈片語。若某單詞首字母之前使用過且沒有r引數,則存在單詞環。
5.閱讀有關 UML 的內容,畫出 UML 圖顯示計算模組部分各個實體之間的關係(畫一個圖即可)。(2’)
6.計算模組介面部分的效能改進。
記錄在改進計算模組效能上所花費的時間,描述你改進的思路,並展示一張效能分析圖(由VS 2019的效能分析工具自動生成),並展示你程式中消耗最大的函式。(3')
從上圖可以看出耗時最長的是遍歷圖的部分,應該儘量減少遍歷次數。
在當前演算法中,需要遍歷a到z作為首個單詞的首字母,若遇到h,則只需要從特定首字母開始遍歷。而遇到t時,則仍會遍歷所有首字母,在單詞鏈獲取完成後判斷。因此可減少t的遍歷次數。
所以對只有t沒有h的情況進行改進,將鄰接矩陣進行轉置,將首字母和尾字母進行調換,使t可以類似於h,從特定尾字母開始遍歷,減少了遍歷次數。
7.看 Design by Contract,Code Contract 的內容,並描述這些做法的優缺點,說明你是如何把它們融入結對作業中的。(5')
呼叫者和被呼叫者地位平等,雙方都有自己的權力和義務,需要雙方嚴格遵守契約。需要規定好前置條件、後置條件、不變式,除引數之外,我們還需要約定在傳參時對於引數的規範化應該在哪個模組實現。
好處是由於它明確地指定了模組單元,無需關注其他模組的執行情況,可以多個模組同步程式設計,不需要等一方寫完另一方才能開始。且模組獨立,功能清晰,容易測試。
壞處是契約需要進行修改時,需要雙方同時改動,比較麻煩。
8.計算模組部分單元測試展示。
展示出專案部分單元測試程式碼,並說明測試的函式,構造測試資料的思路。並將單元測試得到的測試覆蓋率截圖,發表在部落格中。要求總體覆蓋率到 90% 以上,否則單元測試部分視作無效。(6')
在單元測試中,我們對計算模組進行了七個引數的驗證,包括引數間的組合。
下面的單元測試測試了h和w的組合,構造了單詞陣列,並呼叫gen_chain_word介面,將返回後的結果與答案進行對比,驗證正確。資料構造的思路是,含有一個符合h的單詞鏈,但是有其他不符合h的單詞鏈比該單詞鏈長,以此來驗證h和w的處理是否符合要求。
下面的單元測試測試了r和w的組合,驗證思路與上述單元測試相同。資料構造的思路是,單詞鏈中含有一個單詞環,但是同時含有一個比該單詞環更長的單詞鏈,以此根據結果判斷r和w是否符合要求。
下面的單元測試測試了h,t,r和w的組合,驗證思路與上述單元測試相同。資料構造的思路是,單詞鏈中含有一個單詞環且這個單詞環中有首尾符合h和t的一種單詞鍊形態,但是同時含有一個比該單詞環更長的單詞鏈,以此根據結果判斷h,t,r和w是否符合要求。
單元測試程式碼覆蓋率結果:
9.計算模組部分異常處理說明。
在部落格中詳細介紹每種異常的設計目標。每種異常都要選擇一個單元測試樣例釋出在部落格中,並指明錯誤對應的場景。(5')
我們一共定義了8種類型的異常,每種異常會丟擲對應的異常種類,在單元測試中捕獲對應的異常類否則不通過。
- 檔案格式異常,若檔案不是以.txt結尾則報檔案格式錯誤。
TEST_METHOD(Test_WrongFile_Error) {
char* words[101] = { "wordlist.exe","-r", "-n", "D:\\grade_three\\word.md" };
int arg_c = 4;
try {
main(arg_c, words);
Assert::IsTrue(false);
}
catch (file_illegal_exception& e) {
Assert::IsTrue(true);
}
}
2.檔案查詢異常,如果目標檔案不存在,則報錯。
(下例中的檔案不存在。)
TEST_METHOD(Test_NonFile_Error) {
char* words[101] = { "wordlist.exe","-r", "-n", "D:\\grade_three\\wordx.txt" };
int arg_c = 4;
try {
main(arg_c, words);
Assert::IsTrue(false);
}
catch (file_nonexist_exception& e) {
Assert::IsTrue(true);
}
}
3.未定義的引數,若命令列給出的引數非要求的引數則報錯
-p非定義的引數
TEST_METHOD(Test_DefPara_Error)
{
char* words[101] = { "wordlist.exe","-p","-n", "D:\\grade_three\\word.txt" };
int arg_c = 4;
try {
main(arg_c, words);
Assert::IsTrue(false);
}
catch (para_undefine_exception& e) {
Assert::IsTrue(true);
}
}
4.引數格式錯誤,若-t,-h後的指令不是單個英語字母,而是‘1’等非英文字母或‘abc’等多個連續英文字母則報錯。
TEST_METHOD(Test_ParaForm_Error) {
char* words[101] = { "wordlist.exe","-t", "1","-n", "D:\\grade_three\\word.txt" };
int arg_c = 5;
try {
main(arg_c, words);
Assert::IsTrue(false);
}
catch (para_form_exception& e) {
Assert::IsTrue(true);
}
}
5.輸出引數錯誤,如-n和-w一起使用,兩引數要求的輸出衝突,此時報錯。
TEST_METHOD(Test_MulOut_Error) {
char* words[101] = { "wordlist.exe","-w","-n", "D:\\grade_three\\word.txt" };
int arg_c = 4;
try {
main(arg_c, words);
Assert::IsTrue(false);
}
catch (para_conflict_exception& e) {
Assert::IsTrue(true);
}
}
6.輸出引數錯誤,如引數中沒有任何對輸出進行要求的引數,只有-h,-t,-r時,無法輸出,報錯
TEST_METHOD(Test_ParaNout_Error) {
char* words[101] = { "wordlist.exe","-t","a","-r", "D:\\grade_three\\word.txt" };
int arg_c = 5;
try {
main(arg_c, words);
Assert::IsTrue(false);
}
catch (para_nonout_exception& e) {
Assert::IsTrue(true);
}
}
7.無可輸出的單詞鏈,即所有可構成的單詞鏈均不滿足引數,無法輸出,報錯。下例中無法構成a開頭,z結尾的兩個單詞以上的單詞鏈,故有錯誤。
TEST_METHOD(Test_Nochain_Error)
{
char* words[101] = { "abc", "def", "fgh", "ijk", "uv", "yz" };
try {
handleOutput(words, 6, 'c', 'a', 'z', true);//提供的引數為-c -h a -t z -r
Assert::IsTrue(false);
}
catch (word_Nochain_exception& e) {
Assert::IsTrue(true);
}
}
8.在沒有-r的情況下給出的單詞包括單詞環。
下例中前兩個單詞構成了單詞環。
TEST_METHOD(Test_WordCircle_Error)
{
char* words[101] = { "fddsu", "uasdasf", "ugfl", "laght", "adbon", "tasdu" };
char* result[101];
for (int i = 0; i < 101; i++)
{
result[i] = (char*)malloc(sizeof(char) * 601);
}
try {
gen_chain_word(words, 6, result, 0, 0, false);
Assert::IsTrue(false);
}
catch (const char* msg) {
Assert::AreEqual("存在單詞環", msg);
}
for (int i = 0; i < 101; i++)
{
free(result[i]);
}
}
10.介面模組的詳細設計過程。
在部落格中詳細介紹介面模組是如何設計的,並寫一些必要的程式碼說明解釋實現過程。(5')
使用命令列模組,對輸入的引數進行解析,解析後對相應的模組進行呼叫,程式碼如下。
char type = '0'; //n,w,m,c
char h = '0'; //h
char t = '0'; //t
int r = 0; //r
string wstr = "";//wrongStr用於存不正確的引數
string rstr = "";//repeatStr用於存重複的有輸出引數
string filePath;
int paraNum = 0;
string s;
try {
//處理命令列引數
for (int count = 1; count < argc; count++) {
if (argv[count][0] == '-') {
if (argv[count][1] == 'n' || argv[count][1] == 'w' || argv[count][1] == 'm' || argv[count][1] == 'c') {
type = argv[count][1];
paraNum++;
rstr = rstr + " " + argv[count][1];
//filePath = argv[++count];
}
else if (argv[count][1] == 'h') {
h = argv[++count][0];
string m = argv[count];
if (m.length() != 1) {
throw para_form_exception();
}
else if (!(h <= 'z' && h >= 'a' || h <= 'Z' && h >= 'A')) {
throw para_form_exception();
}
if (h <= 'Z') {
h = h - 'A' + 'a';
}
}
else if (argv[count][1] == 't') {
t = argv[++count][0];
string m = argv[count];
if (m.length() != 1) {
throw para_form_exception();
}
else if (!(t <= 'z' && t >= 'a' || t <= 'Z' && t >= 'A')) {
throw para_form_exception();
}
if (t <= 'Z') {
t = t - 'A' + 'a';
}
}
else if (argv[count][1] == 'r') {
r = 1;
}
else {
wstr = wstr + " " + argv[count][1];
}
}
else {
filePath = argv[count];
}
}
if (wstr.length() != 0) {
throw para_undefine_exception();
}
else if (paraNum > 1) {
throw para_conflict_exception();
}
else if (paraNum == 0) {
throw para_nonout_exception();
}
//得到單詞陣列
char* words[20000];
int wordsSize = getwords(filePath, words);
//根據引數處理檔案輸出
handleOutput(words, wordsSize, type, h, t, r);
}
catch (exception& e) {
e.what();
}
11.介面模組與計算模組的對接。
詳細地描述 UI 模組的設計與兩個模組的對接,並在部落格中截圖實現的功能。(4')
命令列輸入引數,程式對輸入的引數進行處理,並按要求進行輸出。
呼叫handleOutput(words, wordsSize, type, h, t, r);
進入計算模組
12.描述結對的過程
提供兩人在討論的結對影象資料(比如 Live Share 的截圖)。關於如何遠端進行結對參見作業最後的注意事項。(1')
採用線上騰訊會議進行結對
13.說明結對程式設計的優點和缺點。同時描述結對的每一個人的優點和缺點在哪裡(要列出至少三個優點和一個缺點)。(5')
結對程式設計優點:可以相互學習,若有一方掌握某些知識而另一方不掌握,學習新知識的時間大大減少;可以更快發現錯誤,自己疏忽的地方會被對方發現;鍛鍊溝通表達能力。
結對程式設計缺點:溝通費時,需要統一觀點,明確目標。
結對夥伴優點:效率高,在他的帶動下我也能提高效率;積極主動,主導專案的進展;容易溝通,有問題的時候反饋速度快。
結對夥伴缺點:不夠細心。
我的優點:完成程式碼細心;容易溝通,尊重彼此意見;對待專案積極主動。
我的缺點:效率比較低。