SharpDevelop是一个非常优秀的开源项目,其中有一些思想非常出色的,如插件结构,服务设计,设计模式的应用,UI与行为的抽离,以及可插入式的设计结构, 其中有些设计思想我已经应用到我以前开发过的一些项目中。由于我的文笔不好及工作太忙,所以一直没有写什么心得之类的笔记。现在有点时间,也来记录一下我的分析随笔,先来分析一下SharpDevelop中模式的应用,至于其非常优秀的插件结构,博客园已有兄弟作过分析了。 

           在剖析Command模式之前,先来看一下.NET Framework中的菜单及工具栏处理存在的一些缺点: 

1.            无法自动同步更新菜单项与工具项的状态以及相关的行为及特性,需要手动去处理两个事件,从而造成了相同的两个操作需要两次处理,也就造成了需要手动地同时维护多份相同的操作; 

2.            无法重用菜单项这部分的功能,因为在dotnet中菜单项的单击需要集成在UI中; 

3.            无法很好地扩展,如需要增加或删除菜单项,则需要更改原有的代码及UI部分的设计,从而违反了OCP(开闭)原则。按照OCP原则,当扩展相关的功能时,不应该修改原始的代码,而应该扩展该代码; 

4.            无法将相关的消息当作原子状态处理,试想一下,如果一个系统不仅通过菜单、工具栏来操作用户接口,也可通过命令(如Visual Studio就可以通过输入命令而执行相关的操作)来执行,如果不将相关的操作抽象出来的话,维护这个操作的成本太大。并且如果想实现更进一步的控制比如精确到原子状态的权限控制,则很难实现。 

我们可以运用Command模式,将菜单项相应的操作抽象出来,定义一个命令接口ICommand,此接口仅具有Run方法,可以作为任何命令的基接口。但是由于菜单还具有一些其它的特性,如是否可见,是否可用,文本,需要执行此菜单项的宿主,所以再定义了一个IMenuCommand接口继承此接口,加入了一些新的特性,并定义了一个实现IMenuCommand接口的抽象基类MenuCommand,其它类可以派生此类。由于我自已修改了SharpDevelop中的一些设计,所以可能有些与原版的不一样。 

剖析SharpDevelop:Command模式的应用_菜单项


 

          ICommand接口:是一个最基本的接口,代表一个动作的行为; 

IMenuCommand接口:派生于ICommand接口,作为菜单项或工具项所实现的行为及特性来使用; 

IStatusUpdate接口:描述一个能够更新状态的接口,当对象需要更新状态时将调用此接口,如菜单项需要动态地更新Enable,Visible特性; 

MenuCommand抽象基类:实现了IMenuCommand接口,任何菜单命令可以从此继承; 

CustomCommandBarItem:继承于CommandBar组件的CommandBarButton类,类似于菜单项或工具项,实现了IStatusUpdate接口,以根据IMenuCommand接口的Visible、Enabled属性的改变而相应地更新其Enabled,Visible属性; 

CustomCommandBarMenu:继承于CommandBar组件的CommandBarMenu类,类似于菜单条。            

    当我们在客户端需要创建命令时,只需写相关的类继承于MenuCommand         

         

剖析SharpDevelop:Command模式的应用_菜单项_02

           在这里使用了另外一个开源组件CommandBar。CustomCommandBarItem类的构造函数通过传入一个IMenuCommand类的实例与IMenuCommand关联起来,将单击事件(OnClick方法)委托给ICommand接口的Run方法来执行,其Update方法用于更新状态。CustomCommandBarMenu类中的OnDropDown方法用于当打开菜单条时通过调用IStatusUpdate的Update方法自动更新所有菜单项的状态。 

           在SharpDevelop处理所有插件的菜单中,此处的设计是支持的基础。 

           

           如果更进一步,可以在SharpDevelop中加入类似于Visual Studio的“命令窗口”;如果是一个ERP系统或MIS系统,可以将权限控制写在IMenuCommand中的Enabled中,在执行Run方法之前先检测Enabled,如果Enabled为false则禁止执行,我先前写过一个权限框架,通过Attribute及Reflect技术来实现权限的自动控制。