項目地址:https://gitee.com/wxrqforever/object_oriented_exp1.git
一、需求分析:
一個基於控制台的四則運算系統,要能實現生成並計算含有真,假分數,整數的不超過三個運算符帶有括號的四則運算表達式,並且要能根據用戶所提交的答案生成答題報告,答題報告中主要包括,本次答題的正確,錯誤,和重復表達式出現的情況。生成的表達式和答案要存入文件中。對生成的表達式有如下要求,不能在過程中產生負數,因為小學生並不會計算負數,以及不能出現除0的情況,因為小學生不會計算除以0。
從整個需求來看,大致可以分為三個模塊,生成表達式,表達式計算(包括將表達式和答案寫入文件),答題報告的生成(包括表達式的查重和根據輸入完成的校驗)。各個模塊之間關系密切,故采用由下至上的不斷迭代的開發模式,先開發最底層的各個樁模塊,在開發每個樁模塊時再采用測試驅動開發的方法,從編寫小的測試用例開始開發樁模塊,當對樁模塊進行整合時,再編寫測試模塊,這樣當開發完成后測試也就完成了。
生成表達式模塊:主要的關鍵點在於如何能夠全覆蓋所有不超過三個運算符含有真,假分數,整數的可以帶有括號的四則運算表達式。在忽略優先級的條件下,我們觀察表達式形如(1+2+3)*6,1+2+3, 1+2,的三個表達式,我們會發現任何一個復雜的表達式均可看作,其少一個運算符的表達式和一個運算符以及一個運算數構成,如上的例子中
(1+2+3)*6 可以看作是由(1+2+3)和*以及6構成,而1+2+3 則可以看做是由1+2 和+以及3構成。這就給了一個思路只要編寫一個能隨機生成所有情況下的帶一個運算符的表達式,就可以通過不斷添加運算符和運算操作數的方式而窮盡所有的可能。
表達式計算:可采用將隨機生成的表達式轉換為后綴,在對后綴表達式進行計算完成。
答題報告的生成:關鍵點在於如何實現查重,首先我們要明白何為重復的表達式?根據題目中的定義“程序一次運行生成的題目不能重復,即任何兩道題目不能通過有限次交換+和×左右的算術表達式變換為同一道題目。例如,23 + 45 = 和45 + 23 = 是重復的題目,6 × 8 = 和8 × 6 = 也是重復的題目。3+(2+1)和1+2+3這兩個題目是重復的,由於+是左優先計算的,1+2+3等價於(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重復的兩道題,因為1+2+3等價於(1+2)+3,而3+2+1等價於(3+2)+1,它們之間不能通過有限次交換變成同一個題目。" 仔細觀察題目中所給的兩個例子,你會發現這里所說的重復的意思就是你不能破壞原本計算時的優先級,在這個基礎上你可以交換加法或者乘法的。解析一下題中的例子,比如3+(2+1)和1+2+3這兩個題目,為什么是重復的呢?按照優先級,我們是如何計算左邊題目的,是先計算2+1的這個加法再計算3加上2+1的結果的這個加法的對吧,而右邊這個題目根據加法的左結合,先計算1+2 的這個加法 再計算3加上1+2 這個結果的加法,運算時的符號的優先級並沒有被改變僅僅改變了加法的左右操作數,滿足重復的定義,所以是重復的。
再看一個不重復的例子,1+2+3和3+2+1,同樣的左邊的題目,先計算的是1+2的這個加法再計算3加上1+2的結果的這個加法,而右邊的則是先計算3+2的這個加法再計算1加上3+2的結果的加法.可以理解為在進行運算時整個運算的流程是不同的,所以是不同的表達式.
通過上述的分析我們可以看到如何判定兩個表達式是否重復關鍵在於如果在計算這兩個表達式時的流程完全一致或者僅在加法或者乘法運算時交換了左右操作數則這樣的兩個運算表達式是重復的,這樣的分析很容易讓我們相到用后綴表達式解決查重,但僅僅依靠后綴表達式是不夠的,后綴表達式是能夠體現計算過程但卻無法用於判斷兩個表達式之間計算過程是否相同的直接體現,這是·兩個重復的表達式很可能會有不同后綴表達式。比如以(1+2)*3+5和3*(1+2) +5 為例,(1+2)*3+5的后綴表達式為1 2 + 3 * 5 + 而3*(1+2) +5的后綴表達式為3 1 2 + * 5+,雖然是相同運算過程的體現但表達式之間的差距卻非常的大,那該如何解決?
所謂相同的運算過程就是,你在做什么運算我也做什么運算,你的操作數是啥我的操作數也是啥,出於這個引入一個新的表達式,我將其命名為查重表達式,他的結構是運算在先后面跟着這個運算符的操作數,以上述為例(1+2)*3+5的查重表達式就為: +12 * 3 +5 這個表達式的含義就是第一個運算的是加法,加法的操作數是2 和3 第二個運算是乘法,乘法的操作數是前一步計算的結果和3以此類推,而3*(1+2) +5的查重表達式為:+12 * 3+5 與上述完全一致!這樣在做查重是只需判斷查重表達式是否一致或者在查重表達式中第一個字符為‘+’ 或者‘*’的情況下后續的兩個操作數互換位置后是否一致即可。也就是說上述的查重表達式於+21 * 3+5 也是等價的。
那該如何生成查重表達式,所謂的查重表達式就是描述表達式正在運算的過程,那就在你使用后綴表達式計算時,去生成即可。算法之后給出
二、功能設計:
功能設計如圖:
com.wx.appEntrance是作為項目的入口。
com.wx.test 是作為測試功能使用
com.wx.randomTool是作為生成隨機的四則運算表達式的,共有四個類組成其中RandExpressionExport(可直接生成表達式)是頂層類,是對RandOperatorNumberExport(可隨機生成各類操作數和操作符)進一步封裝,而RandOperatorNumberExport是對RandomExportMachine(可生成數字和字符)的進一步封裝,Ruler則是描述生成表達式的功能.
com.wx.expression是描述表達式的結構
com.wx.calculateTool是用於計算表達式,PostfixExpression用於生成后綴表達式,CalculateRuler描述計算規則,CalculateExpression頂層類對可直接計算表達式,對前面兩個類的封裝。
com.wx.fileIO用於實現文件操作
com.wx.expressionCnki 用於實現表達式的查重,工具類.
com.wx.report 用於生成答題報告.
三、代碼實現
3.1表達式類主要用於存儲表達式的代碼,如下:
3.2.1 用於隨機產生一個表達式的頂層類RandExpressionExport中的產生隨機表達式getExpression方法代碼如下:
3.2.2 用於隨機產生一個表達式的頂層類RandExpressionExport中的隨即產生一個操作符表達式的getOneOperatorExpression方法的代碼如下:
(其余多操作符的情況均是對該方法的進一步封裝)
3.2.3用於隨機產生一個表達式的頂層類RandExpressionExport中的隨即產生帶有兩個操作符的表達式的getTwoOperatorExpression方法的代碼如下:
3.3.1用於將表達式轉換成后綴表達式的PostfixExpression類中的getPostFixExpression代碼如下:
3.3.2用於計算后綴表達式的CalculateExpression類中的calculatePostFixExpression方法代碼如下:
3.3.3用於描述計算規則的CalculateRuler中的用於化簡表達式的方法simplificationFracrion的代碼如下:
4.1用於實現查重的Cnki類中的得到查重表達式的getCnkiExpressionArray方法的代碼如下:
4.2用於實現查重的Cnki類中的判斷兩個表達式是否重復的代碼如下:
4.3用於生成報告的AnswerResport中生成答題報告getAnswerResport方法的代碼:4.4用於生成報告的AnswerResport中生成查重報告cnkiExpressionAnswerReport方法的代碼:
四、測試運行:
測試截圖如下:
輸入題目數為10 生成的數字范圍為10
文件中的截圖如下:
對於查重進行單獨測試:
當輸入的表達式為1+2+3 與3+(2+1)時,截圖如下:其中第一,二行為1+2+3的后綴表達式和查重表達式,第三,四行為3+(2+1)的后綴表達式和查重表達式。
第五行為查重結果,余下的為查重報告。
當輸入的表達式為1+2+3 與3+1+2時,截圖如下:其中第一,二行為1+2+3的后綴表達式和查重表達式,第三,四行為3+1+2的后綴表達式和查重表達式。
第五行為查重結果,余下的為查重報告。
當輸入的表達式為(1+2)*3+5 與3*(1+2) +5 時,截圖如下:其中第一,二行為(1+2)*3+5的后綴表達式和查重表達式,第三,四行為3*(1+2) +5 的后綴表達式和查重表達式。
第五行為查重結果,余下的為查重報告
五、psd個人過程: