Selasa, 09 Mei 2017

PBO ATM Case Study Part 2 (tugas 5)


Tugas kali ini diambil dari buku Java How to Program 9th edition. Merupakan part 2 dari tugas atm case study. Langsung saja berikut ini programnya:


Source code class ATM:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class ATM
{
    private boolean userAuthenticated;  // whether user is authenticated
    private int currentAccountNumber;   // current user's account number
    private Screen screen;  // ATM's screen
    private Keypad keypad;  // ATM's keypad
    private CashDispenser cashDispenser;    // ATM's cash dispenser
    private DepositSlot depositSlot;        // ATM's deposit slot
    private BankDatabase bankDatabase;      // account information database
   
    // constants corresponding to main menu options
    private static final int BALANCE_INQUIRY = 1;
    private static final int WITHDRAWAL = 2;
    private static final int DEPOSIT = 3;
    private static final int EXIT = 4;
   
    // no-argument ATM constructor initializes instance variables
    public ATM(){
        userAuthenticated = false;  // user is not authenticated to start
        currentAccountNumber = 0;   // no current account number to start
        screen = new Screen();      // create screen
        keypad = new Keypad();      // create keypad
        cashDispenser = new CashDispenser();    // create cash dispenser
        depositSlot = new DepositSlot();        // create deposit slot
        bankDatabase = new BankDatabase();      // create account info database
    }   // end no argument ATM constructor
   
    // start ATM
    public void run(){
        // welcome and authenticate user; perform transactions
        while(true){
            // loop while user is not yet authenticated
            while(!userAuthenticated){
                screen.displayMessageLine("\nWelcome!");
                authenticateUser();     // authenticate user
            }   // end while
           
            performTransactions();      // user is now authenticated
            userAuthenticated = false;  // reset before next ATM session
            currentAccountNumber = 0;   // reset before next ATM session
            screen.displayMessageLine("\nThank You!\nGoodbye!");
        }   // end while
    }   // end method run
   
    // attempts to authenticate user against database
    private void authenticateUser(){
        screen.displayMessage("\nPlease enter your account number : ");
        int accountNumber = keypad.getInput();  // input account number
        screen.displayMessage("\nEnter your PIN : ");   // prompt for PIN
        int pin = keypad.getInput();    // input PIN
       
        // set userAuthenticated to boolean value returned by database
        userAuthenticated = bankDatabase.authenticateUser(accountNumber, pin);
       
        // check whether authentication succeeded
        if(userAuthenticated){
            currentAccountNumber = accountNumber;   // save user's account
        }   // end if
        else{
            screen.displayMessageLine("Invalid Account Number or PIN.");
            screen.displayMessageLine("Please Try Again.");
        }
    }   // end method authenticateUser
   
    // display the main menu and perform transactions
    private void performTransactions(){
        // local variable to store transaction currently being processed
        Transaction currentTransaction = null;
        boolean userExited = false;     // user has not chosen to exit
       
        // loop while user has not chosen option to exit system
        while(!userExited){
            // show main menu and get user selection
            int mainMenuSelection = displayMainMenu();
           
            // decide how to proceed based on user's menu selection
            switch(mainMenuSelection){
                // user choose to perform one of three transaction types
                case BALANCE_INQUIRY :
                case WITHDRAWAL :
                case DEPOSIT :
               
                    // initialize as new object choosen type
                    currentTransaction = createTransaction(mainMenuSelection);
                   
                    currentTransaction.execute();   // execute transaction
                    break;
               
                case EXIT :
                // user choose to terminate session
                    screen.displayMessageLine("\nExiting the system...");
                    userExited = true;      // this ATM session should end
                    break;
                   
                default :
                // user did not enter an integer between 1-4
                    screen.displayMessageLine("\nYou did not enter a valid selection.");
                    screen.displayMessageLine("Please try again.");
                    break;
            }   // end switch
        }   // end while
    }   // end method performTransactions
   
    // display the main menu and return an input selection
    private int displayMainMenu(){
        screen.displayMessageLine("\nMain Menu :");
        screen.displayMessageLine("1 - View my balance");
        screen.displayMessageLine("2 - Withdraw cash");
        screen.displayMessageLine("3 - Deposit funds");
        screen.displayMessageLine("4 - Exit\n");
        screen.displayMessage("Enter a choice : ");
        return keypad.getInput();   // return user's selection
    }   // end method of displayMainMenu
   
    // return object of specified Transaction subclass
    private Transaction createTransaction(int type){
        Transaction temp = null;        // temporary Transaction variable
       
        // determine which type of Transaction to create
        switch(type){
            case BALANCE_INQUIRY :
            // create new BalanceInquiry transaction
                temp = new BalanceInquiry(currentAccountNumber, screen, bankDatabase);
                break;
               
            case WITHDRAWAL :
            // create new Withdrawal transaction
                temp = new Withdrawal(currentAccountNumber, screen, bankDatabase, keypad, cashDispenser);
                break;
               
            case DEPOSIT :
            // create new Deposit transaction
                temp = new Deposit(currentAccountNumber, screen, bankDatabase, keypad, depositSlot);
                break;
        }   // end switch
       
        return temp;    // return newly created object
    }   // end method createTransaction
}   // end class ATM

