弥合菜单控件与命令模式之间的差距






4.50/5 (3投票s)
本文阐述了一个将命令模式应用于 ASP.NET 菜单控件的案例

引言
将设计模式应用于实际软件开发非常有趣,只有当你尝试应用时,才能掌握教科书中所述的优点。本文阐述了一个将命令模式应用于 ASP.NET 菜单控件的案例。我还演示了使用 Delegate
的通用命令的实现,这样开发人员就可以“重用”它来实现他们的实现,而无需创建新的命令类。
问题描述
所有 ASP.NET 菜单控件最常用于显示网站的超链接结构(即站点地图)。但是,您可能希望使用它来实现以下场景:在用户单击客户端上的一个菜单项后,您的程序将根据单击的菜单项(例如 MenuItem.Text
)在服务器端做出反应。让我们以 RadMenu
(在 Telerik 的 RadControls
中)为例;您不需要知道 RadMenu
的内部细节即可继续(下面讨论的思想可以应用于各种菜单控件)。最直观的解决方案通常会导致如下所示的 “if
---else
” 结构的实现
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
{
// do something
}
}
DefaultRadMenu_ItemClick
是任何被点击的菜单项的处理程序 (postback=true
)。如果您看过讨论设计模式或代码可维护性的文章,您应该已经闻到了问题的气味:一旦出现一个名为 lemon
的新项,您不仅需要实现 doLemon()
,还必须修改 “if
…else
” 结构。此外,如果您的应用程序包含许多页面,这些页面分别使用 RadMenu
来做不同的事情,您必须在整个应用程序中单调地重复这种代码模式。这时,命令模式就能派上用场。
将命令模式应用于菜单控件
命令模式 是 OOP 中一种非常流行的设计模式。如果您不熟悉它,请自行 Google!在本文中,命令模式被设计为一个接口 IMenuItemCommand
(如下所示),我们提供了一个默认的通用命令:稍后描述的 BaseMenuItemCommand
类;当然,您可以通过应用程序实现您的 IMenuItemCommand
具体类来进行救援。IMenuItemCommand
简单地定义了一个命令的行为,如下所示
public interface IMenuItemCommand
{
// Execute Command
void Execute();
// Describe the command
string Text { get; set;}
}
Execute()
是服务器端反应由您自定义的地方。使用命令模式,我们可以实现一个通用的 ItemClicked
处理程序,可以在任何地方重用
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();
}
}
请注意,为了让前面的 DefaultRadMenu_ItemClicked
工作,我们必须在构建 RadMenu
时将一个具体的 IMenuItemCommand
对象(即 BaseMenuItemCommand
)分配到 RadMenuItem.DataItem
中
RadMenuItem item1 = new RadMenuItem("Hello");
item1.DataItem = new BaseMenuItemCommand (
delegate {
//do something on server-side;
});
RadMenu1.Items.Add(item1);
上面的代码片段也演示了通用命令 BaseMenuItemCommand
的使用。构造函数中的参数是一个 delegate
(即以下代码中的 ToDoDelegate
),它在 BaseMenuItemCommand.Execute()
中执行,如下所示
public void Execute()
{
if(ToDo != null)
{
ToDo();
}
}
…
private ToDoDelegate _toDo;
public ToDoDelegate ToDo
{
get { return _toDo; }
set { _toDo = value; }
}
public delegate void ToDoDelegate();
BaseMenuItemCommand
的目的是让您重用这个类来实现各种命令。想象一下,如果您有 10 个菜单项,它们的命令无法在其他地方重用。您是否愿意实现 10 个单独的 IMenuItemCommand
类来使您的系统复杂化?
总之,将命令模式应用于菜单控件消除了使用菜单的页面中的 “if
-else
” 结构。此外,命令可以通过其他菜单控件重用。更重要的是,使用命令模式的代码比没有使用命令模式的代码更加一致,从而产生更具可维护性的代码。
结论
我希望这个代码示例可以帮助您减少重复的代码,当您决定使用菜单控件来实现本文中描述的场景时。虽然我们专门使用 RadMenu
来演示命令模式的应用,但这个概念绝对可以应用于其他菜单控件。
历史
- 2008 年 6 月 24 日:提交了初始文章