Requirements
- Parkign Lot has floors and each floor has parking spots
- There will be vehicle types, for each vehicle type parking fee will be different
- Parking fee is based on duration
- there will be entry time and exit time will be calculated
Define Core Objects
Core Objects
- models
Vehicle
VehicleType
ParkingSpot
ParkingFloor
ParkingLOt
ParkingTicket
- services
PArkingService
ParkingFeeservice
Analyze Relationships
- Each Vehicle has Vehicle Type
- Each oarking floor has parking spots based on vehicle type
- each parking lot has multiple parking floors
- For each parking ticket there will be vehicle entry and exit time
Establish Hierarchy
Design inheritance trees where applicable to promote code reuse and polymorphism. This step involves identifying common attributes and behaviors that can be abstracted into parent classes...
Design Patterns
- ParkingLot is a singleton
Define Class Members (write code)
Attributes: For each class, define the attributes (data) it will hold...
Methods: Define the methods (functions) that operate on the attributes. Ensure they align with the object's responsibilities and adhere to the principle of encapsulation.
public class ParkingFloor {
private Integer floorNumber;
private List<ParkingSpot> parkingSpots;
public ParkingFloor(Integer floorNumber) {
this.floorNumber = floorNumber;
this.parkingSpots = new ArrayList<>();
}
public void addParkingSpot(ParkingSpot spot) {
parkingSpots.add(spot);
}
public ParkingSpot getAvailableSpot(VehicleType vehicleType) {
for (ParkingSpot spot : parkingSpots) {
if (spot.isAvailable() && spot.getVehicleType()==vehicleType) {
return spot;
}
}
return null;
}
public Integer getFloorNumber() {
return floorNumber;
}
public List<ParkingSpot> getParkingSpots() {
return parkingSpots;
}
}
public class ParkingLot {
private String name;
private List<ParkingFloor> floors;
public ParkingLot(String name) {
this.name = name;
this.floors = new ArrayList<>();
}
public void addFloor(ParkingFloor floor) {
floors.add(floor);
}
public ParkingSpot assignParkingSpot(Vehicle vehicle) {
for (ParkingFloor floor : floors) {
ParkingSpot spot = floor.getAvailableSpot(vehicle.getVehicleTYpe());
if (spot!=null) {
spot.setCurrentVehicle(vehicle);
return spot;
}
}
return null;
}
public void releaseParkingSpot(ParkingSpot spot) {
spot.removeVehicle();
}
public List<ParkingSpot> getAvailableSpots(VehicleType vehicleType) {
List<ParkingSpot> availableSpots = new ArrayList<>();
for (ParkingFloor floor : floors) {
for (ParkingSpot spot : floor.getParkingSpots()) {
if (spot.isAvailable() && spot.getVehicleType()==vehicleType) {
availableSpots.add(spot);
}
}
}
return availableSpots;
}
public String getName() {
return name;
}
public List<ParkingFloor> getFloors() {
return floors;
}
}
public class ParkingSpot {
private String spotID;
private VehicleType vehicleType;
private boolean isAvailable;
private Vehicle currentVehicle;
public ParkingSpot(String spotID, VehicleType vehicleType) {
this.spotID = spotID;
this.vehicleType = vehicleType;
this.isAvailable = true;
}
public String getSpotID() {
return spotID;
}
public VehicleType getVehicleType() {
return vehicleType;
}
public boolean isAvailable() {
return isAvailable;
}
public void setCurrentVehicle(Vehicle currentVehicle) {
this.currentVehicle = currentVehicle;
this.isAvailable = false;
}
public Vehicle getCurrentVehicle() {
return currentVehicle;
}
public void removeVehicle() {
this.currentVehicle = null;
this.isAvailable = true;
}
}
public class ParkingTicket {
private String ticketId;
private Vehicle vehicle;
private ParkingSpot parkingSpot;
private LocalDateTime entryTime;
private LocalDateTime exitTime;
private double fee;
public ParkingTicket(String ticketId, Vehicle vehicle, ParkingSpot parkingSpot, LocalDateTime entryTime) {
this.ticketId = ticketId;
this.vehicle = vehicle;
this.parkingSpot = parkingSpot;
this.entryTime = entryTime;
}
public void setExitTime(LocalDateTime exitTime) {
this.exitTime = exitTime;
}
public void setFee(double fee) {
this.fee = fee;
}
public String getTicketId() {
return ticketId;
}
public Vehicle getVehicle() {
return vehicle;
}
public ParkingSpot getParkingSpot() {
return parkingSpot;
}
public LocalDateTime getEntryTime() {
return entryTime;
}
public LocalDateTime getExitTime() {
return exitTime;
}
public double getFee() {
return fee;
}
}
public class Vehicle {
private String vehicleNumber;
private VehicleType vehicleTYpe;
public Vehicle(String vehicleNumber, VehicleType vehicleTYpe) {
this.vehicleNumber = vehicleNumber;
this.vehicleTYpe = vehicleTYpe;
}
public String getVehicleNumber() {
return vehicleNumber;
}
public VehicleType getVehicleTYpe() {
return vehicleTYpe;
}
}
public enum VehicleType {
MOTORCYCLE,
COMPACT,
REGULAR,
LARGE
}
public class FeeCalculator {
private static final double MOTORCYCLE_RATE = 10.0;
private static final double COMPACT_RATE = 20.0;
private static final double REGULAR_RATE = 30.0;
private static final double LARGE_RATE = 40.0;
public static double calculateFee(ParkingTicket ticket) {
Duration duration = Duration.between(ticket.getEntryTime(), ticket.getExitTime());
long hours = duration.toHours();
if (duration.toMinutes() % 60 > 0) {
hours += 1; // Charge for an additional hour if not on the hour mark
}
double ratePerHour = getRatePerHour(ticket.getVehicle().getVehicleTYpe());
return hours * ratePerHour;
}
private static double getRatePerHour(VehicleType vehicleType) {
switch (vehicleType) {
case MOTORCYCLE:
return MOTORCYCLE_RATE;
case COMPACT:
return COMPACT_RATE;
case REGULAR:
return REGULAR_RATE;
case LARGE:
return LARGE_RATE;
default:
return REGULAR_RATE;
}
}
}
public class ParkingService {
private ParkingLot parkingLot;
private Map<String, ParkingTicket> activeTickets;
public ParkingService(ParkingLot parkingLot) {
this.parkingLot = parkingLot;
this.activeTickets = new HashMap<>();
}
public ParkingTicket parkVehicle(Vehicle vehicle) {
ParkingSpot parkingSpot = parkingLot.assignParkingSpot(vehicle);
if (parkingSpot==null) {
System.out.println("No avaialble spot for vehicle type: "+vehicle.getVehicleTYpe().toString());
}
String ticketId = UUID.randomUUID().toString();
ParkingTicket ticket = new ParkingTicket(ticketId, vehicle, parkingSpot, LocalDateTime.now());
System.out.println("Vehicle parked at spot: "+parkingSpot.getSpotID().toString());
return ticket;
}
public void exitVehicle(String ticketId) {
ParkingTicket ticket = activeTickets.get(ticketId);
if (ticket == null) {
System.out.println("Invalid ticket ID.");
return;
}
ticket.setExitTime(LocalDateTime.now());
double fee = FeeCalculator.calculateFee(ticket);
ticket.setFee(fee);
parkingLot.releaseParkingSpot(ticket.getParkingSpot());
activeTickets.remove(ticketId);
System.out.println("Vehicle exited. Parking fee: $" + fee);
}
// Check available spots for a vehicle type
public void checkAvailability(VehicleType vehicleType) {
int availableSpots = parkingLot.getAvailableSpots(vehicleType).size();
System.out.println("Available spots for " + vehicleType + ": " + availableSpots);
}
}
Adhere to SOLID Guidelines
Check and explain whether your design adheres to solid principles (Ask interviewer what SOLID principle is if you can not recall it.)...
Consider Scalability and Flexibility
Explain how your design can handle changes in scale and whether it would be easily to extend with new functionalities...
Create/Explain your diagram(s)
Try creating a class, flow, state and/or sequence diagram using the diagramming tool. Mermaid flow diagrams can be used to represent system use cases. You can ask the interviewer bot to create a starter diagram if unfamiliar with the tool. Briefly explain your diagrams if necessary...
Future improvements
Critically examine your design for any flaws or areas for future improvement...