I have the following type hierarchy:
interface I:
----+class B implements I
----+class C implements I
----+class D implements I
I have another class Consumer1
that supports types C
and D
but not B
(in its various methods) and a class Consumer2
that supports type B
. I have total control over Consumer1
and Consumer2
so I can choose how to implement them. Now, at runtime I expect my callers to give me a collection of I
s and I will decide internally whether to route them to Consumer1
or Consumer2
.
Now, a very bad non-OOP way is to do an if instanceof
check all over the place and mess things up. One alternative is to register a supporting class Map<Class<?>, Class<?>>
that shall contain {{B,Consumer2}, {C,Consumer1}, {D,Consumer1}}
. This is as bad as the previous one because I shall have to cast objects after figuring out whether to send them to Consumer1
or Consumer2
.
A second alternative is to apply a Visitor
pattern which would solve this rather neatly but prevent my interface from being extended further (unless I modify the visitor). Is there a neater alternative?
5
I think Chain of responsibility is best fit for this problem. This will make it properly extensible, while encapsulating eventual instanceof
calls into the consumer themselves.
To add to this. I don’t think using instanceof
is wrong. It just needs to be properly encapsulated, just like in this case.
0
Consider the acyclic visitor pattern. It allows extensions to the hierarchy without necessarily impacting all the visitors (only the ones that need to visit all objects, which don’t seem to be present in your design).
Alternatively, I think it’s not a problem to have the type checks in the consumer themselves, since they’ll be concerned with checking only the types that they work with (not that different from the acyclic visitors). Then you could either dispatch the I
s to all consumers and only the ones that really care about the runtime type will do anything with them, or you could do it in a chain of responsibility style, as already suggested in the comments by John Cartwright.
Why is consumers not able to do their work with just I interface? Consumers should require instances of I, not rely on specifics of B,C or D.