C#實(shí)現(xiàn)模擬ATM自動(dòng)取款機(jī)功能
本篇用C#實(shí)現(xiàn)ATM自動(dòng)取款機(jī)的一些功能。面臨的第一個(gè)問(wèn)題是:如何把與自動(dòng)取款機(jī)相關(guān)的有形的、無(wú)形的方面抽象出來(lái)。
(1)關(guān)于用戶帳號(hào)的類:Account
該類包含與卡號(hào)、密碼、可用余額、總余額相關(guān)的字段和屬性,比提供了存款和取款的方法。
namespace MyATM
{
/// <summary>
/// 用戶帳號(hào)
/// </summary>
public class Account
{
private int accountNumber; //卡號(hào)
private int pin;//用來(lái)驗(yàn)證
private decimal availableBalance;//可用余額
private decimal totalBalance;//總余額
public Account(int theAccountNumber, int thePIN, decimal theAvailableBalance, decimal theTotalBalance)
{
accountNumber = theAccountNumber;
pin = thePIN;
availableBalance = theAvailableBalance;
totalBalance = theTotalBalance;
}
//卡號(hào) 只讀屬性
public int AccountNumber
{
get { return accountNumber; }
}
//可提取余額 只讀屬性
public decimal AvailableBalance
{
get { return availableBalance; }
}
//總余額 只讀屬性
public decimal TotalBalance
{
get { return totalBalance; }
}
//驗(yàn)證輸入密碼是否正確
public bool ValidatePIN(int userPIN)
{
return (userPIN == pin);
}
//存款
public void Credit(decimal amount)
{
totalBalance += amount;
}
//取款
public void Debit(decimal amount)
{
availableBalance -= amount;
totalBalance -= amount;
}
}
}(2)關(guān)于銀行數(shù)據(jù)庫(kù)的類:BankDatabase
該類維護(hù)著一個(gè)Account類型的數(shù)組,并提供驗(yàn)證用戶,查詢余額,存款、取款等方法。
namespace MyATM
{
/// <summary>
/// 銀行數(shù)據(jù)庫(kù)
/// </summary>
public class BankDatabase
{
private Account[] accounts;
public BankDatabase()
{
accounts = new Account[2];
accounts[0] = new Account(12345,54321,1000.00M, 1200.00M);
accounts[1] = new Account(98765, 56789, 200.00M, 200.00M);
}
//根據(jù)用戶銀行卡號(hào)獲取該用戶帳號(hào)
private Account GetAccount(int accountNumber)
{
foreach (Account currentAccount in accounts)
{
if (currentAccount.AccountNumber == accountNumber)
{
return currentAccount;
}
}
return null;
}
//驗(yàn)證用戶,根據(jù)卡號(hào)和密碼
public bool AuthenticateUser(int userAccountNumber, int userPIN)
{
//先根據(jù)卡號(hào)獲取帳號(hào)
Account userAccount = GetAccount(userAccountNumber);
if (userAccount != null)
{
return userAccount.ValidatePIN(userPIN);
}
else
{
return false;
}
}
//返回可提取的余額,根據(jù)卡號(hào)
public decimal GetAvailableBalance(int userAccountNumber)
{
Account userAccount = GetAccount(userAccountNumber);
return userAccount.AvailableBalance;
}
//返回所有余額
public decimal GetTotalBalance(int userAccountNumber)
{
Account userAccount = GetAccount(userAccountNumber);
return userAccount.TotalBalance;
}
//給用戶存款
public void Credit(int userAccountNumber, decimal amount)
{
Account userAccount = GetAccount(userAccountNumber);
userAccount.Credit(amount);
}
//給用戶取款
public void Debit(int userAccountNumber, decimal amount)
{
Account userAccount = GetAccount(userAccountNumber);
userAccount.Debit(amount);
}
}
}(3)關(guān)于ATM屏幕顯示的類:Screen
該類提供了分行顯示、不分行顯示、顯示金額這3個(gè)方法。
using System;
namespace MyATM
{
/// <summary>
/// 屏幕
/// </summary>
public class Screen
{
//顯示不分行的信息
public void DisplayMessage(string message)
{
Console.Write(message);
}
//顯示分行的信息
public void DisplayMessageLine(string message)
{
Console.WriteLine(message);
}
//顯示金額
public void DisplayDollarAmmount(decimal amount)
{
Console.Write("{0:c}", amount);
}
}
}(4)關(guān)于ATM鍵盤(pán)的類:Keypad
該類的職責(zé)很明確,就是把輸入的數(shù)字返回。
using System;
namespace MyATM
{
/// <summary>
/// 輸入鍵盤(pán)
/// </summary>
public class Keypad
{
//根據(jù)用戶輸入,返回一個(gè)整型
public int GetInput()
{
return Convert.ToInt32(Console.ReadLine());
}
}
}(5)關(guān)于進(jìn)鈔、出鈔口的類:DepositSlot
該類主要是確認(rèn)進(jìn)鈔、出鈔口是否收到錢(qián),默認(rèn)返回true。
namespace MyATM
{
/// <summary>
/// 存款槽
/// </summary>
public class DepositSlot
{
//判斷是否收到錢(qián)
public bool IsMoneyReceived()
{
return true;
}
}
}(6)關(guān)于ATM出錢(qián)的類:CashDispendser
就像在現(xiàn)實(shí)生活中,ATM中肯定會(huì)預(yù)先存放一些人民幣,出錢(qián)的時(shí)候首先要判斷余額是否足夠,如果足夠就把ATM中當(dāng)前的票數(shù)做適當(dāng)?shù)臏p法。
namespace MyATM
{
/// <summary>
/// ATM取款
/// </summary>
public class CashDispendser
{
private const int INITIAL_COUNT = 500;//初始票數(shù)
private int billCount;//當(dāng)前取款機(jī)內(nèi)票數(shù)
public CashDispendser()
{
billCount = INITIAL_COUNT;
}
//出錢(qián)
public void DispenseCash(decimal amount)
{
int billsRequired = ((int)amount) / 20;
billCount -= billsRequired;
}
//判斷是否有余額
public bool IsSufficientCashAvailable(decimal amount)
{
//假設(shè)取款機(jī)內(nèi)鈔票的面值是20
int billsRequired = ((int) amount)/20;
return (billCount >= billsRequired);
}
}
}(7)關(guān)于事務(wù)的基類:Transaction
我們可以回想一下,現(xiàn)實(shí)生活中,ATM的主要功能包括:查詢余額,取款,存款等。雖然執(zhí)行的過(guò)程不盡相同,但所有的這些事務(wù)包含相同的部分:比如說(shuō),必須有屏幕必須針對(duì)卡號(hào)一定和數(shù)據(jù)庫(kù)打交道,等等。于是,我們先抽象出一個(gè)有關(guān)事務(wù)的基類,這個(gè)基類是不需要被實(shí)例化的,所以把它定義成抽象類。如下:
namespace MyATM
{
/// <summary>
/// ATM事務(wù)
/// </summary>
public abstract class Transaction
{
private int accountNumber;//卡號(hào)
private Screen userScreen;//屏幕
private BankDatabase database;//銀行數(shù)據(jù)庫(kù)
public Transaction(int userAccount, Screen theScreen, BankDatabase theDatabase)
{
accountNumber = userAccount;
userScreen = theScreen;
database = theDatabase;
}
//銀行卡號(hào)屬性 只讀
public int AccountNumber
{
get { return accountNumber; }
}
//用戶使用的屏幕屬性 只讀
public Screen UserScreen
{
get { return userScreen; }
}
//用戶使用的數(shù)據(jù)庫(kù) 只讀
public BankDatabase Database
{
get { return database; }
}
//抽象方法 子類必須重寫(xiě)
public abstract void Execute();
}
}以上,在其它有關(guān)事務(wù)的派生類中都可以訪問(wèn)到基類的只讀屬性,并且子類必須重寫(xiě)抽象基類的Execute方法。
(8)關(guān)于查詢的事務(wù)類:BalanceInquiry
該類調(diào)用Database類的方法查詢可用余額和總余額。
namespace MyATM
{
/// <summary>
/// ATM余額查詢事務(wù)
/// </summary>
public class BalanceInquiry : Transaction
{
public BalanceInquiry(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase) : base(userAccountNumber, atmScreen, atmBankDatabase){}
public override void Execute()
{
//獲取可用余額
decimal availableBalance = Database.GetAvailableBalance(AccountNumber);
//獲取總余額
decimal totalBalance = Database.GetTotalBalance(AccountNumber);
//打印信息
UserScreen.DisplayMessageLine("\n余額信息為:");
UserScreen.DisplayMessage(" -可用余額為:");
UserScreen.DisplayDollarAmmount(availableBalance);
UserScreen.DisplayMessage("\n -總余額為:");
UserScreen.DisplayDollarAmmount(totalBalance);
UserScreen.DisplayMessageLine("");
}
}
}(9)關(guān)于取款的事務(wù)類:Withdrawl
當(dāng)用戶輸入取款的金額,該類必須要做的事情是:在用戶的銀行數(shù)據(jù)庫(kù)中和ATM上做相應(yīng)的減法,還必須考慮什么時(shí)候退出循環(huán),用戶是否按了取消鍵,用戶賬戶上是否有余額,以及ATM中是否有余額。
namespace MyATM
{
/// <summary>
/// ATM取款事務(wù)
/// </summary>
public class Withdrawl : Transaction
{
private decimal amount;//取款金額
private Keypad keypad;//鍵盤(pán)
private CashDispendser cashDispenser;//出錢(qián)
private const int CANCELED = 6;//對(duì)應(yīng)菜單中的取消
public Withdrawl(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase, Keypad atmKeypad,
CashDispendser atmCashDispenser) : base(userAccountNumber, atmScreen, atmBankDatabase)
{
keypad = atmKeypad;
cashDispenser = atmCashDispenser;
}
public override void Execute()
{
bool cashDispensed = false; //表示還沒(méi)出錢(qián)
bool transactionCanceled = false; //表示不取消事務(wù)
do
{
int selection = DisplayMenuOfAmounts();
if (selection != CANCELED)//如果用戶沒(méi)有按取消
{
amount = selection; //確定取款金額
//根據(jù)卡號(hào)獲取可用余額
decimal availableBalance = Database.GetAvailableBalance(AccountNumber);
if (amount <= availableBalance)//如果取款金額小于可用余額
{
if (cashDispenser.IsSufficientCashAvailable(amount))//如果ATM余額足夠
{
Database.Debit(AccountNumber, amount);//賬戶扣款
cashDispenser.DispenseCash(amount);//ATM扣款
cashDispensed = true;//跳出循環(huán)
UserScreen.DisplayMessageLine("\n您可以拿著錢(qián)離開(kāi)了~~");
}
else//如果ATM余額不夠
{
UserScreen.DisplayMessageLine("\n ATM余額不足." + "\n\n請(qǐng)?zhí)崛「〉慕痤~~~");
}
}
else
{
UserScreen.DisplayMessageLine("\n 賬戶余額不足." + "\n\n請(qǐng)?zhí)崛「〉慕痤~~~");
}
}
else //如果用戶按了取消,提示正在退出并跳出循環(huán)
{
UserScreen.DisplayMessageLine("\n正在取消......");
transactionCanceled = true;
}
} while ((!cashDispensed) && (!transactionCanceled));
}
/// <summary>
/// 顯示提款金額
/// </summary>
/// <returns></returns>
private int DisplayMenuOfAmounts()
{
int userChoice = 0; //默認(rèn)提款金額
int[] amounts = {0, 20, 40, 60, 100, 200};
while (userChoice ==0)
{
//顯示菜單
UserScreen.DisplayMessageLine("\nWithdrawal options:");
UserScreen.DisplayMessageLine("1-20元");
UserScreen.DisplayMessageLine("2-40元");
UserScreen.DisplayMessageLine("3-60元");
UserScreen.DisplayMessageLine("4-100元");
UserScreen.DisplayMessageLine("5-200元");
UserScreen.DisplayMessageLine("6-取消操作");
UserScreen.DisplayMessage("\n輸入數(shù)字(1-6),選擇選項(xiàng):");
int input = keypad.GetInput();
switch (input)
{
case 1: case 2: case 3: case 4: case 5:
userChoice = amounts[input];
break;
case CANCELED:
userChoice = CANCELED;
break;
default:
UserScreen.DisplayMessageLine("\n輸入無(wú)效數(shù),請(qǐng)重試~~");
break;
}
}
return userChoice;
}
}
}以上,
維護(hù)的amount變量表示的是取款金額,在每次用戶輸入提款金額后為該變量賦值。
Keypad類型的變量kepad和CashDispendser類型的變量cashDispenser需要在構(gòu)造函數(shù)中為其賦初值,而這2個(gè)因素是在取款時(shí)特有的,在事務(wù)的抽象基類中不需要考慮這2個(gè)因素。
通過(guò)DisplayMenuOfAmounts方法,會(huì)向用戶顯示一些面值,以及對(duì)應(yīng)的數(shù)字鍵,然后根據(jù)用戶按下的數(shù)字鍵返回對(duì)應(yīng)的、int類型的面值。
在Execute方法中,首先循環(huán)的2個(gè)條件是用戶沒(méi)有按取消鍵和還沒(méi)出錢(qián)的時(shí)候。然后把DisplayMenuOfAmounts方法的返回值賦值給表示取款金額的amount變量,據(jù)此判斷用戶賬戶的余額是否足夠,判斷ATM的余額是否足夠,最后在用戶賬戶和ATM中分別扣款。這期間,如果用戶按了取消鍵,就把表示取消事務(wù)的變量transactionCanceled設(shè)置為true以跳出循環(huán),完成扣款后把表示扣款完成的變量cashDispensed設(shè)置為true以跳出循環(huán)。
(10)關(guān)于存款的事務(wù)類:Deposit
該類最終是使用Database屬性把用戶輸入的金額保存到用戶賬戶上。另外需要考慮的是:用戶在存款的時(shí)候是否按了取消鍵。
namespace MyATM
{
/// <summary>
/// ATM存款事務(wù)
/// </summary>
public class Deposit : Transaction
{
private decimal amount;
private Keypad keypad;
private DepositSlot depositSlot;
private const int CANCELED = 0;
public Deposit(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase, Keypad atmKeypad,
DepositSlot atmDepositSlot) : base(userAccountNumber, atmScreen, atmBankDatabase)
{
keypad = atmKeypad;
depositSlot = atmDepositSlot;
}
public override void Execute()
{
//確定存款金額
amount = PromptForDepositAmount();
if (amount != CANCELED)
{
UserScreen.DisplayMessage("\n請(qǐng)輸入的存款金額為" + amount);
//確認(rèn)是否收到錢(qián)
bool isReceived = depositSlot.IsMoneyReceived();
if (isReceived)
{
UserScreen.DisplayMessageLine("\n存款成功~~");
Database.Credit(AccountNumber, amount);//存款到賬戶
}
else
{
UserScreen.DisplayMessageLine("\n存款時(shí)發(fā)生錯(cuò)誤~~");
}
}
else
{
UserScreen.DisplayMessageLine("\n正在取消交易......");
}
}
/// <summary>
/// 顯示存款金額
/// </summary>
/// <returns></returns>
private decimal PromptForDepositAmount()
{
UserScreen.DisplayMessage("\n請(qǐng)輸入存款金額(輸入0退出)");
int input = keypad.GetInput();
if (input == CANCELED)
{
return CANCELED;
}
else
{
return input;
}
}
}
}以上,
私有方法PromptForDepositAmount用來(lái)返回用戶輸入的金額,如果用戶按取消鍵,就返回0。
(11)關(guān)于ATM本身的類:ATM
該類主要是提供給外部一個(gè)方法用來(lái)運(yùn)行。
namespace MyATM
{
public class ATM
{
private bool userAuthenticated;//表示用戶是否驗(yàn)證通過(guò)
private int currentAccountNumber;//當(dāng)前交易的銀行卡號(hào)
private Screen screen;//屏幕
private Keypad keypad;//鍵盤(pán)
private CashDispendser cashDispendser;//出款
private DepositSlot depositSlot;//存款
private BankDatabase bankDatabase;//數(shù)據(jù)庫(kù)
//菜單選項(xiàng)枚舉
private enum MenuOption
{
BANLANCE_INQUIRY = 1,//余額查詢
WITHDRAWAL = 2,//取款
DEPOSIT = 3,//存款
EXIT_ATM = 4//退出
}
public ATM()
{
userAuthenticated = false;//默認(rèn)驗(yàn)證不通過(guò)
currentAccountNumber = 0;//默認(rèn)卡號(hào)
screen = new Screen();//默認(rèn)屏幕
keypad = new Keypad();//默認(rèn)鍵盤(pán)
cashDispendser = new CashDispendser();//默認(rèn)出款幫助類
bankDatabase = new BankDatabase();//默認(rèn)銀行數(shù)據(jù)庫(kù)
depositSlot = new DepositSlot();//默認(rèn)存款幫助類
}
//運(yùn)行
public void Run()
{
while (true)
{
while (!userAuthenticated)//如果用戶沒(méi)有驗(yàn)證通過(guò),就一直循環(huán)
{
screen.DisplayMessageLine("\n歡迎");
AuthenticateUser();
PerormTransactions();
//重新設(shè)置一些參數(shù)
userAuthenticated = false;
currentAccountNumber = 0;
screen.DisplayMessageLine("\n謝謝,再見(jiàn)~~");
}
}
}
//驗(yàn)證用戶
private void AuthenticateUser()
{
screen.DisplayMessage("\n請(qǐng)輸入卡號(hào)");
int accountNumber = keypad.GetInput();
screen.DisplayMessage("\n輸入密碼");
int pin = keypad.GetInput();
userAuthenticated = bankDatabase.AuthenticateUser(accountNumber, pin);
if (userAuthenticated)
{
currentAccountNumber = accountNumber; //保存當(dāng)前的用戶卡號(hào)
}
else
{
screen.DisplayMessageLine("無(wú)效的卡號(hào)或密碼,請(qǐng)重試~~");
}
}
//執(zhí)行交易
private void PerormTransactions()
{
Transaction currenTransaction;
bool userExited = false; //用戶還沒(méi)選擇退出
while (!userExited)
{
//確定選擇的具體事務(wù)
int mainMenuSelction = DisplayMainMenu();
switch ((MenuOption)mainMenuSelction)
{
case MenuOption.BANLANCE_INQUIRY:
case MenuOption.WITHDRAWAL:
case MenuOption.DEPOSIT:
currenTransaction = CreateTransaction(mainMenuSelction);
currenTransaction.Execute();
break;
case MenuOption.EXIT_ATM:
screen.DisplayMessageLine("\n正在退出系統(tǒng)......");
userExited = true;//退出循環(huán)
break;
default:
screen.DisplayMessageLine("\n無(wú)效選項(xiàng),請(qǐng)重新選擇~~");
break;
}
}
}
//顯示菜單
private int DisplayMainMenu()
{
screen.DisplayMessageLine("\n主菜單:");
screen.DisplayMessageLine("1-查詢余額");
screen.DisplayMessageLine("2-提取現(xiàn)金");
screen.DisplayMessageLine("3-存款");
screen.DisplayMessageLine("4-退出\n");
screen.DisplayMessage("請(qǐng)輸入選擇:");
return keypad.GetInput();
}
//創(chuàng)建交易
private Transaction CreateTransaction(int type)
{
Transaction temp = null;
switch ((MenuOption)type)
{
case MenuOption.BANLANCE_INQUIRY:
temp = new BalanceInquiry(currentAccountNumber, screen, bankDatabase);
break;
case MenuOption.WITHDRAWAL:
temp = new Withdrawl(currentAccountNumber, screen, bankDatabase, keypad, cashDispendser);
break;
case MenuOption.DEPOSIT:
temp = new Deposit(currentAccountNumber, screen, bankDatabase, keypad, depositSlot);
break;
}
return temp;
}
}
}以上,
向外部提供了一個(gè)Run方法,客戶端只要調(diào)用該實(shí)例方法就可以了。在Run方法內(nèi)部又實(shí)現(xiàn)了對(duì)用戶的驗(yàn)證和進(jìn)行用戶選擇的事務(wù)。
私有方法DisplayMainMenu用來(lái)顯示主菜單項(xiàng),并返回用戶的選擇。
在PerormTransactions方法中,根據(jù)用戶的選擇,使用CreateTransaction(int type)方法創(chuàng)建具體的事務(wù),并最終執(zhí)行。并需要考慮用戶按退出按鈕的情況。
(12)運(yùn)行
using System;
namespace MyATM
{
class Program
{
static void Main(string[] args)
{
ATM theATM = new ATM();
theATM.Run();
Console.ReadKey();
}
}
}
總結(jié):ATM案例很好地體現(xiàn)了面向?qū)ο蟮囊恍┨攸c(diǎn),尤其是:當(dāng)我們面對(duì)一個(gè)看似復(fù)雜的案例時(shí),首先需要一種對(duì)有形和無(wú)形事物抽象的能力,其次要盡可能地把代碼中一些重復(fù)的部分提煉到基類中去,就像本案例中有關(guān)事務(wù)的抽象基類。
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
C#算法函數(shù):獲取一個(gè)字符串中的最大長(zhǎng)度的數(shù)字
這篇文章介紹了使用C#獲取一個(gè)字符串中最大長(zhǎng)度的數(shù)字的實(shí)例代碼,有需要的朋友可以參考一下。2016-06-06
C#程序中session的基本設(shè)置示例及清除session的方法
這篇文章主要介紹了C#程序中session的基本設(shè)置示例及清除session的方法,是C#入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-04-04
C#組件系列 你值得擁有的一款Excel處理神器Spire.XLS
又一款Excel處理神器Spire.XLS,這篇文章主要為大家詳細(xì)介紹了第三方組件Spire.XLS,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
C#基于Socket實(shí)現(xiàn)簡(jiǎn)單聊天室功能
這篇文章主要為大家詳細(xì)介紹了C#基于Socket實(shí)現(xiàn)簡(jiǎn)單聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
在WinForm應(yīng)用程序中快速實(shí)現(xiàn)多語(yǔ)言的處理的方法
在國(guó)際化環(huán)境下,越來(lái)越多的程序需要做多語(yǔ)言版本,這篇文章主要介紹了在WinForm應(yīng)用程序中快速實(shí)現(xiàn)多語(yǔ)言的處理的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2018-07-07
c#之滾動(dòng)字幕動(dòng)畫(huà)窗體的實(shí)現(xiàn)詳解
本篇文章是對(duì)c#中滾動(dòng)字幕動(dòng)畫(huà)窗體的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06

