Use Cases
I currently do not have any classes that derive from each other. I considered creating an abstract parking spot class and then making derived classes for other spots based on size, but I felt like this was unnecessary as the only differences between spots are the size of the spot and the name of the spot type.
Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...
Singletons are being used here for the Parking lot, payment manager, and settings classes. The settings object will be provided to objects through dependency injection
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.
class ParkingLot:
def __init__(self):
self.floors = []
self.settings = Settings()
self.paymentManager = PaymentManager(settings)
self.tickets = {}
def addFloor(self, parkingSpotAllocation):
self.floors.append(len(self.floors), ParkingLotFloor(parkingSpotAllocation)
def assignSpot(self, String CarType):
if CarType not in settings.ValidCarTypes():
#handle error
return 1
else:
for floor in self.floors:
parkingSpotID = floor.GetFreeParkingSpot(CarType)
newTicket = Ticket(datetime.now(), parkingSpotID)
self.tickets[newTicket.getID()] = newTicket
return newTicket.getID()
#handle no tickets available
return 1
def makePayment(self, ticketID):
ticket = self.tickets[ticketID]
if paymentManager.makePayment(ticket) == 0:
ticket.isPaid = True
carFloor, spotNum, carType = ticket.parkingSpotID.split('-')
self.floors[carFloor].SetSpotAvailable(ticket.parkingSpotID)
class ParkingLotFloor:
def init(self, floorNum, parkingSpotAllocation):
self.floorNum = floorNum
self.spots = {}
for spotType, numSpots in parkingSpotAllocation:
for I in range(numSpots):
newSpot = ParkingSpot(spotType, spotNum, floorNum)
self.spots[newSpot.id] = newSpot
def GetFreeParkingSpot(self, carType):
for spot in spots:
if spot.isAvailable and carType == spot.type:
spot.isAvailable = False
return spot.id
class SpotType(Enum):
...
class ParkingSpot:
def init(self, spotType, spotNum, floorNum):
self.id = generateID(spotType, spotNum, floorNum)
self.isAvailable = True
class Ticket:
def init(self, entryTime, parkingSpotID):
self.entryTime = entryTime
self.id = generateTicketID()
self.isPaid = False
self.parkingSpotID = parkingSpotID
class PaymentManager:
def init(self, settings):
self.settings = settings
def makePayment(self, ticket):
carFloor, spotNum, carType = ticket.parkingSpotID.split('-')
spotRate = settings.getRate(carType)
payment = (datetime.now() - ticket.startTime) * spotRate
#payment logic here
if paymentSuccessful:
return 0
else:
return 1
Check and explain whether your design adheres to solid principles (Ask interviewer what SOLID principle is if you can not recall it.)...
Currently, every request is handled sequentially. Furthermore, there is no queueing system if multiple requests are made at the same time. I am operating under the assumption that there is one parking lot entrance system where users can queue up and request a parking spot.
In the future, a queueing system can be created to process both entrance requests and ticket payment requests. Requests can also be made to run in parallel if resources allow.
The addition of new parking spot types is relatively easy as you can just add new types to the SpotType Enum. new ways to make payments can also be added by creating new payment functions within the Payment manager.
The parking lot system is also relatively extensible as you can add a new floor easily with the add floor method
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...
Critically examine your design for any flaws or areas for future improvement...