Tuesday, 4 February 2020

Design a Parking Lot

Vehicle Parking

OODesign for Parking lot

Requirements

  • We need a simple system which can be used by a cutomer to check if there is a parking available
  • Customer should be able to park the vehicle and later retrieve it back
  • Customer can pay by card or cash

Actors and usecases

  • For now lets keep things simple and only have a customer who comes and parks the vehicle
  • Customer should be able to :
    • Check available parking and cost
    • Park
    • Unpark
    • Pay
    • Search by ticket

Classes and responsibilities

  • Vehicle
    • Take care of parking area / size required to park it
    • Park/Unpark itself
    • The identity of the vehicle
    • This will be an abstract class
  • User
    • a super class responsible for identifying the user
    • This can be extended by Customer , Agent or Parking lot manager later on
  • ParkingSpot
    • this will represent the actual spot used to park
    • there can be different types of the spots - small medium large
    • these spots can be added or remove wrt to the parking lot
  • ParkingLot
    • This holds all pieces together
    • This should be responsible to tie all the things together
    • This should take a parking request, park, generate ticket and return to the customer
    • This should also take a ticket and then search the vehicle and unpark upon the request
  • Payment
    • this should handle the way customer wants to make payment
    • it can be an interface and different types of payments can implement it
    • implementations can implement their functionality
  • ParkingLotCLI
    • This will be a helper CLI for cutomer (should be extensible to other actors later)
    • This will be primarily responsible for taking inputs from user and display of state for user
  • Ticket
    • this will just be a simple object to identify the reservation with customer
    • it handles the way ticket should be printed and what needs to printed on it
    • it will be responsible for maintainig the count of ticket id uniquely

plot_cd.jpg

In [50]:
from abc import ABC, abstractmethod
import time
import enum

class Vehicle(ABC):
    
    def __init__(self, vehicle_id):
        self.id = vehicle_id
    
    def park(self, spot):
        spot.hold_spot(self)
    
    def unpark(self, spot):
        spot.free_spot(self)
    
    @abstractmethod
    def size(self):
        pass
    
    @abstractmethod
    def pricing(self):
        pass
    
class SpotSize(enum.Enum):
    SMALL = 0
    MEDIUM = 1
    LARGE = 2
    XLARGE = 3
    
class PriceStrategy(object):
    BIKE = 100
    CAR = 300
    BUS = 1000

    
class Bike(Vehicle):
    def size(self):
        return SpotSize.SMALL
    
    def pricing(self):
        return PriceStrategy.BIKE

class Car(Vehicle):
    def size(self):
        return SpotSize.MEDIUM
    
    def pricing(self):
        return PriceStrategy.CAR
    
class User(object):
    def __init__(self, name):
        self.name = name
        
class Customer(User):
    def __init__(self, name):
        super(Customer, self).__init__(name)
        vehicle = None

class Ticket(object):
    COUNTER = 0
    def __init__(self, customer, vehicle):
        self.id = Ticket.COUNTER
        Ticket.COUNTER += 1
        
        self.customer_name = customer.name
        self.vehicle_id = vehicle.id
        self.creation_time = time.time()
        
    def get_print(self):
        s = ('------------------------\n  Ticket id : %s\n  Customer name : %s\n'
             '  Vehicle Id: %s\n  Creation time : %f\n------------------------\n')%(self.id, self.customer_name, self.vehicle_id, self.creation_time)
        return s

class ParkingSpot(object):
    def __init__(self, id, size):
        self.id = id
        self.size = size
        self.available = True
        
        self.parked = False
        self.vehicle = None
        
    def hold_spot(self, vehicle):
        self.parked = True
        self.vehicle = vehicle
        
    def free_spot(self):
        self.parked = False
        self.vehicle = None

class ParkingLot(object):
    def __init__(self, parking_spots):
        self.parking_spots = parking_spots
        self.ticket_to_spot = {}
        
    def print_ticket(self, ticket):
        print(ticket.get_print())
        
    def book_parking(self, customer, vehicle)-> Ticket:
        booked_spot = None
        for spot in self.parking_spots:
            if spot.available and vehicle.size() == spot.size:
                spot.hold_spot(vehicle)
                booked_spot = spot
                break
        if booked_spot:
            ticket = Ticket(customer, vehicle)
            self.ticket_to_spot[ticket.id] = booked_spot
            return ticket
        else:
            return None
    
    def free_parking(self, ticket_id):
        if ticket_id in self.ticket_to_spot:
            booked_spot = self.ticket_to_spot[ticket_id]
            booked_spot.free_spot()
            del self.ticket_to_spot[ticket_id]
In [51]:
class UserType(enum.Enum):
    CUSTOMER = 0
    AGENT = 1
    MANAGER = 2
    
