I asked a similar question yesterday that was specific to a technology, but now I find myself wondering about the topic in the broad sense.
For simplicity’s sake, we have two classes, A and B, where B is derived from A. B truly ‘is a’ A, and all of the routines defined in A have the same meaning in B.
Let’s say we want to display a list of As, some of which are actually Bs. As we traverse our list of As, if the current object is actually a B, we want to display some of Bs additional properties….or maybe we just want to color the Bs differently, but neither A nor B have any notion of ‘color’ or ‘display stuff’.
Solutions:
-
Make the A class semi-aware of B by basically including a method called isB() in A that returns false. B will override the method and return true. Display code would have a check like: if (currentA.isB()) B b = currentA;
-
Provide a display() method in A that B can override…. but then we start merging the UI and the model. I won’t consider this unless there is some cool trick I’m not seeing.
-
Use instanceof to check if the current A object to be displayed is really a B.
-
Just add all the junk from B to A, even though it doesn’t apply to A. Basically just contain a B (that does not inherit from A) in A and set it to null until it applies. This is somewhat attractive. This is similar to #1 I guess w/ composition over inheritance.
It seems like this particular problem should come up from time to time and have an obvious solution.
So I guess the question maybe really boils down to:
If I have a subclass that extends a base class by adding additional functionality (not just changing the existing behavior of the base class), am I doing something tragically wrong? It all seems to instantly fall apart as soon as we try to act on a collection of objects that may be A or B.
A variant of option 2 (or hybrid of 1 and 2) may make sense: after all, polymorphism is the standard solution to ‘Bs are As but need to behave differently in situation X.’ Agreed, a display() method would probably tie the model to the UI too closely, but presumably the different renderings you want at the UI level reflect semantic or behavioural differences at the model level. Could those be captured in a method? For example, instead of an outright getDisplayColour() method, could it be a getPriority() (for example) method, to which A and B return different values but it is still up to the UI to decide how to translate that into a colour?
Given your more general question, however, of ‘how can we handle additional behaviour that we can’t or won’t allow to be accessed polymorphically via the base class,’ for example if the base class isn’t under our control, your options are probably option 3, the Visitor pattern or a helper class. In both cases you are effectively farming out the polymorphism to an external entity — in option 3, the UI (e.g. the presenter or controller), which performs an instanceOf check and does different things depending on whether it’s a B or not; in Visitor or the helper case, the new class. Given your example, Visitor is probably overkill (also, if you were not able/willing to change the base class to accommodate it, it wouldn’t be possible to implement it I think), so I’d suggest a simple class called something like ‘renderer’:
This encapsulates the run-time type checking and bundles the code up into reasonably well-defined classes with clear responsibilities, without the conceptual overhead of Visitor. (Per GrizzlyNyo’s answer, though, if your hierarchy or function set is more complex than what you’ve shown here, Visitor could well be more appropriate, but many people find Visitor hard to get their heads around and I would tend to avoid it for simple situations — but your mileage may vary.)