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