一、课程设计要求与目的
- 模仿个人银行账户管理系统的C++版本(第4章-第9章),使用Java语言重新实现该系统,比较C++与Java在实现上的异同,熟练掌握Java基础及语法。
- 根据业务需求的增加,对个人银行账户管理系统进行功能上的完善,利用面向对象的思想对代码进行重构,体会抽象、封装、继承、多态等特性在实际系统中的应用,掌握构造可复用、可扩展、可维护软件的基本技能。
二、课程版本记录
1.个人个人银行账户管理系统版本0.1(对应第4章记录)
系统需求
一个活期储蓄账户包括 账号(id) 、 余额(balance) 、 年利率(rate) 等信息,还包括 显示账户信息(show) 、 存款(deposit) 、取款(withdraw) 、 结算利息(settle) 等操作。
系统设计
设计一个 类 Bank , 其数据成员为 id, balance, rate , 类的方法有 show(), deposit(), withdraw(), settle()
系统实现
数据成员
class bank{
int id; //账号
double balance; //余额
double rate; //存款的年利率
int lastDate; //上次变更余额的时期
double accumulation; //余额按日累加之和
}
类中方法
class bank{
public bank(int _date,int _id,double _rate){
lastDate=_date;
id=_id;
rate=_rate;
}
//记录一笔帐,date为日期,amount为金额,desc为说明
void record(int date, double amount){
accumulation = accumulate(date);
lastDate = date;
amount = Math.floor(amount * 100 + 0.5) / 100; //保留小数点后两位
balance += amount;
System.out.println(date+"\t#"+id+"\t"+amount+"\t"+balance);
}
//获得到指定日期为止的存款金额按日累积值
final double accumulate(int date) {
return accumulation + balance * (date - lastDate);
}
int getId() { return id; }
double getBalance() { return balance; }
double getRate() { return rate; }
//存入现金
void deposit(int date, double amount){
record(date, amount);
}
//取出现金
void withdraw(int date, double amount){
if (amount > getBalance())
System.out.println("Error: not enough money");
else
record(date, -amount);
}
//结算利息,每年1月1日调用一次该函数
void settle(int date){
double interest = accumulate(date) * rate / 365; //计算年息
if (interest != 0)
record(date, interest);
accumulation = 0;
}
//显示账户信息
void show(){
System.out.println("#"+id+"\tBalance:"+balance);
}
}
系统测试
体会心得
java 在输出浮点数时,整数不经过处理时会输出小数点后一位的零,而 c++ 的输出会舍弃。java 在实例化对象时的语法与 c++ 相比有些不同,例如 className c;
在 c++ 中即表示实例化一个对象,而在 java 中虽然表达相同,但实际仅仅是对象的声明,此时并没有实例化真正的对象,同时 java 实例化对象时需要使用关键字 new
。
2.个人个人银行账户管理系统版本0.2(对应第5章记录)
系统需求
相较于上一版本,在活期账户中添加一个用来记录各个账户的总金额的功能,同时可以获取这个总金额(total)。
系统设计
在Account类中添加一个静态数据成员 total
, 用来记录各个账户的总金额,并为其增加相应的静态成员方法 getTotal
用来对其进行访问。
系统实现
增加如下代码
private static double total=0; //所有账户的总金额
public static double getTotal() { return total; }
系统测试
体会心得
类中的静态变量只占用该类的一个空间,可以当作本类的一个计数器。静态数据成员仅由静态成员方法来访问。
3.个人个人银行账户管理系统版本0.3(对应第6章记录)
系统需求
新增一个日期类Date,具有输出当前日期,判断闰年,计算两个日期值之间相差天数等功能
增加了报告错误信息
系统设计
银行账户用字符串进行表示
用desc为账目进行了说明
新添Date类
系统实现
新增类
public class Date {
private final int[] DAYS_BEFORE_MONTH={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
private int year; //年
private int month; //月
private int day; //日
private int totalDays; //该日期是从公元元年1月1日开始的第几天
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) {}
}
Account的改动
private String id; //帐号
private Date lastDate; //上次变更余额的时期
//记录一笔帐,date为日期,amount为金额,desc为说明
private void record(final Date date, double amount, final String desc){
accumulation = accumulate(date);
lastDate = date;
amount = Math.floor(amount * 100 + 0.5) / 100; //保留小数点后两位
balance += amount;
total += amount;
date.show();
System.out.println("\t#"+id+"\t"+amount+"\t"+balance+"\t"+desc);
}
//报告错误信息
private final void error(final String msg){
System.out.println("Error(#"+id+"): "+msg);
}
//存入现金
public void deposit(final Date date, double amount, final String desc){
record(date, amount, desc);
}
//取出现金
public void withdraw(final Date date, double amount, final String desc){
if (amount > getBalance())
error("not enough money");
else
record(date, -amount, desc);
}
//结算利息,每年1月1日调用一次该函数
public void settle(final Date date){
double interest = accumulate(date) * rate //计算年息
/ date.distance(new Date(date.getYear()-1,1,1));
if (interest != 0)
record(date, interest, "interest");
accumulation = 0;
}
系统测试
体会心得
组合类方便了一些功能的实现和管理,Date类使得有关日期的操作可以和Account类的实现相互独立,无需关心Date类的具体实现
4.个人个人银行账户管理系统版本0.4(对应第7章记录)
系统需求
新增信用账户
信用账户允许透支(要支付利息),但应在信用额度内。每月1日结算利息,每年1月1日结算年费
系统设计
基类Account派生SavingAccount和CreditAccount两个子类。
基类Account中,保留数据成员:id账号,balance余额,total静态数据成员账户总金额,成员方法show输出信息。原来的record,error 方法的访问控制权限修改为 protected,供派生类调用,同时还有一个protected的构造方法。
处理存款deposit、处理取款withdraw、结算settle方法因具体处理方式不同,放置在派生类中。
增加Accumulator类实现各个账户的按日累加和的功能
系统实现
Accumulator类
public class Accumulator {
private Date lastDate; //上次变更数值的时期
private double value; //数值的当前值
private double sum; //数值按日累加之和
//构造函数,date为开始累加的日期,value为初始值
public Accumulator(final Date date, double value) {}
//获得到日期date的累加结果
public final double getSum(final Date date) {}
//在date将数值变更为value
public void change(final Date date, double value) {}
//初始化,将日期变为date,数值变为value,累加器清零
public void reset(final Date date, double value) {}
}
Account类
public class Account {
private String id; //帐号
private double balance; //余额
static double total=0; //所有账户的总金额
//供派生类调用的构造函数,id为账户
protected Account(final Date date, final String id){}
//记录一笔帐,date为日期,amount为金额,desc为说明
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() { }
//显示账户信息
void show() {}
}
CreditAccount类
public class CreditAccount extends Account{
private Accumulator acc; //辅助计算利息的累加器
private double credit; //信用额度
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){}
//结算利息和年费,每月1日调用一次该函数
public void settle(final Date date){}
public final void show() {}
}
SavingsAccount类
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) {}
//结算利息,每年1月1日调用一次该函数
public void settle(final Date date){}
}
系统测试
体会心得
设计一个共同的父类 Account 类来派生出需要的两个子类,继承派生使得同类不同功能的实现更加的容易
利用super()对父类初始化
5.个人个人银行账户管理系统版本0.5(对应第8章记录)
系统需求
新增了输入功能,让用户选择实现存取等功能。
系统设计
添加switch选择语句,完成让用户选择功能
用Scanner实现数据类型的输入
Account变为抽象类,deposit、withdraw、settle为抽象方法。可以通过父类的引用来调用子类的方法。这样可以通过一个父类的数组来实现不同的账户的存储操作。
系统实现
Account类修改
abstract public class Account {
//存入现金,date为日期,amount为金额,desc为款项说明
abstract public void deposit(final Date date, double amount, final String desc) ;
//取出现金,date为日期,amount为金额,desc为款项说明
abstract public void withdraw(final Date date, double amount, final String desc) ;
//结算(计算利息、年费等),每月结算一次,date为结算日期
abstract public void settle(final Date date) ;
}
CreditAccount类修改
public final void show() {
super.show();
System.out.println("\tAvailable credit:" + getAvailableCredit());
}
BANK类输入和switch语句
import java.util.Scanner;
public class BANK5 {
public static void main(String[] args){
char cmd;
Scanner scanner=new Scanner(System.in);
do {
//显示日期和总金额
date.show();
System.out.println("\tTotal: "+Account.getTotal()+"\tcommand>");
int index, day;
double amount;
String desc;
cmd=scanner.next().charAt(0);
switch (cmd) {
case 'd': //存入现金
index=scanner.nextInt();
amount=scanner.nextDouble();
desc=scanner.nextLine();
accounts[index].deposit(date, amount, desc);
break;
case 'w': //取出现金
index=scanner.nextInt();
amount=scanner.nextDouble();
desc=scanner.nextLine();
accounts[index].withdraw(date, amount, desc);
break;
case 's': //查询各账户信息
for (int i = 0; i < n; i++) {
System.out.print("[" + i + "] ");
accounts[i].show();
System.out.println();
}
break;
case 'c': //改变日期
day=scanner.nextInt();
if (day < date.getDay())
System.out.println("You cannot specify a previous day");
else if (day > date.getMaxDay())
System.out.println("Invalid day");
else
date =new Date(date.getYear(), date.getMonth(), day);
break;
case 'n': //进入下个月
if (date.getMonth() == 12)
date =new Date(date.getYear() + 1, 1, 1);
else
date =new Date(date.getYear(), date.getMonth() + 1, 1);
for (int i = 0; i < n; i++)
accounts[i].settle(date);
break;
}
} while (cmd != 'e');
scanner.close();
}
}
系统测试
体会心得
Java中没有c++的运算符重载功能,需要通过具体方法来实现。
抽象类不能有对象但是可以声明引用其子类。
6.个人个人银行账户管理系统版本0.6(对应第9章记录)
系统需求
使得测试程序操作更便捷
系统设计
使用ArrayList创建账户数组,动态改变数组大小,添加新账户的功能。
系统实现
BANK类
import java.util.ArrayList;
public class BANK6 {
public static void main(String[] args) {
ArrayList<Account> accounts=new ArrayList<Account>();//创建账户数组,元素个数为0
}
}
系统测试
体会心得
学习了Java类库中的 ArrayList 实现了类的对象数组功能
一个共同的父类的对象数组可以统一管理其子类的对象
三、总结
最终功能:
1.一个简单的switch语句,供用户测试各个功能
2.一个日期累加器功能,记录日期的累加值
3.由Account类派生SavingsAccount和CreditAccount两个子类。第一个子类实现基本信息的存储、每月利息计算等功能,第二个子类实现扣除年费、信用卡透支等功能
Java中的输入问题,通过CSDN上各路大佬罗列的输入方法,选择了Scanner来实现不同数据的读入。
Java中没有C++的运算符重载功能,只能通过具体方法来实现。
C++中的floor在Java中需要通过Math.floor调用。
Arrylist声明的对象数组不必关心空间分配问题。
银行系统的六个版本,让我熟悉了Java的基本语法,也体会到了Java和C++的不同的程序设计思想。我也更加了解了面向对象的封装性、继承性、多态性。各种访问权限的定义,继承的使用,父类方法的覆写……