課程設計報告一:我的銀行帳戶管理系統 此文檔及源碼僅供參考 不得直接複製使用html
author: [xxxxxxxxx xx xxxx]java
date: "2019-04-12"c++
做 者:31415926535xgit
出 處:http://www.javashuo.com/article/p-vpvyazbt-gc.htmlgithub
版權聲明:署名 - 非商業性使用 - 禁止演繹,協議普通文本 | 協議法律文本。編程
不建議直接複製文檔、源碼,沒意義,這東西仍是本身手敲一下才能漲經驗數組
項目全部的內容都已上傳至本人github,有需自取😀安全
一我的能夠有多個活期帳戶,一個活期儲蓄帳戶包括 帳號(id) 、 餘額(balance) 、 年利率(rate) 等信息,還包括 顯示帳戶信息(show) 、 存款(deposit) 、取款(withdraw) 、 結算利息(settle) 等操做。函數
設計一個 類 SavingAccount , 其數據成員爲 id, balance, rate , 類的方法有 show(), deposit(), withdraw(), settle()測試
UML:
不管是存款、取款仍是結算利息,都須要修改當前的餘額而且將餘額的變更輸出,這些公共操做由 私有成員方法 record 來執行。
利息的計算: 因爲帳戶的餘額是不斷變化的,所以不能經過餘額與年利率相乘的方法來計算年利,而是須要將一年當中天天的餘額累計起來再除以一年的總天數,獲得一個日均餘額,再乘以年利率。爲了計算餘額的按日累計值,SavingAccount 類引入了一個 私有數據成員lastDate , accumulation 和私有成員函數 accumulate。 lastDate 用來存儲上一次viyue變更的日期,accumulation 用來存儲上次計算利息之後直到最近一次餘額變更時餘額按日累加的值,accumulate 成員函數用來計算截止指定日期的帳戶餘額按日累加值。當餘額變更時,須要作的事將變更前的餘額與該餘額所持續的天數相乘,累加到 accumulation 中,再修改 lastDate。
爲了簡便,該類中的全部日期均用一個整數來表示,該整數是一個以日爲單位的相對日期,例如若是以開戶日爲1,那麼開戶往後的第3天就用4來表示, 這樣哦他難過將兩個日期相減就能夠獲得兩個日期相差的天數。
SavingAccount()
類的定義:public class SavingsAccount {}
private int id; //帳號 private double balance; //餘額 private double rate; //存款的年利率 private int lastDate; //上次變動餘額的時期 private double accumulation; //餘額按日累加之和
public SavingsAccount(int date, int id, double rate) {} //構造方法 private void record(int date, double amount) {} //記錄一筆帳 private double accumulate(int date) {} //得到到指定日期爲止的存款金額按日累積值 public int getId() {} //返回編號 public double getBalance() {} //返回餘額 public double getRate() {} //返回存款的年利率 public void deposit(int date, double amount) {} //存入現金 public void withdraw(int date, double amount) {} //取出現金 public void settle(int date) {} //結算利息,每一年1月1日調用一次該函數 public void show() {} //顯示帳戶信息 public static void main(String[] args) {} //主函數,呈現所實現的功能
目的:
#xxxxxx is created
;#xxxxx Balance: xxxx
無實際輸入內容,輸出結果爲:
1 #21325302 is created 1 #58320212 is created 5 #21325302 5000 5000 25 #58320212 10000 10000 45 #21325302 5500 10500 60 #58320212 -4000 6000 90 #21325302 27.64 10527.64 90 #58320212 21.78 6021.78 #21325302 Balance: 10527.64#21325302 Balance: 10527.64 --------10527.64 #58320212 Balance: 6021.78#58320212 Balance: 6021.78 --------6021.78
程序在計算年息時經過四捨五入的方法以及去除整數小數點後的零使得最後的輸出結果符合實驗預期,同 c++ 實現的輸出結果相同。
與 c++ 實現相比,java 的項目實現更加的嚴謹,同時也有一些不一樣的語言特性,例如 java 在輸出浮點數時,整數不通過處理時會輸出小數點後一位的零,而 c++ 的輸出會捨棄。
java 在實例化對象時的語法與 c++ 相比有些不一樣,例如 className c;
在 c++ 中即表示實例化一個對象,而在 java 中雖然表達相同,但實際僅僅是對象的聲明,此時並無實例化真正的對象,同時 java 實例化對象時須要使用關鍵字 new
。
此版本的項目在上一版作出以下改進:
SavingAccount
類中添加一個靜態數據成員 total
, 用來記錄各個帳戶的總金額,併爲其增長相應的靜態成員方法 getTotal
用來對其進行訪問。SavingAccount
類中的例如 getBalance()
, accumulate()
這些不須要改變對象狀態的成員方法聲明爲 常成員方法。SavingAccount 的UML圖爲:
除上版本的數據成員和成員方法外,增長:
static double total = 0; //全部帳戶的金額
同時在 record()
方法中增長 total += amount;
來實現 各個帳戶的總金額的計算
增長獲取總金額的靜態方法:
public static double getTotal() {} //顯示總金額
除了和上一版本的測試用例之外,添加一個顯示總金額的測試,預期輸出爲: Total: xxxx
;
程序仍無輸入操做,最後的輸出結果爲:
1 #21325302 is created 1 #58320212 is created 5 #21325302 5000 5000 25 #58320212 10000 10000 45 #21325302 5500 10500 60 #58320212 -4000 6000 90 #21325302 27.64 10527.64 90 #58320212 21.78 6021.78 #21325302 Balance: 10527.64 #58320212 Balance: 6021.78 Total: 16549.42
除 Total: 16549.42
外,其餘的輸出結果與 0.1版本 的輸出一致。
同 c++ 同樣,類中的靜態變量只佔用該類的一個空間,能夠看成本類的一個計數器。
靜態數據成員僅由靜態成員方法來訪問。
SavingAccount
類專門增長了一個用來 報告錯誤 的方法,當其餘函數須要輸出錯誤信息時,直接把信息子字符串形式傳遞給該方法計科,簡化了錯誤信息的輸出。UML圖爲:
爲了計算兩個日期相差天數,能夠先選取一個比較規整的 基準日期,在構造日期對象時將該日期到基準日期的相對天數計算出來,(稱這個相對天數爲 「相對日期」),這樣計算兩個日期相差的天數時,只需將兩者的相對日期相減便可。
假設將公元元年1月1日做爲基準日期,將y年m月d日相距這一天的天數記爲 \(f(y/m/d,1/1/1)\),能夠將其分解爲3個部分:
\[ { f(y/m/d, 1/1/1) = f(y/1/1, 1/1/1) + f(y/m/1, y/1/1) + f(y/m/d, y/m/1) } \]
上面的等數右邊的第一項表示當年的1月1日與公元元年1月1日相距的天數,即公元元年到公元y-1年的總天數。平年每一年有365天,閏年多一天,所以該值爲 \(365(y-1)\) 加上公元元年到 y - 1 年之間的閏年數。因爲4年一閏,100的倍數免閏,400的倍數再閏,故有:
\[ { f(y/m/d, 1/1/1) = 365(y-1) + \lfloor{\frac{y-1}{4}} \rfloor - \lfloor{\frac{y-1}{100}} \rfloor + \lfloor{\frac{y+1}{400}} \rfloor } \]
其中 \(\lfloor x \rfloor\) 表示對 \(x\) 的向下取整, \(f(y/m/d, y/1/1)\) 表示y年m月1日與1月1日相距天數。
因爲每個月的天數不一樣,因此難以表示爲一個同一的公式,但每個月的1日與1月1日相差的天數能夠有月份m惟一肯定,所以能夠把每個月1日到1月1日由一個數組保存,計算時只需查詢該數組便可,對於閏年,當 \(m>2\) 時將查得的值加一便可。該值只依賴於x和y,記爲 \(g(m,y)\)。
同時:
\[ f(y/m/d, y/m/1) = d - 1 \]
將公元元年1月1日做爲基準日期,則公元y年m月d日的相對日期就是;
\[ f(y/m/d, 1/1/1) + 1 = 365(y - 1) + \lfloor{\frac{y-1}{4}} \rfloor - \lfloor{\frac{y-1}{100}} \rfloor + \lfloor{\frac{y+1}{400}} \rfloor + g(m, y) + d \]
兩個日期的天數的差即可以簡單的計算出來。
Date類的數據成員包括 year
, month
, day
和 totalDays
(相對日期); 成員函數有:getMaxDay
獲取當月的天數, isLeapYear
判斷當前年是否爲閏年, show
輸出當前日期, distance
判斷當前日期與指定日期相差的天數;
//數據成員: private int year; private int month; private int day; private int totalDays; final int DAYS_BEFORE_MONTH[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; //方法: public Date(int year, int month, int day){} public final int getYear(){} public final int getMonth(){} public final int getDay(){} public final int getMaxDay(){} public final boolean isLeapYear(){} public final void show(){} public final int distance(final Date date){}
在上一版本的基礎上,有以下改動:
int
改成 string
;int
改成 Date
類,併爲 deposit
, withdraw
和 settle
增長了一個用來存儲該筆帳目信息的 string
型的 desc
參數;error
方法;private String id; //帳號 private Date lastDate; //上次變動餘額的時期 private void record(final Date date, double amount, final String desc){} private final void error(final String msg){} public void deposit(final Date date, double amount, final String desc){} public void withdraw(final Date date, double amount, final String desc){} public void settle(final Date date){}
目的:
date #xxxxxx is created
;date #xxxxxx xxxx xxxx msg
date #xxxx xx xxxx interest xxxxxx balance: xxxx
Total: xxxx
;程序無輸入操做,輸出的結果爲:
2008-11-1 #S3755217 is created 2008-11-1 #02342342 is created 2008-11-5 #S3755217 5000 5000 salary 2008-11-25 #02342342 10000 10000 sell stock 0323 2008-12-5 #S3755217 5500 10500 salary 2008-12-20 #02342342 -4000 6000 buy a laptop 2009-1-1 #S3755217 17.77 10517.77 interest S3755217 Balance: 10517.77 2009-1-1 #02342342 13.2 6013.2 interest 02342342 Balance: 6013.2 Total: 16530.97
最後的輸出與實驗預期相一致。
同上一版本相比,這一版本增長了 信用帳戶 的需求:
根據需求設計一個 基類Account 用來描述全部帳戶的共性,派生除 SavingsAccount 以及在派生出表示信用帳戶的類 CreditAccount。
在基類Account中,保留數據成員: id帳號
, balance餘額
, total靜態數據成員帳戶總金額
, 成員方法: show輸出信息
。原來的 record
, error
方法的訪問控制權限修改成 protected,供派生類調用,同時還有一個保護的構造方法。
對於 處理存款的成員方法 deposit 、 處理取款的成員方法 withdraw 、 處理結算的成員方法 settle 都放在各個派生類中,緣由是兩種帳戶的具體處理方式不一樣。
儲蓄帳戶用來表示年利率的rate 、 信用帳戶用來表示信用額度的credit 、表示日利率 rate、 表示年費fee 以及其獲取他們的成員方法都做爲相應的派生類的成員。
建立一個新類用來實現各個帳戶的按日累加和的功能,有該類題用計算一項數據的按日累加之和所需的接口,在兩個派生類中分別將其實例化,經過該類的實例計算利息。這個類命名爲 Accumulator
。
該類包括3個數據成員: lastDate被累加數值上次變動日期
、 value被累加數值的當前值
、 sum到上次變動被累加數值位置的按日累加總和
;
該類包括4個成員方法: 構造方法、 getSum計算到指定日期的累加結果
、 change指定日期更改數值
、 reset將累加器清零並從新設定初始日期和數值
;
UML圖:
private String id; private double balance; private static double total = 0; protected Account(final Date date, final String id){} protected void record(final Date date, double amount, final String desc){} protected final void error(final String msg){} public final String getId(){} public final double getBalance(){} public static double getTotal(){} public void show(){}
private Date lastDate; double value; double sum; public Accumulator(final Date date, double value){} public final double getSum(final Date date){} public void change(final Date date, double value){} public void reset(final Date date, double value){}
public class SavingsAccount extends Account{ private Accumulator acc; private double rate; public SavingsAccount(final Date date, final String id, double rate){} public final double getRate(){} public void deposit(final Date date, double amount, final String desc){} public void withdraw(final Date date, double amount, final String desc){} public void settle(final Date date){} }
public class CreditAccount extends Account{ private Accumulator acc; private double cred`it; private double rate; private double fee;` private final double getDebt(){} public CreditAccount(final Date date, final String id, double credit, double rate, double fee) {} public final double getCredit(){} public final double getRate(){} public final double getFee(){} public final double getAvailableCredit(){} public void deposit(final Date date, double amount, final String desc){} public void withdraw(final Date date, double amount, final String desc){} public void settle(final Date date){} public final void show(){} }
Date類與上一版本保持不變
目的:
date #xxxxxxxx created
;date #xxxxxxx xxxx xxxx msg
;date #xxxxxxxx xxxx xxxx interest
;date #xxxxxxxx xxxx xxxx interest/annual fee
;xxxxxxxxx Balance: xxxx / Available credit: xxxx
Total: xxxx
;這一版本仍無輸入,因此輸出爲:
2008-11-1 #S3755217 created 2008-11-1 #02342342 created 2008-11-1 #C5392394 created 2008-11-5 #S3755217 5000 5000 salary 2008-11-15 #C5392394 -2000 -2000 buy a cell 2008-11-25 #02342342 10000 10000 sell stock 0323 2008-12-1 #C5392394 -16 -2016 interest 2008-12-1 #C5392394 2016 0 repay the creadit 2008-12-5 #S3755217 5500 10500 salary 2009-1-1 #S3755217 17.77 10517.77 interest 2009-1-1 #02342342 15.16 10015.16 interest 2009-1-1 #C5392394 -50 -50 annual fee S3755217 Balance: 10517.77 02342342 Balance: 10015.16 C5392394 Balance: -50 Available credit:9950 Total: 20482.93
輸出與預期內容相同。
這一版本改進上通常版本中的兩個不足:
deposit
, withdraw
, settle
等函數彼此獨立,只有知道一個實例的具體類型以後才能調用這些函數。show
函數就能夠在具體的類中實現,在Java中的解決方法是子類調用父類實現一部分的功能。deposit
, withdraw
, settle
聲明爲抽象方法,這樣能夠經過父類的引用來調用子類的方法。settle
方法容許接受的參數統一爲每個月1日,同時對活期儲蓄帳戶的 settle
進行修改,使它在結算利息以前先判斷是否爲1月,只有參數所給的日期是1月才進行結算。原來的Date類中的 distance1
函數在c++中改成 "-" 運算符重載可使程序更加的直觀,在Java中的解決方法是增長一個 sub
方法來實現兩日期相差天數的功能。
abstract public class Account { abstract public void deposit(final Date date, double amount, final String desc); abstract public void withdraw(final Date date, double amount, final String desc); abstract public void settle(final Date date); public void show() { NumberFormat nf = new DecimalFormat("0.##"); System.out.print(id + "\tBalance: " + nf.format(balance)); } }
public final void show() { super.show(); NumberFormat nf = new DecimalFormat("0.##"); System.out.print("\tAvailable credit:" + nf.format(getAvailableCredit())); }
public final int sub(final Date date) { return this.totalDays - date.totalDays; }
目的:
accounts
對象數組,便於以後的操做,此時無輸出;(d)deposit (w)withdraw (s)show (c)change day (n)next month (e)exit
;date Total: xxxx.x command>
;c 5
,此時在下一次等待輸入的提示指令顯示將是合法更改後的日期,對應這條輸入輸出結果應該爲: 2008-11-5 Total: 0.0 command>
;d 0 5000 salary
, 此時應該輸出: 2008-11-5 #S3755217 5000 5000 salary
;w 2 2000 buy a cell
, 此時應該輸出: 2008-11-25 #02342342 10000 10000 sell stock 0323
;n
, 此時輸出: 2008-12-1 #C5392394 -16 -2016 interest
, 2008-12-1 Total: 12984.0 command>
;d 2 2016 repay the credit
, 輸出應該爲: 2008-12-1 #C5392394 2016 0 repay the credit
;c 5
, 此時的輸出應該爲: 2008-12-5 Total: 15000.0 command>
;d 0 5500 salary
, 此時的輸出應該爲: 2008-12-5 #S3755217 5500 10500 salary
;n
, 此時輸出爲:2009-1-1 #S3755217 17.77 10517.77 interest 2009-1-1 #02342342 15.16 10015.16 interest 2009-1-1 #C5392394 -50 -50 annual fee
s
, 此時應該輸出:[0] S3755217 Balance: 10517.77 [1] 02342342 Balance: 10015.16 [2] C5392394 Balance: -50 Available credit:9950
e
, 此時將退出測試程序;這一版本的系統增長了具體的輸入的操做,使得用戶可以自行進行一些對各帳戶的操做,最終的輸出與預期的輸出相同。
2008-11-1 #S3755217 created 2008-11-1 #02342342 created 2008-11-1 #C5392394 created (d)deposit (w)withdraw (s)show (c)change day (n)next month (e)exit 2008-11-1 Total: 0.0 command> c 5 2008-11-5 Total: 0.0 command> d 0 5000 salary 2008-11-5 #S3755217 5000 5000 salary 2008-11-5 Total: 5000.0 command> c 15 2008-11-15 Total: 5000.0 command> w 2 2000 buy a cell 2008-11-15 #C5392394 -2000 -2000 buy a cell 2008-11-15 Total: 3000.0 command> c 25 2008-11-25 Total: 3000.0 command> d 1 10000 sell stock 0323 2008-11-25 #02342342 10000 10000 sell stock 0323 2008-11-25 Total: 13000.0 command> n 2008-12-1 #C5392394 -16 -2016 interest 2008-12-1 Total: 12984.0 command> d 2 2016 repay the credit 2008-12-1 #C5392394 2016 0 repay the credit 2008-12-1 Total: 15000.0 command> c 5 2008-12-5 Total: 15000.0 command> d 0 5500 salary 2008-12-5 #S3755217 5500 10500 salary 2008-12-5 Total: 20500.0 command> n 2009-1-1 #S3755217 17.77 10517.77 interest 2009-1-1 #02342342 15.16 10015.16 interest 2009-1-1 #C5392394 -50 -50 annual fee 2009-1-1 Total: 20482.93 command> s [0] S3755217 Balance: 10517.77 [1] 02342342 Balance: 10015.16 [2] C5392394 Balance: -50 Available credit:9950 2009-1-1 Total: 20482.93 command> e
進一步改進測試程序中的實現,使得測試程序操做更加的便捷。
在上一版本中,使用父類對象數組來處理不一樣派生類對象,從而實現多態性調用,本版本中使用Java中的 ArrayList
來代替原來的對象數組,以實現動態的改變大小,添加新帳戶的功能。
除 Main
類外,其他類文件都無需更改。在 Main
類中導入Java實用包中的 ArrayList
。建立對象數組。
本版本的UML圖與上一版本的相同。
ArrayList<Account> accounts = new ArrayList<Account>();
目的:
a s S3755217 0.015 a s 02342342 0.015 a c C5392394 10000 0.0005 50
表示錄入兩個活期帳戶和一個信用帳戶,同時對應顯示應該爲: date #xxxxxxxx created
;
其餘的輸入輸出測試與上一版本的一致;
輸入和最後的輸出符合預期。
(a)add account (d)deposit (w)withdraw (s)show (c)change day (n)next month (e)exit 2008-11-1 Total: 0.0 command> a s S3755217 0.015 2008-11-1 #S3755217 created 2008-11-1 Total: 0.0 command> a s 02342342 0.015 2008-11-1 #02342342 created 2008-11-1 Total: 0.0 command> a c C5392394 10000 0.0005 50 2008-11-1 #C5392394 created 2008-11-1 Total: 0.0 command> c 5 2008-11-5 Total: 0.0 command> d 0 5000 salary 2008-11-5 #S3755217 5000 5000 salary 2008-11-5 Total: 5000.0 command> c 15 2008-11-15 Total: 5000.0 command> w 2 2000 buy a cell 2008-11-15 #C5392394 -2000 -2000 buy a cell 2008-11-15 Total: 3000.0 command> c 25 2008-11-25 Total: 3000.0 command> d 1 10000 sell stock 0323 2008-11-25 #02342342 10000 10000 sell stock 0323 2008-11-25 Total: 13000.0 command> n 2008-12-1 #C5392394 -16 -2016 interest 2008-12-1 Total: 12984.0 command> d 2 2016 repay the credit 2008-12-1 #C5392394 2016 0 repay the credit 2008-12-1 Total: 15000.0 command> c 5 2008-12-5 Total: 15000.0 command> d 0 5500 salary 2008-12-5 #S3755217 5500 10500 salary 2008-12-5 Total: 20500.0 command> n 2009-1-1 #S3755217 17.77 10517.77 interest 2009-1-1 #02342342 15.16 10015.16 interest 2009-1-1 #C5392394 -50 -50 annual fee 2009-1-1 Total: 20482.93 command> s [0] S3755217 Balance: 10517.77 [1] 02342342 Balance: 10015.16 [2] C5392394 Balance: -50 Available credit:9950 2009-1-1 Total: 20482.93 command> e
系統逐步完善,最後實現的功能有:
對於系統的每個功能,如 SavingAccount , CreditAccount , Account , Date , Main 等功能都是用類實現的,其中每個類中須要和外界通信的數據成員、成員方法先定義了具體的權限,如 public , protected 等,而無需通信的私有成員則爲 private ,使得最後的各功能只提供一些接口參數,而不是具體的實現細節,使用(調用)者無需關心其內部的實現即可實現本身的功能;
該系統設計了一個各帳戶共同的父類: Account , 其餘兩個帳戶類都是由此繼承出,他們有一些共同的方法、數據成員由父類實現(或聲明),而其不一樣則由本身聲明實現。
對於一些子類繼承自父類的數據成員,成員方法,他們中的一些的實現與父類略有不一樣,覆蓋了原父類的內容,使得最後同一個方法有多種實現以供用戶不一樣的需求;
系統中一些支持類(Date, Accumulation等等)與其餘類組合實現了一些基本的功能。
Scanner
來實現不一樣狀況下的數據讀入;charAt()
來取得操做指令的字符;NumberFormat
來格式化數字;floor
,嘗試調用Java中 math
包中的 floor()
來實現時發現最後的效果很差,換用 bDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
語句來實現這個功能;這個銀行管理系統的完成讓我熟悉了Java的基本語法,同時體會到了Java與c++的不一樣的程序設計思想;在完成項目的同時遇到了不少的問題,可是都經過本身獨立查閱資料逐一解決,瞭解了Java中基本的輸入輸出等一些已有的包的功能;最後文檔的書寫也使我清晰的認識到了一個簡單項目從用戶需求到系統設計、系統實現以及最後的代碼的編寫測試這一個流程,同時uml圖的書寫也讓我理清了各功能直接的具體關係,使得最後的代碼間的聯繫更加的清晰明瞭。
此外經過每一版本的需求的更新以及系統的實現,我體會到了面向對象程序設計在實現功能的過程與面向過程以及c++面向對象程序設計的不一樣,Java萬物皆爲類的思想,包括測試用的Main方法都爲類,從最開始的一個儲蓄活期帳戶的功能的實現,date類的實現以及累加日期類的實現實現了系統的基本功能,此後新增活期帳戶功能相似的信用帳戶的需求,經過比較兩個類的共同特色,抽象出其共同的父類 Account
,這樣使得一些共同點得以複用,減小代碼量的同時也使得各種之間的關係加強,同時在最後幾個版本中,由於Java中父類的引用同時能夠引用其子類的特色,使得經過一個父類的對象數組即可以輕易的操縱其子類,使得最後的循環處理測試時的代碼能夠有不一樣類對應不一樣操做代碼合二爲一,大大的使程序的可讀性加強,代碼量減小,開發的負擔也減輕許多,最後的 ArrayList 聲明的對象數組也使得開發者沒必要關心數組空間的分配問題,也使得程序的安全性加強。