結對編程博客一、GitHub項目地址二、PSP表格三、看教科書和其它資料中關於Information Hiding, Interface Design, Loose Coupling的章節,說明大家在結對編程中是如何利用這些方法對接口進行設計的 四、計算模塊接口的設計與實現過程 Input類PreProcess類DFS類RingDFS類Core類Error類五、畫出UML圖顯示計算模塊部分各個實體之間的關係 六、計算模塊接口部分的性能改進。 記錄在改進計算模塊性能上所花費的時間,描述你改進的思路,並展現一張性能分析圖(由VS 2015/2017的性能分析工具自動生成),並展現你程序中消耗最大的函數 七、看Design by Contract, Code Contract的內容 ,描述這些作法的優缺點, 說明你是如何把它們融入結對做業中的八、計算模塊部分單元測試展現。 展現出項目部分單元測試代碼,並說明測試的函數,構造測試數據的思路 九、計算模塊部分異常處理說明 十、界面模塊的詳細設計過程開發平臺一、設計界面二、編寫後端十一、界面模塊與計算模塊的對接十二、描述結對的過程1三、看教科書和其它參考書,網站中關於結對編程的章節, 明結對編程的優勢和缺點。結對的每個人的優勢和缺點在哪裏 1四、PSP表格1五、鬆耦合html
PSP2.1 | 預估耗時(分鐘) | 實際耗時(分鐘) | |
---|---|---|---|
Planning | 計劃 | 10 | |
· Estimate | · 估計這個任務須要多少時間 | 10 | |
Development | 開發 | 970 | |
· Analysis | · 需求分析 (包括學習新技術) | 240 | |
· Design Spec | · 生成設計文檔 | 40 | |
· Design Review | · 設計複審 (和同事審覈設計文檔) | 20 | |
· Coding Standard | · 代碼規範 (爲目前的開發制定合適的規範) | 30 | |
· Design | · 具體設計 | 100 | |
· Coding | · 具體編碼 | 300 | |
· Code Review | · 代碼複審 | 120 | |
· Test | · 測試(自我測試,修改代碼,提交修改) | 120 | |
Reporting | 報告 | 170 | |
· Test Report | · 測試報告 | 120 | |
· Size Measurement | · 計算工做量 | 20 | |
· Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 30 | |
合計 | 1150 |
Information Hiding:ios
信息隱藏指在設計和肯定模塊時,使得一個模塊內包含的特定信息(過程或數據),對於不須要這些信息的其餘模塊來講,是不可訪問的。git
信息集中化。減小函數之間的耦合,函數間僅經過不多的的變量來協做處理數據。github
隱藏變量。儘可能使用private變量,並儘可能避免其餘類須要訪問本類的數據。算法
Interface Design:編程
頁面佈局的首要目的就是爲了頁面功能的秩序感,使其在頁面功能的分類以及輕重緩急的表現上更加合理,符合用戶的心智模型。後端
UI使用了vertical spacer,各個選項增長了中文註釋,而且有錯誤提示。數據結構
Loose Coupling:ide
鬆耦合的目標是最小化依賴。鬆耦合這個概念主要用來處理可伸縮性、靈活性和容錯這些需求。
減小函數之間的耦合,在不一樣模塊之間的的交互的信息儘量的少。
計算模塊主要有6個類,Core類
,DFS類
,Error類
,Input類
,PreProcess類
,RingDfs類
。
Input類
用於從輸入中提取所須要的信息,如模式、開頭結尾、路徑等。
PreProcess類
用於處理數據,包括分割單詞,並依據分割出的單詞生成圖,輸出結果等。
DFS類
用於尋找圖中是否有環。
RingDfs類
用於根據生成的圖進行搜索,尋找符合要求的最長路徑。
Core類
用於封裝。
Error類
用於異常時報錯。
方法名 | 做用 | 調用方法 |
---|---|---|
Input(int num, char * paras[]) | 根據程序參數,提取相應信息,如各種參數,文件路徑等 | 本類私有方法,Error(string str)方法 |
Input(string str); | 根據輸入字符串提取相應信息 | 本類私有方法 |
int getMode() | 返回指定的單詞鏈類型,1爲單詞數,2爲字母數 | |
int getIfRing() | 返回是否容許環 | |
int getHead() | 返回指定的單詞鏈開頭,0爲無限制,不然爲字母的ASCII碼值 | |
int getTail() | 返回指定單詞鏈結尾,規則同上 | |
string getPath() | 返回輸入的文件路徑 | |
string getInput() | 返回輸入的完整字符串,用於調試 |
方法名 | 做用 | 調用方法 |
---|---|---|
PreProcess(char* wordss[], int len, int r); | 根據輸入的單詞表、長度、是否有環,判斷是否合法並生成圖 | 本地私有方法,Error(string str)方法 |
PreProcess(string str, int n, char* words[], int r) | 根據輸入的包含全部單詞的字符串、長度、是否有環,生成單詞表與圖。單詞表char* []是爲了知足接口要求。 | 本地私有方法 |
PreProcess(string str, int r) | 根據輸入的路徑與是否有環,生成單詞表與圖 | 本地私有方法 |
void printGraph() | 打印合並同首尾單詞後的圖 | |
void printRingGraph() | 答應元素 | |
void print(vector <string> ary) | 根據輸入的容器,將其中單詞按順序輸出至solution.txt | |
void VecToStr(char* result[], vector <string> ans) | 將圖轉化爲單詞表格式,以知足同接口要求 | Error(string str)方法 |
方法名 | 做用 | 調用方法 |
---|---|---|
DFS(PreProcess pp) | 生成實例 | |
void getGraph() | 獲取已生成好的圖 | |
bool hasRing() | 判斷圖中是否有除了自環之外的環 |
方法名 | 做用 | 調用方法 |
---|---|---|
RingDFS(PreProcess pp) | 生成實例,pp中含有圖等信息 | |
vector <string> initDFS(int mode, int head, int tail, int ring) | 根據輸入的各種參數,以及獲取到的圖,搜索符合要求的單詞鏈,並返回結果 | 本地私有方法,Error(string str)方法 |
方法名 | 做用 | 調用方法 |
---|---|---|
int gen_chain_word(char* words[], int len, char* result[], char h ead, char tail, bool enable_loop) | 根據輸入的單詞表、長度、參數等,搜索單詞數量最多的符合要求的單詞鏈 | Input::Input |
int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop) | 根據輸入的單詞表、長度、參數等,搜索字母數量最多的符合要求的單詞鏈 | 同上 |
方法名 | 做用 | 調用方法 |
---|---|---|
void Error(std::string str) | 根據輸入的報錯信息拋出異常 |
如下爲無環,單詞數量9900的運行狀況:
可見,大部分時間花在了建圖時的各類關於內存的操做上。這是由於在優化了無環的搜索算法後,將搜索部分的複雜度限制在了O(26x26),速度很快,所以關於內存的各種操做成爲了最佔用時間的操做。
對於算法的具體優化以下:
對於無環的搜索,按以下方法建圖:由於無環,因此以26個字母爲節點,單詞爲邊,以a
開頭b
結尾的單詞,表現爲由節點a
指向節點b
的一條邊。
在搜索算法上,以遞歸BFS搜索
爲基礎,在節點b
的遞歸退出時,便可確保b
日後的全部路徑均已遍歷,所以能夠獲得以b
爲開頭,能搜索到的最長符合要求的單詞鏈長度,保存該長度,記爲L(b)
。以後若其餘節點訪問節點b
時,好比上述例子中的a
節點訪問b
節點,不須要再次進入b
遞歸,只須要比較(L(b)
)與(由a
指向b
的邊長度)之和,與本來的L(a)
的大小,並將大者保存爲新的L(a)
便可。
這樣,在全部節點遞歸結束後,獲得了每一個節點日後所能達到的符合要求的單詞鏈的最大長度。根據此信息輸出最長路徑便可。
該算法確保了每條邊只走一次,不會重複走同一條邊(同一個單詞),所以,在無環的基礎上其複雜度爲O(26x26)。
可是,在有環的問題中,由於環的存在以及該方法沒法判斷L(b)
中有哪些節點,所以可能會致使重複走同一條邊,該算法沒法使用。
契約式設計就是按照某種規定對一些數據等作出約定,若是超出約定,程序將再也不運行,例如要求輸入的參數必須知足某種條件。
咱們要求發現了bug以後,先對輸入進行測試,保證了輸入符合約定以後,再將相關模塊交給負責人修改。
部分單元測試代碼以下:
這兩部分測試數據,測試的是方法Input Input(string str)
,方法Input Input(int num, char* paras[])
。兩個方法的做用分別是根據輸入的字符串,或程序的參數提取相應的設置信息,文件路徑等。
測試的思路是構造符合被測方法輸入數據結構要求的數據,並儘可能複雜,以達到更高的分支覆蓋率。
以圖中的測試用例爲例,由於測試的是處理輸入的方法,所以在構造輸入數據時儘可能構造較爲複雜的輸入,即儘可能輸入更多的參數,以覆蓋較多的分支。
對於異常測試,測試代碼以下:
在catch
方法中經過判斷異常信息是否符合預期的方式,來判斷是否觸發了所要測試的異常。
同時,在應該觸發異常的代碼下一行加入一條永假的斷言Assert::AreEqual("Error Test Didn't Throw Error!", " ");
,以確保經過的測試,是觸發了正確的異常,而不是沒有觸發異常致使沒有進入catch
,根本沒有運行catch
中的斷言。
全部的異常以下:
輸入錯誤
Chain Type Parameter Error
在已經輸入過-w
或-c
參數,即指定過單詞鏈類型的狀況下,再次輸入這兩個參數。
單元測試:
try
{
Input input("-w -c ..\Pair_Programming\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Chain Type Parameter Error";
Assert::AreEqual(s, str);
}
Head Duplicate Definition Error
在已經使用-h
指令規定過開頭的狀況下,再次指定開頭。
單元測試:
try
{
Input input("-w -h a -h a ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Head Duplicate Definition Error";
Assert::AreEqual(s, str);
}
Lack Space Error
在一次性輸入全部參數時,參數之間、-h
指令與制定的開頭字母之間應有空格。沒有空格時拋出次異常。
單元測試:
try
{
Input input("-w -ha ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Lack Space Error";
Assert::AreEqual(s, str);
}
Head Letter Error
指定的開頭字符不是字母。
單元測試:
try
{
Input input("-w -h + ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Head Letter Error";
Assert::AreEqual(s, str);
}
Tail Duplicate Definition Error
使用-t
指令指定過結尾的狀況下再次使用該指令。
單元測試:
try
{
Input input("-w -t a -t a ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Tail Duplicate Definition Error";
Assert::AreEqual(s, str);
}
Tail Letter Error
制定的結尾字符不是字母。
單元測試:
try
{
Input input("-w -t + ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Tail Letter Error";
Assert::AreEqual(s, str);
}
Ring Parameter Duplicate
屢次使用-r
參數。
單元測試:
try
{
Input input("-w -r -r ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Ring Parameter Duplicate";
Assert::AreEqual(s, str);
}
Parameter Type Error
輸入的參數不符合規定。
單元測試:
try
{
Input input("-w -z ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Parameter Type Error";
Assert::AreEqual(s, str);
}
Lack Chain Type Parameter
在輸入中沒有使用-w
或-c
制定指定單詞鏈類型。
單元測試:
try
{
Input input("-h a ..\\Pair_Programming\\DFSTest2.txt");
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Lack Chain Type Parameter";
Assert::AreEqual(s, str);
}
數據錯誤
Input File Doesn't Exit
輸入的文件路徑不存在。
單元測試:
try
{
PreProcess pp ("noFile.txt", 0);
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Input File Doesn't Exit";
Assert::AreEqual(s, str);
}
Multiple Self Ring Found
在不容許有環的狀況下,出現了多個自環。
單元測試:
try
{
PreProcess pp("..\\Pair_Programming\\PPErrorTest1.txt", 0);
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Multiple Self Ring Found";
Assert::AreEqual(s, str);
}
其中,PPPErrorTest1.txt
的內容以下:
bc
cc
cd
df
ff
beee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeee
ef
fg
gb
No Word Chain in File
輸入的文件中單次數量小於2,不構成單詞鏈。
單元測試:
try
{
PreProcess pp("..\\Pair_Programming\\PPErrorTest2.txt", 0);
}
catch (string str)
{
string s = "No Word Chain in File";
Assert::AreEqual(s, str);
}
其中,PPErrortEST2.TXT
文件內容以下:
bc
Ring Detected When not Allowed
在沒有使用-r
參數,的狀況下,單詞鏈中出現了環。
單元測試:
try
{
PreProcess pp("..\\Pair_Programming\\DFSTest1.txt", 0);
DFS dfs(pp);
dfs.getGraph();
dfs.hasRing(0);
Assert::AreEqual("Error Test Didn't Throw Error!", " ");
}
catch (string str)
{
string s = "Ring Detected When not Allowed";
Assert::AreEqual(s, str);
}
其中,DFSTest1.txt
文件的內容以下:
bc
cc
cd
df
ff
beee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ef
fg
gb
使用的是Qt Creator 3.4.2進行開發的,因爲Qt自帶了前端設計的功能,開發起來比較簡單。
使用的是Qt Creator自帶的設計面板,操做簡單隻須要拖拽便可,如下是具體設計。
在設計好了界面以後,只須要編寫好slots函數就可在設計面板中簡單的關聯(代碼未所有貼出)
mainwindow.h:
mainwindow.cpp:
編寫完成後,須要作的就是將函數與組件關聯起來,一樣在設計面板中操做。
關於Qt的信號槽機制,具體能夠看這篇博客,因爲是在設計模板中關聯的,因此並不須要手動編寫connect函數。
首先,將計算模塊打包成dll
文件,爲了使用方便,將統一的接口gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop)
與接口gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop)
定義爲函數而非類方法。
打包好後,將生成的Core.dll
文件複製到工程的debug
文件夾或release
文件夾中,經過如下代碼導入兩個上述接口:
typedef int(*ptr_word)(char* words[], int len, char* result[], char head, char tail, bool enable_loop);
typedef int(*ptr_char)(char* words[], int len, char* result[], char head, char tail, bool enable_loop);
HINSTANCE CoreDLL = LoadLibrary("Core.dll");
ptr_word gen_chain_word = (ptr_word)GetProcAddress(CoreDLL, "gen_chain_word");
ptr_char gen_chain_char = (ptr_word)GetProcAddress(CoreDLL, "gen_chain_char");
導入後,即可以直接調用兩個函數。
在結對的過程當中,首先咱們在一塊兒預估各個難度的複雜度,以後對於部分邏輯極爲簡單且不重要的部分如讀入等,進行分工,並行開發提升速度。對於核心的部分,如搜索算法的完成、優化等,咱們按照結對編程的原則,一人寫一人檢查,確保沒有BUG以及算法的正確性。
優勢:在複審中對於能以找到的bug,結對編程可以避免鑽牛角尖,增長debug的速度。在編寫代碼過程當中,結對編程有助於促進兩方思考,避免遺漏,增長正確性。也能相互監督保證代碼質量。
缺點:對於一些比較簡單的代碼,結對編程會拖累雙方的進度,影響項目進程。對於兩我的都不擅長的領域,就沒有結對的必要。
個人優缺點:
積極交流,認真負責,複審仔細
比較拖沓
同伴的優缺點:
主動負責,思路敏捷,完成工做多
缺少交流
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(小時) |
---|---|---|---|
Planning | 計劃 | 10 | 0.5 |
· Estimate | · 估計這個任務須要多少時間 | 10 | 55+ |
Development | 開發 | 970 | 50+ |
· Analysis | · 需求分析 (包括學習新技術) | 240 | 1 |
· Design Spec | · 生成設計文檔 | 40 | 0.2 |
· Design Review | · 設計複審 (和同事審覈設計文檔) | 20 | 0.1 |
· Coding Standard | · 代碼規範 (爲目前的開發制定合適的規範) | 30 | 0.1 |
· Design | · 具體設計 | 100 | 1 |
· Coding | · 具體編碼 | 300 | 40+ |
· Code Review | · 代碼複審 | 120 | 1 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 120 | 10+ |
Reporting | 報告 | 170 | 2 |
· Test Report | · 測試報告 | 120 | 0.5 |
· Size Measurement | · 計算工做量 | 20 | 0.1 |
· Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 30 | 0.5 |
合計 | 1150 | 55+ |
咱們與學號1606109三、16061155的隊伍進行了鬆耦合測試,結果正確,對方使用我方Core.dll
的運行結果截圖以下:
在剛開始耦合時出現了問題,由於在對於head
的定義中,咱們組的邏輯是當head
不爲0即認爲是規定的開頭字母,但接口內部沒有檢查其正確性,而對方認爲head
不規定時爲'0'
。 出現問題後,咱們組在接口內部加2上了對於參數的合法性判斷,以後沒有其餘問題。
以後咱們還與1606116七、16061170組