Object-Oriented Design of a Simulated ATM System with State Management

This object-oriented Java code simulates an ATM system with various functionalities. Here’s a breakdown of key classes:

Abstract Class:

  • ATMState: Defines ATM states (idle, check balance, withdraw, etc.) with core methods for displaying messages and transitioning between states.

Concrete State Classes:

  • CheckBalanceState: Enables users to view their account balance.
  • CashWithdrawalState: Allows users to withdraw cash with PIN verification and security checks.
  • TransferMoneyState: Facilitates funds transfer to other accounts with validation.
  • HasCardState: Handles card insertion and PIN verification for authentication.
  • IdleState: Waits for user interaction, prompting card insertion.
  • SelectOperationState: Presents available options for users to choose.

Additional Classes:

  • ATM: Maintains the current state, interacts with other components, and manages the overall flow.
  • Account: Represents user bank accounts with functionalities like balance inquiry and withdrawals.
  • Bank/MockBank: Simulates bank communication for account verification and transactions (replace with your actual bank integration).
  • User: Stores user information and connects them to their bank account.
  • Printer, Keypad, Screen, CardReader, CashDispenser: Represent physical ATM components (implementations needed based on your choices).

Main Class:

  • Main: Creates a sample user, account, and Bank (mock for testing), instantiates the ATMRoom, and starts the ATM operation.
public class ATMRoom {

    private final ATM atm;
    private final User user;

    public ATMRoom(User user, Bank bank) {
        this.user = user;
        this.atm = new ATM(bank.getAccount(user.getBankAccountNumber()));
    }

    public void start() {
        atm.run();
    }

    // Getters and setters for user and atm (if needed)
}

public class User {

    private final String name;
    private final String bankAccountNumber;

    public User(String name, String bankAccountNumber) {
        this.name = name;
        this.bankAccountNumber = bankAccountNumber;
    }

    public String getName() {
        return name;
    }

    public String getBankAccountNumber() {
        return bankAccountNumber;
    }
}

public abstract class Bank {

    public abstract Account getAccount(String bankAccountNumber);

    // Methods for other bank operations (if needed)
}

**BankAccount Class (abstract):**

