Bird
Raised Fist0

Design an ATM System - States, Transitions, Card, PIN, Transaction, Security

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
🏗️
Design an ATM System - States, Transitions, Card, PIN, Transaction, Security
Model ATM operations using state machines with secure card and PIN handling, transaction processing, and concurrency control.
mediumSystems with State MachinesFreq: high
Prerequisites:OOP BasicsFinite State Machines
⚙️
Functional Requirements
  • Validate card authenticity upon insertion
  • Validate PIN with maximum 3 attempts
  • Allow selection of transaction types after successful PIN validation
  • Process transactions atomically with bank server
  • Eject card after transaction or on failure
  • Lock ATM after 3 incorrect PIN attempts
  • Maintain ATM state transitions strictly
👤
Use Cases
  • Insert Card
  • Enter PIN
  • Select Transaction Type (Withdrawal, Deposit, Balance Inquiry)
  • Process Transaction
  • Eject Card
  • Handle Incorrect PIN Attempts
  • Lock ATM on Security Breach
🧑‍💻
Actors
  • Customer
  • ATM Machine
  • Bank Server
  • Security Module
❓
Clarifying Questions to Ask
  • How many concurrent users/threads can access the ATM simultaneously? (Typically one per ATM)
  • Is there a pricing or fee strategy for transactions? (No fees in scope)
  • What happens if the ATM loses power mid-transaction? (Out of scope)
  • Are multiple cards supported simultaneously? (No, single card per ATM session)
  • How to handle card retention on suspected fraud? (Lock ATM and notify security)
Out of Scope
✗ Network communication protocols with bank server
✗ Physical cash dispensing hardware details
✗ User interface design specifics
🔢
Enumerations
enum ATMState
IDLE | CARD_INSERTED | PIN_ENTERED | TRANSACTION_SELECTED | PROCESSING | EJECT_CARD | LOCKED
Defines all possible ATM states to enforce strict state transitions and prevent invalid operations. Using enum prevents typo bugs and enables exhaustive switch-case handling.
enum TransactionType
WITHDRAWAL | DEPOSIT | BALANCE_INQUIRY
Enumerates supported transaction types to avoid string literals and enable type-safe transaction processing.
enum CardStatus
VALID | BLOCKED | EXPIRED
Represents card validity states to enforce security checks before allowing transactions.
enum PinValidationResult
SUCCESS | FAILURE | LOCKED
Encapsulates PIN validation outcomes to handle retries and ATM locking logic.
📦
ATM
5 fields
private volatile ATMState currentStateprivate Card insertedCardprivate int pinRetryCountprivate final int MAX_PIN_RETRY = 3private Transaction currentTransaction
Manages ATM state machine, card insertion, PIN validation, transaction processing, and card ejection with concurrency control.
Why thisSynchronized methods ensure thread safety for single ATM session concurrency.
Why notAvoided reactive frameworks as ATM sessions are single-threaded and require strict state control.
public synchronized boolean insertCard(Card card)Atomically inserts a card if ATM is IDLE, transitions state to CARD_INSERTED.
public synchronized PinValidationResult enterPin(String pin)Validates PIN against inserted card, increments retry count, locks ATM if max retries exceeded.
public synchronized boolean selectTransaction(TransactionType type)Sets current transaction type if PIN validated, transitions state to TRANSACTION_SELECTED.
public synchronized boolean processTransaction()Processes the current transaction atomically, communicates with bank server, transitions state accordingly.
public synchronized void ejectCard()Ejects the card and resets ATM state to IDLE.
private synchronized void lockATM()Locks the ATM after security breach or max PIN retries.
📦
Card
5 fields
private final String cardNumberprivate final CardStatus statusprivate final String cardHolderNameprivate final String expiryDateprivate final String hashedPin
Represents a bank card with immutable attributes and secure PIN storage.
Why thisImmutable design prevents accidental modification and enhances security.
Why notAvoided mutable card objects to reduce risk of state corruption.
public boolean validatePin(String pin)Validates the input PIN against stored hashed PIN securely.
public boolean isValid()Checks if card status is VALID and not expired.
📦
Transaction
3 fields
private final TransactionType typeprivate final double amountprivate boolean isProcessed
Encapsulates transaction details and processing status.
Why thisSynchronized process method ensures atomic transaction processing.
Why notAvoided asynchronous processing to maintain strict transaction order.
public synchronized boolean process()Processes the transaction atomically with bank server interaction.
public boolean isProcessed()Returns whether the transaction has been completed.
📦
SecurityModule
1 fields
private volatile boolean isLocked
Monitors security events and locks ATM on suspicious activities.
Why thisVolatile flag with synchronized lock method ensures thread-safe security state.
Why notAvoided external security services to keep design self-contained.
public synchronized void lock()Locks the ATM and sets isLocked flag.
public boolean isLocked()Returns current lock status.
📦
BankServer
0 fields
Simulates bank server for validating and processing transactions.
Why thisSynchronized processing ensures consistency in transaction handling.
Why notAvoided asynchronous calls to simplify transaction atomicity.
public boolean validateCard(Card card)Validates card authenticity and status.
public synchronized boolean processTransaction(Transaction transaction)Processes transaction atomically and returns success status.
🔗
Relationships
ATM◇──►Card[1]
aggregationCard exists independently of ATM session
ATM◆──►Transaction[0..1]
compositionTransaction lifecycle bound to ATM session
ATM──►SecurityModule[1]
associationSecurityModule exists independently, ATM references it
ATM──►BankServer[1]
associationBankServer exists independently, ATM communicates with it
Card──►PinValidationResult[1]
associationPinValidationResult is transient result, no lifecycle ownership
🗄️
Cards
PK: cardNumber
cardNumber STRINGcardHolderName STRINGstatus STRINGexpiryDate STRINGhashedPin STRING
Stores immutable card details for validation and lookup.
🗄️
Transactions
PK: transactionId
transactionId STRINGcardNumber STRINGtype STRINGamount DOUBLEstatus STRINGtimestamp TIMESTAMP
Records transaction details and status for audit and processing.
🔌
InsertCard
Request
{
  "cardNumber": "STRING",
  "expiryDate": "STRING"
}
Response
{
  "success": "BOOLEAN",
  "message": "STRING"
}
Validates and inserts card into ATM session.
🔌
EnterPin
Request
{
  "pin": "STRING"
}
Response
{
  "result": "PinValidationResult"
}
Validates PIN and returns result with retry and lock info.
🔌
ProcessTransaction
Request
{
  "transactionType": "TransactionType",
  "amount": "DOUBLE"
}
Response
{
  "success": "BOOLEAN",
  "message": "STRING"
}
Processes the requested transaction atomically.

