博客班级 https://edu.cnblogs.com/campus/ahgc/AHPU-SE-19
作业要求 https://edu.cnblogs.com/campus/ahgc/AHPU-SE-19/homework/11477
作业目标 做出ATM管理系统
学号 3190704214

要求:编写一个ATM管理系统
本文采用面向对象的编程思想,采用Java语言编写了一个ATM管理系统,希望能够尽可能的模仿银行ATM的系统。
具体功能如下:
一:没有银行卡时能够办理银行卡。包括创建账号,设置密码,系统随机生成银行卡号。
二:有了银行卡时能够体验ATM基本的功能。
1、查询余额
2、存款
3、转账
4、取款
5、销户
6、退出当前系统
三:退出整个系统

下面是本系统的完整代码:
银行系统类BankSystem:

package ATM;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class BankSystem {
    private static ATM_Machine atm = new ATM_Machine();
    private static Set<BankCard> allBankCard = new HashSet<>();
    
    public static void addBanCard(BankCard card){
        allBankCard.add(card);
    }
    public static Set getAllBanCard(){
        return allBankCard;
    }

    public static boolean loginATM(ATM_Machine atm){
        Scanner input = new Scanner(System.in);
        String cardNum;
        System.out.println("请输入您的银行卡号:(误操作,按#号键敲回车可再次回到系统主页面)");
        cardNum = input.nextLine();
        if (cardNum.equals("#")){
            start();
        }
        ArrayList<BankCard> allBankCard = new ArrayList<>(BankSystem.getAllBanCard());

        BankCard card = null;
        boolean isExist = false;
        for (int i = 0;i<allBankCard.size();i++){
            if(allBankCard.get(i).getCARDNUM().equals(cardNum)){
                card = allBankCard.get(i);//卡号存在,实例化该银行卡
                isExist = true;
            }
        }
        if (isExist == false){
            System.err.println("您输入的银行卡号不存在,请重新输入");
            loginATM(atm);//递归调用
        }
        String name = card.getHolder().getName();
        System.out.println("欢迎"+name+"使用本公司智能提示ATM系统\n请输入您的银行卡密码:");
        int password = input.nextInt();
        int n = 3;//3次输入密码的机会
        while (n>0) {
            if (!atm.loginCheck(card,password)) {
                n--;
                System.err.println("您输入的密码错入,请重新输入,您还有" + n + "次输入机会!");
                if(n==0){
                    atm.exit();
                    return false;
                }
                password = input.nextInt();
            }else{
                System.out.println("密码正确,正在启动系统···");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                atm.showOperation(card);
                return true;
            }
        }
        atm.exit();
        return false;
    }
    public static void start(){
        System.out.println("\t=============欢迎进入我们的银行系统=============\t");
        System.out.println("1.没有银行卡,我要办理\t\t\t2.已有银行卡,我要通过ATM办理一些业务");
        System.out.println("3.退出整个银行系统");
        System.out.println("请选择您的操作:");
        Scanner input = new Scanner(System.in);
        //只需要输入名字,即可办理银行卡。身份证号,手机号,银行卡号,自动随机生成(只是为了最大限度模拟现实情景的同时,又不让测试时输入太多繁琐的东西)
        String option = input.nextLine();
        if (option.equals("1")){
            Customer customer = new Customer();
            customer.registerIdentify();
            BankCard card = customer.applyBankCard(customer.getIdentityCard(), customer.getPhoneNum());
            //allBankCard.add(card);//将新办理的银行卡存入系统中
            //办理完银行卡会在applyBankCard方法内自动存入系统中
            System.out.println("您的银行卡已经办理完毕,即将再次进入系统···");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            start();
        }else if(option.equals("2")){
            loginATM(atm);
        }else if (option.equals("3")){
            System.out.println("您慢走,感谢你的到来,欢迎下次再来办理业务");
        }else {
            System.err.println("您输入了不合法的字符");
            start();
        }
    }
}

ATM_Machine类:

package ATM;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.Scanner;

public class ATM_Machine {
    private boolean isFirstShow = true;
    public boolean loginCheck(BankCard card,int password){
        int truePassword = card.getPassword();
        if (truePassword == password){
            return true;
        }
        return false;
    }
    public void showTitle(){
        System.out.println("------------ATM系统------------");
    }
    //登录成功后,系统开始工作
    public void showOperation(BankCard card){
        //登录,查询余额,存款,取款,转账,销户,开户,退出
        Scanner input = new Scanner(System.in);
        if(isFirstShow) {
            this.showTitle();
            isFirstShow = false;
        }
        System.out.println("1.查询余额\t\t\t2.存款");
        System.out.println("3.转账    \t\t\t4.取款");
        System.out.println("5.销户    \t\t\t6.退出");
        System.out.println("请输入您要进行的操作:");
        int option = input.nextInt();
        input.nextLine();
        switch (option){
            case 6:exit();
                BankSystem.start();
                break;
            case 1:showBalance(card);
                break;
            case 2:showDeposit(card);
                break;
            case 3:showTransfer(card);
                break;
            case 4:showWithdrawal(card);
                break;
            case 5:closeAccount(card);
                break;
            default:
                System.err.println("您输入了不合法字符,建议您重新输入!");
                showOperation(card);//递归调用
        }
    }
    //退出系统,密码输入错误3次,或者交易完成后,应该退出系统
    public void exit(){
        System.out.println("ATM系统关闭");
    }

