I wanted to learn object oriented design and after listening to some online tutorials and some reading, I started with designing a simple parking garage.Problem Description:Design interfaces/classes required to implement a parking garage.Requirements:Parking garage should have multiple parking spaces and designated spaces for motorcycle, handicapped, veterans.Ability to find a free spot for a vehicle. The algorithm to choose a free spot should be configurable in the future.Calculate parking fee based on a defined fee structure. Fee calculation algorithm should be configurable to implement different fee structure.Accept different payment methods with ability to add or remove payment methods in futureIf there are no free spots available, should reject parking requestOnce a vehicle is parked, support an option to locate the parking spot given vehicle informationI would like to get community feedback on my design specifically whether it's in a reasonable shape for extension, does it expose any detail that can be hidden, is the responsibilities of each interface clearly defined etc.I am interested in the below:How can this design be made extensible if I want to add support to accept cash transaction in addition to credit card transaction?When I wrote this my thought process was like if I make interfaces, it gives flexibility by allowing to plug in different implementations at run time. But I understand now that it's not true because the method signature makes it tough to change. How can I change this to make it extensible?When a vehicle needs to be parked, it calls vehicle.park(garage) method and that in turn will invoke garage.park(this) method. Is this relation between IVehicle and Garage class correct? To map the real world entity to Objects, I am thinking Vehicle here represents the vehicle and the driver. When a driver wants to park vehicle, he/she will think I want to park my vehicle in this garage and that translated to vehicle.park(garage). Is this reasonable?IParkingSpace getFreeSpot(IParkingSpace[], VehicleType, Placard) - this takes VehicleType and Placard information of IVehicle. Is it ok to pass IVehicle instead of passing separate parameters like IParkingSpace getFreeSpot(IParkingSpace[], IVehicle)?. I feel like this can make getFreeSpot method consume any other data it may need in the future from IVehicle thus making it open for extension. Thoughts?Executable Code:import java.util.HashMap;import java.util.Map;interface IParkingSpace {   boolean park();   void unPark();   boolean isFree();   SpotType getType();}class ParkingSpace implements IParkingSpace {   boolean isFree;   SpotType spotType;   public ParkingSpace(SpotType spotType) {      this.spotType = spotType;      this.isFree = true;   }   @Override   public boolean park() {      if( isFree ) {         isFree = false;         return true;      }      return false;   }   @Override   public void unPark() {      isFree = true;   }   @Override   public boolean isFree() {      return isFree;   }   @Override   public SpotType getType() {      return spotType;   }}interface IFreeSpotStrategy {   // Can be as simple as returning the first free spot   // or return a spot that is closer to building entrance.   IParkingSpace getFreeSpot(IParkingSpace[] spaces, VehicleType vehicleType,                             Placard placardType);}class FirstFreeSpotStrategy implements IFreeSpotStrategy {   @Override   public IParkingSpace getFreeSpot(IParkingSpace[] spaces, VehicleType vehicleType,                                    Placard placardType) {      for(IParkingSpace space : spaces ) {         if (space.isFree())            return space;      }      // No free spots available      return null;   }}interface IVehicle {   String getLicensePlate();   VehicleType getType();   Placard getPlacard();   // CreditCardInfo getPaymentInfo();   boolean park(Garage garage); // this will call garage.park(this);   boolean unPark(Garage garage); // // this will call garage.unPark(this);   PaymentMode getPreferredPaymentMode();}class SimpleVehicle implements IVehicle {   String license;   VehicleType type;   Placard placard;   PaymentMode paymentMode;   public SimpleVehicle(String license, VehicleType type, Placard placard,                        PaymentMode payMode) {      this.license = license;      this.type = type;      this.placard = placard;      this.paymentMode = payMode;   }   @Override   public String getLicensePlate() {      return license;   }   @Override   public VehicleType getType() {      return type;   }   @Override   public Placard getPlacard() {      return placard;   }   @Override   public boolean park(Garage garage) {      return garage.park(this);   }   @Override   public boolean unPark(Garage garage) {      return garage.unPark(this);   }   @Override   public PaymentMode getPreferredPaymentMode() {      return paymentMode;   }}// Maintains state for each parked vehicle such as//  - entryTime//  - spot where a vehicle is parkedinterface IStateManager {   void recordParking(String licensePlate, IParkingSpace parkingSpace);   void eraseRecord(String licensePlate);   Long getEntryTime(String licensePlate);   IParkingSpace getSpotOfVehicle(String licensePlate);}class SimpleStateManager implements IStateManager {   Map<String, IParkingSpace> licenseToSpot;   Map<String, Long> licenseToEntryTime;   public SimpleStateManager() {      licenseToSpot = new HashMap<>();      licenseToEntryTime = new HashMap<>();   }   @Override   public void recordParking(String licensePlate, IParkingSpace parkingSpace) {      Long entryTime = System.currentTimeMillis();      licenseToSpot.put(licensePlate, parkingSpace);      licenseToEntryTime.put(licensePlate, entryTime);   }   @Override   public void eraseRecord(String licensePlate) {      licenseToSpot.remove(licensePlate);      licenseToEntryTime.remove(licensePlate);   }   @Override   public Long getEntryTime(String licensePlate) {      return licenseToEntryTime.get(licensePlate);   }   @Override   public IParkingSpace getSpotOfVehicle(String licensePlate) {      return licenseToSpot.get(licensePlate);   }}// Given entry time, calculates total parking fare. Different// implementations can have different strategy.interface IFareCalculator {   double calcFare(Long entryTime);}class SimpleFareCalculator implements IFareCalculator {   @Override   public double calcFare(Long entryTime) {      int minCharge = 5;      Long currentTime = System.currentTimeMillis();      Long elapsed = currentTime - entryTime;      int numberOfHours = (int) Math.ceil(elapsed/(double)(3600*1000));      return minCharge + (numberOfHours * 5);   }}interface IPaymentProcessor {   boolean charge(double charges);}class CreditCardPayment implements IPaymentProcessor {   @Override   public boolean charge(double charges) {      // 1. Prompt user for credit card information      // 2. Process payment through payment gateway      // I am not sure what is the best way to get credit card or cash from the user.      // How to model that in OO terms?      return true;   }}class CashPayment implements IPaymentProcessor {   @Override   public boolean charge(double charges) {      // Prompt user for cash and validate.      // I am not sure what is the best way to get credit card or cash from the user.      // How to model that in OO terms?      return true;   }   }class PaymentProcessorFactory {   static IPaymentProcessor creditCardProcessor = new CreditCardPayment();   static IPaymentProcessor cashProcessor = new CashPayment();   public static IPaymentProcessor createPaymentProcessor(PaymentMode mode) {      if (mode == PaymentMode.CREDITCARD)         return creditCardProcessor;      return cashProcessor;   }}// Different parking typesenum SpotType {   AUTOMOIBLE,   MOTORCYCLE,   HANDICAPPED}// Different vehicle typesenum VehicleType {   SMALL,   COMPACT,   FULLSIZE,   SUV,   MOTORCYCLE}// Placard typesenum Placard {   NONE,   HANDICAPPED,   VETERAN}enum PaymentMode {   CREDITCARD,   CASH}// Concrete Garage class.class Garage {   IParkingSpace[] spaces;   IFreeSpotStrategy strategy;   IStateManager stateManager;   IFareCalculator fareCalculator;   IPaymentProcessor paymentProcessor;   public Garage(IParkingSpace[] spaces,               IFreeSpotStrategy strategy,              IStateManager stateManager,              IFareCalculator fareCalculator ) {      this.spaces = spaces;      this.strategy = strategy;      this.stateManager = stateManager;      this.fareCalculator = fareCalculator;   }   boolean park(IVehicle vehicle) {      IParkingSpace freeSpace = strategy.getFreeSpot(spaces, vehicle.getType(),                                                     vehicle.getPlacard());      if (freeSpace == null)         return false;      stateManager.recordParking(vehicle.getLicensePlate(), freeSpace);      freeSpace.park();      return true;   }   boolean unPark(IVehicle vehicle) {      IParkingSpace parkingSpace =          stateManager.getSpotOfVehicle(vehicle.getLicensePlate());      double charges =         fareCalculator.calcFare(stateManager.getEntryTime(                                    vehicle.getLicensePlate()));      paymentProcessor = PaymentProcessorFactory.createPaymentProcessor(                               vehicle.getPreferredPaymentMode());      if(paymentProcessor.charge(charges)) {         parkingSpace.unPark();         stateManager.eraseRecord(vehicle.getLicensePlate());         return true;      }      return false;   }   public static void main(String args[]) throws InterruptedException {      IParkingSpace[] spaces = new IParkingSpace[] {                                new ParkingSpace(SpotType.AUTOMOIBLE),                                new ParkingSpace(SpotType.MOTORCYCLE),                                new ParkingSpace(SpotType.HANDICAPPED)};      Garage garage = new Garage(spaces, new FirstFreeSpotStrategy(),                                 new SimpleStateManager(),                                 new SimpleFareCalculator());      IVehicle vehicle = new SimpleVehicle(4gta223, VehicleType.FULLSIZE,                                           Placard.NONE, PaymentMode.CREDITCARD);      vehicle.park(garage);      Thread.sleep(2000);      vehicle.unPark(garage);   }}
Modeling a parking garage
java;object oriented