Practice

(1/5)
1. You are designing a Vehicle abstraction for a parking system. Should Vehicle be an abstract class or an interface if you need to store state like licensePlate and provide default behavior for getSize()? Why?
easy
A. Use an interface, because it allows multiple inheritance and state can be stored externally.
B. Use an interface, because interfaces can hold state and default methods provide behavior.
C. Use an abstract class, because it can hold instance variables and provide default method implementations.
D. Use an abstract class, because interfaces cannot define any methods.

Solution

  1. Step 1: Analyze state and behavior requirements

    The design requires storing state (licensePlate) and providing default behavior (getSize()).
  2. Step 2: Choose correct OOP construct

    Abstract classes can have instance variables and concrete methods with default behavior. Interfaces in Java 8+ can have default methods but cannot hold instance state. Therefore, abstract class fits the need.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Abstract class supports state and default behavior [check]
Hint: State needs abstract class; interfaces lack instance variables [check]
Common Mistakes:
2. A class has a private constructor and a clone() method that returns a copy of itself. Which design pattern is applied here and why is this the correct use case?
easy
A. Builder pattern, because it separates object construction from representation
B. Singleton pattern, because it restricts instantiation to one object
C. Factory pattern, because it creates objects through a factory method
D. Prototype pattern, because cloning avoids expensive object construction

Solution

  1. Step 1: Identify the pattern from constructor and clone()

    The private constructor prevents direct instantiation, and the presence of a clone() method indicates object copying rather than new creation.
  2. Step 2: Match pattern intent to scenario

    The Prototype pattern is used to clone objects when construction is expensive, which fits the scenario. Singleton restricts to one instance, Factory creates new instances, and Builder separates construction steps.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + clone() -> Prototype pattern [check]
Hint: Private constructor + clone() means Prototype pattern [check]
Common Mistakes:
3. The current Facebook design uses a PrivacyStrategy interface for post visibility. To add a WeekendPrivacyStrategy that restricts posts only on weekends, what is the minimum change required to comply with SOLID principles?
medium
A. Modify the existing PrivacyStrategy implementations to add weekend checks.
B. Create a new WeekendPrivacyStrategy class implementing PrivacyStrategy without changing existing classes.
C. Add a boolean flag isWeekend in the base Post class and check it in all privacy methods.
D. Combine all privacy logic into a single class with conditional weekend logic.

Solution

  1. Step 1: Identify applicable SOLID principle

    Open/Closed Principle (OCP) requires extending behavior without modifying existing code.
  2. Step 2: Apply OCP to privacy strategies

    Adding a new class implementing PrivacyStrategy extends functionality without changing existing classes.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New class for new behavior -> OCP compliance [check]
Hint: OCP: extend with new class, don't modify existing [check]
Common Mistakes:
4. You want to add a WeekendFeeStrategy to calculate parking fees differently on weekends using the current Template Method design. What is the minimum change that respects SOLID principles?
medium
A. Modify the base class to add a weekend flag and conditional logic in the template method.
B. Add a boolean isWeekend field to all subclasses and override fee calculation accordingly.
C. Create a new class implementing FeeStrategy for weekends and inject it without changing existing classes.
D. Add weekend logic inside each subclass's fee calculation method, duplicating code.

Solution

  1. Step 1: Identify applicable SOLID principle

    Open/Closed Principle (OCP) requires extending behavior without modifying existing code.
  2. Step 2: Use strategy injection

    Creating a new FeeStrategy class for weekends and injecting it respects OCP and Dependency Inversion Principle (DIP).
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    New strategy class added; no existing class modified [check]
Hint: OCP: add new class, don't modify existing [check]
Common Mistakes:
5. The system needs to support ElectricCar playback devices that require ChargingSpot management. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Add ELECTRIC_CAR to DeviceType enum, CHARGING to SpotType enum, create ElectricCar extends Device, and update SpotCompatibility map externally.
B. Modify existing Device class to add charging logic and add ElectricCar as a flag inside it.
C. Create a new ElectricCar class unrelated to Device and duplicate playback logic.
D. Add charging logic inside the PlaybackQueue class to handle ElectricCar specifics.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclassing allows extension without changing existing class code.
  2. Step 2: Update compatibility externally

    Updating SpotCompatibility map outside existing classes respects OCP and avoids class explosion or god-class logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Extend enums + subclass + external map update -> minimal change [check]
Hint: Extend enums + subclass + external map -> minimal change [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard