My Solution for Design a Parking Lot with Score: 4/10
by pulse_alchemy255
Requirements
The parking lot caters to different vehicles. It has multiple spots available based on size of the vehicle(bike , car , semi trcuk etc. The main functionalities will include:
- Parking spot assignment
- Multiple floor support
- Spot availability
- User or Admin
- Ticketing
- Paymet
Define Core Objects
Analyze Relationships
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...
Design Patterns
Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <mutex>
using namespace std;
// Enumeration for Vehicle Size
enum VehicleSize {
SMALL,
MEDIUM,
LARGE
};
// Abstract Vehicle class
class Vehicle {
public:
virtual VehicleSize getSize() const = 0;
virtual double calculateFee(int hoursParked) const = 0;
virtual ~Vehicle() = default;
};
// Car class derived from Vehicle
class Car : public Vehicle {
public:
VehicleSize getSize() const override { return SMALL; }
double calculateFee(int hoursParked) const override { return hoursParked * 2.0; }
};
// Truck class derived from Vehicle
class Truck : public Vehicle {
public:
VehicleSize getSize() const override { return LARGE; }
double calculateFee(int hoursParked) const override { return hoursParked * 5.0; }
};
// ParkingSpot class
class ParkingSpot {
private:
VehicleSize size;
string identifier;
int floorNumber;
bool isOccupied;
Vehicle* v;
time_t checkInTime;
time_t checkOutTime;
std::mutex spotMutex; // Mutex for thread safety
public:
// Constructor
ParkingSpot(VehicleSize sz, string id, int floor)
: size(sz), identifier(id), floorNumber(floor), isOccupied(false), v(nullptr) {}
// Accessor methods
VehicleSize getSize() const { return size; }
string getIdentifier() const { return identifier; }
int getFloorNumber() const { return floorNumber; }
bool getIsOccupied() const { return isOccupied; }
// Assign a vehicle to the parking spot
void assignVehicle(Vehicle* vehicle) {
std::lock_guard<std::mutex> lock(spotMutex);
if (!isOccupied && vehicle->getSize() == size) {
v = vehicle;
checkInTime = time(nullptr); // Record check-in time
isOccupied = true;
}
}
// Remove the vehicle from the parking spot
void removeVehicle() {
std::lock_guard<std::mutex> lock(spotMutex);
if (isOccupied) {
v = nullptr;
isOccupied = false;
}
}
// Calculate fee based on parking time
double calculateFee() {
std::lock_guard<std::mutex> lock(spotMutex);
checkOutTime = time(nullptr); // Record check-out time
int hoursParked = difftime(checkOutTime, checkInTime) / 3600; // Calculate hours parked
return v->calculateFee(hoursParked); // Delegate fee calculation to the vehicle
}
};
// ParkingFloor class
class ParkingFloor {
private:
int floorNumber;
vector<ParkingSpot> spots;
public:
// Constructor
ParkingFloor(int floorNum, int totalSpots) : floorNumber(floorNum) {
for (int i = 0; i < totalSpots; i++) {
spots.push_back(ParkingSpot(SMALL, "S" + to_string(i), floorNum)); // Example: all small spots
}
}
// Find available spot for a vehicle
ParkingSpot* findAvailableSpot(Vehicle* v) {
for (auto& spot : spots) {
if (!spot.getIsOccupied() && spot.getSize() == v->getSize()) {
return &spot;
}
}
return nullptr;
}
};
// ParkingLot class
class ParkingLot {
private:
vector<ParkingFloor> floors;
int totalFloors;
int spotsPerFloor;
public:
// Constructor
ParkingLot(int totalFloors, int spotsPerFloor) : totalFloors(totalFloors), spotsPerFloor(spotsPerFloor) {
for (int i = 0; i < totalFloors; i++) {
floors.push_back(ParkingFloor(i, spotsPerFloor)); // Initialize each floor
}
}
// Assign a spot for a vehicle
void assignSpot(Vehicle* v) {
for (auto& floor : floors) {
ParkingSpot* availableSpot = floor.findAvailableSpot(v);
if (availableSpot != nullptr) {
availableSpot->assignVehicle(v);
cout << "Assigned vehicle to spot " << availableSpot->getIdentifier()
<< " on floor " << availableSpot->getFloorNumber() << endl;
return;
}
}
cout << "No available spot for vehicle." << endl;
}
// Release a spot occupied by a vehicle
void releaseSpot(Vehicle* v) {
for (auto& floor : floors) {
for (auto& spot : floor.spots) {
if (spot.getIsOccupied() && spot.getSize() == v->getSize()) {
double fee = spot.calculateFee(); // Calculate parking fee
spot.removeVehicle();
cout << "Released spot " << spot.getIdentifier() << " on floor "
<< spot.getFloorNumber() << ". Parking fee: $" << fee << endl;
return;
}
}
}
cout << "Vehicle not found." << endl;
}
};
int main() {
// Create a parking lot with 2 floors and 5 spots per floor
ParkingLot lot(2, 5);
// Create vehicles
Car car1;
Truck truck1;
// Assign spots
lot.assignSpot(&car1);
lot.assignSpot(&truck1);
// Release spots
lot.releaseSpot(&car1);
lot.releaseSpot(&truck1);
return 0;
}
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.)...
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...