Bird
Raised Fist0

Design a Vending Machine - States, Product Selection, Payment, Change, Refill

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
VendingMachine Singleton

VendingMachine is a Singleton to ensure a single instance controls the machine state.

🎯 Tests if candidate knows volatile is needed on Singleton instance to prevent JVM reordering and partial construction visibility.
public class VendingMachine {
  private static volatile VendingMachine instance;
  private List<ProductSlot> productSlots;
  private PaymentProcessor paymentProcessor;
  private ChangeDispenser changeDispenser;
  private VendingMachine() {
    // initialize components
  }
  public static VendingMachine getInstance() {
    if (instance == null) {
      synchronized(VendingMachine.class) {
        if (instance == null) instance = new VendingMachine();
      }
    }
    return instance;
  }
Product abstract class

Product is abstract to hold shared state like id, name, and price which interfaces cannot hold in Java.

🎯 Tests whether candidate understands abstract class is chosen over interface because it holds instance state fields.
public abstract class Product {
  protected String id;
  protected String name;
  protected double price;
  public double getPrice() { return price; }
  public String getName() { return name; }
}
ProductSlot realization

ProductSlot extends Product to represent a slot holding a product and quantity, realizing the abstract class.

🎯 Tests if candidate knows inheritance is used to extend shared state and add slot-specific behavior like dispense and availability.
public class ProductSlot extends Product {
  private int quantity;
  public synchronized boolean isAvailable() {
    return quantity > 0;
  }
  public synchronized void dispense() {
    if (quantity > 0) quantity--;
  }
}
PaymentProcessor interface

PaymentProcessor is an interface to allow multiple payment strategies without modifying VendingMachine, enforcing OCP.

🎯 Tests if candidate understands interface is used here for behavior abstraction without state, enabling extensibility.
public interface PaymentProcessor {
  boolean processPayment(double amount);
}
📐
Class Diagram
Class Diagram
       +--------------------+
       | <<Singleton>>      |
       | VendingMachine     |
       |--------------------|
       | - productSlots:List|
       | - paymentProcessor |
       | - changeDispenser  |
       |--------------------|
       | + selectProduct(id)|
       | + insertPayment()  |
       | + dispenseProduct()|
       | + refill()         |
       +--------------------+
               ◆ composition
               │
       +--------------------+
       | <<Abstract>>       |
       | Product            |
       |--------------------|
       | - id: String       |
       | - name: String     |
       | - price: double    |
       |--------------------|
       | + getPrice():double|
       | + getName():String |
       +--------------------+
               ▲ inheritance
               │
       +--------------------+
       | ProductSlot        |
       |--------------------|
       | - product: Product |
       | - quantity: int    |
       |--------------------|
       | + isAvailable():bool|
       | + dispense(): void |
       +--------------------+
               ─ ─ ─► realization
               │
       +--------------------+
       | PaymentProcessor   |
       | <<Interface>>      |
       |--------------------|
       | + processPayment() |
       +--------------------+
               ▲
               │
       +--------------------+
       | ChangeDispenser    |
       |--------------------|
       | + dispenseChange() |
       +--------------------+

This Vending Machine design uses a volatile Singleton pattern for VendingMachine to ensure thread-safe lazy initialization and a single instance controlling the machine lifecycle. The Product class is abstract because it holds shared instance state such as id, name, and price, which interfaces cannot hold in Java. ProductSlot extends Product to add slot-specific state and synchronized methods for availability and dispensing, ensuring thread-safe state mutation. PaymentProcessor is an interface to allow multiple payment implementations following the Open-Closed Principle, enabling extensibility without modifying existing code. Composition is used as VendingMachine owns ProductSlots, enforcing lifecycle dependency.

Primary Focus

✓ Composition lifecycle + Abstract class state + Interface realization + Singleton volatile

Practice

(1/5)
1. A class has a private constructor and a static synchronized getInstance() method returning a single instance. Which pattern is applied and why is this the CORRECT use case?
easy
A. Factory Method pattern, because it controls object creation with a static method.
B. Prototype pattern, to clone existing instances instead of creating new ones.
C. Builder pattern, to construct complex objects step-by-step.
D. Singleton pattern, ensuring only one instance exists and is thread-safe.

Solution

  1. Step 1: Identify the pattern from constructor and method

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single shared instance with thread safety.
  2. Step 2: Eliminate other creational patterns

