Suppose I have the following class structure:
Page
The Page
, StaticPage
and DynamicPage
interfaces are to be implemented by the clients. They provide various data depending on the page type (static or dynamic), which is used to render the page by the Renderer
. There might be many implementations of these interfaces.
Renderer
The Renderer
s render the pages. Also, there might be multiple implementations of this interface (for different rendering techniques).
RenderManager
This is just a simple facade which is supposed to invoke the appropriate render method on the provided renderer depending on the given page type. And here lies
The problem
How to determine which method to invoke on the Renderer
object depending on the provided page type?
Current (unsatisfactory) solution
Currently I am dispatching using a conditional:
void render(Page page, Renderer renderer) {
if (page is StaticPage) {
renderer.renderStaticPage(page);
} else if (page is DynamicPage) {
renderer.renderDynamicPage(page);
} else {
throw new Exception("page type not supported");
}
}
What's wrong
The problem with this solution is that whenever I wish to add another page type (i.e. extending the Page
interface) I need to adjust this method too. Actually, this is what polymorphic (virtual) methods in object oriented languages are supposed be used for, but in this case this doesn't work (see below why).
Other solutions I considered but rejected
Abstract class instead of interface. This would place an unneccessary constraint on the type hierarchy of the implementors: they would no longer be able to extend any class they want and would instead be forced to extend the abstract
StaticPage
orDynamicPage
class, which sucks.Add a
dispatch(Renderer render)
method to the interface and force the implementors to call the appropriate method on the renderer object depending on the page type. This obviously sucks, because the implementors should not care about the rendering: they just need to provide data which is to be rendered.
So, maybe there is some pattern or some alternative design which might help in this situation? Any ideas are welcome. :)
Use
dynamic
to select appropriate method overload at runtime:But of course dynamic typing has performance costs. Benefits - when new type of page added, all you need to change is renderer - just add another overloaded method.
Another option is visitor. In this case each page should do dispatching (seems like your second approach):
In this case page 'knows' about rendering. And you still should modify renderer when adding new pages.