Requirements

Functional:

1. Assign nearest spot across the floors from the entrance

2. Calculate and collect fee at the checkout based on hours.

Non-functional:

1. New vehicle sizes could be added without affecting the rest of the system

2. New floors could be added without affecting the rest of the system

3. New spots could be added without affecting the rest of the system

4. New payment methods could be added without affecting the rest of the system

5. Fee calculation strategy could be changed without affecting the rest of the system


Define Core Objects

VehicleSize (enum)


Spot (abstract class)

CompactSpot

LargeSpot


Lot

AssignmentManager

PQManager

Booking


AssignmentStrategy (interface)

PQAssignmentStrategy


Floor


FareCalculatorStrategy (interface)

CompactFareCalculatorStrategy

LargeFareCalculatorStrategy

FareCalculatorManager


PaymentType (enum)

PaymentProcessor (interface)

CardPaymentProcessor

PaypalPaymentProcessor

PaymentProcessorFactory


Analyze Relationships


Spot has Floor

CompactSpot is-a Spot

LargeSpot is-a Spot


PQAssignmentStrategy is-a AssignmentStrategy


AssignmentManager has AssignmentStrategy

Booking has Vehicle

Booking has Spot


CompactFareCalculatorStrategy is-a FareCalculatorStrategy

LargeFareCalculatorStrategy is-a FareCalculatorStrategy


CardPaymentProcessor is-a PaymentProcessor

PaypalPaymentProcessor is-a PaymentProcessor


Establish Hierarchy

Spots of multiple sizes are inherited from Spot

PQAssignmentStrategy implements AssignmentStrategy

fareCalculatorStrategies of multiple sizes implement fareCalculatorStrategy

PaymentProcessors of different payment type implement PaymentProcessor


Design Patterns

PQAssignmentStrategy implements AssignmentStrategy

AssignmentManager holds a singleton of AssignmentStrategy

PQManager holds singletons of PriorityQueues of different sizes in a map

fareCalculatorStrategies of multiple sizes implement fareCalculatorStrategy

FareCalculatorManager holds singletons of fareCalculatorStrategies of different size in a map

PaymentProcessors of different payment type implement PaymentProcessor

PaymentProcessorFactory creates paymentProcessor of a size


Define Class Members (write code)



