Requirements


Functional Requirements:


  • Assign parking spots based on vehicle size, allowing motorcycles to park in small spots, cars in medium spots, and trucks in large spots, with the option to park in larger spots if needed.
  • Issue a ParkingTicket upon vehicle entry, which records the vehicle information, assigned parking spot, and entry timestamp.
  • Compute the parking fee upon vehicle exit based on the duration of stay and a configurable pricing strategy.
  • Handle scenarios where the parking lot is full by rejecting entry and displaying a lot-full indicator to the driver.
  • Support multiple floors in the parking lot, with each floor containing a mix of small, medium, and large parking spots.



Non-Functional Requirements:


  • lock the spot assigmnment as if not can same spot be assigned to two people.
  • payment should be relation based like per hour, per day and advance booking. apaptive accordinlgy


Core Objects & Relationships

Based on the requirements and use cases, identify the main objects of the system and analyze how they interact and relate to each other...


  • we have small, medium and large. larger one we will use combination of small, medium and large if size consecitve spot if its size greater than larger.
  • we need defined object as vechile and we can use multiple class with abstarct class. we can add more class as well as per out need.
  • another object is parking spot which contain floor, gate to exist and size
  • other object is parking tcket, contain price, time, time stamp, it also has pricing startegy
  • we can use interface to im-limentpricing startegy



public abstarct class vechile{ private String licencePlate; private String type; public vechile(String licencePlate, String type){ this.licencePlate= licencePlate; this.type= type;

}}

we will implement it like


public class car extend vechile{

public car(String licnecplate){

super(licenceplate, vechiletype.car)

}

}


we make oject vechioe type


public enum vechiletype{ MotorCycle(1), Car(2), Truck(3); private final int size; vechiletype(int size){ this.size=size; } public int getseize(){ return size; } } public enum spottype{ SMALL(1), MEDIUM(2), LARGE(3); private final int size; spottype(int size){ this.size=size; } public int getseize(){ return size; } }

Now we will do pricing startegy. we weill use interface and impliment our funciton with that.


public interface PricingStrategy{ double calculateFee(long durationMinutes, VehicleType vehicleType); } public class hourlypricing impliment PricingStrategy{ private final Map<vechiletype, doube> hourlyrates; public hourlypricing(Map<vechiletype, doube> hourlyrates){ this.hourlyrates=hourlyrates; } @override public double calculateFee(long durationMinutes, VehicleType vehicleType){ double hours = Math.ceil(durationMinutes / 60.0); return hours * hourlyRates.getOrDefault( vehicleType, 5.0); } } public class FlatRatePricing implements PricingStrategy { private final double flatRate; public FlatRatePricing(double flatRate) { this.flatRate = flatRate; } @Override public double calculateFee(long durationMinutes, VehicleType vehicleType) { return flatRate; } } public class AdvanceBookingPricing implements PricingStrategy { private final double bookingCharge; private final double hourlyRate; public AdvanceBookingPricing( double bookingCharge, double hourlyRate) { this.bookingCharge = bookingCharge; this.hourlyRate = hourlyRate; } @Override public double calculateFee( long durationMinutes, VehicleType vehicleType) { double hours = Math.ceil(durationMinutes / 60.0); return bookingCharge + (hours * hourlyRate); } }

Now we define parking spot object


class parkingSpot{ private final string id; private final SpotType spotType; private boolean isAvailable; private Vehicle assignedVehicle; public parkingSpot(string id, SpotType spotType ){ this.id= id; this.spotType= spotType; } public boolean canFit(Vehicle vehicle){ if(!isAvailable){ return false; this.assignedVehicle= vehicle; this.isAvailable=false; return true; } } public synchorized void release(){ this.assignedVehicle= null; this.isAvailable=true; } public String getId() { return id; } public SpotType getSpotType() { return spotType; } public boolean isAvailable() { return isAvailable; } public Vehicle getAssignedVehicle() { return assignedVehicle; } }

}


now we will make object o fparking ticket


public class parkingTicket{ private final String ticketId; private final Vehicle vehicle; private final ParkingSpot spot; private final LocalDateTime entryTime; private LocalDateTime exitTime; public ParkingTicket(String ticketId, Vehicle vehicle, ParkingSpot spot) { this.ticketId = ticketId; this.vehicle = vehicle; this.spot = spot; this.entryTime = LocalDateTime.now(); } } int double calculateFee(PricingStrategy strategy){ if(exitTime==null){ exitTime = LocalDateTime.now(); } long minutes = Duration.between(entryTime, exitTime) .toMinutes(); return strategy.calculateFee(minutes, vehicle.getType()); } public void setExitTime(LocalDateTime exitTime) { this.exitTime = exitTime; } public String getTicketId() { return ticketId; } public Vehicle getVehicle() { return vehicle; } public ParkingSpot getSpot() { return spot; } public LocalDateTime getEntryTime() { return entryTime; }

}


public class ParkingFloor { private final String floorId; private final List<ParkingSpot> spots; public ParkingFloor(String floorId, List&lt;ParkingSpot&gt; spots) { this.floorId = floorId; this.spots = spots; } public ParkingSpot findAvailableSpot(VehicleType vehicleType) { for (ParkingSpot spot : spots) { if (spot.isAvailable() &amp;&amp; spot.getSpotType().getSize() &gt;= vehicleType.getSize()) { return spot; } } return null; } public String getFloorId() { return floorId; } public List&lt;ParkingSpot&gt; getSpots() { return spots; }

}


public class ParkingLot {

private final List floors;

private final PricingStrategy pricingStrategy;

private final Map activeTickets;

private final AtomicInteger ticketCounter;

private final ReentrantLock entryLock;


public ParkingLot(List floors,

PricingStrategy pricingStrategy) {

this.floors = floors;

this.pricingStrategy = pricingStrategy;

this.activeTickets = new ConcurrentHashMap<>();

this.ticketCounter = new AtomicInteger(0);

this.entryLock = new ReentrantLock();

}


public ParkingTicket enter(Vehicle vehicle) {

entryLock.lock();

try {

for (ParkingFloor floor : floors) {

ParkingSpot spot = floor.findAvailableSpot(

vehicle.getType());

if (spot != null && spot.assign(vehicle)) {

String ticketId = "T-"

+ ticketCounter.incrementAndGet();

ParkingTicket ticket = new ParkingTicket(

ticketId, vehicle, spot);

activeTickets.put(ticketId, ticket);

return ticket;

}

}

throw new RuntimeException(

"Parking lot is full for vehicle type: "

+ vehicle.getType());

} finally {

entryLock.unlock();

}

}


public double exit(ParkingTicket ticket) {

ticket.setExitTime(LocalDateTime.now());

double fee = ticket.calculateFee(pricingStrategy);

ticket.getSpot().release();

activeTickets.remove(ticket.getTicketId());

return fee;

}


public boolean isFull() {

for (ParkingFloor floor : floors) {

for (ParkingSpot spot : floor.getSpots()) {

if (spot.isAvailable()) return false;

}

}

return true;

}

}



APIs & Class Members

For each class, define the attributes (data) it will hold and the methods (functions) that operate on the attributes. Ensure they align with the object's responsibilities and adhere to the principle of encapsulation. Write your code in the code editor below.



Deep Dive

Explain design tradeoffs you considered. Check and explain whether your design adheres to SOLID principles. Explain how your design can handle changes in scale and whether it would be easy to extend with new functionalities. Identify areas for future improvement...