現代軟件工程講義 個人項目和結對項目練習 四則運算


這是構建之法 《現代軟件工程》課的作業題之一。

下面的題目, 從簡單的命令行處理和數據處理開始開始,讓同學們逐步練習,鞏固算法,學會松耦合的設計,學會PSP,源代碼控制,單元測試,回歸測試,增量改進程序,等等。

 

第一步: 像《構建之法》的人物阿超那樣,花二十分鍾寫一個能自動生成小學四則運算題目的命令行 “軟件”。


具體要求:任何編程語言都可以,命令行程序接受一個數字輸入,然后輸出相應數目的四則運算題目和答案。例如輸入數字是 30, 那就輸出 30 道題目和答案。 運算式子必須至少有兩個運算符,運算數字是在 100 之內的正整數,答案不能是負數。 如:

23 - 3 * 4 = 11

擴展要求:看看小學三、四、五年級的四則運算要求, 逐步實現各個年級的難度。 寫博客紀錄自己實現每一個擴展的思路。 在擴展的過程種,你是獨立開發每個年級的運算題的功能,處理四年級的代碼和三年級的代碼沒有任何聯系,還是逐步把一些公共的代碼放在一起? 或者你用面向對象的方法,運用基類 (base class) 和子類來管理各種不同的需求和實現的細節?  

 

第二步, 分別滿足下面的各種需求。

從這一步開始,我們要求學生填寫個人軟件流程 PSP 的耗時估計和實際時間的表格,要求把代碼簽入到源代碼管理服務器上。  

下面這些需求都可以用命令行參數的形式來指定:

a) 一次可以出一千道道題目,並且沒有重復的,把題目寫入一個文件中。我們大家都知道,(1+2) 和 (2+1) 是重復的題目。 高級要求: 怎么嚴格定義題目重復呢,請看詳細題目要求

和同學們比較一下各自程序的功能、性能、實現方法的異同等等。

b) 當你有多於一個運算符的時候,如何對一個表達式求值?逐步擴展功能和可以支持的表達式類型,最后希望能支持下面類型的題目 (最多 10 個運算符,括號的數量不限制):

25 - 3 * 4 - 2 / 2 + 89 = ?
1/2 + 1/3 - 1/4 = ? 
(6 - 4 ) * (3 + 28) =?

提示:很多學生在開始的時候用簡單的條件判斷來處理運算,如果只有一個運算符,那還是比較簡明的,運算符多了之后,怎么辦呢?  一些學生就用很多條件判斷來處理運算的優先級,這是某學生代碼片段:

復制代碼
        public void jisuan(double a, string operation1,double b, string operation2,double c, string rightanswer)
        {
            bool aa = false;
            if (operation1 == "+" || operation1 == "-")
            {
                if (operation2 == "*" || operation2 == "/")
                {
                    aa = true;
                }
                else
                {
                    aa = false;
                }
            }
            else
            {
                aa = false;
            }
            if (aa == true)
...
復制代碼

那如果有 3 個運算符呢?怎么辦,繼續增加不同的 if/else 來解決?4個運算符呢?... 顯然這不是一個好的算法, 一個好的算法,即使問題變得更復雜,算法本身應該依然是簡明的, 並且程序本身的代碼量並不會變得異常復雜。 我們看看有什么好的數據結構能高效地表示四則運算。

請參考調度場算法: 

          http://hczhcz.github.io/2014/02/27/shunting-yard-algorithm.html

          https://en.wikipedia.org/wiki/Shunting-yard_algorithm  (中文版

c) 除了整數以外,還要支持真分數的四則運算。 (例如:  1/6 + 1/8 = 7/24  )

d) 讓程序能接受用戶輸入答案,並判定對錯。 最后給出總共 對/錯 的數量。

e) 到目前為止,這個程序的界面都是中文的, 隨着這個應用大受歡迎,別的國家的用戶也要用,那么怎么能高效地讓這個 App 支持不同文字界面互換呢?你是在程序里面不斷插入 if ... else ... 來處理中英文,還是有高效率,可以擴展的辦法?這個程序最終會擴展為支持10種語言,而且每個語言的用戶需要符合他們文化的圖標。請問你還是用 if/else 來解決么?

例如:你的程序已經支持了兩種語言,並且中文界面有一個符合中國用戶期望的圖標,英文界面有一個符合美國用戶期望的圖標,  現在你要支持第三個語言 - 日文,並且需要一個符合日本用戶的圖標(假設是富士山的圖像)。 然后還有另外 7 個語言 (德國、法國、意大利、...)和不同的圖像要支持。那么,這可以用if/else 來解決, 還是有更高效的辦法?

當顯示文字直接放在代碼中,例如像下面這樣:

