Requirements
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
Define Core Objects
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
Analyze Relationships
Determine how these objects will interact with each other to fulfill the use cases...
- Composition: Parking Lot contains Parking Floor
- Aggregation: ParkingFloor contains Parking Spot
- Association: ParkingSpot contains VehicleData
- Dependencies: ParkingFeeCalculator depends on VehicleData
- Inheritance: We may built a base class Vehicle and create class like electric cars, SUV based on Vehicle
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...
Vehicle Class
- String licenseNumber
- String vehicleType
- DateTime arrivalTime
- park
- unpark
Car Inherit vehicle class
- carType
Truck inherits vehicle class
- loadCapactiy
Electric vehicle inherits vehicle class
- int batteryLevel
Design Patterns
Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...
- Singleton Pattern: Parking lot
- Factory pattern: create instances of different vehicle types
- Observer pattern: ParkingSpot status updates
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 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
}
}
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.)...
- Single Responsibility Principle (SRP)
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):
- If you want to introduce new vehicle types (e.g.,
ElectricVehicle), you can do this by creating new subclasses without modifying existing classes likeVehicle. 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):
- When a method expects a
Vehicletype, it should be able to accept any subclass (likeCarorTruck) without any undesired side effects. For instance, using aTruckobject where aVehicleis expected should not cause issues.
4.Interface Segregation Principle (ISP):
- Definition: Clients should not be forced to depend on interfaces they do not use.
- Example:
- Instead of having one large
Vehicleinterface with all possible methods (for all vehicle types), create smaller, specific interfaces, such asChargeablefor electric vehicles, which contains only methods related to charging.
- Instead of having one large
public interface Chargeable { void charge();};}
5. Dependency Inversion Principle (DIP):
- Definition: High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces).
- Example:
- In your system, instead of directly depending on specific vehicle implementations (Car, Truck), a class that manages parking should rely on a
Vehicleinterface. This decouples the code and enables easier changes or enhancements.
- In your system, instead of directly depending on specific vehicle implementations (Car, Truck), a class that manages parking should rely on a
public class ParkingManager { public void parkVehicle(Vehicle vehicle) { // Logic to park the vehicle }}
Consider Scalability and Flexibility
Explain how your design can handle changes in scale and whether it would be easily to extend with new functionalities...
- Vehicle Management:
- Design the
Vehicleclass 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.
- Design the
- Parking Fee Calculation:
- Implement a flexible fee structure using various strategies for different vehicle types, making it easy to adapt to changes without a complete system overhaul.
- Distributed Architecture:
- If your parking lot management system gains popularity, consider a cloud-based solution that supports scaling both horizontally and vertically. This could involve using distributed databases or Microservices, where different services (e.g., vehicle registration, fee calculation, reporting) can be scaled independently.
- Event-Driven Architecture:
- Implementing an event-driven model (e.g., using message queues) may facilitate updates across different parts of the system (like notifications about free spots) without coupling components too tightly.
Example of Scalability Consideration:
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...}
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...
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
Future improvements
Critically examine your design for any flaws or areas for future improvement...
1. Mobile Application Integration
- Enhancement: Develop a mobile app that allows users to find available parking spots, reserve them in advance, and make payments.
- Benefit: Improves user convenience and could enhance occupancy rates by allowing pre-booking.
2. Dynamic Pricing Model
- Enhancement: Implement a dynamic pricing structure that adjusts fees based on demand, time of day, or special events.
- Benefit: This could maximize revenue for the parking lot and better allocate resources based on demand.
3. Real-time Availability Updates
- Enhancement: Use IoT sensors to provide real-time data on space availability and status updates to both users and the display board.
- Benefit: Customers can make informed decisions about where to park, and better use of space can lead to reduced congestion.
4. Data Analytics and Reporting
- Enhancement: Implement tools to analyze usage patterns, peak usage times, and customer behavior.
- Benefit: Insights derived can guide future pricing strategies, marketing efforts, and operational optimizations.
5. Integration with Navigation Apps
- Enhancement: Collaborate with navigation applications (like Google Maps or Waze) to show real-time parking availability to drivers as they approach the area.
- Benefit: Helps attract more users by ensuring they know parking is available when they arrive.
6. Support for Electric Vehicle Charging
- Enhancement: Install charging stations for electric vehicles, allowing them to charge while parked.
- Benefit: Attracts more electric vehicle users and keeps your system up-to-date with emerging technologies.
7. Automated Payment Solutions
- Enhancement: Integrate automated payment systems, such as mobile wallets or QR code scanning for contactless payments.
- Benefit: Streamlines the payment process, reducing time spent at kiosks or in queues.
8. Enhanced User Authentication and Security
- Enhancement: Implement an authentication mechanism for user profiles and transactions, including features like biometrics or two-factor authentication.
- Benefit: Enhances security, protecting user data and payment information.