In a previous post, I showed some examples of how to create custom view components in MonoRail and touched on the ability to create composite view components. Since then I’ve refactored towards the use of interfaces which I think is a cleaner approach, so I thought I’d share.
First, let’s review the code that I want to improve upon:
Having this logic inside of the SearchForm component pretty clearly violates SRP and is just plain ugly. So coming at this from a TDD-like approach, I write what I want to be able to do in this method.
Notice the design decisions I’ve made in this one statement. I’ve said that I want to call a new method named RenderComponent which will take in an instance of a view component and a string array of key/value pairs as component parameters to use when rendering this view component to html.
(Side Note: The Castle MonoRail framework provides a great little utility class named DictHelper for converting an array of string key/value pairs (“key=value”) to a an IDictionary. Very handy for situations like this. More on that in a sec.)
For now, I’ll just add a new private method in this same class named RenderComponent and move the logic needed to render the LinkSubmitButton view component into this new private method.
But this logic for rendering the LinkSubmitButton to html is still sitting in my SearchForm class. Also notice how nothing in this method is directly using our LinkSubmitButton component, just any class that inherits from ViewComponent. I smell some opportunities for reuse here; more on that in a sec.
This may be jumping a little ahead, but I want to go ahead and create a common interface for my view components. Unfortunately, no common interface already exists in the MonoRail framework, but it’s easy enough to create yourself. Just extract an interface based on the ViewComponent class.
I then changed the two view components I’m working with to implement my new custom interface:
Now I’ll perform a “Pull Members Up” refactoring on the private method named RenderComponent in our SearchForm component to place that method on our newly created IViewComponent interface which will of course change the method to be public.
(One minor change I’ve also made is the RenderComponent method now accepts the interface IViewComponent instead of MonoRail’s ViewComponent class. This is just because I always like to program to interfaces when at all possible.)
Ok, all seems good except the fact that our LinkSubmitButton component won’t compile because it doesn’t implement the RenderComponent method on the IViewComponent interface. Remember when I mentioned that it appears that all of the logic in that method is completely generic and can probably easily be reused? Well, instead of just duplicating this method in the LinkSubmitButton class, I’m going to perform an “Extract Superclass” refactoring to create a base class for my view components and then another “Pull Members Up” refactoring to move the RenderComponent method up to our new base class as shown below:
Then we’ll change our two classes LinkSubmitButton and SearchForm to inherit from this new base class:
Now our rendering logic for the LinkSubmitButton in our SearchForm composite view component is simplified to:
And we have the added benefit of reusability on our rendering logic making future composite view components easy to create. Note: This steps shown in this post were actually performed in a matter of minutes, so it was a very quick refactoring. Writing up this post took considerably longer than the work itself, as is usually the case.
As usual you can find the full source code here.
Anyways, hope this can be of some use to those utilizing this great MVC framework we call MonoRail.