Source code class Screen:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class Screen
{
    // display a message without a carriage return
    public void displayMessage(String message){
        System.out.print(message);
    }   // end method displayMessage
   
    // display a message with a carriage return
    public void displayMessageLine(String message){
        System.out.println(message);
    }   // end method displayMessageLine
   
    // displays a dollar amount
    public void displayDollarAmount(double amount){
        System.out.printf("$%,.2f", amount);
    }   // end method displayDollarAmount
}   // end class Screen

Source code class Keypad:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
import java.util.Scanner;
 
public class Keypad
{
    private Scanner input;  // reads data from the command line
   
    // no-argument constructor initializes the Scanner
    public Keypad(){
        input = new Scanner(System.in);
    }   // end no-argument Keypad constructor
   
    // return an integer value entered by user
    public int getInput(){
        return input.nextInt();     // we assume that user enters an integer
    }   // end method getInput
}   // end class Keypad

Source code class CashDispenser:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class CashDispenser
{
    // the default initial number of bills in the cash dispenser
    private final static int INITIAL_COUNT = 500;
    private int count;      // number of $20 bills remaining
   
    // no-argument CashDispenser constructor initializes count to default
    public CashDispenser(){
        count = INITIAL_COUNT;  // set count attribute to default
    }   // end CashDispenser constructor
   
    // simulates dispensing of specified amount of cash
    public void dispenseCash(int amount){
        int billsRequired = amount / 20;    // number of $20 bills required
        count -= billsRequired;     // update the count of bills
    }   // end method dispenseCash
   
    // indicates whether cash dispenser can dispense desired amount
    public boolean isSufficientCashAvailable(int amount){
        int billsRequired = amount / 20;
       
        if(count >= billsRequired){
            return true;    // enough bills required
        }
        else{
            return false;   // not enough bills required
        }
    }   // end method isSufficientCashAvailable
}   // end class CashDispenser

Source code class DepositSlot:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class DepositSlot
{
    // indicate whether envelope was received (always returns true)
    // because this is only a software simulation of a real deposit slot
    public boolean isEnvelopeReceived(){
        return true;    // deposit envelope was received
    }   // end method isEnvelopeReceived
}   // end class DepositSlot

