Bird
Raised Fist0

Design an Online Stock Brokerage - Portfolio, Trade, Order, Market Data, P&L

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
Portfolio and PortfolioManager composition

PortfolioManager composes multiple Portfolio instances, owning their lifecycle strongly.

🎯 Tests understanding of composition in Java where PortfolioManager holds and manages Portfolio objects lifecycle.
public class PortfolioManager {
    private final Map<String, Portfolio> portfolios = new HashMap<>();
    public synchronized Portfolio createPortfolio(String ownerId) {
        Portfolio p = new Portfolio(ownerId);
        portfolios.put(ownerId, p);
        return p;
    }
    public synchronized Portfolio getPortfolio(String ownerId) {
        return portfolios.get(ownerId);
    }
}
Portfolio as abstract class holding state

Portfolio is abstract because it holds shared state like positions and ownerId, which interfaces cannot hold in Java.

🎯 Tests why abstract class is chosen over interface due to instance fields like positions and ownerId.
public abstract class Portfolio {
    protected List<Position> positions = new ArrayList<>();
    protected String ownerId;
    public Portfolio(String ownerId) {
        this.ownerId = ownerId;
    }
    public abstract double getPnL();
    public synchronized void addPosition(Position pos) {
        positions.add(pos);
    }
    public synchronized void removePosition(Position pos) {
        positions.remove(pos);
    }
}
OrderBook association with Order

OrderBook holds a list of Orders but does not own their lifecycle strictly, indicating association.

🎯 Tests understanding of association vs composition and lifecycle independence in Java collections.
public class OrderBook {
    private final List<Order> orders = new ArrayList<>();
    public synchronized void addOrder(Order order) {
        orders.add(order);
    }
    public synchronized void removeOrder(Order order) {
        orders.remove(order);
    }
}
Trade as concrete realization

Trade is a concrete class with execute() method realizing trade behavior.

🎯 Tests candidate's ability to identify concrete class implementing behavior and managing trade execution.
public class Trade {
    private final String tradeId;
    private final double price;
    public Trade(String tradeId, double price) {
        this.tradeId = tradeId;
        this.price = price;
    }
    public void execute() {
        // execute trade logic
    }
}
📐
Class Diagram
Class Diagram
       +------------------+
       |  <<Abstract>>    |
       |    Portfolio     |
       +------------------+
       | -positions: List |
       | -ownerId: String |
       +------------------+
       | +addPosition()   |
       | +removePosition()|
       | +getPnL(): double|
       +------------------+
              ◆ composition
              │
       +------------------+
       | PortfolioManager |
       +------------------+
       | -portfolios: Map |
       +------------------+
       | +createPortfolio()|
       | +getPortfolio()   |
       +------------------+
              ──► association
              │
       +------------------+
       |    OrderBook     |
       +------------------+
       | -orders: List    |
       +------------------+
       | +addOrder()      |
       | +removeOrder()   |
       +------------------+
              ──► association
              │
       +------------------+
       |      Trade       |
       +------------------+
       | -tradeId: String |
       | -price: double   |
       +------------------+
       | +execute()       |
       +------------------+

This class diagram illustrates key Java design decisions in an online stock brokerage system. Portfolio is an abstract class because it holds shared mutable state like positions and ownerId, which interfaces cannot hold in Java. PortfolioManager composes Portfolio instances, enforcing strong lifecycle ownership (composition). OrderBook associates with Orders, reflecting a weaker lifecycle relationship (association). Trade is a concrete class realizing trade execution behavior. These decisions enforce SOLID principles: Portfolio abstraction supports Open-Closed Principle by allowing extensions without modification, and composition in PortfolioManager supports Single Responsibility Principle by managing portfolios' lifecycle. The diagram also clarifies lifecycle ownership and state management using Java-specific constructs like synchronized methods for thread safety.

Primary Focus

✓ Composition lifecycle + Abstract class state + Association vs Composition + Realization of Trade

Practice

(1/5)
1. In designing the Player abstraction for the Snake and Ladder game, should Player be an abstract class or an interface, and why?
easy
A. Player should be an interface because it only defines behavior without state.
B. Player should be an abstract class because it holds common state like current position and provides default methods.
C. Player should be an interface to allow multiple inheritance of behaviors.
D. Player should be an abstract class to enforce implementation of all methods in subclasses.

