There are multiple ways of solving the same problem.
Interface segregation means to keep the interface as small as possible.
Different versions of solution to the same problem should still have a common interface.
We do this so swapping out service or component becomes easy.
public interface ParkingLot { void parkCar(); // Decrease empty spot count by 1 void unparkCar(); // Increase empty spots by 1 void getCapacity(); // Returns car capacity double calculateFee(Car car); // Returns the price based on number of hours void doPayment(Car car); } class Car { }
When we want to implement a free parkinglot:
public class FreeParking implements ParkingLot { @Override public void parkCar() { } @Override public void unparkCar() { } @Override public void getCapacity() { } @Override public double calculateFee(Car car) { return 0; } @Override public void doPayment(Car car) { throw new Exception("Parking lot is free"); } }
In above example, ParkingLot
interface is trying to do too much.
ParkingLot
implemented both parking and payment related logic.We can improve this by separating the logic to following:
ParkingLot < PaidParkingLot < HourlyFeeParkingLot < ConstantFeeParkingLot < FreeParkingLot
Now the model is more flexible, extendable, and the clients do not need to implement any irrelevant logic because we provide only parking-related functionality in the parking lot interface.