该代码有点长,期间我会穿插点我困惑并解决了的一些知识,那我们开始吧。
老规矩,我们要先思考ATM是怎么运行的,给大家一张图
这样我们便能清楚的知道他为提供我们的服务有哪些,但由于这个是插卡服务直接登录的,而我们是模拟的,所以我们要建立一个注册账户和登陆的功能,这个机器还可以被许多人使用,所以我们还要创造一个账户类,来模拟一个个的账户
用户类的创建,要符合JavaBean的要求
如下
public class Account {
private String userName;
private String loginNumber;
private String cardNumber;
private double money;
private double Limit;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getLoginNumber() {
return loginNumber;
}
public void setLoginNumber(String loginNumber) {
this.loginNumber = loginNumber;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public double getLimit() { return Limit; }
public void setLimit(double transferLimit) {
this.Limit = transferLimit;
}
}
再把我们的模拟注册登陆功能写上,登陆和注册都写成一个个方法
public class ATM {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
ArrayList<Account> accounts=new ArrayList<>();
while (true) {
System.out.println("===========欢迎您进入黑心ATM系统============");
System.out.println("您可以选择:");
System.out.println("1.登陆账户");
System.out.println("2.注册账户");
int command=sc.nextInt();
switch (command){
case 1:
logIn(accounts,sc);
break;
case 2:
register(accounts,sc);
break;
default:
System.out.println("指令错误,请重新输入");
}
}
}
这样,简简单单的开头就结束了
为什么是黑心呢,相信运行过的都知道为什么,这个答案最后说
由于我们的atm提款机刚成立,是没有任何账户的,所以当我们选择1的时候肯定是不允许的,便要退出并提醒我们要创建一个账户的,所以,登陆账户的时候首先要判断账户集合是否为0,如下
private static void logIn(ArrayList<Account> accounts, Scanner sc) {
if (accounts.size()==0){
System.out.println("该系统还未有账户,请您先开通一个吧");
return; //卫语言风格,解决方法的执行
}
}
在上述代码的注释中有一个卫语言,我来解释一下什么叫卫语言
卫语言就是反向思考模式,优化代码,防止臃肿
它可以把我们的视线从多层嵌套的异常处理中解放出来,集中精力处理真正的业务代码,且能够使得代码结构更为清晰可读
emm,简单来说就是直接结束该代码,不往下执行了
所以,我们首先要写注册账户的方法,输入我们的用户名,密码,取款余额后,让系统为我们随机生成一个卡号,但这个卡号要保证与其他用户的卡号不相同,这一点便是这个创建账户中较难的一步了
我先把简单的写上,其中密码要进行一次判断,很好理解的
/**
* 开户
* @param accounts 所有账户的集合
* @param sc 扫描器
*/
private static void register(ArrayList<Account> accounts, Scanner sc) {
System.out.println("==============欢迎您进入开户系统==============");
Account acc=new Account();
System.out.println("请输入用户名");
String name=sc.next();
acc.setUserName(name);
while (true) {
System.out.println("请输入您的密码");
String login=sc.next();
System.out.println("请再一次输入您的密码");
String againLogin=sc.next();
if (againLogin.equals(login)){
acc.setLoginNumber(login);
break;
}else {
System.out.println("您两次输入的密码不相同,请重新输入");
}
}
System.out.println("请输入您的账户每次限额");
double limitMoney=sc.nextDouble();
acc.setLimit(limitMoney);
String num= cardNumber(accounts);
}
在上面代码的最后一行中可以看到我们单独创建了一个生成卡号的方法,这样显得简洁,这个方法代码如下.
/**
* 随即生成不重复的卡号
* @param accounts 所有账户的集合
* @return 生成的卡号
*/
private static String cardNumber(ArrayList<Account> accounts) {
Random r=new Random();
while (true) {
String cardNumber="";
for (int i = 0; i <8 ; i++) {
cardNumber+=r.nextInt(10);
}
Account acc=accountCardNumber(accounts,cardNumber);
if (acc==null){
return cardNumber;
}
}
}
这里也有一个点需要注意,这个方法是String类型的,应该是需要返回的,但我们在方法的末端并未写返回值,但没报错,原因是这样的:
当一个带返回值的方法的内部启动一个死循环可以没有返回值,循环的条件必须为常量布尔值 true ——来自 星辰笑了 博主的总结
这只是一个简单的生成8位随机卡号的代码,但判断是否有与之前账户所重复的我们又重新写了一个方法,这样是因为,在后续中,我们要转账或者其他功能要用得到,这样少些一些代码,就显得不那么臃肿,这个方法如下
/**
* 根据卡号查询集合中是否有账户的卡号与所输入的相同
* @param accounts 所有账户的集合
* @param cardNumber 卡号
* @return 账户对象/null
*/
private static Account accountCardNumber(ArrayList<Account> accounts,String cardNumber){
for (int i = 0; i < accounts.size(); i++) {
Account acc=accounts.get(i);
if (acc.getCardNumber().equals(cardNumber)){
return acc;
}
}
return null;
}
这两个方法下来就生成了一个独一无二的卡号,我们赋值给一个对象并把该对象放在集合中这个注册账户的方法就OK了,如下
String num= cardNumber(accounts);
acc.setCardNumber(num);
accounts.add(acc);
System.out.println("您已开户成功");
System.out.println("欢迎您"+acc.getUserName()+"女士/先生,您的卡号为"+acc.getCardNumber());
把我们的账户登录后
接下来,便要模拟我所给的那一张图的功能了,如下
/**
*
* @param acc 当前用户
* @param sc 扫描器
* @param accounts 用户集合
*/
private static void serve(Account acc, Scanner sc,ArrayList<Account> accounts) {
System.out.println("===============欢迎您!"+acc.getUserName()+"女士/先生===================");
while (true) {
System.out.println("您有以下服务");
System.out.println("1.查询账户");
System.out.println("2.存款");
System.out.println("3.取款");
System.out.println("4.转账");
System.out.println("5.修改密码");
System.out.println("6.退出服务");
System.out.println("7.注销账户");
System.out.println("请选择:");
int command=sc.nextInt();
switch (command){
case 1:
//查询账户
queryAccount(acc);
break;
case 2:
deposit(acc,sc);
//存款
break;
case 3:
//取款
withDrawal(acc,sc);
break;
case 4:
//转账
transferAccounts(accounts,acc,sc);
break;
case 5:
//修改密码
changePassworld(acc,sc);
return; //修改密码后重新登录账户
case 6:
//退出服务
System.out.println("退出成功");
return; //直接结束当前方法,退出服务
case 7:
//注销账户
boolean bo = unSubscribe(accounts,acc,sc);
if (bo==true){
System.out.println("注销成功");
return;
}else {
System.out.println("您已放弃注销");
break;
}
default:
System.out.println("没有该服务,请重新输入");
}
}
}
结合以前的经验,我们知道,每一个指令都是一个个方法,我们现从简单的写起
1.查询账户
/**
* 查询该账户的信息
* @param acc 当前账户
*/
private static void queryAccount(Account acc) {
System.out.println("卡号:"+acc.getCardNumber());
System.out.println("户主:"+acc.getUserName());
System.out.println("余额:"+acc.getMoney());
System.out.println("限额:"+acc.getLimit());
}
6.退出服务,这个直接return就行(卫语言风格),上面已经写了了
下面,我们就按顺序写吧
2.存款,这个只需要注意把钱加入当前账户中就没问题了
/**
* 存款
* @param acc 当前账户
* @param sc 扫描器
*/
private static void deposit(Account acc, Scanner sc) {
System.out.println("您当前的余额为"+acc.getMoney());
System.out.println("请输入您想存款的金额:");
double depositMOney=sc.nextDouble();
acc.setMoney(acc.getMoney()+depositMOney);
System.out.println("存款成功");
}
3.取款,和存款几乎一样,但要注意进行一个判断,如果余额不足的话该怎么做随爱好编写,也可以用卫语言做一些有趣的事情,想我写的这样
/**
* 取款
* @param acc 当前账户
* @param sc 扫描器
*/
private static void withDrawal(Account acc, Scanner sc) {
if (acc.getMoney()<100){
System.out.println("抱歉,您账户的余额不支持使用改机器,请到人工服务区处理");
return;
}
while (true) {
System.out.println("您当前的余额为"+acc.getMoney());
System.out.println("请输入您想取得金额");
Double withDrawalMoney=sc.nextDouble();
if (withDrawalMoney>acc.getMoney()){
System.out.println("余额不足");
}else {
while (true) {
if (withDrawalMoney>acc.getLimit()){
System.out.println("您的取款限度为"+acc.getLimit());
break;
}else {
acc.setMoney(acc.getMoney()-withDrawalMoney);
System.out.println("取款成功");
return;
}
}
}
}
}
4.转账,这个要注意至少有两个账户才行,钱款不足的判断使用可以参照取款中的代码来写,并且要保证转账的卡号不能与自己的相同,但我这一步忘写了,有想法的可以自己下去写一下,并不难,最主要的是,这个代码中用到了前面查询卡号时写的方法,这个铺垫也是等了好久啊 ,代码如下
/**
* 从当前账户转给其他账户
* @param accounts 账户集合
* @param acc 当前账户
* @param sc 扫描器
*/
private static void transferAccounts(ArrayList<Account> accounts, Account acc, Scanner sc) {
if(accounts.size()<2){
System.out.println("当前系统中还未有两个账户,请再注册一个吧");
return;
}
if(acc.getMoney()==0){
System.out.println("您的余额为0,不能进行转账");
return;
}
while (true) {
System.out.println("您当前的余额为"+acc.getMoney());
System.out.println("请输入您想转账的卡号");
String cardNUmber=sc.next();
Account acc1=accountCardNumber(accounts,cardNUmber);
if (acc1==null){
System.out.println("未检索到该卡号,请重新输入");
}else {
String tip="*"+acc1.getUserName().substring(1);
System.out.println("请输入"+tip+"的姓氏");
String s=sc.next();
if (acc1.getUserName().startsWith(s)){
System.out.println("请输入您想转账的金额");
double transferAccountsMoney=sc.nextDouble();
if (transferAccountsMoney>acc.getMoney()){
System.out.println("您的账户余额不支持您所转账的金额,请重新输入");
}else{
acc.setMoney(acc.getMoney()-transferAccountsMoney);
acc1.setMoney(acc1.getMoney()+transferAccountsMoney);
System.out.println("转账成功");
return;
}
}else {
System.out.println("您输入的信息有误");
}
}
}
}
5.修改密码,emm.......和注册密码时的代码大差不差
/**
* 修改当前账户的密码
* @param acc
* @param sc
*/
private static void changePassworld(Account acc, Scanner sc) {
while (true) {
System.out.println("请输入您的密码");
String passWord=sc.next();
if (passWord.equals(acc.getLoginNumber())){
while (true) {
System.out.println("请输入您的新密码");
String newPassWord=sc.next();
System.out.println("请再一次输入您的新密码");
String newPassWord1=sc.next();
if (newPassWord1.equals(newPassWord)){
acc.setLoginNumber(newPassWord1);
System.out.println("您的密码修改成功,请重新登录");
return;
}else {
System.out.println("您两次修改的密码不一样,请重新输入");
}
}
}else {
System.out.println("密码错误,请重新输入");
}
}
}
7.注销账户,其实注销本来直接remove......return直接就得了,但我们虽然是个黑心atm,我们也是有良心滴,让你看看钱在做判断吧,这个方法运行结束后在主方法进行再判断就OK了,前面代码已经展示过了
/**
* 注销账户
* @param accounts 账户集合
* @param acc 所要注销的账户(当前账户)
*/
private static boolean unSubscribe(ArrayList<Account> accounts, Account acc,Scanner sc) {
System.out.println("您的账户还有余额,为:"+acc.getMoney()+"元");
System.out.println("若您仍要注销该账户,请选择T");
System.out.println("若放弃注销,请选择F");
System.out.println("请选择");
String choose=sc.next();
switch (choose){
case "T":
accounts.remove(acc);
return true;
}
return false;
}
这样,一个简简单单的atm提款机就完成了
那我来解答一下上面的答案吧,黑心呢,是因为你执行一个功能后必须把这个功能执行完才能退出,你进到取钱界面后,不取钱出不来,不转账出不来,不取款出不来
所以说,这个东西是不能用于实际的,但重要的是这个思维,我们已经能写出这个大致的框架了,如果想更完善的话,可以继续加代码,我相信我们完全有能力,但我觉得没必要,我们现阶段写这个只是为了体验一番,这个代码已经有点像以后开发业务的东西了,如果有一个数据库的话,这个代码已经算是一个较完整的系统了,体验一番也没什么不好的,而且这个代码可以理解为对前面知识的总结,写一遍巩固理解一下也不错。