Solution

  1. Step 1: Analyze state and behavior requirements

    The Player has common state such as current position on the board and methods like move().
  2. Step 2: Choose abstraction type

    An abstract class allows sharing state and default method implementations, which interfaces (pre-Java 8) cannot provide.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Abstract class holds shared state and behavior [check]
Hint: State + default behavior -> abstract class, not interface [check]
Common Mistakes:
2. In the ATM system, the Transaction class uses a private constructor and exposes a static synchronized getInstance() method to create transaction objects. Which design pattern is applied here and why is it the correct choice?
easy
A. Factory Method pattern, because it allows subclasses to decide which Transaction subclass to instantiate.
B. Singleton pattern, because it ensures only one Transaction instance exists system-wide.
C. Builder pattern, because it separates complex Transaction construction from its representation.
D. Singleton pattern, because synchronized getInstance() ensures thread-safe lazy initialization.

Solution

  1. Step 1: Identify the pattern from private constructor and static synchronized getInstance()

    This is a classic Singleton pattern implementation ensuring only one instance per JVM with thread-safe lazy initialization.
  2. Step 2: Eliminate other patterns

    Factory Method involves subclassing and delegation, not private constructors. Builder separates construction steps, unrelated here. Singleton pattern, because it ensures only one Transaction instance exists system-wide. is wrong because Singleton is about single instance, but synchronized getInstance() is the key for thread safety.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized getInstance() -> thread-safe Singleton [check]
Hint: Private constructor + synchronized getInstance() -> thread-safe Singleton [check]
Common Mistakes:
3. A class has a private constructor and a static synchronized getInstance() method that returns the single instance. Which design pattern is applied here and why is this the CORRECT use case?
easy
A. Singleton pattern, because it ensures only one instance exists and provides global access.
B. Factory Method pattern, because it controls object creation through a static method.
C. Builder pattern, because it constructs complex objects step-by-step.
D. Prototype pattern, because it clones existing instances to create new ones.

Solution

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

    The private constructor prevents external instantiation, and the static synchronized getInstance() method controls instance creation, which matches Singleton pattern characteristics.
  2. Step 2: Explain why Singleton fits this use case

    Singleton ensures a single instance with thread-safe access via synchronization, suitable for shared resources like configuration or logging.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized static getInstance() -> Singleton pattern [check]
Hint: Private constructor + static synchronized getInstance() -> Singleton [check]
Common Mistakes:
4. In designing an Elevator system using the State pattern, should the ElevatorState be an abstract class or an interface, and why?
easy
A. Interface, because states only define behavior without shared implementation
B. Abstract class, because states share common code and state variables
C. Abstract class, because it enforces a single inheritance hierarchy
D. Interface, because it allows multiple inheritance of state behaviors

Solution

  1. Step 1: Analyze shared code in states

    Elevator states often share common fields (e.g., reference to context) and helper methods, which favors an abstract class.
  2. Step 2: Evaluate interface limitations

    Interfaces cannot hold state or provide default implementations (prior to Java 8), so they are less suitable if shared code exists.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Shared code and state -> abstract class [check]
Hint: Shared code and state -> abstract class; behavior only -> interface [check]
Common Mistakes:
5. In the FollowService, the method followUser() checks if the follower already follows the followee before adding. Without synchronization, which exact thread interleaving causes a double-follow entry?
medium
A. Thread 1 and Thread 2 both wait on a lock, preventing double-follow.
B. Thread 1 reads follower list, Thread 2 removes follower, both add follower again.
C. Thread 1 adds follower, Thread 2 reads follower list after addition, no conflict.
D. Thread 1 checks isFollowing() -> false, context switch, Thread 2 checks isFollowing() -> false, both add follower.

Solution

  1. Step 1: Identify the check-then-act race condition

    Both threads call isFollowing() and get false before either adds the follower, due to lack of synchronization.
  2. Step 2: Resulting double addition

    Both threads proceed to add the follower, causing duplicate entries.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Check-then-act gap -> both see false -> both add follower [check]
Hint: Check-then-act without sync -> double add race [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