class UserAction(enum.Enum):
    PARK = 0
    UNPARK = 1
    ADD_VEHICLE = 2
    REMOVE_VEHICLE = 3
    ADD_AGENT = 4
    REMOVE_AGENT = 5
    ADD_SPOT = 6
    REMOVE_SPOT = 7
    SEE_ALL_TICKETS = 8

class ParkingLotCLI(object):
    def __init__(self, total_spots):
        small_spots = total_spots//3
        medium_spots = total_spots//3
        large_spots = total_spots - small_spots - medium_spots
        
        spots = []
        for i in range(small_spots):
            spots.append(ParkingSpot('s_%d'%i, SpotSize.SMALL))
        for i in range(medium_spots):
            spots.append(ParkingSpot('m_%d'%i, SpotSize.MEDIUM))
        for i in range(large_spots):
            spots.append(ParkingSpot('l_%d'%i, SpotSize.LARGE))
        
        self.parking_lot = ParkingLot(spots)
        
    
    def _choose_user(self):
        print('Choose 1)Customer 2)Agent 3)Manager\n')
        choice = input('?')
        if choice == '1':
            return UserType.CUSTOMER
        elif choice == '2':
            return UserType.AGENT
        else:
            print('Not supported yet')
        
    def _choose_action(self, user_type):
        if user_type == UserType.CUSTOMER:
            print('Choose action 1)Park 2)Unpark\n')
            choice = input('?')
            if choice == '1':
                return UserAction.PARK
            elif choice == '2':
                return UserAction.UNPARK
            else:
                print('Not supported yet')
        elif user_type == UserType.AGENT:
            print('Choose action 1)See all tickets\n')
            choice = input('?')
            if choice == '1':
                return UserAction.SEE_ALL_TICKETS
            else:
                print('Not supported yet')
        else:
            print('Not supported yet')
            
            
    def _act(self, user_action):
        if user_action == UserAction.PARK:
            name = input('What is your name ? ')
            customer = Customer(name)
            vehicle = None
            vehicle_type = input('What is your Vehicle type ? 1) Car 2) Bike')
            vehicle_id = input('What is your Vehicle identifier ? ')
            if vehicle_type == '1':
                vehicle = Car(vehicle_id)
            elif vehicle_type == '2':
                vehicle = Bike(vehicle_id)
            else:
                print('Not supported yet')
                
            ticket = self.parking_lot.book_parking(customer, vehicle)
            if ticket:
                print('Congrats, here is your ticket : \n %s \n' % ticket.get_print())
            else:
                print('Sorry unable to book parking')
        elif user_action == UserAction.UNPARK:
            ticket_id = input('What is yout ticket number ? ')
            self.parking_lot.free_parking(int(ticket_id))
        elif user_action == UserAction.SEE_ALL_TICKETS:
            print('Following are all the tickets active :\n')
            if len(self.parking_lot.ticket_to_spot) == 0:
                print('[[[ No active tickets ]]]\n')
            for ticket_id, spot in  self.parking_lot.ticket_to_spot.items():
                print('----------------------------\n')
                print('Ticket id : %d\n' % ticket_id)
                print('Parking spot id : %s\n' % spot.id)
                print('----------------------------\n')
        else:
            print('Not supported yet')
    
    def start(self):
        while True:
            user_type = self._choose_user()
            action = self._choose_action(user_type)
            self._act(action)
In [ ]:
cli = ParkingLotCLI(10)
cli.start()
Choose 1)Customer 2)Agent 3)Manager

?2
Choose action 1)See all tickets

?1
Following are all the tickets active :

[[[ No active tickets ]]]

Choose 1)Customer 2)Agent 3)Manager

?1
Choose action 1)Park 2)Unpark

?1
What is your name ? Vikas
What is your Vehicle type ? 1) Car 2) Bike2
What is your Vehicle identifier ? JK Q1
Congrats, here is your ticket : 
 ------------------------
  Ticket id : 0
  Customer name : Vikas
  Vehicle Id: JK Q1
  Creation time : 1580818396.674687
------------------------
 

Choose 1)Customer 2)Agent 3)Manager

?2
Choose action 1)See all tickets

?1
Following are all the tickets active :

----------------------------

Ticket id : 0

Parking spot id : s_0

----------------------------

Choose 1)Customer 2)Agent 3)Manager

?1
Choose action 1)Park 2)Unpark

?2
What is yout ticket number ? 0
Choose 1)Customer 2)Agent 3)Manager

?2
Choose action 1)See all tickets

?1
Following are all the tickets active :

[[[ No active tickets ]]]

Choose 1)Customer 2)Agent 3)Manager

In [ ]:
 

No comments:

Post a Comment