Source code class Account:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class Account
{
    private int accountNumber;      // account number
    private int pin;        // PIN for authentication
    private double availableBalance;    // funds available for withdrawal
    private double totalBalance;        // funds available + pending deposits
   
    // Account constructor initializes attributes
    public Account(int theAccountNumber, int thePIN, double theAvailableBalance, double theTotalBalance){
        accountNumber = theAccountNumber;
        pin = thePIN;
        availableBalance = theAvailableBalance;
        totalBalance = theTotalBalance;
    }   // end Account constructor
   
    // determines whether a user-specified PIN matches PIN in Account
    public boolean validatePIN(int userPIN){
        if(userPIN == pin){
            return true;    // means the PIN input is match with the user's PIN
        }
        else{
            return false;   // means the PIN input is not match with the user's PIN
        }
    }   // end method validatePIN
   
    // returns available balance
    public double getAvailableBalance(){
        return availableBalance;
    }
   
    // returns the total balance
    public double getTotalBalance(){
        return totalBalance;
    }
   
    // credits an amount to the account
    public void credit(double amount){
        totalBalance += amount;     // add to total balance
    }
   
    // debits an amount from the account
    public void debit(double amount){
        availableBalance -= amount;     // substract from available balance
        totalBalance -= amount;         // substract from total balance
    }
   
    // returns account number
    public int getAccountNumber(){
        return accountNumber;
    }
}   // end class Account

Source code class BankDatabase:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class BankDatabase
{
    private Account[] accounts;     // array of Accounts
   
    // no-argument BankDatabase constructor initializes accounts
    public BankDatabase(){
        accounts = new Account[2];      // just 2 accounts for testing
        accounts[0] = new Account(12345, 54321, 1000.0, 1200.0);
        accounts[1] = new Account(98765, 56789, 200.0, 200.0);
    }   // end no-argument BankDatabase constructor
   
    // retrieve Account object containing specified account number
    private Account getAccount(int accountNumber){
        // loop through accounts searching for matching account number
        for(Account currentAccount : accounts){
            // return current account if match found
            if(currentAccount.getAccountNumber() == accountNumber) return currentAccount;
        }   // end for
       
        return null;    // if no matching account was found, return null
    }   // end method
   
    // determine whether user-specified account number and PIN match
    // those of an account in the database
    public boolean authenticateUser(int userAccountNumber, int userPIN){
        // attempt to retrieve the account with the account number
        Account userAccount = getAccount(userAccountNumber);
       
        if(userAccount != null){
            return userAccount.validatePIN(userPIN);
        }
        else{
            return false;   // account number not found, so return false
        }  
    }   // end method
   
    // return available balance of Account with specified account number
    public double getAvailableBalance(int userAccountNumber){
        return getAccount(userAccountNumber).getAvailableBalance();
    }   // end method
   
    public double getTotalBalance(int userAccountNumber){
        return getAccount(userAccountNumber).getTotalBalance();
    }   // end method
   
    public void credit(int userAccountNumber, double amount){
        getAccount(userAccountNumber).credit(amount);
    }   // end method
   
    public void debit(int userAccountNumber, double amount){
        getAccount(userAccountNumber).debit(amount);
    }   // end method
}   // end class BankDatabase

Source code class Transaction:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public abstract class Transaction
{
    private int accountNumber;      // indicates account involved
    private Screen screen;          // ATM's screen
    private BankDatabase bankDatabase;  // account info database
   
    // Transaction constructor invoked by subclasses using super()
    public Transaction(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase){
        accountNumber = userAccountNumber;
        screen = atmScreen;
        bankDatabase = atmBankDatabase;
    }   // end Transaction constructor
   
    // return account number
    public int getAccountNumber(){
        return accountNumber;
    }   // end method
   
    // return reference to screen
    public Screen getScreen(){
        return screen;
    }   // end method
   
    // return reference to bank database
    public BankDatabase getBankDatabase(){
        return bankDatabase;
    }   // end method
   
    // perform the transaction (overridden by each subclass)
    abstract public void execute();
}   // end class Transaction

