Determine the different ways the system will be used. This includes main functions the system needs to perform and who will use it.
1) Include multiple level of building floors which means having including multiple list inside a list in Java
2) For each list in Java or building floor, we define a class VehicleData which includes vehicle size - Small, Medium and Big and availability of space for medium and big vehicles and parked duration of the vehicle. This List Data type will of this class type VehicleData
Based on the requirements and use cases, identify the main objects of the system...
1) Parking Lot Class contains
a) ParkingFloor Class - contains methods for available floor, add floor and allot vehicle size parking quantity for each floor
b) Vehicle Data - contains method for checking vehicle size - small, medium and large and track global quantity of vehicle for each size
c) ParkingSpot Class - contains methods for each floor, we check available spot for Small and Large Size vehicles and allot or not allot base on availability. If we allot, we catch the timestamp and add the quantity of vehicle size and decrease the allotment quantity
d) Parking Fee Calculator - We check for each vehicle how much time we charge for Small, medium and large size vehicles based on time. Time will be current timestamp - timestamp when the vehicle was parked
Determine how these objects will interact with each other to fulfill the use cases...
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...
Vehicle Class
Car Inherit vehicle class
Truck inherits vehicle class
Electric vehicle inherits vehicle class
Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...
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 Car { ... } // Example
1. Vehicle Class (Base Class)
public abstract class Vehicle {
private String licenseNumber;
private String vehicleType; // e.g. Car, Truck, Electric Vehicle
private LocalDateTime arrivalTime;
public Vehicle(String licenseNumber, String vehicleType) {
this.licenseNumber = licenseNumber;
this.vehicleType = vehicleType;
this.arrivalTime = LocalDateTime.now();
}
public String getLicenseNumber() {
return licenseNumber;
}
public String getVehicleType() {
return vehicleType;
}
public LocalDateTime getArrivalTime() {
return arrivalTime;
}
public abstract void park();
public abstract void unpark();
}
2. Car Class (Inherits from Vehicle)
public class Car extends Vehicle {
private String carType; // e.g. sedan, convertible
public Car(String licenseNumber, String carType) {
super(licenseNumber, "Car");
this.carType = carType;
}
public String getCarType() {
return carType;
}
@Override
public void park() {
// specific parking logic for Cars
}
@Override
public void unpark() {
// specific un-parking logic for Cars
}
}
3. Truck Class (Inherits from Vehicle)
public class Truck extends Vehicle {
private float loadCapacity; // in tons
public Truck(String licenseNumber, float loadCapacity) {
super(licenseNumber, "Truck");
this.loadCapacity = loadCapacity;
}
public float getLoadCapacity() {
return loadCapacity;
}
@Override
public void park() {
// specific parking logic for Trucks
}
@Override
public void unpark() {
// specific un-parking logic for Trucks
}
}
4. ElectricVehicle Class (Inherits from Vehicle)
public class ElectricVehicle extends Vehicle {
private int batteryLevel; // in percentage
public ElectricVehicle(String licenseNumber, int batteryLevel) {
super(licenseNumber, "Electric Vehicle");
this.batteryLevel = batteryLevel;
}
public int getBatteryLevel() {
return batteryLevel;
}
public void charge() {
// Logic to charge the vehicle's battery
}
@Override
public void park() {
// specific parking logic for Electric Vehicles
}
@Override
public void unpark() {
// specific un-parking logic for Electric Vehicles
}
}
5. ParkingSpot Class
import java.util.ArrayList;
import java.util.List;
public class ParkingSpot {
private int spotNumber;
private boolean isAvailable;
private Vehicle currentVehicle;
public ParkingSpot(int spotNumber) {
this.spotNumber = spotNumber;
this.isAvailable = true;
this.currentVehicle = null;
}
public boolean isAvailable() {
return isAvailable;
}
public void allocateVehicle(Vehicle vehicle) {
this.currentVehicle = vehicle;
this.isAvailable = false;
}
public Vehicle removeVehicle() {
Vehicle vehicle = this.currentVehicle;
this.currentVehicle = null;
this.isAvailable = true;
return vehicle;
}
public int getSpotNumber() {
return spotNumber;
}
}
6. ParkingLot Class
import java.util.ArrayList;
import java.util.List;
public class ParkingLot {
private List
public ParkingLot(int numberOfSpots) {
parkingSpots = new ArrayList<>(numberOfSpots);
for (int i = 0; i < numberOfSpots; i++) {
parkingSpots.add(new ParkingSpot(i + 1));
}
}
public ParkingSpot findAvailableSpot() {
for (ParkingSpot spot : parkingSpots) {
if (spot.isAvailable()) {
return spot;
}
}
return null; // No available spots
}
public void parkVehicle(Vehicle vehicle) {
ParkingSpot spot = findAvailableSpot();
if (spot != null) {
spot.allocateVehicle(vehicle);
vehicle.park(); // Call specific parking logic for the vehicle
} else {
System.out.println("No available parking spots!");
}
}
public void unparkVehicle(ParkingSpot spot) {
Vehicle vehicle = spot.removeVehicle();
vehicle.unpark(); // Call specific un-parking logic for the vehicle
}
}
Check and explain whether your design adheres to solid principles (Ask interviewer what SOLID principle is if you can not recall it.)...
ParkingFeeCalculator ParkingFeeCalculator class should only be responsible for calculating fees.
public class ParkingFeeCalculator { public double calculateFee(Vehicle vehicle, Duration parkedDuration) { // Calculation logic based on vehicle size and duration }}
2.Open/Closed Principle (OCP):
ElectricVehicle), you can do this by creating new subclasses without modifying existing classes like Vehicle. This allows expansion without risk of breaking existing functionality.public class ElectricVehicle extends Vehicle { private int batteryLevel; // Additional methods specific to electric vehicles}
3.Liskov Substitution Principle (LSP):
Vehicle type, it should be able to accept any subclass (like Car or Truck) without any undesired side effects. For instance, using a Truck object where a Vehicle is expected should not cause issues.4.Interface Segregation Principle (ISP):
Vehicle interface with all possible methods (for all vehicle types), create smaller, specific interfaces, such as Chargeable for electric vehicles, which contains only methods related to charging.public interface Chargeable { void charge();};}
5. Dependency Inversion Principle (DIP):
Vehicle interface. This decouples the code and enables easier changes or enhancements.public class ParkingManager { public void parkVehicle(Vehicle vehicle) { // Logic to park the vehicle }}
Explain how your design can handle changes in scale and whether it would be easily to extend with new functionalities...
Vehicle class hierarchy to easily incorporate new types of vehicles in the future without modifying existing code. This allows easy extension of functionalities while maintaining compatibility with existing services.Imagine your parking lot expands to multiple locations. You would need the system to manage multiple floors and hundreds of parking spots across various sites. Designing your classes in a way that they can be instantiated for different locations without significant code changes would be crucial. For instance, if each parking lot requires operating independently, you can create a ParkingLot manager that dynamically loads each instance based on configuration.
public class ParkingLotManager { private List<ParkingLot> parkingLots; public ParkingLotManager() { this.parkingLots = new ArrayList<>(); // Load parking lots dynamically from configuration } public void addParkingLot(ParkingLot newLot) { parkingLots.add(newLot); } public void parkVehicleInLot(String lotId, Vehicle vehicle) { ParkingLot lot = findParkingLot(lotId); if (lot != null) { lot.parkVehicle(vehicle); } } // More methods for managing multiple parking lots...}
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...
classDiagram class Vehicle { +String licenseNumber +String vehicleType +LocalDateTime arrivalTime +park() void +unpark() void } class Car { +String carType } class Truck { +float loadCapacity } class Truck { +float loadCapacity } class ElectricVehicle { +int batteryLevel +charge() void } class ParkingSpot { +int spotNumber +isAvailable() boolean +allocateVehicle(Vehicle vehicle) void +removeVehicle() Vehicle }class ParkingLot { +List<ParkingSpot> parkingSpots +findAvailableSpot() ParkingSpot +parkVehicle(Vehicle vehicle) void } class ParkingFeeCalculator { +calculateFee(Vehicle vehicle, Duration parkedDuration) double } Vehicle <|-- Car : Inherits Vehicle <|-- Truck : Inherits Vehicle <|-- ElectricVehicle : Inherits ParkingLot "1" o-- "*" ParkingSpot : contains ParkingLot --> ParkingFeeCalculator : uses
Critically examine your design for any flaws or areas for future improvement...