C#模拟银行ATM系统源码与逻辑解析

栗子
栗子
发布时间:2026-10-14| 4人浏览过
原创

本文详细介绍了一个使用 C# 编写的银行 ATM 系统模拟项目。通过定义抽象基类 Account 及其子类 SavingAccount 和 CreditAccount,实现了不同账户类型的差异化取款逻辑;利用 Bank 类统一管理账户生命周期与资金流水;结合 Program 类的控制台交互,完整演示了从用户开户、身份验证到存款、取款及额度管理的业务闭环。

结果或目标

本示例旨在通过控制台应用程序模拟真实银行的业务逻辑,展示 C# 在面向对象编程(OOP)中的核心特性应用。主要实现的功能包括:

  • 多态性:不同账户类型对 Withdraw 方法有不同的行为实现。
  • 封装性:银行账户的核心状态(如密码、余额)由内部逻辑保护,通过受控方法访问。
  • 集合管理:Bank 类作为中央管理器,统一处理所有账户的注册、查找与统计。
  • 业务流程:覆盖开户、登录认证、存取款校验、信用额度设置等典型金融场景。

准备条件

开发此项目需要基础的 C# 编程环境:

  • 操作系统:Windows / Linux / macOS(.NET 兼容环境)。
  • 开发工具:Visual Studio, VS Code 或 JetBrains Rider。
  • 运行时:.NET Framework 4.x 或 .NET Core / .NET 5+。
  • 输入方式:标准输入输出(Console.ReadLine / Console.WriteLine)。

真实操作顺序

第1步:构建抽象账户基类 Account

目的:提取所有账户共有的属性与方法,定义规范。

代码实现:

using System;
namespace ATM
{
    abstract class Account
    {
        // 基本属性
        protected long id;           // 账户号码
        protected string password;   // 密码
        protected string name;       // 姓名
        protected string personId;   // 身份证
        protected string email;      // 邮箱
        protected double balance;    // 余额

        public long ID { get { return id; } set { id = value; } }
        public string PassWord { get { return password; } set { password = value; } }
        public string Name { get { return name; } set { name = value; } }
        public string PersonId { get { return personId; } set { personId = value; } }
        public string Email { get { return email; } set { email = value; } }
        public double Balance { get { return balance; } set { balance = value; } }

        private static long idBuilder = 100000;
        public static long IdBuilder { get { return idBuilder; } set { idBuilder = value; } }

        // 公共存款方法
        public void Deposit(double sum)
        {
            if (sum < 0)
                throw new InvalidOperationException("输入的金额为负数");
            balance += sum;
        }

        // 抽象取款方法,由子类实现具体逻辑
        public abstract void Withdraw(double sum);

        public Account() { }

        public Account(string password, string name, string personId, string email)
        {
            this.id = ++idBuilder;
            this.password = password;
            this.name = name;
            this.personId = personId;
            this.email = email;
        }
    }
}

第2步:实现信用账户 CreditAccount

目的:实现允许透支特性的子类,重写取款逻辑以校验是否超出(余额+额度)。

入口/动作:继承 Account,添加 ceiling 属性。

class CreditAccount : Account
{
    protected double ceiling; // 透支额度
    public double Ceiling 
    { 
        get { return ceiling; } 
        set { ceiling = value; } 
    }

    public CreditAccount(string password, string name, string personId, string email)
        : base(password, name, personId, email) { }

    public override void Withdraw(double sum)
    {
        if (sum < 0)
            throw new InvalidOperationException("输入的金额为负数!");
        
        // 关键逻辑:总额不能超过 余额 + 信用额度
        if (sum > balance + ceiling)
            throw new InvalidOperationException("金额已经超出余额和透支度的总数了");
            
        balance -= sum;
    }
}

第3步:实现储蓄账户 SavingAccount

目的:实现普通账户逻辑,不支持透支,取款金额不得超过当前余额。

class SavingAccount : Account
{
    public SavingAccount(string password, string name, string personId, string email)
        : base(password, name, personId, email) { }

    public override void Withdraw(double sum)
    {
        if (sum < 0)
            throw new InvalidOperationException("输入的金额为负数!");
            
        // 关键逻辑:不能透支
        if (sum > balance)
            throw new InvalidOperationException("金额已经超出金额!");
            
        balance -= sum;
    }
}

第4步:构建银行管理中心 Bank 类

目的:管理所有账户对象的集合,提供开户、查找、存取款及统计接口。

重要参数:List<Account> 存储所有账户,支持多态调用。

class Bank
{
    private List<Account> accounts;
    public List<Account> Accounts 
    { 
        get { return accounts; } 
        set { accounts = value; } 
    }

    private int currentAccountNumber;
    public int CurrentAccountNumber 
    { 
        get { return currentAccountNumber; } 
        set { currentAccountNumber = value; } 
    }

    public Bank()
    {
        accounts = new List<Account&gt();
    }

    // 开户逻辑
    public Account OpenAccount(string password, string confirmationPassword, string name, string personId, string email, int typeOfAccount)
    {
        Account newAccount;
        if (!password.Equals(confirmationPassword))
            throw new InvalidOperationException("两次密码输入的不一致");

        switch (typeOfAccount)
        {
            case 1: newAccount = new SavingAccount(password, name, personId, email); break;
            case 2: newAccount = new CreditAccount(password, name, personId, email); break;
            default: throw new ArgumentOutOfRangeException("账户类型是1和2之间的整数");
        }
        accounts.Add(newAccount);
        return newAccount;
    }