    public static void main(String[] args) {
        ATM_Machine a = new ATM_Machine();

    }
    public BigDecimal queryBalance(BankCard card){
        return card.getBalance();
    }
    public void showBalance(BankCard card){
        this.showTitle();
        System.out.println("您的余额为:"+queryBalance(card));
        this.showOperation(card);
    }
    //deposit存款
    public void deposit(BankCard card,int amount){
        card.setBalance(card.getBalance().add(new BigDecimal(amount)));
    }
    public void showDeposit(BankCard card){
        this.showTitle();
        int amount = checkAmountInput("存款",20000);//一次最多存2万
        deposit(card,amount);//执行存款操作
        System.out.println("存款成功,您当前卡内余额为:"+card.getBalance());
        showOperation(card);
    }
    //取款:withdrawal
    public void withdrawal(BankCard card,int amount){
        card.setBalance(card.getBalance().subtract(new BigDecimal(amount)));
    }
    public void showWithdrawal(BankCard card){
        this.showTitle();
        int amount = checkAmountInput("取款",3000);//一次最多存2万
        withdrawal(card,amount);//执行存款操作
        System.out.println("取款成功,您当前卡内余额为:"+card.getBalance());
        showOperation(card);
    }
    //销户:closing an account
    public void closeAccount(BankCard card ){
        Scanner input = new Scanner(System.in);
        System.err.println("销户是一个危险操作,你的所有余额将被清空,卡号将会回收,您确定要继续吗?");
        System.out.println("1.是的,继续\t2.取消该操作");
        String s = input.nextLine();
        if (s.equals("1")){
            BankSystem.getAllBanCard().remove(card);
            card = null;
            System.out.println("您已经成功销户");
            exit();
            BankSystem.start();
        }else if (s.equals("2")){
            showOperation(card);
        }else{
            System.err.println("您输入了不合法字符!!!\n麻烦您重复确认您的操作:");
            closeAccount(card);//递归调用
        }
    }

    //转账:transfer
    public void transfer(BankCard myCard,BankCard anotherCard,int amount){
        myCard.setBalance(myCard.getBalance().subtract(new BigDecimal(amount)));
        anotherCard.setBalance(anotherCard.getBalance().add(new BigDecimal(amount)));
    }
    public void showTransfer(BankCard myCard){
        Scanner input = new Scanner(System.in);
        System.out.println("请输入对方的银行卡号:");
        String cardNum = input.nextLine();
        ArrayList<BankCard> allBankCard = new ArrayList<>(BankSystem.getAllBanCard());
        BankCard anotherCard = null;
        boolean isExist = false;
        for (int i = 0;i<allBankCard.size();i++){
            if(allBankCard.get(i).getCARDNUM().equals(cardNum)){
                anotherCard = allBankCard.get(i);//卡号存在,实例化该银行卡
                isExist = true;
                break;
            }
        }
        if (isExist == false){
            System.err.println("您输入的银行卡号不存在,请重新输入");
            showTransfer(myCard);//递归调用
        }
        int amount = checkAmountInput("转账",5000);//转账每次只能转5000
        if (myCard.getBalance().compareTo(new BigDecimal(amount)) == -1){
            System.err.println("对不起,您的余额不足");
            System.out.println();
            showOperation(myCard);
        }
        transfer(myCard,anotherCard,amount);
        System.out.println("转账成功!请继续您的操作");
        showOperation(myCard);
    }
    //====================================
    private int checkAmountInput(String operation,int maxAmount){
        Scanner input = new Scanner(System.in);
        int amount;
        System.out.println("请输入您要"+operation+"的金额(一次不得超过"+maxAmount+"):");
        while (true) {
            try {
                amount = input.nextInt();
                input.nextLine();
                if (amount % 100 != 0) {
                    System.err.println(operation+"数目必须是100的整数倍,请重新输入:");
                    continue;
                }
                if (amount > maxAmount) {
                    System.err.println(operation+"数目一次不得超过"+maxAmount+",请重新输入:");
                    continue;
                }
                break;
            } catch (InputMismatchException e) {
                input.nextLine();//当用户输入的类型不匹配,清空输入栈
                System.err.println(operation+"数额必须是整数,请重新输入:");
            }
        }
        return amount;
    }
    //===================================================
}