Source code class BalanceInquiry:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class BalanceInquiry extends Transaction
{
    // BalanceInquiry constructor
    public BalanceInquiry(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase){
        super(userAccountNumber, atmScreen, atmBankDatabase);
    }   // end BalanceInquiry constructor
   
    // performs the transaction
    @Override
    public void execute(){
        // get references to bank database and screen
        BankDatabase bankDatabase = getBankDatabase();
        Screen screen = getScreen();
       
        // get the available balance for the account involved
        double availableBalance = bankDatabase.getAvailableBalance(getAccountNumber());
       
        // get the total balance for the account involved
        double totalBalance = bankDatabase.getTotalBalance(getAccountNumber());
       
        // display the balance information on the screen
        screen.displayMessageLine("\nBalance Information : ");
        screen.displayMessage(" - Available Balance : ");
        screen.displayDollarAmount(availableBalance);
        screen.displayMessage("\n - Total Balance : ");
        screen.displayDollarAmount(totalBalance);
        screen.displayMessageLine("");
    }   // end method execute
}   // end class BalanceInquiry

Source code class Withdrawal:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class Withdrawal extends Transaction
{
    private int amount;     // amount to withdraw
    private Keypad keypad;  // references to keypad
    private CashDispenser cashDispenser;    // references to cash dispenser
   
    // constant corresponding to menu option to cancel
    private final static int CANCELED = 6;
   
    // Withdrawal constructor
    public Withdrawal(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase, Keypad atmKeypad, CashDispenser atmCashDispenser){
        // initializes superclass variables
        super(userAccountNumber, atmScreen, atmBankDatabase);
       
        // initializes references to keypad and cash dispenser
        keypad = atmKeypad;
        cashDispenser = atmCashDispenser;
    }   // end Withdrawal constructor
   
    // perform transaction
    @Override
    public void execute(){
        boolean cashDispensed = false;  // cash was not dispensed yet
        double availableBalance;        // amount available for withdrawal
       
        // get references to bank database and screen
        BankDatabase bankDatabase = getBankDatabase();
        Screen screen = getScreen();
       
        // loop until cash is dispensed or the user cancels
        do{
            // obtain a chosen withdrawal amount from the user
            amount = displayMenuOfAmounts();
           
            // check whether user choose a withdrawal amount or canceled
            if(amount != CANCELED){
                // get available balance of account involved
                availableBalance = bankDatabase.getAvailableBalance(getAccountNumber());
               
                // check whether the user has enough money in the account
                if(amount <= availableBalance){
                   
                    // check whether the cash dispenser has enough money
                    if(cashDispenser.isSufficientCashAvailable(amount)){
                       
                        // update the account involved to reflect the withdrawal
                        bankDatabase.debit(getAccountNumber(), amount);
                       
                        cashDispenser.dispenseCash(amount);     // dispense cash
                        cashDispensed = true;   // cash was dispensed
                       
                        // instructs user to take cash
                        screen.displayMessageLine("\nYour cash has been dispensed. Please take your cash now.");
                    }   // end if
                    else{
                        // cash dispenser does not have enough cash
                        screen.displayMessageLine("\nInsufficient cash available in the ATM.");
                        screen.displayMessageLine("\nPlease choose a smaller amount.");
                    }   // end if
                }   // end if
                else{
                    // not enough money available in user's account
                    screen.displayMessageLine("\nInsufficient funds in your account.");
                    screen.displayMessageLine("\nPlease choose a smaller amount.");
                }   // end if
            }   // end if
            else{
                // user choose cancel menu option
                screen.displayMessageLine("\nCancelling transactions...");
                return;     // return to main menu because user canceled
            }   // end if
        }   while(!cashDispensed);
    }   // end method execute
   
    // display a menu of withdrawal amounts and the options to cancel
    // return the chosen amount or 0 if the user chooses to cancel
    private int displayMenuOfAmounts(){
        int userChoice = 0;     // local variable to store return value
       
        Screen screen = getScreen();    // get screen references
       
        // array of amounts to correspond to menu numbers
        int[] amounts = {0, 20, 40, 60, 100, 200};
       
        // loop while no valid choice has been made
        while(userChoice == 0){
            // display the withdrawal menu
            screen.displayMessageLine("\nWithdrawal Menu : ");
            screen.displayMessageLine("1 - $20");
            screen.displayMessageLine("2 - $40");
            screen.displayMessageLine("3 - $60");
            screen.displayMessageLine("4 - $100");
            screen.displayMessageLine("5 - $200");
            screen.displayMessageLine("6 - Cancel Transaction");
            screen.displayMessage("\nChoose a withdrawal amount : ");
           
            int input = keypad.getInput();      // get user input through keypad
           
            // determine how to proceed based on the input value
            switch(input){
                // if the user choose a withdrawal amount
                // i.e choose option 1, 2, 3, 4 or 5
                // return the corresponding amount from amounts's array
                case 1 :
                case 2 :
                case 3 :
                case 4 :
                case 5 :
                    userChoice = amounts[input];        // save user's choice
                    break;
               
                case CANCELED :
                    // the user choose to cancel
                    userChoice = CANCELED;      // save user's choice
                    break;
               
                default :
                    // the user did not enter value between 1-6
                    screen.displayMessageLine("\nInvalid selection.");
                    screen.displayMessageLine("Try again.");
            }   // end switch
        }   // end while
       
        return userChoice;      // return withdrawal amount or CANCELED
    }   // end method displayMenuOfAmounts
}   // end class Withdrawal

