Question

I am reading about OOD and came across Parking lot design problem.Parking lot has parking floors which has parking spots.The parking spot class looks as follow:

public enum ParkingSpotType {
  HANDICAPPED, COMPACT, LARGE, MOTORBIKE, ELECTRIC
}
public abstract class ParkingSpot {
  private String number;
  private boolean free;
  private Vehicle vehicle;
  private final ParkingSpotType type;

  public boolean IsFree();

  public ParkingSpot(ParkingSpotType type) {
    this.type = type;
  }

  public boolean assignVehicle(Vehicle vehicle) {
    this.vehicle = vehicle;
    free = false;
  }

  public boolean removeVehicle() {
    this.vehicle = null;
    free = true;
  }
}

public class HandicappedSpot extends ParkingSpot {
  public HandicappedSpot() {
    super(ParkingSpotType.HANDICAPPED);
  }
}

public class CompactSpot extends ParkingSpot {
  public CompactSpot() {
    super(ParkingSpotType.COMPACT);
  }
}

public class LargeSpot extends ParkingSpot {
  public LargeSpot() {
    super(ParkingSpotType.LARGE);
  }
}

public class MotorbikeSpot extends ParkingSpot {
  public MotorbikeSpot() {
    super(ParkingSpotType.MOTORBIKE);
  }
}

public class ElectricSpot extends ParkingSpot {
  public ElectricSpot() {
    super(ParkingSpotType.ELECTRIC);
  }
}

The parameters are self explanatory.So here why do we need separate classes for each ENUM value?What is the advantage of this?I thought of having only one ParkingSpot class type with one field representing type of parking slot.But why do we need to have separate classes for each ENUM value along with storing Enum as a field also?

Note: For complete design please refer https://www.educative.io/courses/grokking-the-object-oriented-design-interview/gxM3gRxmr8Z

Was it helpful?

Solution

You are correct that right now the derived classes are superfluous, because their only difference is one specific enum value, which is labeled the exact same way. You could omit either the enum or the derived classes, and nothing would change.

However, that conclusion might change when there are more differences than just the enum value.

For example, if the price of the parking spot is calculated differently based on which type of spot it is. By having the derived classes, you can keep each parking spot type's calculation logic separately and have them override the same base method.
Comparatively, if you only had the base class to work with, it'd have to contain all of the calculation logic.

However, the current example is a bit light on context and list of future features to decide whether the inheritance is warranted here or not. We shouldn't only evaluate the current state of the code (in which your observation is correct), but also account for any changes that are planned/expected in the near future.


That being said, I suspect that you're generally going to end up either having to remove the derived classes or the enum. I don't see the benefit of implementing the same information in two different ways.

OTHER TIPS

The difference becomes apparent if we consider

CompactSpot.Assign(Car.SUV)

this should obviously produce an error of some kind and we have two choices about how to implement it.

either:

ParkingSpot.Assign(car)
{
    if(car is SUV && this.type = COMPACT)
    {
        throw CarTooLarge()
    }
    if(car != HANDICAPPED && this.type == HANDICAPPED)
    ....
}

CompactSpot : ParkingSpot
    Assign(car)
    {
        if(car is SUV)
        {
            throw CarTooLarge()
        }
        base.assign(car);
    }
}

The Inheritance approach allows us to divide the conditional logic between multiple classes rather than having a large conditional block and logic in the base class.

If I consume your ParkingSpot class as a binary dll, I can inherit a new type of ParkingSpot and add my own logic. Which I can't do if you have an enum

The question answers itself if we think about behavior instead of state, and we should. Inheritance is motivated by "doing the same thing, but differently" or having additional functionality for various subtypes. Perhaps the designers have a good notion that ParkingSpot and Vehicle behavior will expand and evolve. Maybe for the sake of learning they simply baked in sub-typing.

While an ENUM will differentiate same-type vehicles/parkingSpots the requirements for functionality should be an overriding consideration. Even so, an enum may still be appropriate.

There is a need to match vehicles and parking spots - that it is an ENUM is merely an implementation detail. So a VehicleType pubic property seems to fit. This property is much more in the spirit of OO than, say, the client code rummaging thru Reflection / metadata. Client code should not calculate state of another object.


But there must be some service let us say ParkingAllocator that will first look for a relevant free slot for a given vehicle and only if a free slot of a particular vehicle is available, we will park a vehicle there.So if we are trying to assign a vehicle to a spot ,we are absolutely sure that the spot is large enough for vehicle. Does this make sense?

The use case diagram shows parking attendant and customer actors. They're not on the class diagram but they are part of the problem space.


I think there are missing or defective requirements.

  • Is a smaller vehicle allowed in a larger slot? Motorcycles fit everywhere.

  • Any given vehicle object could be electric or have handicap permissions or both - in real life anyway - so I see ElectricSlot & HandicapSlot as attributes of a parking spot. As shown, the class diagram here is inconsistent with the concept of different size vehicles fitting in different size slots.

  • There is no apparent match between parking spot types and vehicle types. Which vehicle(s) require "large", for example? Off hand, a Dictionary can explicitly match spots to vehicles, and/or vice versa. Also underlying enum integer values can represent relative parking spot size. And as I said above, "electric" is not a size.


Data Structures!

this stuff ...

if(car is SUV)
    {
        throw CarTooLarge()
    }
    base.assign(car);
}

goes away if this vehicle-type/spot-type matching is a data structure. A Dictionary is a data structure. Off hand, I see two dictionaries - vehicle->spot and spot->vehicle - as the core of a class with appropriate methods.

Licensed under: CC-BY-SA with attribution
scroll top