    Factory Method creates objects but doesn't enforce single instance; Builder constructs complex objects but not singleton; Prototype clones instances, not restricts to one.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized static getter -> Singleton pattern [check]
Hint: Private constructor + static synchronized getter -> Singleton [check]
Common Mistakes:
2. The brokerage system currently calculates fees using a FeeCalculator class. To add a new WeekendFeeStrategy without modifying existing code, which SOLID principle applies and what is the minimum change required?
medium
A. Open/Closed Principle: Create a new WeekendFeeStrategy class implementing FeeStrategy interface; FeeCalculator uses polymorphism.
B. Single Responsibility Principle: Modify FeeCalculator to handle weekend fees explicitly.
C. Dependency Inversion Principle: Inject concrete WeekendFeeStrategy directly into FeeCalculator constructor.
D. Liskov Substitution Principle: Replace FeeCalculator with WeekendFeeCalculator subclass overriding fee logic.

Solution

  1. Step 1: Identify the SOLID principle for extensibility

    Open/Closed Principle (OCP) states software entities should be open for extension but closed for modification.
  2. Step 2: How to apply OCP here

    Create a new class WeekendFeeStrategy implementing FeeStrategy interface; FeeCalculator uses polymorphism to apply different strategies without modification.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class + polymorphism -> OCP compliance [check]
Hint: Add new fee strategy class, no FeeCalculator changes [check]
Common Mistakes:
3. LinkedIn wants to add a WeekendFeeStrategy for job posting fees without modifying existing classes. According to SOLID principles, what is the minimum change required to support this?
medium
A. Extend FeeCalculator with a subclass that overrides fee calculation for weekends.
B. Modify the existing FeeCalculator class to add weekend fee logic with an if-else block.
C. Add a boolean flag isWeekend to JobPosting and handle fees internally.
D. Create a new class implementing FeeStrategy for weekend fees and inject it where needed.

Solution

  1. Step 1: Identify the SOLID principle involved

    The Open-Closed Principle (OCP) requires that classes be open for extension but closed for modification.
  2. Step 2: Apply OCP to fee strategy

    Creating a new WeekendFeeStrategy class implementing the existing FeeStrategy interface allows extension without modifying existing classes.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    New FeeStrategy class extends behavior without modifying existing code [check]
Hint: OCP: add new class, don't modify existing [check]
Common Mistakes:
4. You want to add a WeekendFeeStrategy to a parking system using the Observer pattern. According to SOLID principles, what is the minimum change required to support this new pricing without modifying existing classes?
medium
A. Modify the existing FeeStrategy class to add weekend logic with an if-else block.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and register it as an observer without changing existing code.
C. Add a boolean flag in the Subject to indicate weekend and notify observers to adjust fees accordingly.
D. Create a subclass of the existing FeeStrategy with weekend logic and replace all references.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires adding new behavior without modifying existing code.
  2. Step 2: Evaluate options

    Modify the existing FeeStrategy class to add weekend logic with an if-else block. modifies existing class, violating OCP; Create a new WeekendFeeStrategy class implementing FeeStrategy and register it as an observer without changing existing code. adds new class but registering as observer for fee strategy is not typical; Create a subclass of the existing FeeStrategy with weekend logic and replace all references. requires replacing references, increasing coupling.
  3. Step 3: Add a boolean flag in the Subject to indicate weekend and notify observers to adjust fees accordingly. adds a weekend flag in Subject and notifies observers to adjust fees, allowing extension without modifying existing classes.

  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Weekend flag in Subject triggers observers -> new behavior without modifying existing classes [check]
Hint: OCP: add weekend flag and notify observers, no class changes [check]
Common Mistakes:
5. ElectricCar requires ChargingSpots in the Amazon Locker Service design. What is the minimum change to support this without modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
B. Modify Vehicle and Spot classes to add electric-specific fields and methods for charging compatibility.
C. Create a new ElectricCarChargingManager class that extends LockerManager and handles charging spots separately.
D. Add a boolean isElectric field to Vehicle and Spot classes and update existing logic to handle charging.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Enums VehicleType and SpotType can be extended with new constants without changing existing class logic. Creating ElectricCar subclass extends Vehicle cleanly.
  2. Step 2: Update SpotCompatibility map externally

    Maintaining compatibility mapping outside existing classes avoids modifying them, preserving OCP and avoiding class explosion.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Extend enums + subclass + external compatibility map -> minimal change [check]
Hint: Extend enums + subclass + external map -> no existing class 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