Source code class Deposit:

/**
 * OOP dalam mesin ATM
 * 
 * Monica I H 
 * 08 Mei 2017
 */
public class Deposit extends Transaction
{
    private double amount;      // amount to deposit
    private Keypad keypad;      // references to keypad
    private DepositSlot depositSlot;    // references to deposit slot
    private final static int CANCELED = 0;  // constant for cancel option
   
    // Deposit constructor
    public Deposit(int userAccountNumber, Screen atmScreen, BankDatabase atmBankDatabase, Keypad atmKeypad, DepositSlot atmDepositSlot){
        // initializes superclass variables
        super(userAccountNumber, atmScreen, atmBankDatabase);
       
        // initialize references to keypad and deposit slot
        keypad = atmKeypad;
        depositSlot = atmDepositSlot;
    }   // end Deposit constructor
   
    // perform transaction
    @Override
    public void execute(){
        BankDatabase bankDatabase = getBankDatabase();      // get reference
        Screen screen = getScreen();        // get reference
       
        amount = promptForDepositAmount();  // get deposit amount from user
       
        // check whether the user entered a deposit amount or canceled
        if(amount != CANCELED){
            // request deposit envelope containing specified amount
            screen.displayMessage("\nPlease insert a deposit envelope containing ");
            screen.displayDollarAmount(amount);
            screen.displayMessage(".");
           
            // receive deposit envelope
            boolean envelopeReceived = depositSlot.isEnvelopeReceived();
           
            // check whether deposit envelope was received
            if(envelopeReceived){
                screen.displayMessageLine("\nYour envelope has been received.");
                screen.displayMessage("NOTE: The money just deposited will not be available until we verify the amount");
                screen.displayMessage("of any enclosed cash and your checks clear.");
               
                // credit account to reflect the deposit
                bankDatabase.credit(getAccountNumber(), amount);
            }   // end if
            else{
                // deposit envelope not received
                screen.displayMessageLine("\nYou did not insert an envelope");
                screen.displayMessageLine("So, the ATM has canceled your transaction.");
            }   // end else
        }   // end if
        else{
            // user canceled instead of entering amount
            screen.displayMessageLine("\nCanceling transaction...");
        }   // end else
    }   // end method execute
   
    // prompt user to enter a deposit amount in cents
    private double promptForDepositAmount(){
        Screen screen = getScreen();    // get references to screen
       
        // display the prompt
        screen.displayMessage("\nPlease enter a deposit amount in CENTS (or 0 to cancel)");
        int input = keypad.getInput();  // receive input of deposit amount
       
        // check whether the user canceled or entered a valid amount
        if(input == CANCELED) return CANCELED;
        else{
            return (double) input / 100;        // return dollar amount
        }   // end else
    }   // end method
}   // end class Deposit