```java
public abstract class BankAccount {

    public abstract int getBalance();

    public abstract void checkBalance();

    public abstract void withdraw(int amount);

    // Methods for other account operations (transfer, deposit, etc.)
}

public class ATM {

    private final Account account;
    private ATMState state;
    private final Printer printer;
    private final Keypad keypad;
    private final Screen screen;
    private final CardReader cardReader;
    private final CashDispenser cashDispenser;

    public ATM(Account account) {
        this.account = account;
        this.printer = new Printer();
        this.keypad = new Keypad();
        this.screen = new Screen();
        this.cardReader = new CardReader();
        this.cashDispenser = new CashDispenser();
        this.state = new IdleState(this);
    }

    public void run() {
        while (true) {
            state.displayMessage();
            String input = keypad.getInput();
            state = state.nextState(input);
        }
    }

    // Getters and setters for components (printer, keypad, etc.)

    private abstract class ATMState {

        protected final ATM atm;

        public ATMState(ATM atm) {
            this.atm = atm;
        }

        public abstract void displayMessage();

        public abstract ATMState nextState(String input);

        // Methods for handling specific state logic (check balance, withdraw, etc.)
    }

    public class CheckBalanceState extends ATMState {

    public CheckBalanceState(ATM atm) {
        super(atm);
    }

    @Override
    public void displayMessage() {
        screen.display("Your current balance is: " + atm.getAccount().getBalance());
    }

    @Override
    public ATMState nextState(String input) {
        // Handle user input and transition to next state
        if (input.equals("1")) {
            return new CashWithdrawalState(atm);
        } else if (input.equals("2")) {
            return new TransferMoneyState(atm);
        } else {
            return new SelectOperationState(atm);
        }
    }
}

public class CashWithdrawalState extends ATMState {

    private int amount;

    public CashWithdrawalState(ATM atm) {
        super(atm);
    }

    @Override
    public void displayMessage() {
        screen.display("Enter the amount you want to withdraw:");
    }

    @Override
    public ATMState nextState(String input) {
        try {
            amount = Integer.parseInt(input);
            atm.getAccount().withdraw(amount);
            cashDispenser.dispenseCash(amount);
            return new PrintReceiptState(atm, amount);
        } catch (NumberFormatException e) {
            screen.display("Invalid input. Please enter a numerical amount.");
            return this;
        } catch (InsufficientFundsException e) {
            screen.display("Insufficient funds.");
            return new SelectOperationState(atm);
        }
    }
}

public class TransferMoneyState extends ATMState {

    private String recipientAccountNumber;
    private int amount;

    public TransferMoneyState(ATM atm) {
        super(atm);
    }

    @Override
    public void displayMessage() {
        if (recipientAccountNumber == null) {
            screen.display("Enter recipient's account number:");
        } else {
            screen.display("Enter amount to transfer:");
        }
    }

    @Override
    public ATMState nextState(String input) {
        if (recipientAccountNumber == null) {
            recipientAccountNumber = getRecipientAccountNumber(input);
            if (recipientAccountNumber == null) {
                return this; // Stay in state for invalid input
            }
        } else {
            amount = getAmountInput(input);
            if (amount == -1) {
                return this; // Stay in state for invalid input
            }

            try {
                atm.getAccount().transfer(recipientAccountNumber, amount);
                return new PrintReceiptState(atm, amount, recipientAccountNumber);
            } catch (InsufficientFundsException e) {
                screen.display("Insufficient funds.");
                return new SelectOperationState(atm);
            } catch (InvalidAccountException e) {
                screen.display("Invalid recipient account number.");
                return new SelectOperationState(atm);
            } catch (Exception e) {
                screen.display("An error occurred. Please try again later.");
                return new SelectOperationState(atm);
            }
        }
        return this; // Should not reach here, just for clarity
    }

    private String getRecipientAccountNumber(String input) {
        // Implement validation logic (not empty, valid format, etc.)
        // Return null for invalid input or the validated account number otherwise
    }

    private int getAmountInput(String input) {
        // Implement validation logic (numeric, non-negative, etc.)
        // Return -1 for invalid input or the parsed amount otherwise
    }
}
public class HasCardState extends ATMState {

    public HasCardState(ATM atm) {
        super(atm);
    }

    @Override
    public void displayMessage() {
        screen.display("Please enter your PIN:");
    }

    @Override
    public ATMState nextState(String input) {
        try {
            atm.getAccount().verifyPIN(input);
            return new SelectOperationState(atm);
        } catch (SecurityException e) {
            screen.display("Invalid PIN. Please try again.");
            return this;
        }
    }
}

public class IdleState extends ATMState {

    public IdleState(ATM atm) {
        super(atm);
    }

    @Override
    public void displayMessage() {
        screen.display("Welcome to the ATM. Please insert your card.");
    }

    @Override
    public ATMState nextState(String input) {
        // Simulate card insertion
        return new HasCardState(atm);
    }
}

public class SelectOperationState extends ATMState {

    public SelectOperationState(ATM atm) {
        super(atm);
    }

    @Override
    public void displayMessage() {
        screen.display("Select an operation:");
        screen.display("1. Check Balance");
        screen.display("2. Withdraw Cash");
        screen.display("3. Transfer Money");
        screen.display("4. Exit");
    }

    @Override
    public ATMState nextState(String input) {
        switch (input) {
            case "1":
                return new CheckBalanceState(atm);
            case "2":
                return new CashWithdrawalState(atm);
            case "3":
                return new TransferMoneyState(atm);
            case "4":
                return new IdleState(atm);
            default:
                screen.display("Invalid option. Please choose 1-4.");
                return this;
        }
    }
}

public class Main {

    public static void main(String[] args) {
        // Create a sample bank account with dummy data for testing
        Account account = new Account("123456", 1000, "1234");
        Bank bank = new MockBank(account); // Example, replace with actual Bank implementation

        // Create a user instance
        User user = new User("John Doe", "123456");

        // Create the ATM room and start using it
        ATMRoom atmRoom = new ATMRoom(user, bank);
        atmRoom.start();
    }
}


Balance inquiry 
The sequence diagram for how to complete the balance inquiry using an ATM should have the following actors and objects that will interact with each other:

Actors: Cardholder, Card issuer

Objects: ATM and Printer

Here are the steps for balance inquiry from ATM:

The cardholder inserts their ATM card into the ATM.

The ATM then asks the cardholder for their PIN.

The cardholder enters their PIN code, and the ATM sends the code to the card issuer for verification.

The card issuer verifies the PIN code:

If the PIN is valid, the card issuer sends a message back to the ATM indicating that the verification was successful.

The ATM then displays the main menu to the cardholder.

The cardholder selects the balance inquiry option.

The ATM sends a message to the card issuer to get the account balance, and the card issuer returns the balance to the ATM.

The ATM displays the balance to the cardholder and asks if they would like a receipt printed.

If the cardholder selects "yes," the ATM sends a message to the printer to print a receipt and ejects the ATM card.

If the cardholder does not want a receipt, the ATM card is simply ejected.

If the PIN is not verified, and the ATM card is simply ejected.






































































CardHolder ATM CardIssuer Printer sd balance inquiry insert ATM card ask for PIN code enterPin() verifyPin() verification successful displayMainMenu() balanceInquiry() getAccountBalance() return balance display balance ask for receipt accept requestReceipt() print receipt reject verification unsuccessful error message ATM card ejected alt [PIN verified] [PIN not verified] alt [accepted] [rejected]

You may also like...