Requirements

Determine the different ways the system will be used. This includes main functions the system needs to perform and who will use it.


System users:

1- Parking owner

2- Client


1- Parking owner functionalities:

  • Add new spot to the parking with the main information like spot size and the fees pair hour
  • Remove or update spot information
  • get total fees for all transactions


2- Client

  • Check spot availability and check the spot size if it can fit with the car size
  • Reserve a new spot
  • Release the reservation and see the total fees depending on the parking time


class CarModel{ private final int ID; private float size; private string model; private string ownerName; public Car( float size, String model, String ownerName); public getters(); public setters(); }


class SpotModel{ private final int ID; private float size; private float feesPerHour; private int floorNumber; private boolean available; public Spot(float size, float feesPerHour, int floorNumber); public getters(); public setters(); }


public class SpotService{ private static SpotService spotService; private final Map<Integer, SpotModel> spots = new HashMap<>(); public static synchronized SpotService getInstance(); public boolean checkSpotSize(SpotModel spot, float carSize); public void addNewSpot(SpotModel spot); public void removeSpot(int spotId); public Collection<SpotModel> getAllSpots(); }



class BookingModel{ private final int ID; private Spot spot; private Car car; private Date startTime; private Date endTime; private float totalFees; public BookingModel(CarModel car, SpotModel spot, LocalTime endTime); public BookingModel(CarModel car, SpotModel spot, LocalTime startTime, LocalTime endTime) public getters(); public setters(); }


public class BookingService { private static BookingService bookingService; private final Map<Integer, BookingModel> bookings = new HashMap<>(); public static synchronized BookingService getInstance(); public boolean checkBookingAvailability(float size, SpotModel spot, LocalTime startTime, LocalTime endTime) public void addNewBooking(BookingModel booking) public BookingModel getBooking(int bookingId) public void releaseReservation(BookingModel bookingModel) }


class Parking { private static Parking parking; private static float totalProfit = 0; public static Parking getInstance() public void addNewInstantlyBooking(Spot spot, Car car, LocalTime endTime); public void addNewFutureBooking(Spot spot, Car car, LocalTime startTime, LocalTime endTime); public void releaseBooking(int bookingId); public static void getTotalOwnerProfit(); public Collection<Spot> getAllSpots(); }



Analyze Relationships

Determine how these objects will interact with each other to fulfill the use cases...


  1. Composition relationship between Parking and Spot because Parking has an all spots
  2. Aggregation relationship between parking and Booking-Spot
  3. Association relationship between Booking-Spot and Car because Booking-Spot
  4. Association relationship between Booking-Spot and Spot




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...


The Parking Lot system Doesn't need any type of inheritance or polymorphism





Design Patterns

Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...

