The “Design an Object-Oriented (OO) Parking Lot” question is a common topic in Amazon’s interview process. This question tests a candidate’s ability to apply object-oriented design principles to solve real-world problems. Understanding this question is crucial as it demonstrates your proficiency in designing scalable, maintainable systems, which is a key skill for software development roles at Amazon.
Here’s a detailed breakdown of the requirements for designing an object-oriented (OO) parking lot system for an Amazon interview:
Parking Spot Assignment:
Parking Spot Availability:
Vehicle Entry and Exit:
Payment System:
Monitoring and Reporting:
ParkingLot:
parkVehicle()
, leaveSpot()
, getAvailableSpots()
.ParkingSpot:
assignVehicle()
, removeVehicle()
.Vehicle:
getType()
.Ticket:
calculateFee()
, issueReceipt()
.Payment:
processPayment()
, generateReceipt()
.This design ensures a structured and scalable approach to managing a parking lot system.
Here are the key classes and objects for designing an OO parking lot:
ParkingLot
name
, address
, totalSpots
, availableSpots
, parkingSpots
(list of ParkingSpot)addParkingSpot()
, removeParkingSpot()
, findAvailableSpot()
, parkVehicle()
, removeVehicle()
ParkingSpot
spotId
, spotType
(enum: Regular, Handicapped, Compact), isAvailable
, vehicle
(Vehicle)assignVehicle()
, removeVehicle()
Vehicle
licensePlate
, vehicleType
(enum: Car, Truck, Motorcycle)getVehicleType()
Ticket
ticketId
, vehicle
(Vehicle), parkingSpot
(ParkingSpot), entryTime
, exitTime
calculateParkingFee()
ParkingAttendant
name
, employeeId
issueTicket()
, processPayment()
Relationships:
ParkingLot
contains multiple ParkingSpot
.ParkingSpot
can be assigned to a Vehicle
.Vehicle
is associated with a Ticket
.ParkingAttendant
manages Ticket
issuance and payment processing.This structure ensures a clear and organized design for the parking lot system.
Let’s dive into the design patterns and principles for designing an object-oriented parking lot system, focusing on the Singleton, Factory, and Strategy patterns.
ParkingLot
class to ensure there’s only one instance of the parking lot throughout the application.Car
, Bike
, Truck
).CompactSpotStrategy
, LargeSpotStrategy
, and HandicappedSpotStrategy
.ParkingSpot
managing spot details and Vehicle
managing vehicle details.Car
or Bike
can replace Vehicle
without altering the correctness of the program.IParkable
for parking-related methods.These patterns and principles will help you create a robust, flexible, and maintainable parking lot system.
Here’s a step-by-step implementation strategy for designing an object-oriented parking lot system:
public abstract class ParkingSpot {
private String number;
private boolean isAvailable;
private Vehicle vehicle;
public ParkingSpot(String number) {
this.number = number;
this.isAvailable = true;
}
public boolean isAvailable() {
return isAvailable;
}
public void parkVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
this.isAvailable = false;
}
public void removeVehicle() {
this.vehicle = null;
this.isAvailable = true;
}
public abstract boolean canFitVehicle(Vehicle vehicle);
}
public abstract class Vehicle {
private String licensePlate;
private final VehicleSize size;
public Vehicle(String licensePlate, VehicleSize size) {
this.licensePlate = licensePlate;
this.size = size;
}
public VehicleSize getSize() {
return size;
}
}
public enum VehicleSize {
MOTORCYCLE, COMPACT, LARGE
}
public class Car extends Vehicle {
public Car(String licensePlate) {
super(licensePlate, VehicleSize.COMPACT);
}
}
public class Bike extends Vehicle {
public Bike(String licensePlate) {
super(licensePlate, VehicleSize.MOTORCYCLE);
}
}
public class Truck extends Vehicle {
public Truck(String licensePlate) {
super(licensePlate, VehicleSize.LARGE);
}
}
public class ParkingLot {
private List<ParkingSpot> compactSpots;
private List<ParkingSpot> largeSpots;
private List<ParkingSpot> motorcycleSpots;
public ParkingLot(int compactCount, int largeCount, int motorcycleCount) {
compactSpots = new ArrayList<>(compactCount);
largeSpots = new ArrayList<>(largeCount);
motorcycleSpots = new ArrayList<>(motorcycleCount);
for (int i = 0; i < compactCount; i++) {
compactSpots.add(new CompactSpot("C" + i));
}
for (int i = 0; i < largeCount; i++) {
largeSpots.add(new LargeSpot("L" + i));
}
for (int i = 0; i < motorcycleCount; i++) {
motorcycleSpots.add(new MotorcycleSpot("M" + i));
}
}
public boolean parkVehicle(Vehicle vehicle) {
ParkingSpot spot = findAvailableSpot(vehicle);
if (spot != null) {
spot.parkVehicle(vehicle);
return true;
}
return false;
}
private ParkingSpot findAvailableSpot(Vehicle vehicle) {
List<ParkingSpot> spots = getSpots(vehicle.getSize());
for (ParkingSpot spot : spots) {
if (spot.isAvailable() && spot.canFitVehicle(vehicle)) {
return spot;
}
}
return null;
}
private List<ParkingSpot> getSpots(VehicleSize size) {
switch (size) {
case MOTORCYCLE:
return motorcycleSpots;
case COMPACT:
return compactSpots;
case LARGE:
return largeSpots;
default:
return new ArrayList<>();
}
}
}
public class CompactSpot extends ParkingSpot {
public CompactSpot(String number) {
super(number);
}
@Override
public boolean canFitVehicle(Vehicle vehicle) {
return vehicle.getSize() == VehicleSize.COMPACT || vehicle.getSize() == VehicleSize.MOTORCYCLE;
}
}
public class LargeSpot extends ParkingSpot {
public LargeSpot(String number) {
super(number);
}
@Override
public boolean canFitVehicle(Vehicle vehicle) {
return true; // Large spots can fit any vehicle
}
}
public class MotorcycleSpot extends ParkingSpot {
public MotorcycleSpot(String number) {
super(number);
}
@Override
public boolean canFitVehicle(Vehicle vehicle) {
return vehicle.getSize() == VehicleSize.MOTORCYCLE;
}
}
public class ParkingTicket {
private String ticketNumber;
private LocalDateTime issuedAt;
private LocalDateTime paidAt;
private ParkingSpot spot;
private Vehicle vehicle;
public ParkingTicket(String ticketNumber, ParkingSpot spot, Vehicle vehicle) {
this.ticketNumber = ticketNumber;
this.issuedAt = LocalDateTime.now();
this.spot = spot;
this.vehicle = vehicle;
}
public void payTicket() {
this.paidAt = LocalDateTime.now();
}
}
public class ParkingDisplayBoard {
private int availableCompactSpots;
private int availableLargeSpots;
private int availableMotorcycleSpots;
public void updateDisplay(int compact, int large, int motorcycle) {
this.availableCompactSpots = compact;
this.availableLargeSpots = large;
this.availableMotorcycleSpots = motorcycle;
display();
}
private void display() {
System.out.println("Compact Spots: " + availableCompactSpots);
System.out.println("Large Spots: " + availableLargeSpots);
System.out.println("Motorcycle Spots: " + availableMotorcycleSpots);
}
}
This should give you a solid foundation for designing an OO parking lot system. You can expand on this by adding more features like payment processing, reservation systems, and more.
Overcomplicating the Design:
Ignoring Edge Cases:
Poor Class Design:
Lack of Flexibility:
Understand Requirements Thoroughly:
Use Design Patterns:
Modular Design:
Consider Extensibility:
Start with a High-Level Design:
Iterate and Refine:
Use UML Diagrams:
Code Reviews and Feedback:
By keeping these points in mind, you can create a robust and scalable design for the parking lot system. Good luck with your interview preparation! 🅿️
It’s essential to focus on the core concepts and prepare thoroughly for this challenging question.
A well-designed parking lot system should have classes for different types of vehicles (e.g., compact, large, motorcycle), as well as a class to manage the parking spots. Each class should have its own responsibilities and attributes, making it easier to maintain and extend the system.
To avoid common pitfalls, ensure you understand the requirements thoroughly, use design patterns, and consider extensibility when designing the system. Start with a high-level design, iterate and refine it based on feedback and new insights, and use UML diagrams to visualize the design effectively.
By focusing on these key points and preparing thoroughly, you’ll be well-equipped to tackle the Amazon interview question and showcase your skills in designing an OO parking lot system.