public enum VehicleSize { Compact, Large } public abstract class Spot { private String id = new String(""); // a random string private int timeFromGround; private Floor floor; Spot(Floor floor, int timeFromElevator) { this.floor = floor; this.timeFromGround = floor.getTimeFromGround() + timeFromElevator; } public String getId() { return id; } public int getTimeFromGround() { return timeFromGround; } public Floor getFloor() { return floor; } public abstract VehicleSize getVehicleSize(); } public class CompactSpot extends Spot { private final VehicleSize vehicleSize = VehicleSize.Compact; CompactSpot(Floor floor, int timeFromElevator) { super(floor, timeFromElevator); } @Override public VehicleSize getVehicleSize() { return vehicleSize; } } public class CompactSpot extends Spot { private final VehicleSize vehicleSize = VehicleSize.Compact; CompactSpot(Floor floor, int timeFromElevator) { super(floor, timeFromElevator); } @Override public VehicleSize getVehicleSize() { return vehicleSize; } } public class Lot { public Booking assignSpot(String vehicleId, VehicleSize vehicleSize) { AssignmentStrategy assignmentStrategy = AssignmentManager.getAssignmentStrategy(); return assignmentStrategy.assignSpot(vehicleId, vehicleSize); } public boolean checkout(Booking booking, PaymentType paymentType) { FareCalculatorStrategy fareCalculatorStrategy = FareCalculatorManager .getFareCalculatorStrategy(booking.getSpot().getVehicleSize()); long fare = fareCalculatorStrategy.calculateFare(System.currentTimeMillis() - booking.getAllottedAt()); PaymentProcessor paymentProcessor = PaymentProcessorFactory.getPaymentProcessor(paymentType); return paymentProcessor.makePayment(fare); } } public class AssignmentManager { private static final AssignmentStrategy assignmentStrategy = new PQAssignmentStrategy(); public static AssignmentStrategy getAssignmentStrategy() { return assignmentStrategy; } } public class PQManager { private static Map<VehicleSize, PriorityBlockingQueue<Spot>> pqMap = new HashMap<>(); static { pqMap.put(VehicleSize.Compact, new PriorityBlockingQueue<Spot>(10, (a, b) -> Integer.compare(a.getTimeFromGround(), b.getTimeFromGround()))); pqMap.put(VehicleSize.Large, new PriorityBlockingQueue<>(10, (a, b) -> Integer.compare(a.getTimeFromGround(), b.getTimeFromGround()))); } public static PriorityBlockingQueue&lt;Spot&gt; getPriorityBlockingQueue(VehicleSize vehicleSize) { return pqMap.get(vehicleSize); } } public class Booking { private final String id = new String(""); // a random string private final String vehicleId; private final long allottedAt = System.currentTimeMillis(); private final Spot spot; public Booking(String vehicleId, Spot spot) { this.vehicleId = vehicleId; this.spot = spot; } public String getId() { return this.id; } public String getVehicleId() { return this.vehicleId; } public long getAllottedAt() { return allottedAt; } public Spot getSpot() { return spot; } } public interface AssignmentStrategy { public Booking assignSpot(String vehicleId, VehicleSize vehicleSize); } public class PQAssignmentStrategy implements AssignmentStrategy { @Override public Booking assignSpot(String vehicleId, VehicleSize vehicleSize) { PriorityBlockingQueue&lt;Spot&gt; pq = PQManager.getPriorityBlockingQueue(vehicleSize); Spot spot = pq.poll(); return new Booking(vehicleId, spot); } } public class Floor { private String id = new String(""); // a random string private int timeFromGround; Floor(int timeFromGround) { this.timeFromGround = timeFromGround; } public String getId() { return id; } public int getTimeFromGround() { return timeFromGround; } } public interface FareCalculatorStrategy { public long calculateFare(long minutes); } class CompactFareCalculatorStrategy implements FareCalculatorStrategy { public long calculateFare(long minutes) { return 100 * minutes; } } class LargeFareCalculatorStrategy implements FareCalculatorStrategy { public long calculateFare(long minutes) { return 200 * minutes; } } public class FareCalculatorManager { private static Map<VehicleSize, FareCalculatorStrategy> fareCalculatorMap = new HashMap<>(); static { fareCalculatorMap.put(VehicleSize.Compact, new CompactFareCalculatorStrategy()); fareCalculatorMap.put(VehicleSize.Large, new LargeFareCalculatorStrategy()); } public static FareCalculatorStrategy getFareCalculatorStrategy(VehicleSize vehicleSize) { return fareCalculatorMap.get(vehicleSize); } } public enum PaymentType { CARD, PAYPAL } public interface PaymentProcessor { public boolean makePayment(long fee); } public class CardPaymentProcessor implements PaymentProcessor { public boolean makePayment(long fee) { // make card api call return true; } } class PaypalPaymentProcessor implements PaymentProcessor { public boolean makePayment(long fee) { // make paypal api call return true; } } public class PaymentProcessorFactory { public static PaymentProcessor getPaymentProcessor(PaymentType paymentType) { switch (paymentType) { case CARD: return new CardPaymentProcessor(); case PAYPAL: return new PaypalPaymentProcessor(); default: return null; } } }





Adhere to SOLID Guidelines


All components have only single responsibility

All components are closed for modification and open for extensions

We are not missing any methods in child classes which are in base classes

Only iterfaces with relevant methods are implemented

All dependencies are with interfaces


Consider Scalability and Flexibility

1. New vehicle sizes could be added without affecting the rest of the system

2. New floors could be added without affecting the rest of the system

3. New spots could be added without affecting the rest of the system

4. New payment methods could be added without affecting the rest of the system

5. Fee calculation strategy could be changed without affecting the rest of the system




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

Bounded waiting list when the parking lot is full

observer pattern for spot addition and its addition to pq