0

I am studying Spring Boot and I would like to find a more elegant solution for my problem.

At a specific service I need to call the correct impl based on the Enum value.

Right now I am doing something like this:

@Service
public class VehicleHandlerService {
  @Autowired
  private CarService carService; // implements VehicleService interface
  @Autowired
  private BusService busService; // implements VehicleService interface
  @Autowired
  private TruckService truckService; // implements VehicleService interface
  
  public Vehicle doSomething(VehicleType type) {
    return getService(type).doSomething();
  }

  // I might need have different Data types for specific Service here, like a CarData, BusData, TruckData, etc...
  public .???. otherMethod(VehicleType type, Data data) {
    return getService(type).otherMethod(data);
  }

  private VehicleService getService(VehicleType type) {
    if(VehicleType.CAR.equals(type)) {
      return carService;
    } else if(VehicleType.BUS.equals(type)) {
      return busService;
    } else if(VehicleType.TRUCK.equals(type)) {
      return truckService;
    }
    //throw exception
  }
}

I wonder if we have a more Spring-ish way to do it? like injecting a map like:

@Autowired
private Map<VehicleType, VehicleService> services;

and use it besides having a method.

If I need to add more VehicleService impl in the future, I would have to keep adding them manually too.

How do you guys handle this kind of problem on Spring to avoid duplicated code and bunches of if/elses?

Any suggestion that can make me learn a Spring feature is welcome!

  • [injectautowired-beans-to-map-with-enum-as-map-key-in-spring](https://stackoverflow.com/a/57901513/2419499) does it answer your question ? – Tanmoy Majumdar Jun 26 '20 at 21:02

1 Answers1

0

You'll have to make all VehicleService beans self identifiable. One approach that I use myself precisely for this purpose is to add this information in the bean itself. In your case, the VehicleService base class/interface may be enhanced with following additional method

public interface VehicleService {
    /** Add this method for self discovery */
    VehicleType getVehicleType();

    /* ... other methods of VehicleService interface */
}

Then VehicleHandlerService can be modified to something like following:

public class VehicleHandlerService {
    @Autowired
    private List<VehicleService> handlerServices;

    /* ... other methods for this service here ... */
    
    private VehicleService getService(VehicleType type) {
        return handlerServices.stream().filter(x -> x.getVehicleType().equals(type)).findFirst().get();
    }
}

This way any new bean is automatically injected and appropriately used by the service.

Avnish
  • 1,241
  • 11
  • 19