银行卡BankCard类:

package ATM;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Random;

public class BankCard {
    /*对于static关键字的理解:如果某一个属性,设置了static修饰符,就意味着,不管创建多少个对象,该属性却只有一份,被所有对象所共享
    一旦某一个对象修改了这个属性,其他对象的这个属性都会改变,因为这个属性是公共的。
    所以:  千万要注意:static修饰符不可以滥用!!
     */
    private BigDecimal balance = new BigDecimal("0");//余额
    private String CARDNUM;//卡号,一般是19位的,纯数字的
    private Customer holder;//持有者
    private int password;//密码

    public static boolean checkIsExistThisBankCardNum(String bankCardNum){
        boolean flag = false;
        ArrayList<BankCard> allBanCard = new ArrayList<>(BankSystem.getAllBanCard());
        for (int i = 0;i<allBanCard.size();i++){
            while (allBanCard.get(i).getCARDNUM().equals(bankCardNum)){
                flag = true;//存在这个银行卡号了,需要重新生成,虽然概率很低。
            }
        }
        return flag;
    }

    public BankCard(String IDNum,String phoneNum,int password){
        //需要一个身份证号,和一个手机号码
        this.holder = IdentityManageSystem.getIdentifyMsg().get(IDNum);
        String cardNum = new GenerateRandomString().generateIntString(19);//19位随机数字
        while (checkIsExistThisBankCardNum(cardNum)){
            //存在这个银行卡号了,需要重新生成,虽然概率很低。
            cardNum = new GenerateRandomString().generateIntString(19);//19位随机数字
        }
        this.CARDNUM = cardNum;
        this.password = password;
        //设置开户随机金额(模拟一下)
        Double money = new Random().nextDouble()*100+1;
        DecimalFormat df = new DecimalFormat("#.00");
        String bd = df.format(money);
        this.balance = new BigDecimal(bd);
    }
    public boolean equals(Object obj){
        if (this==obj){
            return true;
        }
        if (obj instanceof BankCard){
            BankCard newCard = (BankCard)obj;
            if (newCard.getCARDNUM().equals(this.CARDNUM))
                //只要卡号相同,就认为是同一张银行卡
                return true;
        }
        return false;
    }
    public int hashCode(){
        return this.CARDNUM.hashCode();
    }

    public BigDecimal getBalance() {
        return balance;
    }

    public String getCARDNUM() {
        return CARDNUM;
    }

    public Customer getHolder() {
        return holder;
    }

    public void setBalance(BigDecimal balance) {
        this.balance = balance;
    }

    public void setPassword(int password) {
        this.password = password;
    }

    public int getPassword() {
        return password;
    }
}

顾客Customer类:

package ATM;

import java.util.InputMismatchException;
import java.util.Scanner;

public class Customer {
    private IdentityCard identityCard;//身份证
    private String phoneNum;//手机号
    private String name;//客户的姓名
    private int age;//年龄

    {
        GenerateRandomString g = new GenerateRandomString();
        phoneNum = "1"+ g.generateIntString(10);//第一个数是1,后面10位随机的电话号码
    }

    public Customer(){
        Scanner input = new Scanner(System.in);
        System.out.println("您好,请问您叫什么名字?:");
        String name = input.nextLine();
        this.name = name;
    }
    public Customer(String IDNum){

        //判断身份证号对不对,不是在这里判断!
    }
    //注册身份证
    public IdentityCard registerIdentify(){
        if (this.getName()!=null){
            IdentityCard card = new IdentityCard(this);
            this.identityCard = card;
            IdentityManageSystem.getIdentifyMsg().put(card.getIDNum(),this);//注册完身份证,把键值对身份证号-姓名放入身份管理系统
            return this.identityCard;
        }
        System.err.println("您还没有名字呢");
        return null;
    }
    public BankCard applyBankCard(IdentityCard card,String phoneNum){
        Scanner input = new Scanner(System.in);

        System.out.println("顾客"+this.getName()+"身份证号:"+this.getIdentityCard().getIDNum()+
                "电话号码:"+this.getPhoneNum()+"\n正在申请银行卡···\n请设置您的银行卡密码(规则:密码必须是6位纯数字):");
        int password;
        while (true) {
            try {
                password = input.nextInt();
                break;
            } catch (InputMismatchException e) {
                input.nextLine();//把多余的回车读取走
                System.err.println("您输入的密码不合法,请重新输入:");
            }
        }
        String pswStr = String.valueOf(password);
        while (pswStr.length()!=6) {
            System.err.println("您输入的密码长度不是6位,请重新输入:");
            password = input.nextInt();
            pswStr = String.valueOf(password);
        }

        //需要一个身份证(而不是号码),和一个手机号码
        BankCard bankCard = new BankCard(card.getIDNum(), phoneNum,password);
//        BankSystem.getAllBanCard().add(bankCard);//办理完后自动添加到系统库中
        BankSystem.addBanCard(bankCard);
        System.out.println("银行卡办理完毕,您的卡号是:"+bankCard.getCARDNUM()+"\n请妥善保管您的银行卡,牢记密码!!!");
        return bankCard;
    }

