Introduction
Applying design patterns to practical software development is pretty interesting, and only when you attempt to apply can you grasp the merits described in textbooks. This article illustrates a case where I apply the Command Pattern to ASP.NET Menu controls. I also demonstrate the implementation of a generic command with Delegate
whereby developers can “reuse” to achieve their implementation without creating new command classes.
Problem Description
All ASP.NET Menu controls are most commonly applied to display the hyperlink structures (i.e. Site Map) of a Web site. However, you may want to use it to implement a scenario that after users click one of the menu items on the client-side, your program will react on the server-side according to the menu item clicked (e.g. MenuItem.Text
). Let’s take RadMenu
(within Telerik’s RadControls
) as an example; you do not need to know the nuts and bolts of RadMenu
to continue (and the thought discussed below can be applied to various Menu controls). The most intuitive solution often results in the implementation of an “if
---else
” construct as follows:
protected void DefaultRadMenu_ItemClick(object sender, Telerik.Web.UI.RadMenuEventArgs e)
{
RadMenuItem selItem = e.Item;
if(selItem.Text == "Apple")
{
doApple();
}
else if(selItem.Text == "Orange")
{
doOrange();
}
else
{
}
}
DefaultRadMenu_ItemClick
is a handler for any menu item clicked (postback=true
). If you have taken a look at articles talking about design pattern or code maintainability, you should have smelt what the problem is: once a new item called lemon
comes out, not only do you need to implement doLemon()
, but you must also modify the “if
…else
” construct. Furthermore, if your application contains many pages which individually use RadMenu
to do different things, you have to tediously repeat this kind of code pattern throughout your application. Here Command pattern comes to the rescue.
Apply Command Pattern with Menu Controls
Command pattern is a highly prevailing design pattern in OOP. If you are not familiar with it, please Google by yourself! In this article, Command pattern is designed with an interface IMenuItemCommand
(shown below) and we provide a default generic command: the BaseMenuItemCommand
class described shortly; of course, you can implement your IMenuItemCommand
concrete class for rescue through the application. IMenuItemCommand
simply defines the behavior of a command shown as follows:
public interface IMenuItemCommand
{
void Execute();
string Text { get; set;}
}
The Execute()
is where the server-side reaction is customized by you. With the command pattern, we can implement a generic ItemClicked
handler, which can be reused everywhere:
protected void DefaultRadMenu_ItemClicked
(object sender, Telerik.Web.UI.RadMenuEventArgs e)
{
RadMenuItem selItem = e.Item;
IMenuItemCommand itemCmd = selItem.DataItem as IMenuItemCommand;
if (itemCmd != null)
{
itemCmd.Execute();
}
}
Notice that in order to let the preceding DefaultRadMenu_ItemClicked
work, we must assign a concrete IMenuItemCommand
object (i.e. BaseMenuItemCommand
) into RadMenuItem.DataItem
when building the RadMenu
:
RadMenuItem item1 = new RadMenuItem("Hello");
item1.DataItem = new BaseMenuItemCommand (
delegate {
});
RadMenu1.Items.Add(item1);
The above code snippet also demonstrates the use of the generic command, BaseMenuItemCommand
. The parameter in the constructor is a delegate
(i.e. ToDoDelegate
in the following code) that is executed within BaseMenuItemCommand.Execute()
shown below:
public void Execute()
{
if(ToDo != null)
{
ToDo();
}
}
…
private ToDoDelegate _toDo;
public ToDoDelegate ToDo
{
get { return _toDo; }
set { _toDo = value; }
}
public delegate void ToDoDelegate();
The purpose of BaseMenuItemCommand
is to let you reuse this class to implement a variety of commands. Imagine if you get 10 menu items whose commands cannot be reused elsewhere. Would you like to implement 10 separate IMenuItemCommand
classes to complicate your system?
In sum, applying the Command Pattern to Menu controls eliminates the “if
-else
” construct among pages using Menu. Also, commands can possibly be reused via other Menu controls. More importantly, your codes with Command Pattern become more consistent than without it, resulting in more maintainable code.
Conclusion
I hope this code sample could help you diminish the repetitive codes when you decide to employ Menu controls to implement the scenario described in this article. Although we specifically use RadMenu
to demonstrate the application of the Command Pattern, the concept can definitely be applied to other Menu controls.
History
- 24th June, 2008: Initial article submitted