Suppose I have the following class structure:
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.
The Renderer
s render the pages. Also, there might be multiple implementations of this interface (for different rendering techniques).
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
How to determine which method to invoke on the Renderer
object depending on the provided page type?
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");
}
}
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).
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
or DynamicPage
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:
public class RenderManager
{
public void Render(IPage page, Renderer renderer)
{
try
{
renderer.RenderPage((dynamic)page);
}
catch (RuntimeBinderException ex)
{
throw new Exception("Page type not supported", ex);
}
}
}
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):
public interface IPage
{
void Render(Renderer renderer);
}
public class StaticPage : IStaticPage
{
public void Render(Renderer renderer)
{
renderer.RenderPage(this);
}
}
public class RenderManager
{
public void Render(IPage page, Renderer renderer)
{
page.Render(renderer);
}
}
In this case page 'knows' about rendering. And you still should modify renderer when adding new pages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With