項目 | 內容 |
---|---|
所屬課程:北航-2020-春-軟件工程 | 博客園班級博客連接 |
做業要求:計算平面圖形的公共點個數——新需求 | 結對項目做業要求 |
我在這個課程的目標 | 提高在團隊合做中開發「好軟件」的能力 |
這個做業在哪些具體方面幫助我 | 根據《構建之法》第四章兩人合做的內容,完成結對項目。培養軟件工程、團隊合做相關的能力。 |
教學班級 | 005 |
項目地址 | https://github.com/Cheibniz/PairProject |
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
· Estimate | · 估計這個任務須要多少時間 | 30 | 30 |
Development | 開發 | ||
· Analysis | · 需求分析 (包括學習新技術) | 180 | 120 |
· Design Spec | · 生成設計文檔 | 60 | 90 |
· Design Review | · 設計複審 (和同事審覈設計文檔) | 20 | 30 |
· Coding Standard | · 代碼規範 (爲目前的開發制定合適的規範) | 10 | 20 |
· Design | · 具體設計 | 180 | 200 |
· Coding | · 具體編碼 | 480 | 400 |
· Code Review | · 代碼複審 | 30 | 60 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 120 | 120 |
Reporting | 報告 | ||
· Test Report | · 測試報告 | 60 | 40 |
· Size Measurement | · 計算工做量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 30 | 30 |
合計 | 1230 | 1170 |
在維基百科中,有這樣一段關於information hiding的描述java
In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change).python
Written another way, information hiding is the ability to prevent certain aspects of a class or software component from being accessible to its clients, using either programming language features (like private variables) or an explicit exporting policy.ios
總結一下,細節隱藏是對計算機程序中最容易變化部分的設計方法。在細節隱藏原則下,使用者只調用肯定的模塊接口,而模塊內部的具體實現則被隱藏。類的私有成員等和明確規定的接口都是細節隱藏原則的體現。c++
面向對象思想本就帶有很強的工程氣息,細節隱藏原則蘊含其中。在用面向對象的編程語言編程以後,我的就能對細節隱藏思想有所領會。c++
、java
、python
等編程語言都有對類和接口/抽象類的語言特性支持。git
在本次結對編程項目中,咱們在一些層面的設計中體現了信息隱藏原則github
層面 | 體現 |
---|---|
類 | 函數和變量儘量私有,只將完成類功能的函數公有 |
模塊(幾何圖形容器、文件讀取模塊等) | 模塊具備必定複雜度,實現模塊功能的函數和方法全都私有/使用者不可見。只對使用者開放完成模塊功能的接口(主要是函數) |
先後端接口 | 將幾個函數做爲接口,而且函數的設計儘可能簡單靈活(參數和返回值都使用C++ 標準庫中存在的類型,如string 、vector 和pair ) |
本次做業的一大挑戰是對先後端接口的設計。先後端各自完成複雜且具備必定規模的任務,如何完成靈活高效的接口是一個須要思考的問題。正則表達式
首先,使用接口不可避免地使得軟件的性能下降,因此在設計接口時須要對性能損失有所容忍。相比起少許的軟件性能損失,接口賦予軟件的可維護性、魯棒性等更加劇要。算法
在優秀的API接口設計原則及方法有以下論述編程
一旦API發生變化,就可能對相關的調用者帶來巨大的代價,用戶須要排查全部調用的代碼,須要調整全部與之相關的部分,這些工做對他們來講都是額外的。若是辛辛苦苦完成這些之後,還發現了相關的bug,那對用戶的打擊就更大。若是API常常發生變化,用戶就會失去對提供方失去信心,從而也會影響目前的業務。後端
能夠看出,在設計接口時須要對接口的靈活性加以考量。在本次做業中,附加做業要求先後端接口被兩個組共同使用,咱們採用規格化字符串的手段使接口靈活、輕量。
#pragma once #include <vector> #include <iostream> using namespace std; typedef pair<double, double> InterfacePoint; // parameter = file_name __declspec(dllexport) void readFile(string); // add from standard string fromat of geometry component __declspec(dllexport) void addGeometryObject(string); // remove by standard string format of geometry component, strictly equals __declspec(dllexport) void removeGeometryObject(string); // trigger calculation __declspec(dllexport) pair<vector<string>, vector<InterfacePoint>> getResult();
使用接口須要共同的約定,而在本次做業中兩小組間存在天然的共同約定:做業要求。做業要求博客中給出幾何對象的格式化字符串定義,而格式化字符串定義是絕佳的接口交換數據結構。對於返回值中承載多個對象及課程組未進行點的格式化字符串定義,因此咱們使用C++
標準庫中存在的類vector
和pair
。
在設計結構時咱們發現,對接口的要求不只有輸入和返回值,還有函數的行爲和可能拋出的異常。對於此方面的考量在Loose Coupling
中描述。
在Loose Coupling的WIKI百科中,有這樣一段描述
In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. Subareas include the coupling of classes, interfaces, data, and services.[1] Loose coupling is the opposite of tight coupling.
鬆耦合是老師同窗們時常掛在嘴邊的「軟件設計」原則,可是這與軟件中不一樣模塊之間互相依賴關係有所矛盾。怎樣才能作到鬆耦合呢?咱們認爲「依賴於抽象」是作到鬆耦合的好方法。
仍是以上文提到的先後端接口爲例,對接口的考慮不止有輸入輸出,還有函數的行爲和可能拋出的異常。函數的輸入和輸出可以顯示地包含在函數定義中,那函數的行爲和異常怎麼辦呢?答案就是「依賴於抽象」,關注函數在抽象層面的行爲,忽略函數具體地行爲。例如__declspec(dllexport) void readFile(string);
,咱們只須要指望這個函數被調用後,文件中的幾何對象都被讀取和處理完成,並不須要考慮文件具體狀況對函數行爲的影響和調用模塊內部是怎樣完成幾何對象的處理和求解的。
異常實質上也是函數的一種返回值,一樣能夠在函數聲明中寫出。對異常的約定與對返回值的約定類似,但異常不少地包含函數運行狀態的信息。因此對異常的約定須要更多地對函數行爲的約定,實際上增長了模塊之間的耦合度。異常一樣符合「依賴於抽象」原則,若是模塊須要給其餘模塊拋出異常,那麼該模塊自身不能處理。這種異常通常是與模塊實現細節無關的異常,可以影響甚至中斷函數執行。因此只要將接口中的異常約定爲針對函數抽象行爲的異常,就不會顯著地增長軟件的耦合度。
相較於上次做業,本次做業多出射線和線段,須要對幾何圖形的類結構進行增量設計。
咱們約定直線方程以下:
通過歸一化後的直線係數能爲後續的直線共線判斷提供便利。
咱們約定圓方程以下:
對於全部的幾何對象(除點),都須要實現以下功能
==
運算符<
運算符下面將針對和上次做業不一樣的部分進行闡述
類設計
幾何對象 | 設計 |
---|---|
直線 | 其實是3個係數的封裝 |
射線 | 在直線的基礎上添加起點和方向 |
線段 | 在直線的基礎上添加兩個端點 |
圓 | 圓心和半徑的封裝 |
點 | pair<double, double> 的封裝 |
判斷相等
不一樣種類的幾何對象確定不相等,相同種類的幾何對象則判斷數學上是否相同。
求交點
直線 | 射線 | 線段 | 圓 | |
---|---|---|---|---|
直線 | 直接聯立求交點 | 聯立求出交點後判斷交點是否在射線上 | 聯立求出交點後判斷交點是否在線段上 | 直接聯立求交點 |
射線 | 聯立求出交點後判斷交點是否在射線上 | 1.不共線:聯立求出交點後分別判斷是否在射線上。2.共線:判斷是否只有一個交點。 | 1.不共線:聯立求出交點後分別判斷是否在射線和線段上。2.共線:判斷是否只有一個交點。 | 聯立求出交點後判斷交點是否在射線上 |
線段 | 聯立求出交點後判斷交點是否在線段上 | 1.不共線:聯立求出交點後分別判斷是否在射線和線段上。2.共線:判斷是否只有一個交點。 | 1.不共線:聯立求出交點後分別判斷是否在線段上。2.共線:判斷是否共端點。 | 聯立求出交點後判斷交點是否在線段上 |
圓 | 直接聯立求交點 | 聯立求出交點後判斷交點是否在射線上 | 聯立求出交點後判斷交點是否在線段上 | 直接聯立求交點 |
射線-射線共線有交點
射線-線段共線有交點
線段-線段共線有交點
幾何對象容器的做用是組織幾何對象和交點,其功能以下
存儲組織幾何對象與交點
增刪幾何對象
求解交點
幾何對象容器在內部完成複雜的幾何對象交互邏輯,對外部只須要開放簡單接口便可。這樣設計屏蔽幾何對象相關細節使得修改具體實現變得容易,體現出information hiding
和Loose Coupling
的思想。
幾個對象容器的接口以下
接口名 | 做用 |
---|---|
insertFromString |
由規格化字符串插入幾何對象 |
deleteFromString |
由規格化字符串刪除幾何對象 |
getPointNum |
得到交點數量 |
getPointSet |
取出交點集合 |
getLineSet |
取出線(規格化字符串)集合 |
getCircleSet |
取出圓(規格化字符串)集合 |
檢查文件是否合法(有無n,n和實際幾何對象數量是否相符),處理IO異常(文件不存在、IO錯誤等)。屏蔽IO細節,錯誤局部化。
暴力求解,算法複雜度爲\(O(n^2)\),在短期內沒有改進的空間。
2000個幾何對象,四類幾何對象出現機率均等。
unordered_set
,理論上是\(O(1)\)的複雜度,可是實際應用起來結果卻慘不忍睹。猜想多是哈希操做帶來的大量主存訪問佔用大量時間。採用set
以後,雖然容器訪問還是時間佔用主體,可是相比哈希佔比已經降低不少。在引入先後端接口以後,帶來了必定的性能損失。由於如今所採用的接口是兩個小組通用的,因此兩個小組都爲適配接口增長一層適配函數。在不對後端進行重構的狀況下,咱們很難將這部分性能損失徹底抹除。只能在適配時採用內聯等措施減少性能損失。
徹底消除性能損失也許須要大量的項目經驗和相關思考,但遺憾的是咱們沒能在這次做業中作到。
在Design by Contract的WIKI百科中,有以下描述
It prescribes that software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants. These specifications are referred to as "contracts", in accordance with a conceptual metaphor with the conditions and obligations of business contracts.
承接在2、軟件設計原則 中的討論,接口須要規定以下幾個部分:參數、返回值、行爲、異常,這是針對函數而言。而契約式設計則在ADT的基礎上加入前置條件、後置條件和不變式的約束,讓開發者和使用者都有更加形式化、準確及可驗證的依據。契約式設計的精準性和形式性爲程序驗證作好了準備,微軟爸爸在.NET平臺的基礎上提供了相應工具。
在去年的面向對象課程中,咱們也曾使用過JML進行契約式編程,因此對契約式編程的感覺頗深。
契約式編程的優勢有
而其缺點也是不可忽視的
在咱們的項目中,最能體現契約式編程的部分是幾何對象的構建。幾何對象的行爲都嚴格按照其抽象特性設計。如今編寫幾何對象的方法式屢次按照直線、射線、線段、圓的抽象特性進行檢查,從而保證幾何對象在程序中的行爲和數學上的行爲相同。
結合對象的數學抽象特性使得其天然具備契約,可以爲具體設計提供很好的參考和指導。
針對不一樣的功能點和錯誤點,咱們準備了不一樣的單元測試。
測試覆蓋率92%
測試用例經過狀況
針對幾何對象相交功能直接測試
// 射線端點與直線相交 TEST_METHOD(TestMethod1) { Table table = Table(); Straight s(0, 0, 1, 1); Ray r(0, 0, 0, 1); int result = s.GetCrossPoint(table.getPointSet(), &r); Assert::AreEqual(result, 1); } // 射線和線段端點與圓相交 TEST_METHOD(TestMethod3) { Table table = Table(); Circle c(Point(0, 0), 1); Segment s(0, -1, 0, 1); Ray r(-1, 0, 5, 0); int result = c.GetCrossToLine(table.getPointSet(), s); Assert::AreEqual(result, 2); Assert::AreEqual(c.GetCrossToLine(table.getPointSet(), r), 2); Assert::AreEqual(r.GetCrossPoint(table.getPointSet(), &s), 1); } // 圓之間內切與外切 TEST_METHOD(TestMethod4) { Table table = Table(); Circle c(Point(0, 0), 1); Circle c1(Point(3, 0), 2); Circle c2(Point(2, 0), 1); c.GetCrossToCircle(table.getPointSet(), c1); c1.GetCrossToCircle(table.getPointSet(), c2); Assert::AreEqual(1, (int)(table.getPointNum())); }
總體性測試 + 異常測試
TEST_METHOD(TestMethod6) { Table table = Table(); ofstream output = ofstream("output.txt"); output << "4\n C 0 0 1\nC 3 0 2\nC 2 0 1\nL 0 0 3 0\n" << endl; output.close(); ifstream open = ifstream("output.txt"); // IO模塊測試 readFromFile(table, open); Assert::AreEqual(4, (int)table.getPointNum()); Circle circle = Circle(Point(0, 0), 1); // 刪除圓功能測試 table.eraseCircle(circle); Assert::AreEqual(3, (int)table.getPointNum()); circle = Circle(Point(2, 0), 1); // 刪除圓功能測試 table.eraseCircle(circle); Assert::AreEqual(2, (int)table.getPointNum()); Line* line = new Line(0, 0, 1, 0); try { // 無窮多交點異常測試 table.insertLine(*line); } catch (const Doublication& e) { Assert::AreEqual(line->toString(), (string)(e.what())); } Assert::AreEqual(2, (int)table.getPointNum()); // 刪除線功能測試 table.eraseLine(line); Assert::AreEqual(0, (int)table.getLineSet().size()); } TEST_METHOD(TestMethod7) { Table table = Table(); ofstream output = ofstream("output.txt"); output << "4\n C 0 0 1\nC 3 0 2\nC 2 0 1\nL 0 0 3 0\n" << endl; output.close(); ifstream open = ifstream("output.txt"); readFromFile(table, open); Circle circle = Circle(Point(0, 0), 1); try { // 無窮多交點異常測試 table.insertCircle(circle); } catch (const Doublication & e) { Assert::AreEqual(circle.toString(), (string)(e.what())); } } Table table = Table(); ofstream output = ofstream("output.txt"); output << "1\nL 0 0 0 0\n" << endl; output.close(); ifstream open = ifstream("output.txt"); try { // 定義點重合異常測試 readFromFile(table, open); } catch (const pointDoublication& pd) { Assert::AreEqual(Line(0, 0, 0, 0).toString(), (string)pd.what()); }
易錯點測試
TEST_METHOD(TestMethod11) { Table table = Table(); ofstream output = ofstream("output.txt"); // 線段垂直於X軸,射線垂直於y軸,可能會形成點位置判斷錯誤 output << "2\nR -1 0 1 0\nS 0 1 0 2" << endl; output.close(); ifstream open = ifstream("output.txt"); readFromFile(table, open); Assert::AreEqual(0, (int)table.getPointNum()); }
新增需求特殊點測試
// 線段-線段共線有焦點 TEST_METHOD(TestMethod15) { Table table = Table(); ofstream output = ofstream("output.txt"); output << "2\nS 0 0 1 1\nS 1 1 2 2" << endl; output.close(); ifstream open = ifstream("output.txt"); readFromFile(table, open); Assert::AreEqual(2, (int)table.getLineSet().size()); Assert::AreEqual(1, (int)table.getPointNum()); } // 線段-射線共線有焦點 TEST_METHOD(TestMethod16) { Table table = Table(); ofstream output = ofstream("output.txt"); output << "2\nS 0 0 1 1\nR 1 1 2 2" << endl; output.close(); ifstream open = ifstream("output.txt"); readFromFile(table, open); Assert::AreEqual(2, (int)table.getLineSet().size()); Assert::AreEqual(1, (int)table.getPointNum()); } // 射線-射線共線有交點 TEST_METHOD(TestMethod17) { Table table = Table(); ofstream output = ofstream("output.txt"); output << "2\nR 1 1 0 0\nR 1 1 2 2" << endl; output.close(); ifstream open = ifstream("output.txt"); readFromFile(table, open); Assert::AreEqual(2, (int)table.getLineSet().size()); Assert::AreEqual(1, (int)table.getPointNum()); }
文件不存在或打開失敗
if (!(infile.is_open())) { cout << "open file fail" << endl; exit(0); }
文件讀取異常或N值大於實際幾何對象數目
if (!getline(infile, getLine)) { cout << "n is bigger than the true number of geometry or IO error" << endl; break; }
N值小於實際幾何對象數目
// 循環結束以後 if (getLine(infile, getLine)) { cout << "n is smaller than the true number of geometry" << endl; break; }
N值合法性處理
regex reg1("\\s*\\+?0*[1-9]\\d*\\s*"); // 利用正則檢查N輸入的合法性:形式和範圍 if (!regex_match(getLine, reg1)) { cout << "Error: the first line of input file is not a regular positive number." << endl; }
幾何對象格式化字符串合法性處理
用正則從形式和數值範圍上約束幾何對象格式化字符串
static string number = "([1-9]\\d{0,4})"; static string radius = "(\\+?" + number + ")"; static string number0 = "((0)|(" + number + "))"; static string snumber0 = "([+-]?" + number0 + ")"; static regex reg( "\\s*(" "([LRS]\\s+" + snumber0 + "\\s+" + snumber0 + "\\s+" + snumber0 + "\\s+" + snumber0 + ")" "|" "(C\\s+" + snumber0 + "\\s+" + snumber0 + "\\s+" + radius + ")" ")\\s*" ); if (!regex_match(erase, reg)) { throw domain_error(erase); }
重複幾何對象輸入處理
注意,咱們認爲有無窮多交點但不重複的狀況並不算作異常,只是在計算時不會考慮這種狀況。
if (lineSet.count(&l) > 0) { throw Doublication(l.toString()); } if (circleSet.count(circle) > 0) { throw Doublication(circle.toString()); }
定義點重合處理
if (start == end) { throw pointDoublication(this->toString()); }
mfc
庫進行設計,由於做業要求的界面並不複雜,因此使用不帶菜單欄的對話框做爲設計的基礎。微軟的官方mfc文檔是設計時主要學習和參考的對象。最終的界面以下:從文件導入圖形
界面第一個Import按鈕實現從文件導入的功能,經過用戶輸入讀取的值得到文件路徑,再經過接口與由計算模塊實現具體的解析操做。在用戶點擊按鈕時更新編輯框的控件變量,將獲得的文本做爲輸入參數調用接口便可。
UpdateData(TRUE); std::string path; path = CT2A(m_FILEPATH.GetString()); try { readFile(path); } catch (const std::exception&) { m_EXCEPTMESSAGE = CString(_T("讀取文件出現錯誤,請重啓程序")); UpdateData(FALSE); return; } m_EXCEPTMESSAGE = CString(_T("讀取文件成功")); UpdateData(FALSE);
添加,刪除圖形
經過ADD和DELETE按鈕能夠進行圖形的手工添加和刪除,只需按照規定格式輸入圖形數據便可。
在點擊按鈕後獲取編輯框的控件變量,輸入計算模塊。以添加直線爲例,具體代碼爲
UpdateData(TRUE); std::string line; line = CT2A(m_LineValue.GetString()); try { addGeometryObject(line); } catch (const std::exception&) { m_EXCEPTMESSAGE = CString(_T("添加圖形時出現錯誤,請重啓程序")); UpdateData(FALSE); return; }
求解與繪製
經過Solve按鈕能夠計算圖形的交點個數,此功能也是經過調用計算模塊實現的。在得到交點個數後反向更新控件變量便可顯示數字。
經過Draw按鈕能夠繪製現有圖形的圖像,默認是以網格座標軸爲背景顯示圖形。這部分先從計算模塊獲取圖形信息,再調用相關的圖形API完成繪圖。爲了解決座標與像素大小轉換的問題,在程序中設置了一個比例尺,用來調整座標與像素的對應關係。具體的,在獲得圖形屬性後,經過如下方式調整圖形大小,resize即比例尺:
circle(xc * resize, yc * resize, r1 * resize)
調整座標比例
因爲做業數據上限較大,因此默認的窗口大小可能不能顯示完整的圖形,經過兩個按鈕scale+,scale-來調整內部的比例尺,以達到圖片縮放的效果。每次點擊這兩個按鈕都會改變比例尺。下圖是具體的比例尺增大的效果。
在對接部分最重要的是接口的設計,良好的接口設計能夠避免過多的操做,從而節省資源,提升性能。本做業的接口聲明爲
// parameter = file_name __declspec(dllexport) void readFile(string); // add from standard string fromat __declspec(dllexport) void addGeometryObject(string); // remove by standard string format, strictly equals __declspec(dllexport) void removeGeometryObject(string); // trigger calculation __declspec(dllexport) pair<vector<string>, vector<Point>> getResult();
因爲設計接口時有比較好的協商,界面模塊與計算模塊的對接只須要將數據按照約定的格式調用相關接口便可。固然,在運行前須要把dll文件和h文件添加到項目的包含目錄中。生成與導入dll文件的步驟能夠參考vs的官方文檔。具體的說,導入文件,添加圖形均可以通過相似的過程完成,以添加圖形爲例,大體的對接過程是:
UpdateData(TRUE);//更新輸入數據 std::string line; line = CT2A(m_LineValue.GetString());//由輸入獲取數據 try { addGeometryObject(line);//調用接口 } catch (const std::exception&) { //異常處理,此部分較繁瑣,以僞代碼略去 }
繪圖部分須要進行圖形解析,因爲商議的接口返回的是圖形的幾何,因此此部分對數據進行了分類和處理,再經過繪圖方法繪製圖形。主要邏輯是:
stringstream ss(""); string str = result; ss.clear(); ss << str; char type; ss >> type; switch (type) { case 'C': { setcolor(BLUE); double xc, yc, r1; ss >> xc >> yc >> r1; circle(xc * resize, yc * -resize, r1 * resize);//resize爲上文所說的比例尺 break; //繪圖部分以調用API爲主,步驟相似,爲了博客的可讀性其他繪圖部分省略了 } case 'L': {//繪圖} case 'R': {//繪圖} case 'S': {//繪圖} default:{ break; } }
在前期的開發過程當中咱們是按照Pair Work的方法進行的,即一我的做爲駕駛員控制鍵盤輸入,另外一我的是領航員,起到領航,提醒的做用。而在後期的測試環節咱們經過互相交流,使測試更快速全面。如下是使用騰訊會議屏幕共享和交流的截圖。
如下是交換使用github管理項目的截圖
新冠肺炎席捲全世界,大三下學期的開頭也在家中度過。往常結對編程是對面的進行,雙方能一般快捷的交流;但今年的結對編程是在線上進行,隔着屏幕交流給人不天然的感受。
在特殊的結對編程條件下,我對結對編程的優缺點有了必定的認識。
優勢
缺點
我 | 隊友 | |
---|---|---|
優勢 | 開發高效、軟件設計能力強、對項目總體節奏有所把控 | 特別積極、思路靈活變通、能學習鑽研新方法新技術 |
缺點 | 學習新技術(GUI)時容易急躁 | 軟件設計意識不強 |
與咱們合做的小組是 杜林峯 17373067 & 諸子鈺 16021142
由於商議好了接口的規格,在替換接口時只須要更改VS的連接庫設置便可。運行截圖:
在運行中由於異常的處理不一樣,會出現異常未捕獲的狀況,在修改catch語句後可正常運行。由於計算部分的結構已經設計好了,因此沒有更改核心模塊。
商議接口
由於雙方軟件的差異很大,因此須要商議一個接口做爲橋樑。咱們商議出的接口以下:
#pragma once #include <vector> #include <iostream> using namespace std; typedef pair<double, double> InterfacePoint; // parameter = file_name __declspec(dllexport) void readFile(string); // add from standard string fromat of geometry component __declspec(dllexport) void addGeometryObject(string); // remove by standard string format of geometry component, strictly equals __declspec(dllexport) void removeGeometryObject(string); // trigger calculation __declspec(dllexport) pair<vector<string>, vector<InterfacePoint>> getResult();
適配接口
編寫新的模塊適配接口,從而使先後端可以匯合。適配接口的代碼以下
#include "Interface.h" #include "read_file.h" #include "table.h" Table table; // 適配讀文件接口 void readFile(string inFilePath) { ifstream infile = ifstream(inFilePath); readFromFile(table, infile); infile.close(); } // 適配添加幾何對象接口 void addGeometryObject(string geometryString) { table.insertFromString(geometryString); } // 適配刪除幾何對象接口 void removeGeometryObject(string geometryString) { table.eraseFromString(geometryString); } // 適配獲得最終結果接口 pair<vector<string>, vector<InterfacePoint>> getResult() { vector<string> geometries = vector<string>(table.getLineSet().size() + table.getCircleSet().size()); vector<InterfacePoint> points = vector<InterfacePoint>(table.getPointNum()); geometries.clear(); points.clear(); for (auto i : table.getLineSet()) { geometries.push_back(i->toString()); } for (auto i : table.getCircleSet()) { geometries.push_back(i.toString()); } for (auto i : table.getPointSet()) { points.push_back(InterfacePoint(i.pointX, i.pointY)); } return pair<vector<string>, vector<InterfacePoint>>(geometries, points); }
生成DLL
在接口適配完成後,生成後端DLL庫。
兩組交換對接
該步驟比較順利一次完成。