The obvious solution would be to introduce a supertype of TypeA
and TypeB
that contains the behaviour you require.
A different approach would be to use an adapter. To quote from ye olde Gang of Four book:
Convert the interface of a class into another interface clients expect. Adapter lets class work together that couldn't otherwise because of incompatible interfaces.
So here we would introduce an adapter type (only with a better name than this).
interface Ab {
void someOp();
}
Then we can wrap existing objects.
public static Ab asAb(final TypeA obj) {
return new Ab() {
public void someOp() {
obj.someOp();
}
};
}
The map can use the adapter type as the value.
Map<Animal, List<Ab>>
When I have come across this issue in existing code, it has been because the map actually contains two disjoint maps. The easy solution there is to use two maps.