<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本篇用C#實現ATM自動取款機的一些功能。面臨的第一個問題是:如何把與自動取款機相關的有形的、無形的方面抽象出來。
該類包含與卡號、密碼、可用餘額、總餘額相關的欄位和屬性,比提供了存款和取款的方法。
namespace MyATM { /// <summary> /// 使用者帳號 /// </summary> public class Account { private int accountNumber; //卡號 private int pin;//用來驗證 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; } } //驗證輸入密碼是否正確 public bool ValidatePIN(int userPIN) { return (userPIN == pin); } //存款 public void Credit(decimal amount) { totalBalance += amount; } //取款 public void Debit(decimal amount) { availableBalance -= amount; totalBalance -= amount; } } }
該類維護著一個Account型別的陣列,並提供驗證使用者,查詢餘額,存款、取款等方法。
namespace MyATM { /// <summary> /// 銀行資料庫 /// </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); } //根據使用者銀行卡號獲取該使用者帳號 private Account GetAccount(int accountNumber) { foreach (Account currentAccount in accounts) { if (currentAccount.AccountNumber == accountNumber) { return currentAccount; } } return null; } //驗證使用者,根據卡號和密碼 public bool AuthenticateUser(int userAccountNumber, int userPIN) { //先根據卡號獲取帳號 Account userAccount = GetAccount(userAccountNumber); if (userAccount != null) { return userAccount.ValidatePIN(userPIN); } else { return false; } } //返回可提取的餘額,根據卡號 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個方法。
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); } } }
該類的職責很明確,就是把輸入的數位返回。
using System; namespace MyATM { /// <summary> /// 輸入鍵盤 /// </summary> public class Keypad { //根據使用者輸入,返回一個整型 public int GetInput() { return Convert.ToInt32(Console.ReadLine()); } } }
該類主要是確認進鈔、出鈔口是否收到錢,預設返回true。
namespace MyATM { /// <summary> /// 存款槽 /// </summary> public class DepositSlot { //判斷是否收到錢 public bool IsMoneyReceived() { return true; } } }
就像在現實生活中,ATM中肯定會預先存放一些人民幣,出錢的時候首先要判斷餘額是否足夠,如果足夠就把ATM中當前的票數做適當的減法。
namespace MyATM { /// <summary> /// ATM取款 /// </summary> public class CashDispendser { private const int INITIAL_COUNT = 500;//初始票數 private int billCount;//當前取款機內票數 public CashDispendser() { billCount = INITIAL_COUNT; } //出錢 public void DispenseCash(decimal amount) { int billsRequired = ((int)amount) / 20; billCount -= billsRequired; } //判斷是否有餘額 public bool IsSufficientCashAvailable(decimal amount) { //假設取款機內鈔票的面值是20 int billsRequired = ((int) amount)/20; return (billCount >= billsRequired); } } }
我們可以回想一下,現實生活中,ATM的主要功能包括:查詢餘額,取款,存款等。雖然執行的過程不盡相同,但所有的這些事務包含相同的部分:比如說,必須有螢幕必須針對卡號一定和資料庫打交道,等等。於是,我們先抽象出一個有關事務的基礎類別,這個基礎類別是不需要被範例化的,所以把它定義成抽象類。如下:
namespace MyATM { /// <summary> /// ATM事務 /// </summary> public abstract class Transaction { private int accountNumber;//卡號 private Screen userScreen;//螢幕 private BankDatabase database;//銀行資料庫 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; } } //使用者使用的資料庫 唯讀 public BankDatabase Database { get { return database; } } //抽象方法 子類必須重寫 public abstract void Execute(); } }
以上,在其它有關事務的派生類中都可以存取到基礎類別的唯讀屬性,並且子類必須重寫抽象基礎類別的Execute方法。
該類呼叫Database類的方法查詢可用餘額和總餘額。
namespace MyATM { /// <summary> /// ATM餘額查詢事務 /// </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(""); } } }
當用戶輸入取款的金額,該類必須要做的事情是:在使用者的銀行資料庫中和ATM上做相應的減法,還必須考慮什麼時候退出迴圈,使用者是否按了取消鍵,使用者賬戶上是否有餘額,以及ATM中是否有餘額。
namespace MyATM { /// <summary> /// ATM取款事務 /// </summary> public class Withdrawl : Transaction { private decimal amount;//取款金額 private Keypad keypad;//鍵盤 private CashDispendser cashDispenser;//出錢 private const int CANCELED = 6;//對應選單中的取消 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; //表示不取消事務 do { int selection = DisplayMenuOfAmounts(); if (selection != CANCELED)//如果使用者沒有按取消 { amount = selection; //確定取款金額 //根據卡號獲取可用餘額 decimal availableBalance = Database.GetAvailableBalance(AccountNumber); if (amount <= availableBalance)//如果取款金額小於可用餘額 { if (cashDispenser.IsSufficientCashAvailable(amount))//如果ATM餘額足夠 { Database.Debit(AccountNumber, amount);//賬戶扣款 cashDispenser.DispenseCash(amount);//ATM扣款 cashDispensed = true;//跳出迴圈 UserScreen.DisplayMessageLine("n您可以拿著錢離開了~~"); } else//如果ATM餘額不夠 { UserScreen.DisplayMessageLine("n ATM餘額不足." + "nn請提取更小的金額~~"); } } else { UserScreen.DisplayMessageLine("n 賬戶餘額不足." + "nn請提取更小的金額~~"); } } else //如果使用者按了取消,提示正在退出並跳出迴圈 { UserScreen.DisplayMessageLine("n正在取消......"); transactionCanceled = true; } } while ((!cashDispensed) && (!transactionCanceled)); } /// <summary> /// 顯示提款金額 /// </summary> /// <returns></returns> private int DisplayMenuOfAmounts() { int userChoice = 0; //預設提款金額 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輸入數位(1-6),選擇選項:"); 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輸入無效數,請重試~~"); break; } } return userChoice; } } }
以上,
維護的amount變數表示的是取款金額,在每次使用者輸入提款金額後為該變數賦值。
Keypad型別的變數kepad和CashDispendser型別的變數cashDispenser需要在建構函式中為其賦初值,而這2個因素是在取款時特有的,在事務的抽象基礎類別中不需要考慮這2個因素。
通過DisplayMenuOfAmounts方法,會向用戶顯示一些面值,以及對應的數位鍵,然後根據使用者按下的數位鍵返回對應的、int型別的面值。
在Execute方法中,首先回圈的2個條件是使用者沒有按取消鍵和還沒出錢的時候。然後把DisplayMenuOfAmounts方法的返回值賦值給表示取款金額的amount變數,據此判斷使用者賬戶的餘額是否足夠,判斷ATM的餘額是否足夠,最後在使用者賬戶和ATM中分別扣款。這期間,如果使用者按了取消鍵,就把表示取消事務的變數transactionCanceled設定為true以跳出迴圈,完成扣款後把表示扣款完成的變數cashDispensed設定為true以跳出迴圈。
該類最終是使用Database屬性把使用者輸入的金額儲存到使用者賬戶上。另外需要考慮的是:使用者在存款的時候是否按了取消鍵。
namespace MyATM { /// <summary> /// ATM存款事務 /// </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); //確認是否收到錢 bool isReceived = depositSlot.IsMoneyReceived(); if (isReceived) { UserScreen.DisplayMessageLine("n存款成功~~"); Database.Credit(AccountNumber, amount);//存款到賬戶 } else { UserScreen.DisplayMessageLine("n存款時發生錯誤~~"); } } 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。
該類主要是提供給外部一個方法用來執行。
namespace MyATM { public class ATM { private bool userAuthenticated;//表示使用者是否驗證通過 private int currentAccountNumber;//當前交易的銀行卡號 private Screen screen;//螢幕 private Keypad keypad;//鍵盤 private CashDispendser cashDispendser;//出款 private DepositSlot depositSlot;//存款 private BankDatabase bankDatabase;//資料庫 //選單選項列舉 private enum MenuOption { BANLANCE_INQUIRY = 1,//餘額查詢 WITHDRAWAL = 2,//取款 DEPOSIT = 3,//存款 EXIT_ATM = 4//退出 } public ATM() { userAuthenticated = false;//預設驗證不通過 currentAccountNumber = 0;//預設卡號 screen = new Screen();//預設螢幕 keypad = new Keypad();//預設鍵盤 cashDispendser = new CashDispendser();//預設出款幫助類 bankDatabase = new BankDatabase();//預設銀行資料庫 depositSlot = new DepositSlot();//預設存款幫助類 } //執行 public void Run() { while (true) { while (!userAuthenticated)//如果使用者沒有驗證通過,就一直迴圈 { screen.DisplayMessageLine("n歡迎"); AuthenticateUser(); PerormTransactions(); //重新設定一些引數 userAuthenticated = false; currentAccountNumber = 0; screen.DisplayMessageLine("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; //儲存當前的使用者卡號 } else { screen.DisplayMessageLine("無效的卡號或密碼,請重試~~"); } } //執行交易 private void PerormTransactions() { Transaction currenTransaction; bool userExited = false; //使用者還沒選擇退出 while (!userExited) { //確定選擇的具體事務 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正在退出系統......"); userExited = true;//退出迴圈 break; default: screen.DisplayMessageLine("n無效選項,請重新選擇~~"); break; } } } //顯示選單 private int DisplayMainMenu() { screen.DisplayMessageLine("n主選單:"); screen.DisplayMessageLine("1-查詢餘額"); screen.DisplayMessageLine("2-提取現金"); screen.DisplayMessageLine("3-存款"); screen.DisplayMessageLine("4-退出n"); screen.DisplayMessage("請輸入選擇:"); return keypad.GetInput(); } //建立交易 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方法,使用者端只要呼叫該實體方法就可以了。在Run方法內部又實現了對使用者的驗證和進行使用者選擇的事務。
私有方法DisplayMainMenu用來顯示主選單項,並返回使用者的選擇。
在PerormTransactions方法中,根據使用者的選擇,使用CreateTransaction(int type)方法建立具體的事務,並最終執行。並需要考慮使用者按退出按鈕的情況。
using System; namespace MyATM { class Program { static void Main(string[] args) { ATM theATM = new ATM(); theATM.Run(); Console.ReadKey(); } } }
總結:ATM案例很好地體現了物件導向的一些特點,尤其是:當我們面對一個看似複雜的案例時,首先需要一種對有形和無形事物抽象的能力,其次要儘可能地把程式碼中一些重複的部分提煉到基礎類別中去,就像本案例中有關事務的抽象基礎類別。
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對it145.com的支援。如果你想了解更多相關內容請檢視下面相關連結
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45