    // 私有辅助方法:根据ID获取账户
    private Account GetAccountByID(long id)
    {
        foreach (Account account in accounts)
        {
            if (account.ID == id)
                return account;
        }
        return null;
    }

    // 登录验证
    public Account SignIn(long id, string password)
    {
        foreach (Account account in accounts)
        {
            if (account.ID == id && account.PassWord.Equals(password))
                return account;
        }
        throw new InvalidOperationException("用户名或者密码不正确,请重试");
    }

    // 存款
    public Account Deposit(long id, double sum)
    {
        Account account = GetAccountByID(id);
        if (account != null)
        {
            account.Deposit(sum);
            return account;
        }
        throw new InvalidOperationException("非法账户!");
    }

    // 取款
    public Account Withdraw(long id, double sum)
    {
        Account account = GetAccountByID(id);
        if (account != null)
        {
            account.Withdraw(sum);
            return account;
        }
        throw new InvalidOperationException("非法账户!");
    }

    // 设置信用额度
    public Account SetCeiling(long id, double newCeiling)
    {
        Account account = GetAccountByID(id);
        try
        {
            // 尝试转换为CreditAccount,失败则说明是普通储蓄账户
            (account as CreditAccount).Ceiling = newCeiling;
            return account;
        }
        catch (Exception)
        {
            throw new InvalidOperationException("次账户不是信用账户!");
        }
        throw new InvalidOperationException("非法账户");
    }

    // 统计总余额
    public double GetTotalBalance()
    {
        double totalBalance = 0;
        foreach (Account account in accounts)
        {
            totalBalance += account.Balance;
        }
        return totalBalance;
    }

    // 统计总信用额度
    public double GetTotalCeiling()
    {
        double totalCeiling = 0;
        foreach (Account account in accounts)
        {
            if (account is CreditAccount)
            {
                totalCeiling += (account as CreditAccount).Ceiling;
            }
        }
        return totalCeiling;
    }
}

第5步:实现控制台交互 Program

目的:提供用户界面,循环接收指令并调度 Bank 类的方法。

关键流程:

  1. 初始化:创建 Bank icbc 实例。
  2. 菜单循环:使用 switch-case 监听数字键选择功能。
  3. 开户:校验姓名、身份证长度(18位)、密码一致性,区分账户类型存入银行。
  4. 交易:需先通过 SignIn 获取账户实体,再进行存取款操作。
class Program
{
    static Account SignIn(Bank icbc)
    {
        Console.WriteLine("\nPlease input your account ID");
        long id;
        try
        {
            id = long.Parse(Console.ReadLine());
        }
        catch (FormatException)
        {
            Console.WriteLine("Invalid account ID!");
            return null;
        }

        Console.WriteLine("Please input your password");
        string password = Console.ReadLine();
        Account account;
        try
        {
            account = icbc.SignIn(id, password);
        }
        catch (InvalidOperationException ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
        return account;
    }

    static void Main(string[] args)
    {
        Bank icbc = new Bank();
        while (true)
        {
            Console.WriteLine("Please choose the service your need");
            Console.WriteLine("(1) Open a new account");
            Console.WriteLine("(2) Desposit");
            Console.WriteLine("(3) Withdraw");
            Console.WriteLine("(4) Set Ceiling");
            Console.WriteLine("(5) Get Total Balance");
            Console.WriteLine("(6) Get Total Ceiling");
            Console.WriteLine("(0) Exit");
            string choice;
            choice = Console.ReadKey().KeyChar.ToString();

            switch (choice)
            {
                case "1":
                {
                    // 开户逻辑...
                     // ...省略部分控制台输入代码保持一致性...
                     // 实际运行时需要补全原代码中case 1内读取name, email, password等细节
                    break;
                }
                case "2":
                {
                    Account account = SignIn(icbc);
                    if (account == null) break;
                    int amount;
                    while (true)
                    {
                        Console.WriteLine("Please input the amount;");
                        try { amount = int.Parse(Console.ReadLine()); break; }
                        catch { Console.WriteLine("Invalid input!"); continue; }
                    }
                    try
                    {
                        icbc.Deposit(account.ID, amount);
                        Console.WriteLine("Deposit successfully,our balance is{0}元",account.Balance);
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    break;
                }
                case "0": return;
                default: Console.WriteLine("\nInvalid option,plwase choose again!"); break;
            }
        }
    }
}

完成判断

程序成功编译且无语法错误;控制台启动后能显示主菜单;正确输入ID和密码可登录并执行存取款;新开信用账户后可成功设置 Ceiling;查询 GetTotalBalance 时数值实时刷新。若涉及数据库持久化,目前仅存储在内存 List<Account> 中,重启即丢失。

原文有依据的排错

类型转换异常:在 SetCeiling 方法中,如果传入的 id 对应的账户是 SavingAccount,强制转换为 CreditAccount 会导致异常。代码通过 try-catch 捕获该异常并抛出友好的 "次账户不是信用账户!" 提示。

输入格式错误:在输入金额或ID时,使用了 int.Parse 或 long.Parse,包裹在 try-catch 中以防止非数字字符导致程序崩溃。

简要总结

这是一个经典的面向对象练习案例。通过 Account 基类规范接口,利用 SavingAccount 和 CreditAccount 展现多态差异,Bank 类集中管理状态,清晰展示了封装、继承和多态在构建小型业务系统时的协作关系。以上就是C#模拟银行ATM系统的详细内容,更多关于C#面向对象编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。