Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsMachine Coding Exercises
✓ FreeAdvanced· 7 min read

Multi-Pattern Problem: Design a Ride Booking Class Model

Combining Strategy (matching, pricing) + State (ride lifecycle) + Observer (real-time updates) in one coherent design, and the discipline of justifying every pattern rather than pattern-stacking for its own sake.

Published September 23, 2026


Multi-Pattern Problem: Design a Ride Booking Class Model

Every pattern lesson so far has isolated one pattern per exercise. Real interview prompts rarely do — this one deliberately combines three, and the actual skill being tested is knowing why each one earns its place, not just being able to name them.

Core classes and where each pattern fits

class Ride {
    Rider rider;
    Driver driver;
    RideState state;          // STATE pattern
    MatchingStrategy matcher;  // STRATEGY pattern
    PricingStrategy pricer;    // STRATEGY pattern
    List<RideObserver> observers = new CopyOnWriteArrayList<>(); // OBSERVER pattern
}

Strategy: matching and pricing

interface MatchingStrategy { Optional<Driver> findDriver(Ride ride, List<Driver> available); }
interface PricingStrategy { double calculateFare(Ride ride); }

Both reuse the exact same reasoning as Food Delivery Order Matching and Design a Ride-Sharing System's matching tradeoffs — which driver gets matched, and how fare is calculated, are independently swappable algorithms with zero reason to be hard-coded into Ride itself.

State: the ride lifecycle

interface RideState { RideState next(Ride ride); }
class RequestedState implements RideState { public RideState next(Ride ride) { return new MatchedState(); } }
class MatchedState implements RideState { public RideState next(Ride ride) { return new InProgressState(); } }
class InProgressState implements RideState { public RideState next(Ride ride) { return new CompletedState(); } }
class CompletedState implements RideState { public RideState next(Ride ride) { return this; } } // terminal

Directly reuses the State pattern shape from Vending Machine Design and Elevator System — a ride's behavior (which actions are even valid) genuinely differs per state, the strongest justification for State pattern per its own "when it earns its complexity" guidance.

Observer: real-time updates

interface RideObserver { void onStateChange(Ride ride, RideState newState); }
class RiderNotifier implements RideObserver { public void onStateChange(Ride ride, RideState state) { /* push to rider's app */ } }
class DriverNotifier implements RideObserver { public void onStateChange(Ride ride, RideState state) { /* push to driver's app */ } }

class Ride {
    void transitionTo(RideState newState) {
        this.state = newState;
        observers.forEach(o -> o.onStateChange(this, newState)); // fires on every state transition
    }
}

Every state transition needs to notify potentially multiple interested parties (rider's app, driver's app, an analytics pipeline) — the exact one-to-many, decoupled-notification shape Observer Pattern exists for.

Justifying every pattern used — the actual skill being tested

The risk this exercise specifically probes: using three patterns because they're available, not because each solves a real, distinct problem in this specific design. The honest justification for each, stated explicitly (exactly what a strong interview answer does unprompted):

  • Strategy earns its place because matching algorithm and pricing model are genuinely expected to vary/evolve independently (surge pricing changes, matching algorithm experiments) without touching Ride's core structure.
  • State earns its place because a ride's valid operations and behavior meaningfully differ across its lifecycle stages — not just a status label, but different allowed actions per stage.
  • Observer earns its place because state changes genuinely need to reach multiple, independent, decoupled subscribers (rider app, driver app, potentially more later) without Ride needing to know about each one specifically.

If any one of these three didn't have a genuine, distinct justification like this, the honest answer would be to drop it — pattern-stacking without justification is over-engineering, and naming that risk explicitly (as this lesson does) is itself part of demonstrating mature design judgment.

Follow-up questions this topic invites — and their answers

Q: Could Command pattern also reasonably fit somewhere in this design? A: Possibly, for something like ride cancellation-with-reason-tracking or an audit log of ride actions — but the exercise's own discipline applies: it would need its own genuine justification (a real need to queue, log, or undo specific actions) rather than being added just because Command is available, echoing the 'discuss over-engineering' framing throughout this course.

Q: Why is transitionTo() the single method that both changes state AND notifies observers, rather than two separate calls? A: Coupling them in one method guarantees observers are ALWAYS notified on a state change — if callers had to remember to call notifyObservers() separately after changing state, a forgotten call would silently desync what the UI shows from the ride's actual state, a real correctness risk this design avoids by construction.

Q: How would you unit test RequestedState.next() in isolation from the full Ride class? A: Since each RideState implementation only depends on the Ride passed into next() (and could be tested with a minimal stub Ride), each state's transition logic is independently testable — one of the practical benefits of State pattern's structure beyond just organizational clarity.

Q: Does adding Observer here risk the same memory-leak pitfall covered earlier in this course? A: Yes, directly — a RiderNotifier or DriverNotifier that's added to observers but never removed after a ride completes (or a rider closes their app) would leak exactly like Observer Pattern's own warning describes; a completed/terminal ride's observer list should be explicitly cleared or the observers should hold weak references, the same fix pattern already covered.

Previous

Design Twitter/X

Next

Multi-Pattern Problem: Design a Food Ordering Class Model

AI Tutor

Lesson: Multi-Pattern Problem: Design a Ride Booking Class Model

Quick actions

AI responses can be inaccurate. Verify critical information.