标签:top 包括 可扩展 程序 去除 文本 特性 extend inline
课程设计报告一:个人银行账户管理系统 此文档及源码仅供参考 不得直接复制使用
author: [xxxxxxxxx xx xxxx]
date: "2019-04-12"
作 者:31415926535x
出 处:https://www.cnblogs.com/31415926535x/p/10697659.html
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本。
不建议直接复制文档、源码,没意义,这东西还是自己手敲一下才能涨经验
项目所有的内容都已上传至本人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 声明的对象数组也使得开发者不必关心数组空间的分配问题,也使得程序的安全性增强。
Java实验-课程设计报告一:个人银行账户管理系统SavingAccountManageSystem-具体文档+源码
标签:top 包括 可扩展 程序 去除 文本 特性 extend inline
原文地址:https://www.cnblogs.com/31415926535x/p/10697659.html