A simple factory using Generics
For about a week ago one of my readers asked me to simplify a piece of his code. The code was translating the different tags used by blog comments, such as [url][/url], [img][/img] etc. as we know from WordPress. It was one big method that processed the different types of tags before the comment was saved to a database.
I suggested a very simple factory design by using Generics and an interface. Then for each tag we would create a new class for handling only that single tag. The class had to implement the interface called IHtmlFilter. This is the interface:
public interface IHtmlFilter
{
void Execute(ref string html);
}
For handling the [url][/url] tags we created a class that implement the IHtmlFilter interface like so:
public class UrlFilter : IHtmlFilter
{
private static Regex _Regex
= new Regex(@"(\[url\](.*?)\[\/url\])", RegexOptions.Singleline);
private static string link
= "<a href=\"{0}\">{0}</a>";
public void Execute(ref string html)
{
html
= _Regex.Replace(html, string.Format(link, "$2"));
}
}
As you can see, the UrlFilter class implements the IHtmlFilter member Execute(ref string html) which we will use later. We also created an ImageFilter class to handle the [img][/img] tags using roughly the same technique as the UrlFilter. So now we had the two classes, UrlFilter and ImageFilter.
Because they both implement the IHtmlFilter interface, we were able to treat them as being of same type and put them in a Generic collection. When we have an instance of the two classes in the collection, we can iterate the collection and call the Execute(ref string html) method on each of the classes. The html parameter passed by ref is the blog comment, that needs to be processed for the [img] and [url] tags. Here is how to add the classes to the collection:
private static Collection<IHtmlFilter>
_Filters = FilterSelection();
/// <summary>
/// Select
the filters you need.
/// </summary>
private static Collection<IHtmlFilter>
FilterSelection()
{
Collection<IHtmlFilter>
filters = new Collection<IHtmlFilter>();
filters.Add(new UrlFilter());
filters.Add(new ImageFilter());
return filters;
}
The code fills the static collection _Filters with instances of the two classes that implements the IHtmlFilter interface. Now all we have to do to process the blog comment is to put the comment into the static method ApplyFilters(ref string html) below.
/// <summary>
/// Execute
the chosen filters.
/// </summary>
/// <param
name="html"></param>
private static void ApplyFilters(ref string html)
{
foreach (IHtmlFilter filter in _Filters)
{
filter.Execute(ref html);
}
}
Here is how to use it to write out the filtered comment to the response stream.
protected void Page_Load(object sender, EventArgs e)
{
string html
= "Check out this web page [url]http://www.google.com[/url]";
ApplyFilters(ref html);
Response.Write(html);
}
Whenever you want to add support for a new tag, you can just create a class that implements IHtmlFilter and add it to the generic collection in the FilterSelection() method. This simple factory design can be used for a variety of other purposes and it adds a great layer of abstraction to your code and makes it easier to maintain and reuse.