前言
FizzBuzz 大概是最廣為人知的程式設計題目之一,它的題目是這樣的:
- 打印出
1
到100
的數字- 假如數字是
3
的倍數,則打印Fizz
- 假如數字是
5
的倍數,則打印Buzz
- 假如數字是
3
和5
的公倍數,則打印FizzBuzz
- 假如數字是
解題
基本解
最直接的解法即是製作一個函式會打印 1 ~ 100
的數字,並依照規則判斷是否要打印 Fizz
、Buzz
或 FizzBuzz
。但明顯這樣的做法會將所有數值都寫死在程式當中,未來要擴充條件時就需要修改程式碼,尚不夠靈活。
分離資料與邏輯
既然可以預期規則都是 某數字
要打印 某結果
那麼或許可以使用物件來紀錄這些 Key-Value 結構的資料:
資料是抽離出來了,但邏輯還是依賴指定 map
物件當中的特定內容,讓我們再寫個迴圈自動的將 map
物件的內容取出來,讓資料來驅動邏輯:
保持數值不變(Immutable)
以上解方可以觀察到目前定義了 i
以及 output
兩個變數並且於程式中持續的變動其內容,在某些程式開發風格當中會被視為應當避免的習慣,我們可以嘗試看看將複寫變數的部分改為純粹函式。
補齊文件與檢查邊界案例
JavaScript 是動態型別語言,因此其他人在使用這個函式時可能不清楚具體參數的需求,這裡透過 JSDoc 來補齊文件,也可以考慮使用 TypeScript 來檢測型別或於 Runtime 進行型別檢測:
藉由局部應用來簡化 numberReplacer
你可能會想說:老天!只是要印個 FizzBuzz
為什麼每次都要透過 numberReplacer
來計算?有沒有辦法單純創個函式只傳入最大值就好?就像一開始一樣?讓我們用局部應用函式來透過創造抽象達成簡化:
在這次解題過程中我貫徹 DRY 原則,並且透過不斷的重構來提升程式碼的可讀性與可維護性,但也可以思考真的有必要製造更多抽象嗎?過早的最佳化是萬惡之源,或許 YAGNI。