結對項目——Core設計與實現

寫在前面:關於結對編程


結對編程我一直認爲是一種很是好的合做方式,他的形式主要是由一我的負責代碼編寫,另外一我的則在一旁即時對寫下的代碼進行審查,這樣能夠大大減小代碼實現方面的錯誤。node

此次個人結對夥伴是小蘆薈(學號後四位爲1221)。他平時喜歡打籃球,打的也挺不錯的,三國殺也是高手(都100多級了),是一個比較靠譜的人。可是在編程這方面他可能不太擅長,所以此次結對項目就變成了我一我的寫,他在旁邊看着……不過有時他也會指出個人代碼中很是明顯的問題,這也保證了個人代碼正確性較高。設計的單元測試幾乎全是一次經過。算法

附結對編程圖片:express

pic

pic

關於Design by Contract、Information Hiding


本次結對項目要求對上次的我的項目進行封裝,並寫一個界面來調用這些封裝好的函數。這就須要咱們對相關接口制定一個規範,我和另外一個隊伍(pair16)的同窗約定好了代碼接口,便於以後的測試。編程

對於Information Hiding原則,咱們此次其實作的並很差,全部的類屬性也均爲public,這主要考慮到本次程序會封裝爲程序編寫的方便。數組

咱們core部分均採用Win32 Console Application實現,圖形界面部分均採用MFC Application實現。core編寫完成,測試完成後,生成dll並提供兩個接口,用來實現要求的兩個功能。接口的定義均提早約定。函數

關於接口定義、dll封裝的具體內容在第二篇博客中會詳細介紹。工具

設計與實現


算法設計單元測試

咱們本次項目沿用了上次個人我的項目的設計,只不過在其基礎上添加了對負數、有無括號、有無乘除法的限制,以及對運算符個數的限制。測試

具體來講,對於四則運算題目生成的部分:ui

  1. 獲取到傳入的參數限制,包括運算符個數限制、數值限制、有無分數、有無負數
  2. 遞歸生成一個表達式樹
  3. 遞歸進行表達式的正確性檢驗(是否出現了負數、除0以及不能整除的狀況)
  4. 遞歸對錶達式樹進行最小表示
  5. 若是獲得的算式以前沒有生成過,則將該算式加入到生成隊列中。
  6. 若是當前的表達式個數已經達到要求,則將表達式與答案返回。

其中,在生成表達式樹的過程當中,首先須要判斷樹中當前的節點是否爲分支節點(即運算符)。若是當前的樹的總結點數爲0,那麼該節點必須爲分支節點,若是當前樹中的分支節點已經打到了要求的上限,則該節點必須爲葉子結點(即操做數)。有了這個信息以後,針對當前結點的類型不一樣,就可生成對應的結構,以後若是當前結點爲分支節點的話,就遞歸生成其左右子樹。

在對錶達式進行正確性檢驗的過程當中,若是當前結點爲葉子節點,那麼咱們僅須要檢驗這個葉子結點的數值是否知足要求。不然,先遞歸對它的左右子樹進行正確性檢驗,在確保左右子樹正確的狀況下,檢驗當前結點的運算是否會形成不合法的狀況,若是有的話則進行修復。

在對錶達式最小表示的過程當中,一樣是先遞歸對其左右子樹進行最小表示,以後再看,若是當前結點爲'+'或'×',則判斷一下他的兩個子樹的hash值大小,在不改變運算順序的前提下使表達式變爲最小標識的形式。

檢驗算式仍然採用了第一次做業的形式,以一個STL的set來存放最小表示後的字符串,經過字符串的比較進行判重。

對於計算表達式結果的功能,仍然沒什麼好說的,採用了STL的兩個棧來維護。

具體實現

首先來看UML類圖:

pic

本次項目中共用到了4個類。CFactor類是對上次Factor的一個擴展,加入了對負數的支持。CExpressionNode類是表達式樹的一個節點。CExpression類是表達式樹,CProblemSet類對兩種操做進行了封裝。這四個類造成如上的關聯關係。

根據這個這個類圖,順便說一下本次結對項目的代碼規範:

  1. 類名均以 C 開頭,大括號不換行
  2. 類屬性以 m _ 開頭
  3. 類方法均使用小寫字母,單詞之間採用下劃線分開。
  4. 每一個類方法前必須有必要的註釋

這樣的規範主要考慮到本次項目要與MFC結合,所以使用了一些Win32的代碼習慣。

CFactor類中,我重載了各類運算符,包括輸入輸出、四則運算和比較運算符。重載運算符後會大大下降編程複雜度,可是過多地採用流輸入輸出可能會對程序效率形成影響……這也是我在測試的時候才發現的問題。

CExpressionNode類則沒什麼好說的,就是儲存了一個樹節點的信息,包括其左右子樹、當前結點的運算符以及當前子樹的表達式的值。

CExpression類則是一個表達式樹,他內部採用了一個CExpressionNode類型的數組用來存儲表達式中的全部結點,並經過new_node方法實現獲取一個新節點的操做。這樣作避免了每次的動態內存分配,必定程度上能夠提升程序效率,可是這樣作則要求表達式不能太長,不過在實際應用中不會用到太長的表達式。

CProblemSet類則沒什麼好說的了,他實例化了一個CExpression類的對象,每次調用該類的 build_expression_tree 方法生成一個表達式並使用set進行重複檢驗。

單元測試


本次項目的基礎就是CFactor類,若是該類的實現有問題,那麼全部功能都不能正常工做,所以我主要對該類進行了單元測試。

VS2013單元測試我也是第一次使用,不知道爲何Managed Test Project 建立後會沒法鏈接C++console Application的代碼,最後採用了 Native Unit Test Project 來作單元測試,它的語法與Managed Test Project略有不一樣,可是也很簡單,我針對CFactor類的各類方法寫了37條Unit Test, 而且所有經過了。

代碼覆蓋率:

pic

注:個人VS2013是社區版,沒有代碼覆蓋率分析工具,因此在我編寫完測試用例後,借用了同寢室的另外一我的的電腦來測試並進行代碼覆蓋率檢驗。

相關文章
相關標籤/搜索