OOD

Posted on By Guanzhou Song

Parking Lot Design Using OO Design

Description

Ways to approach a general Design problem.

  • Use Cases Generation: Gather all the possible use cases

  • Constraints and Analysis: How many users, how much data etc.

  • Basic Design: Most basic design. Few users case.

  • Bottlenecks: Find the bottlenecks and solve them.

  • Scalability: A large number of users. 4 and 5 step will go in loop till we get a satisfactory answer

Current Scenario

  1. Use cases for this problem.
    • Parking can be single-level or multilevel.
    • Types of vehicles that can be parked, separate spaces for each type of vehicle.
    • Entry and exit points.
  2. Constraints
    • Number of vehicles that can be accommodated of any type.
  3. Basic Design/High-Level Components
    • Vehicle/Type of vehicle.
    • Entry and Exit points.
    • Different spots for vehicles.
  4. Bottlenecks
    • Capacity breach for any type of vehicle.
  5. Scalability
    • Scalable from single-level to multi-level
    • Scalable from Bike only parking to accommodate all kinds of vehicles.

Keeping these in minds, APIs can be designed in the language of your preference.

Solution

ParkingSlot > Floor > Parking And separate FareController

So, a Parking can have many Floors and Floor and can have many ParkingSlots. Each Parking Slot is of certain slot size.

Vehicle is the interface type and all Vehicles just have to implement getType method to return type of Vehicle.

There is a separate enum for Slot size, and each slot size has the list of vehicle types it can accommodate. This keeps Parking and Vehicle objects independent of each other.

For calculating Fare, there is a separate FareController class which maintains map of each vehicle parked with details of parking and entry and exit time.

Fare for Vehicle type can be kept in Parking and then getFare method can return the final fare on the basis of its inputs which is Parking, entryTime and exitTime.

public enum ParkingStatus {
    EMPTY,
    OCCUPIED;
}

public class ParkingSlot {

    private String slotId;
    private String slotNumber;
    private ParkingStatus status;
    private SlotSize slotSize;
    private Vehicle vehicle;

    public ParkingSlot(String slotId, String slotNumber, ParkingStatus status, SlotSize slotSize) {
        this.slotId = slotId;
        this.slotNumber = slotNumber;
        this.status = status;
        this.slotSize = slotSize;
    }

    public void parkVehicle(Vehicle vehicle) {
        if (this.slotSize.isVehicleParkingPossible(vehicle)) {
            this.vehicle = vehicle;
            status = ParkingStatus.OCCUPIED;
        } else {
            throw new IllegalArgumentException("parking not possible for this vehicle type in this slot");
        }
    }

    public void emptySlot() {
        this.vehicle = null;
        status = ParkingStatus.EMPTY;
    }

}

public class Floor {

    private String floorId;
    private int floorNumber;
    private String floorName;
    private List<ParkingSlot> parkingSlots;

    public Floor(String floorId, int floorNumber, String floorName, List<ParkingSlot> parkingSlots) {
        this.floorId = floorId;
        this.floorNumber = floorNumber;
        this.floorName = floorName;
        this.parkingSlots = parkingSlots;
    }


    public void emptyFloor() {
        for (ParkingSlot slot: parkingSlots) {
            slot.emptySlot();
        }
    }

}

public class Parking {
    private String parkingId;
    private List<Floor> floors;
    private String parkingName;
    private String address;

    public Parking(String parkingId, List<Floor> floors, String parkingName, String address) {
        this.parkingId = parkingId;
        this.floors = floors;
        this.parkingName = parkingName;
        this.address = address;
    }

    public void emptyWholeParkingLot() {
        for (Floor floor : floors) {
            floor.emptyFloor();
        }
    }
}
public enum VehicleType {
    BIKE,
    COMPACT,
    SEDAN,
    TRUCK
}
public interface Vehicle {
    public VehicleType getType();
}
public class Bike implements Vehicle {

    private String bikeNumber;

    public Bike(String bikeNumber) {
        this.bikeNumber = bikeNumber;
    }

    @Override
    public String toString() {
        return "bike number=" + bikeNumber;
    }

    @Override
    public VehicleType getType() {
        return VehicleType.BIKE;
    }

}
public class HatchBackCar implements Vehicle {

    private String carNumber;

    public HatchBackCar(String carNumber) {
        this.carNumber = carNumber;
    }

    @Override
    public String toString() {
        return "car number=" + carNumber;
    }

    @Override
    public VehicleType getType() {
        return VehicleType.COMPACT;
    }
}
public class Sedan implements Vehicle {

    private String carNumber;

    public Sedan(String carNumber) {
        this.carNumber = carNumber;
    }

    @Override
    public String toString() {
        return "car number=" + carNumber;
    }

    @Override
    public VehicleType getType() {
        return VehicleType.SEDAN;
    }

}
public enum SlotSize {

    SMALL(asList(BIKE, COMPACT)),
    MEDIUM(asList(BIKE, COMPACT, SEDAN)),
    LARGE(asList(BIKE, COMPACT, SEDAN, TRUCK));

    private final List<VehicleType> vehicleTypesAllowed;

    SlotSize(List<VehicleType> vehicleTypes) {
        this.vehicleTypesAllowed = vehicleTypes;
    }

    public boolean isVehicleParkingPossible(Vehicle vehicle) {
        return vehicleTypesAllowed.contains(vehicle.getType());
    }
}
public class FareController {

    private Map<Vehicle, ParkingDetails> vehicleParkingDetailsMap = new HashMap<>();

    public void onVehicleEntry(Vehicle vehicle, Parking parking) {
        vehicleParkingDetailsMap.put(vehicle, new ParkingDetails(vehicle, parking, new Date(), null));
    }

    public void onVehicleExit(Vehicle vehicle) {
        ParkingDetails parkingDetails = vehicleParkingDetailsMap.get(vehicle);
        parkingDetails.exitTime = new Date();
    }

    public BigDecimal getFare(Vehicle vehicle) {
        ParkingDetails parkingDetails = vehicleParkingDetailsMap.get(vehicle);
        return getFare(parkingDetails.parking, parkingDetails.entryTime, parkingDetails.exitTime);
    }

    private BigDecimal getFare(Parking parking, Date entryTime, Date exitTime) {
        return null;
    }

}
class ParkingDetails {
    Vehicle vehicle;
    Parking parking;
    Date entryTime;
    Date exitTime;

    public ParkingDetails(Vehicle vehicle, Parking parking, Date entryTime, Date exitTime) {
        this.vehicle = vehicle;
        this.parking = parking;
        this.entryTime = entryTime;
        this.exitTime = exitTime;
    }
}