Problem Statement
Design a ride-sharing system where users can request rides from one location to another. The system should match users with nearby drivers, allow drivers to accept rides, and complete trips while tracking ride status.
Functional Requirements
- Users should be able to request a ride from source to destination
- System should match the ride with an available nearby driver
- Driver should be able to accept or reject a ride request
- Ride status should be tracked (REQUESTED, ACCEPTED, COMPLETED, CANCELLED)
- Once a ride is completed, driver becomes available again
Objects Required
- User
- Driver
- Location
- Ride
- RideStatus
- RideService
- DriverMatchingStrategy
RideStatus Enum
public enum RideStatus {
REQUESTED,
ACCEPTED,
COMPLETED,
CANCELLED
}
This enum represents the lifecycle of a ride. Every ride starts in a requested state and moves through different stages depending on driver and system actions.
Location Class
public class Location {
double x;
double y;
public Location(double x, double y) {
this.x = x;
this.y = y;
}
public double distanceFrom(Location other) {
return Math.sqrt(
Math.pow(this.x - other.x, 2) +
Math.pow(this.y - other.y, 2)
);
}
}
The constructor simply stores the coordinates of a point in the city.
The distanceFrom() method calculates the distance between two locations. This helps in finding the nearest driver during ride matching.
User Class
public class User {
private String userId;
private String name;
private Location location;
public User(String userId, String name, Location location) {
this.userId = userId;
this.name = name;
this.location = location;
}
public Location getLocation() {
return location;
}
public String getName() {
return name;
}
}
The constructor initializes a user with identity details and current location.
The getLocation() method is used by the system to determine where the user is requesting the ride from.
The getName() method is used for display and logging purposes.
Driver Class
public class Driver {
private String driverId;
private String name;
private Location location;
private boolean available;
public Driver(String driverId, String name, Location location) {
this.driverId = driverId;
this.name = name;
this.location = location;
this.available = true;
}
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
public Location getLocation() {
return location;
}
}
The constructor initializes a driver and marks them available by default.
The isAvailable() method helps the system decide whether this driver can be assigned a ride.
The setAvailable() method updates driver status when a ride is accepted or completed.
The getLocation() method is used for matching the closest driver to a user.
Ride Class
public class Ride {
private String rideId;
private User user;
private Driver driver;
private Location source;
private Location destination;
private RideStatus status;
public Ride(String rideId, User user, Location source, Location destination) {
this.rideId = rideId;
this.user = user;
this.source = source;
this.destination = destination;
this.status = RideStatus.REQUESTED;
}
public void assignDriver(Driver driver) {
this.driver = driver;
this.status = RideStatus.ACCEPTED;
driver.setAvailable(false);
}
public void completeRide() {
this.status = RideStatus.COMPLETED;
driver.setAvailable(true);
}
public RideStatus getStatus() {
return status;
}
}
The constructor creates a ride request and sets its initial status as REQUESTED.
The assignDriver() method connects a driver to the ride and marks the ride as accepted. It also immediately marks the driver as unavailable so they don’t get assigned another ride.
The completeRide() method marks the ride as finished and frees the driver so they can accept new requests again.
The getStatus() method helps external systems track the current state of the ride.
DriverMatchingStrategy Interface
import java.util.*;
public interface DriverMatchingStrategy {
Driver findDriver(List drivers, Location source);
}
This interface defines the contract for matching drivers. Different strategies like nearest-driver-first or rating-based matching can be implemented later without changing core logic.
NearestDriverMatchingStrategy
import java.util.*;
public class NearestDriverMatchingStrategy implements DriverMatchingStrategy {
public Driver findDriver(List drivers, Location source) {
Driver bestDriver = null;
double minDistance = Double.MAX_VALUE;
for (Driver driver : drivers) {
if (!driver.isAvailable()) continue;
double dist = driver.getLocation().distanceFrom(source);
if (dist < minDistance) {
minDistance = dist;
bestDriver = driver;
}
}
return bestDriver;
}
}
The method loops through all drivers and ignores those who are not available.
It calculates distance from the user’s location and picks the closest driver.
This keeps matching logic flexible and replaceable in the future.
RideService Class
import java.util.*;
public class RideService {
private List drivers;
private DriverMatchingStrategy strategy;
public RideService(List drivers,
DriverMatchingStrategy strategy) {
this.drivers = drivers;
this.strategy = strategy;
}
public Ride requestRide(User user,
Location source,
Location destination) {
Ride ride = new Ride(
UUID.randomUUID().toString(),
user,
source,
destination
);
Driver driver = strategy.findDriver(drivers, source);
if (driver == null) {
System.out.println("No driver available");
return null;
}
ride.assignDriver(driver);
return ride;
}
public void completeRide(Ride ride) {
ride.completeRide();
}
}
The constructor initializes the system with a pool of drivers and a matching strategy.
The requestRide() method creates a new ride request and asks the strategy to find the best available driver. If no driver is found, the request fails gracefully.
If a driver is found, the ride is assigned immediately and marked as active.
The completeRide() method simply delegates completion logic to the Ride class.
Main Class
import java.util.*;
public class Main {
public static void main(String[] args) {
User user =
new User("U1", "Prasanna", new Location(10, 10));
Driver d1 =
new Driver("D1", "Driver A", new Location(11, 10));
Driver d2 =
new Driver("D2", "Driver B", new Location(20, 20));
List drivers =
Arrays.asList(d1, d2);
RideService service =
new RideService(
drivers,
new NearestDriverMatchingStrategy()
);
Ride ride =
service.requestRide(
user,
new Location(10, 10),
new Location(15, 15)
);
if (ride != null) {
System.out.println("Ride started successfully");
}
service.completeRide(ride);
System.out.println("Ride completed");
}
}
The main method creates users and drivers, then initializes the ride service.
A ride request is made, and the system automatically assigns the nearest available driver.
Finally, the ride is completed and the driver becomes available again.
Comments
Post a Comment