ATM Machine - Low Level Design. State design pattern was required to be incorporated.
This repository implements a simplified ATM transaction workflow using the State Design Pattern.
The core idea is that the ATM behavior changes depending on its current state, and each state decides which operations are valid at that moment.
The system is organized into the following modules:
atm/— contains the main ATM facadestate/— defines the state machine and state-specific behaviorcard_manager/— handles card-type-specific validation and withdrawal logicdata/— defines enums and data transfer objectsdb/— provides persistence-like access for transaction and state management
The ATM class acts as the central controller for the machine.
It:
- holds the current state of the ATM
- delegates operations such as
init(),cancel(),read_card(), andread_withdrawal_details()to the active state - updates the stored state in the database whenever the state changes
The ATM supports the following states:
READYCARD_READINGWITHDRAWAL_DETAILS_READINGCASH_DISPENSINGCARD_EJECTING
The state transitions are managed through StateFactory, which returns the appropriate concrete state based on the current ATMState.
- The ATM starts in
READY. - When
init()is called:- a new transaction is created
- the ATM transitions to
CARD_READING
- Accepts card details for validation.
- If the card is valid:
- card details are stored
- the ATM transitions to
WITHDRAWAL_DETAILS_READING
- If the card is invalid:
- the transaction is disapproved
- the ATM returns to
READY
- Accepts withdrawal amount and transaction information.
- If the withdrawal is valid:
- the ATM transitions to
CASH_DISPENSING - the withdrawal is marked as approved
- the ATM transitions to
- If the withdrawal is invalid:
- the transaction is disapproved
- the ATM returns to
READY
- Executes the withdrawal operation.
- After cash is dispensed, the transaction is marked as executed.
- The ATM remains in the cash dispensing flow until the transaction completes.
- Used when a card needs to be ejected.
- After ejection, the ATM returns to
READY.
The CardManagerFactory selects the appropriate card handler based on the card type:
CreditCardManagerDebitCardManager
Each card manager provides:
validate_card()validate_withdrawal()execute_withdrawal()
This abstraction allows the ATM to support different card types without changing the state flow.
Stores:
- card type
- card number
- PIN
- cardholder name
Represents the current state of the ATM:
READYCARD_READINGWITHDRAWAL_DETAILS_READINGCASH_DISPENSINGCARD_EJECTING
Tracks transaction outcomes:
APPROVEDNOT_APPROVEDEXECUTEDCANCELLED
The DBAccessor acts as the persistence interface for the simulation.
It is responsible for:
- getting the current ATM state
- creating a fresh transaction
- updating ATM state
- storing card details
- storing withdrawal details
- marking transactions as approved / executed / cancelled
- State Design Pattern for ATM behavior control
- Factory Pattern for creating card managers and states
- Separation of concerns across ATM, state, card manager, and DB layers
- ATM is in
READY init()is called- ATM moves to
CARD_READING - User inserts card details
- Card is validated
- ATM moves to
WITHDRAWAL_DETAILS_READING - User enters withdrawal amount
- Withdrawal is validated
- ATM moves to
CASH_DISPENSING - Cash is dispensed
- ATM returns to
READYafter card ejection or completion
This repository is a low-level design example and uses simplified in-memory-style persistence behavior through DBAccessor.
The implementation is structured to demonstrate how state transitions can control ATM behavior in a clean and extensible way.