I have following class/interface structure (can't modify the source):
public interface Car {}
public class CarA implements Car{
public String getASpecifics() {...}
}
public class CarB implements Car{
public String getBSpecifics() {...}
}
public class Summary {...}
I want to have a generic way of creating Summray for concrete implementations of Car interface which will be open to adding new implementations. My approach is following:
public CarSummarizer {
public interface SummaryGenerator<T extends Car> {
Summary generateSummary(T car);
}
static {
SummaryGenerator<CarA> aGen = c -> {... c.getASpecifics(); ...}
SummaryGenerator<CarB> bGen = c -> {... c.getBSpecifics(); ...}
}
}
Now I'd like to store aGen and bgen in a Map. I want to parametrize it so that I can offer one only public static method which accepts Car car and based on it's class object (car.getClass()) uses correct SummaryGenerator implemenation. That should look something like following:
public static Summary getSummaryForCar(Car car) {
return map.get(car.getClass()).generateSummary(car);
}
I don't know how to declare and instantiate that Map so that it's fully type-safe (i.e. doesn't allow inserting pair (CarC.class, SummaryGenerator<CarD>)). I'd like something like this:
public static <T extends Car> Map<Class<T>, SummaryGenerator<T>> map = new LinkedHashMap<>();
static {
// after instantiation
map.put(CarA.class, aGen);
map.put(CarB.class, BGen);
}
// also support following
public static <T extends Car> void addSummaryGenerator(T car, SummaryGenerator<T> sg) {
map.put(car.getClass(), sg);
}
That doesn't work because generics can't be declared on variables like they can be on functions.
I guess I could define new class public class SummarizerStorage<T extends Car> and the place map inside and just delegate calls. That seems like an overkill and ugly. I feel like it should be done somehow directly.
Declaring map like Map<Class<? extends Car>, SummaryGenerator<? extends Car>> would allow paring of Class<> and SummaryGenerator<> of sibling types. I want to allow only same type pairs.