1- Singleton design pattern in a Parking class and booking service and Spot service



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 CarModel { private final int ID; private float size; private String model; private String ownerName; public CarModel(float size, String model, String ownerName){ this.ID = new Random().nextInt(100000); this.size = size; this.model = model; this.ownerName = ownerName; } public int getID(){ return this.ID; } public float getSize(){return this.size;} public String getModel(){ return this.model; } public String getOwnerName() { return ownerName; } public void setModel(String model) { this.model = model; } public void setOwnerName(String ownerName) { this.ownerName = ownerName; } public void setSize(float size) { this.size = size; } } public class SpotModel { private final int ID; private float size; private float feesPerHour; private int floorNumber; public SpotModel(float size, float feesPerHour, int floorNumber){ this.ID = new Random().nextInt(100000); this.floorNumber = floorNumber; this.size = size; this.feesPerHour = feesPerHour; } public int getID() { return ID; } public float getFeesPerHour() { return feesPerHour; } public int getFloorNumber() { return floorNumber; } public float getSize() {return size;} public void setSize(float size) { this.size = size; } public void setFeesPerHour(float feesPerHour) { this.feesPerHour = feesPerHour; } public void setFloorNumber(int floorNumber) { this.floorNumber = floorNumber; } } public class SpotService { private static SpotService spotService; private final Map<Integer, SpotModel> spots = new HashMap<>(); public static synchronized SpotService getInstance(){ if(spotService == null) spotService = new SpotService(); return spotService; } public boolean checkSpotSize(SpotModel spot, float carSize){ return (spot.getSize() &gt;= carSize); } public void addNewSpot(SpotModel spot){ spots.put(spot.getID(), spot); } public void removeSpot(int spotId){ spots.remove(spotId); } public Collection&lt;SpotModel&gt; getAllSpots() { return spots.values(); } } public class BookingModel { private final int ID; private final CarModel car; private final SpotModel spot; private final LocalTime startTime; private LocalTime endTime; private float totalFees; public BookingModel(CarModel car, SpotModel spot, LocalTime endTime){ this.ID = new Random().nextInt(100000); this.car = car; this.spot = spot; this.startTime = LocalTime.now(); this.endTime = endTime; } public BookingModel(CarModel car, SpotModel spot, LocalTime startTime, LocalTime endTime){ this.ID = new Random().nextInt(100000); this.car = car; this.spot = spot; this.startTime = startTime; this.endTime = endTime; } public float getTotalFees(){ return this.totalFees; } public void setTotalFees(float totalFees) { this.totalFees = totalFees; } public CarModel getCar() { return car; } public SpotModel getSpot() { return spot; } public LocalTime getStartTime() { return startTime; } public LocalTime getEndTime() { return endTime; } public int getID() { return ID; } } public class BookingService { private static BookingService bookingService; private final Map<Integer, BookingModel> bookings = new HashMap<>(); public static synchronized BookingService getInstance() { if(bookingService == null) bookingService = new BookingService(); return bookingService; } public boolean checkBookingAvailability(float size, SpotModel spot, LocalTime startTime, LocalTime endTime){ if(!SpotService.getInstance().checkSpotSize(spot, size)){ throw new IllegalArgumentException(&quot;The car size is bigger than spot size&quot;); } bookings.forEach((key, value) -&gt; { SpotModel curSpot = value.getSpot(); if(curSpot.getID() == spot.getID() &amp;&amp; !(endTime.isBefore(value.getStartTime()) || startTime.isAfter(value.getEndTime()))){ throw new UnsupportedOperationException(&quot;This spot is reserved during this time&quot;); } }); return true; } public void addNewBooking(BookingModel booking){ bookings.put(booking.getID(), booking); } public BookingModel getBooking(int bookingId){ return bookings.get(bookingId); } public void releaseReservation(BookingModel bookingModel){ Duration duration = Duration.between(bookingModel.getStartTime(), bookingModel.getEndTime()); float hours = (float) duration.toMinutes() / 60; bookingModel.setTotalFees(hours * bookingModel.getSpot().getFeesPerHour()); } } public class Parking { private static Parking parking; private static float totalProfit = 0; public static Parking getInstance(){ if(parking == null){ parking = new Parking(); } return parking; } public void addNewInstantlyBooking(SpotModel spot, CarModel car, LocalTime endTime){ LocalTime startTime = LocalTime.now(); try{ if(BookingService.getInstance().checkBookingAvailability(car.getSize(), spot, startTime, endTime)){ BookingModel bookingSpot = new BookingModel(car, spot, endTime); BookingService.getInstance().addNewBooking(bookingSpot); } }catch (UnsupportedOperationException | IllegalArgumentException error){ System.out.println(error.getMessage()); } } public void addNewFutureBooking(SpotModel spot, CarModel car, LocalTime startTime, LocalTime endTime){ try{ if(BookingService.getInstance().checkBookingAvailability(car.getSize(), spot, startTime, endTime)){ BookingModel bookingSpot = new BookingModel(car, spot, startTime, endTime); BookingService.getInstance().addNewBooking(bookingSpot); } }catch (UnsupportedOperationException | IllegalArgumentException error){ System.out.println(error.getMessage()); } } public void releaseBooking(int bookingId){ BookingModel bookingSpot = BookingService.getInstance().getBooking(bookingId); BookingService.getInstance().releaseReservation(bookingSpot); totalProfit += bookingSpot.getTotalFees(); System.out.println(&quot;Total fees is: &quot; + bookingSpot.getTotalFees()); } public static void getTotalOwnerProfit(){ System.out.println(&quot;Total profits is: &quot; + totalProfit); } public Collection&lt;SpotModel&gt; getAllSpots() { return SpotService.getInstance().getAllSpots(); } }



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.)...


1- Each class responsible for single task

2- the system is open for extension but close to modified


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...