1022 C++ 程式設計作業四 (繳交時間 103/05/29 星期四 21:00)
迷你銀行金融服務
這個作業擴充我們在實習考試裡 "簡化的迷你銀行",
希望你能夠依照你所觀察到的以及下面所描述的銀行機制來設計這個物件化的系統, 本來像這樣的系統一定有使用者操作介面, 也一定需要設計檔案串流或是資料庫存取的物件序列化機制,
不過我們在實習裡以及前面的作業裡都已經練習過這些東西了, 所以在這個作業中我們刻意避開這些要求。這個作業主要希望大家練習:
- 多個物件之間的合作
- 運用抽象類別以及繼承語法
這個銀行所提供的金融服務描述如下:
- 這個銀行 (Bank) 有兩個行員 (Teller) 提供 開戶 (createAccount), 存款 (deposit), 提款 (withdraw),
帳戶查詢 (inquire), 轉帳 (transfer), 關閉帳戶 (closeAccount) 的功能
- 有很多個客戶, 每一個客戶有唯一的身分証號碼 customerID
- 每一個客戶可以開設一個活存帳戶 (current saving), 有唯一的帳戶號碼 accountID
- 每一個客戶可以有多個定存帳戶 (fixed saving), 每個帳戶記錄一筆定存單 (fixed deposit), 有唯一的帳戶號碼 accountID,
定存單可以為一年期 或是 兩年期, 期滿之後的時間不計息
- 活存帳戶/定存帳戶的存款與提款僅限於現金存款與現金提款, 提款金額不能大於帳戶餘額 (balance)
- 客戶轉帳時僅限於本銀行內不同的活存帳戶互轉, 轉出金額不能大於帳戶餘額
- 活存帳戶以及每一筆定存存單都有自己的利率 (年利率), 所有帳戶皆為機動利率, 單利, 每滿一日計息 (當日存款不計利息), 不定時會調整利率
- 活存帳戶給息時間為 6/20 及 12/20, 利息計算出來以後直接存入該帳戶; 定存帳戶只有在關閉帳戶 (包括存單到期以及提前解約) 時一次給付現金本金及利息,
提前解約時該存單全部利息以八折計算
- 銀行行員每天早上會去金庫 (vault) 領出 200,000 的現金在抽屜 (cash drawer) 裡, 如果現金低於 10,000 或是某一個客戶的提款超過抽屜裡現金時會再去金庫領出
200,000 的現金, 現金高於 400,000 時會把 200,000 繳回金庫, 每天營業結束時需要清點經手的交易總價值以及現金餘額, 確定兩者是一致的,
並且將所有現金繳回金庫
系統設計時請注意下列事項:
- 實習考試時那個銀行只有一個行員, 所以把 開戶, 存款, 提款, 查詢, 轉帳 的功能以及客戶的帳戶都放在 Bank 類別裡就好了, 但是在這個作業裡銀行在運作時有兩個行員,
所以應該要有分離出來的銀行行員類別 (Teller, Clerk), 銀行行員類別負責 開戶, 存款, 提款, 查詢, 轉帳 的功能, 而銀行類別負責記錄所有客戶的帳戶資料,
當然有了銀行行員類別以後, 這些行員也需要記錄姓名, ID 等等基本資料。
- 實習考試時每一個客戶只能有一個帳戶, 在這個作業裡有不同類型的帳戶, 利率和利息的計算方式並不相同, 不同種類的帳戶需要有設計不同的類別, 但是在程式其他部份處理/記錄這些帳戶時又可能用一致的方式來處理,
應該用適當的繼承機制來設計
- 實習考試時設計的系統中客戶是沒有辦法調閱過去一段時間內所有帳戶的活動細節的, 例如如果有人轉帳給你你就不知道什麼時候轉的, 多少錢入帳了, 因為帳戶裡只記錄目前的餘額。
更糟糕的是, 銀行沒有辦法準確計算並支出利息給客戶, 因為根本不知道帳戶中餘額的細部變化。
要解決這樣的問題, 應該要設計記錄所有流水帳 (ledger) 的機制, 一種方式是把每一筆交易記錄在每一個帳戶裡, 就好像你的存簿裡記錄的資料一樣,
不過如果只記錄在存簿裡, 銀行稽核查帳的時候不就要把所有的存簿收回去? 實際上這樣子記錄是不夠的, 第二種方式是在銀行端存下所有顧客完整的交易記錄,
這個交易記錄不見得屬於個別帳戶的, 比方說轉帳的交易記錄就屬於兩個不同的帳戶
所以在設計上可以 把每一筆交易 (Transaction) 獨立出來, 由銀行類別統一管理, 也方便每一筆交易產生出來以後可以記錄在檔案或是資料庫裡。當然為了實作這樣的交易記錄機制,
也需要有獨立的時間和日期的類別, 需要處理一些時間或是日期的比較。
- 每一個帳戶其實應該都可以結清關掉, 當然結清之前銀行其實是要把利息都計算出來的。 由於過去交易的記錄都會保留相當長的一段時間, 客戶或是主管單位或是警政單位都還有可能來查詢,
所以帳戶關掉不能直接就把帳戶刪除, 應該是要把帳戶的狀態設成 "關閉", 有別於 "正常", "透支",
"靜止", "凍結", 等等狀態。
- 上面的描述裡我們假設只有一個銀行, 由於銀行是一個獨立的類別, 照理說如果我們在類別裡設計銀行的名稱, 銀行的 ID, 其實是可以有很多銀行的,
如此轉帳功能其實也就可以跨越不同的銀行來轉帳 (如果你假設銀行之間是有連線的, 轉帳的結果立刻出現在轉入端的帳戶裡, 不過因為要有實體現金的移轉,
也許這種跨行轉帳和行內的轉帳需要適當的區分, 在現金還沒有入帳之前, 目標帳戶中所轉入的金額是沒有辦法進行現金提款的)
另外上面的描述裡也沒有提到票據的作業以及代收付帳款的作業, 沒有談到除了現金之外其他的有價資產, 更沒有描述到銀行真正賺錢的核心功能 - 放款與投資。
以後你自己再練習設計吧!
測試資料(excel 格式)
請參考 excel 檔中按照時間順序排列之測試資料, 其中主要欄位包括 Name(客戶姓名), customerID(客戶身分證號), Teller(行員姓名),
Date(日期), Time(時間), Operation(指定動作), Amount(金額), accountID(帳戶), target accountID(轉帳目標帳戶)
accountID 和 target accountID 這兩個欄位是代號而已, 實際的 ID 需要由你自己的程式產生不重複的 ID
Operation 欄位包括下列幾種指定的動作 (前 8 項為客戶指定動作, 後 5 項為銀行例行操作)
- create account (開戶)
- deposit current (活期存款)
- inquire current (查詢活期存款餘額)
- withdraw current (活期提款)
- transfer (活期轉帳)
- deposit fixed 1year (一年期定存)
- deposit fixed 2year (兩年期定存)
- withdraw fixed (定期解約提款)
- saving interest (變更活存利率)
- fixed 1year interest (變更一年期定存利率)
- fixed 2year interest (變更兩年期定存利率)
- calculate all saving interests (計算所有活存帳戶利息並存入該帳戶)
- print balances of all accounts (列印所有帳戶結存金額與帳戶價值(包含預計發給之利息))
表格中的動作標示紅色部份是會失敗的
請參考 "簡化的迷你銀行",
製作一個單元測試函式來測試這個指定的情境
程式撰寫時請注意下列各項 C++ 程式設計的一般注意事項:
- 如果成員函式不會更改物件狀態與內容的話,請使用 const 成員
- 儘量運用初始化串列 (initialization list) 來撰寫類別的建構元
- 不要讓你的資料成員成為 public,也不要讓不需要公開的輔助成員函式成為 public
- 物件所有成員的初始值要在建構元中一併設定完成
- 請替有控管軟硬體資源的類別撰寫解構元,拷貝建構元,與設定運算子
- 變數及函式名稱請務必使用有意義的英文或是縮寫
- 類別之間傳遞訊息的時候參數不應該太多, 函式的參數如果在函式運作過程中不會更改的話應該使用 const
- 每一個成員函式內請務必只放相關的程式碼,不要把不相干的東西都擠在同一個函式內
- 每一個類別應該只有單一責任,不要讓一個類別有多種目標功能
- 暫時性的變數不要設計為類別內的資料成員
其他額外功能:請自行想像 (歡迎加入各種額外功能)
程式繳交說明:
- 請於時限內 (103/05/29 星期四 21:00) 上傳程式檔案 (逾時無法上傳), 上傳網頁
- 請繪製 類別圖(class diagram), 並且挑選至少兩個使用案例 (usecase)
繪製 合作圖(collaboration diagram) 以及循序圖(sequence
diagram) 將影像匯入 word 報告檔中
- 此次程式不要求列印程式碼, 如果你覺得有需要在紙上呈現的話,
選擇你自己覺得有代表性的程式碼列印, 或是配合心得, 列印你自己覺得有問題, 需要討論的程式碼就可以了
- 程式設計心得與討論 (當然如果你沒有包含任何程式碼, 沒有討論任何程式碼, 沒有什麼有建設性的心得, 就算你有一個可以執行的程式, 你這一部份的分數可能還是很低
)
程式 Demo 說明:
- 時間: 103/06/05 星期四 10:00-12:05, 19:00-21:00
- 程式 demo 時必須能夠現場編譯沒有錯誤
- 請說明你的測試方法與測試資料,並操作測試,
- 執行助教指定的測試資料
- 請回答你的程式在設計上的相關問題