Back to LLD explorer
OOD / Concurrency• Patterns: Strategy, Observer, State

Ride Sharing

Hard

Problem Summary

Design a Carpooling / Ride-Sharing Pool engine matching multiple riders traveling in the same directional corridor, validating detour constraints, and dynamically splitting fares.

Functional Scope

  • Match multiple riders to a single shared vehicle along directional routes.
  • Detour time threshold validation (e.g. maximum 10-minute detour for any passenger).
  • Dynamic passenger fare sharing based on shared vs individual distance ratios.
  • Vehicle capacity tracking (max 4 passengers seated simultaneously).
  • Observer notifications alerting riders of intermediate pickup and dropoff stops.

Entity-Relationship (ER) Schema

PoolRide [1] --> [1] Driver
PoolRide [1] --> [1..4] RiderBooking
PoolRide [1] --> [*] WaypointStop
PoolRide [1] --> [1] DetourStrategy

Design Approach

Apply the Strategy pattern for detour margin calculations and vehicle seat capacity synchronization to ensure carpool limits are strictly enforced.

Core Classes & Models

PoolRide (Driver, active passengers, route waypoints, vehicle capacity)RiderBooking (Rider, pickup, dropoff, fare)WaypointStop (Location, stopType: PICKUP, DROPOFF, riderReference)DetourStrategy (Calculates marginal travel time and route deviation)FareSplitStrategy (Proportionally shares costs among co-riders)
Code Blueprint
62 lines
/**
 * Low-Level Design: Ride Sharing Peer Service
 * Design Patterns Applied:
 *  - Strategy Pattern: Route optimization and dynamic trip fare estimation
 *  - Observer Pattern: Real-time driver telemetry coordinates to rider
 *  - State Pattern: Ride lifecycle state machine (Requested, Matched, InTransit, Finished)
 */

import java.util.*;

enum RidePhase { REQUESTED, MATCHED, IN_TRANSIT, FINISHED }

// --- [DESIGN PATTERN: Strategy] Ride fare calculation ---
interface FareStrategy {
    double calculateFare(double distanceKm, int seats);
}

class StandardCarpoolFareStrategy implements FareStrategy {
    @Override
    public double calculateFare(double distanceKm, int seats) {
        return (4.0 + distanceKm * 1.5) / Math.max(1, seats);
    }
}

// --- [DESIGN PATTERN: Observer] Telemetry tracking observer ---
interface DriverTelemetryObserver {
    void onLocationUpdated(String driverId, double lat, double lng);
}

class RiderTrackingDisplay implements DriverTelemetryObserver {
    @Override
    public void onLocationUpdated(String driverId, double lat, double lng) {
        System.out.printf("📍 [Live Map] Driver %s location: (%.4f, %.4f)%n", driverId, lat, lng);
    }
}

class RideSharingCoordinator {
    private final FareStrategy fareStrategy = new StandardCarpoolFareStrategy();
    private final List<DriverTelemetryObserver> observers = new ArrayList<>();

    public void addObserver(DriverTelemetryObserver o) { observers.add(o); }

    public double quoteTrip(double distanceKm, int seats) {
        return fareStrategy.calculateFare(distanceKm, seats);
    }

    public void updateDriverGps(String driverId, double lat, double lng) {
        for (DriverTelemetryObserver o : observers) o.onLocationUpdated(driverId, lat, lng);
    }
}

public class Main {
    public static void main(String[] args) {
        RideSharingCoordinator service = new RideSharingCoordinator();
        service.addObserver(new RiderTrackingDisplay());

        double fare = service.quoteTrip(15.0, 3);
        System.out.printf("Split Carpool Fare per person: $%.2f%n", fare);

        service.updateDriverGps("DRV-99", 37.7749, -122.4194);
    }
}