    public IdentityCard getIdentityCard() {
        if(this.identityCard==null){
            System.err.println("您还没有注册身份证,赶快申领一个吧!");
        }
        return identityCard;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public String getName() {
        return name;
    }
}

身份证类IdentityCard:

package ATM;

/**
 * 这个类用来描述身份证
 */
public class IdentityCard {
    private String IDNum;//身份证号,一般是18位的,最后一位可以是字母
    private Customer holder;//持有者

    public IdentityCard(Customer holder) {
        //构建一个身份证,必须有持有者才行
        //身份证号,我帮你随机生成
        GenerateRandomString g = new GenerateRandomString();
        this.IDNum = g.generateIDNum();
        this.holder = holder;
    }

    public  String getIDNum() {
        return IDNum;
    }

    public  Customer getHolder() {
        return holder;
    }
}

身份管理系统类IdentityManageSystem :

package ATM;

import java.util.HashMap;
import java.util.Map;

public class IdentityManageSystem {
    private static Map<String,Customer> identityMsg = new HashMap<>();
    public static Map<String,Customer> getIdentifyMsg(){
        return identityMsg;
    }
}

为了尽可能使得随机生成的身份证号码和手机号码和银行卡号切合实际,还手动设计了一个工具类,用来生成随机的号码。
自设计的工具类GenerateRandomString:

package ATM;

import java.util.Random;

public  class GenerateRandomString {
    private char[] str = "qwertyuiopasdfghjklzxcvbnm147258369".toCharArray();
    private String[] head = new String []{"140829","142732"};//两种常见的身份证号头部

    public String generateIntString(int length){
        StringBuilder  intString = new StringBuilder();
        for (int i = 0;i<length;i++){
            intString.append(new Random().nextInt(10));
        }
        return intString.toString();
    }
    public String generateIDNum(){
        String idHead = head[new Random().nextInt(2)];//身份证号头部
        String year = String.valueOf((int)(Math.random()*121)+1900);//1900--2020,1900到2021但不包括2021
        String month = String.valueOf((int)(Math.random()*12)+1);//1到13但不包括13
        month = this.complement(month);
        String day = String.valueOf((int)(Math.random()*30)+1);//1到31但不包括31
        day = this.complement(day);
        String randomstr = generateIntString(3);//身份证的后4位的前3位随机数字
        String last = String.valueOf(str[new Random().nextInt(str.length)]);//身份证的最后一位,随机字母或数字
        StringBuilder builder = new StringBuilder();
        builder.append(idHead).append(year).append(month).append(day).append(randomstr).append(last);
        return builder.toString();
    }
    private String complement(String monthOrDay){
        //补全月份或日期,如果字符串长度小于2,就往前面加个0补全
        if (monthOrDay.length()==1){
            String result = "0".concat(monthOrDay);
            return result;
        }
        return monthOrDay;
    }
}

main方法里通过调用一行代码,完成整个业务流程的顺序调用。
测试类:

package ATM;

public class MyTest {
    public static void main(String[] args) {
        BankSystem.start();
    }
}

其中涉及到的知识,包括但不限于static修饰符的使用,集合的使用,权限修饰符的控制,类与类之间关系的设计,类构建的属性初始化控制,Scanner输入控制,工具类BigDecimal和DecimalFormat的使用,随机数的生成等。
但其实最难的还是设计,类与类之间关系的设计,类的属性和方法的设计,它们都至关重要,它们可以说是面向对象编程的核心。一旦属性或方法设计得不合理,程序即使可以运行,但它的开发过程必然是违背人的正常思维的,也会使得后期的更改和维护变得异常棘手。
编写这个程序相对来讲还是很有挑战性的,虽然用到的知识不多,但也很考究你的设计能力和思维能力。

下面是程序主要运行界面:

示例截图:



个人小结:

psp2.1 任务内容 计划完成需要的时间(min) 实际完成需要的时间(min)
Planning 计划 160 200
Estimate 估计这个任务需要多少时间,并规划大致工作步骤 10 20
Development 开发 120 150
Analysis 需求分析(包括学习新技术) 12 5
Design Spec 生成设计文档 5 5
Design Review 设计复审 5 5
Coding Standard 代码规范 5 3
Design 具体设计 10 12
Coding 具体编码 36 21
Code Review 代码复审 5 7
Test 测试(自我测试,修改代码,提交修改) 10 15
Reporting 报告 9 6
Test Report 测试报告 3 2
Size Measurement 计算工作量 2 1
Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 3 3