if (isEnglish) UIControl.setText("Welcome to my calculator app"); else if (isChinese) UIControl.setText("歡迎使用我的四則運算程序"); else if ...

 

這種用戶顯示的文字和代碼邏輯放在一起的設計,我們稱之為緊耦合。 程序員精通代碼邏輯,但未必精通各國語言,也不太會設計各種圖標,那我們會讓懂法語和德語的團隊成員(或者臨時請來的專家)直接在代碼上面改么?似乎他們會覺得代碼編輯器的界面好難掌握哦... 改錯了,程序編譯不過去怎么辦?我們可以想象,如果這些和邏輯無關的資源能夠放在一個單獨的地方, 這樣負責文字和圖像的人員(他們可能不太懂編程)能去修改,然后在主程序里,我們把各種語言的處理抽象為下面的操作:

    UIControl.setText(GetStringByLanguage(language_Id, string_id);   //根據當前顯示的語言,拿到適當的文字,然后顯示。 

 

這樣會不會更好?邏輯代碼和現實的資源各自分開, 通過良好定義的渠道(language_id, string_id) 結合起來了, 這是一種松耦合。 請看同學的嘗試1嘗試2.

程序可以用很多辦法來提高效率保持簡明:抽象 (把復雜的操作抽象為一個名字/類/函數,把復雜的處理隱藏在內),循環(高效地把類似的事情做 N 遍),遞歸(在處理問題的時候,發現這個子問題也是類似的,那我就調用自己來處理),組合(把各個操作組合起來完成復雜任務)... 等

    

第三步,增加一個運算符,程序應該有怎樣的改變?不得不扔掉全部重寫么,還是可以只改部分模塊?

 

一些高年級的老師看到這個程序,希望讓他們的同學也來用,但是有一個新需求, 要支持乘方 (power) 運算,我們都知道,乘方運算的優先級高於乘除法。如何表示乘方, 有兩種表示方法:

1. 4 ^ 2 = 16,   4 的二次方等於 16。  這里, ^ 表示乘方

2. 4 ** 2 = 16,   4 的二次方等於16。這里, **  表示乘方 (** 之間不能有空格,否則是錯誤的算式)

由於歷史的原因, 不同的學校用了不同的表示方法, 老師希望這兩種表示方法都要支持,可以通過設置來選擇。  

 

 

 

第4步,每個同學選一個方向,把程序擴展一下:

a) 把程序變成一個 Windows/Mac/Linux 電腦圖形界面的程序 (取決於你目前使用的電腦),同時增加 “倒計時” 功能, 每個題目必須在 20 秒鍾完成,如果完不成,則得0 分並進入下一題。增加“歷史紀錄” 功能, 把用戶做題的成績記錄下來並可以展現歷史記錄。 

b) 把程序變成一個智能手機程序 (你正在用什么手機, 就寫那個手機的程序), 增加倒計時,和歷史紀錄功能(見上)。

c) 把程序變成一個網頁程序, 用戶通過設定參數,就可以得到各種題目。

d) 選一個你從來沒有學過的編程語言,試一試實現基本功能。

     估計做好這個軟件需要的時間,並且寫出大概的設計步驟和實現算法。

e)把這個程序的思路變成一個可以一步一步演示的步驟, 可以是命令行的輸出, 也可以是圖形界面:

  輸入:一個正常的四則運算句子

  輸出:程序用動畫表示分詞的過程,后序轉換的過程,處理不同運算符優先級的過程, 逐步算出得出結果的過程。

 

例如:輸入是  (6^2 - 4 ) * (3 + 28)

 

輸出是

(36 - 4 ) * (3 + 28) 

32 * (3 + 28) 

32 * 31 

992 

     如果能做到這一步, 這個程序所牽涉到的 “知識點” 就能說 “精通” 了。

    

可以開始做相關的第二個作業

 

第三步,程序理解和擴展

我們說了程序要能輸出不重復的題目,大家有不同的實現方法,那么能否比較一下各自的異同? 例如這個實現方法:

https://gist.github.com/vczh/2c058aed996effc0a519ed3d265a3eb5  

1) 能否讀一下這個程序,注釋一下它的核心設計是什么,寫一篇博客分析一下?

2) 如果我們要讓這個程序增加一個運算 -- 乘方運算。  你要在現有程序中做什么樣的修改,才能讓這個程序比較優雅地實現這個新的需求。 

 

=========================

其他題目:

    - 最大子數組的和 問題及其擴展

    - 單詞英語單詞頻率問題 黃金點游戲

    - 四則運算練習

    - 計算程序文件的行數 WC 

    - 電梯調度

    - 網頁前端技術的練習題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM