在开始本次之前,有必要对上次的一点儿遗漏的地方再废话一下。
    关机的实现:关机也是调用Windows API 实现的,具体代码参考上次列出的清单 
    PInvokeService.DoExitWin(int) 函数。
值得一提的是 关机对话框调用了 Windows 中一个未公开的 API, 我们不知道这个函数
    的名字,但是我们知道它的地址,我使用 ISO C++ 进行了封装,代码如下:
 1我的 WinClock 项目系列之三 (Mediator模式的应用)    #include <windows.h>
 2我的 WinClock 项目系列之三 (Mediator模式的应用)
 3

    编译生成的 dll 是 CPPCode.Shutdown.dll
    然后你可以在 PInvokeService.cs 里面找到这样的代码:
    [DllImport("CPPCode.Shutdown.dll", ExactSpelling = true, SetLastError = true)]
    public static extern void ShowShutdownDialog();

抛开具体细节讨论抽象,现在可以开始正式讲本次的内容了。

Mediator模式的应用
    动机(Motivation):
      在软件的构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种
    复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。
   
      在这种情况下,我们可以使用一个“中介对象”来管理对象间的关联关系,避免相互的对象之间
    紧耦合引用关系,从而更好地抵御变化。
   
    意图(Intent):
      用一个中介对象来封装一系列对象交互。中介者使各对象不需要显示的相互引用,从而使其
    耦合松散,而且可以独立地改变它们之间的交互。
                                                                    ————《设计模式》GOF
                                                                   
我们抛开这些精典的理论,看看如何把我们的功能细节分离到一系列 class 中,以及让菜单工作。
先总体上看一下最后的类图:
我的 WinClock 项目系列之三 (Mediator模式的应用)

                                      点击下载完整类图

     Element 和 Mediator 都是抽象类,但他们之间存在很强的耦合关系, Element 依赖 Mediator 对象,
同时Mediator对象内部包含 Element 的集合。因此 Mediator 也依赖 Element,Element 了类化就
可以在这些类中实现我们的功能细节。那就先看看这两个抽象类吧:

  1我的 WinClock 项目系列之三 (Mediator模式的应用)    // Element.cs
  2    }

    在这里,MainForm 是主窗口,它充当了中介,它可以被 Element 和 Mediator 引用。
    你可能已经发现,Element还依赖于一个 ICommand 接口,IComand 接口引用了一个 object 的对象
    在它的一个实现类 MenuItemCommand 中,这个对象指向的是一个 ToolStripMenuItem 的对象。

 1我的 WinClock 项目系列之三 (Mediator模式的应用)    // ICommand.cs
 2    }

    那么你可能会问,Element 为什么不直接依赖 ToolStripMenuItem 呢?其实在这个项目里,我们完全
    可以这么做,因为我们要使用的仅仅是ToolStripMenuItem, 我们之所以抽象出来一个 ICommand, 完全是
    考虑到可能会用到其他的UI组件比如 Button 等,那么如果有这样的需求,很简单,我们可以实现一个
    ButtonCommand,让他实现 ICommand 接口,这样保证了接口的统一,它就可以和 ToolStripMenuItem 一起
    工作了。简单地说,抽象一个 ICommand 只是为了统一接口。Element 和 Mediator 还实现了 IDispose
    接口,这是.Net中被经常提到的 Dispose 模式,如果感兴趣,你可以看看我的另一篇博客:
     .Net Dispose 模式 与 C++/CLI 确定性资源清理
    实际使用中,Dispose 方法都是通过 Mediator 对象调用的。
   
    好的,抽象已经完成,看看具体怎么实现各个 Menu 的工作细节吧。举一个穿透桌面功能的例子吧:

 1    }

    OnExecute 是点击菜单是会执行的方法,OnStatusChanged 的调用可能是因为用户单击了任何一个菜单,
    也可能是MainForm中的代码调用了 mediator.Notify(), 由于 Mediator 中引用着所有 Element 的集合,
    所以调用 Notify() 将导致所有 Element 的 OnStatusChanged() 被调用,同样,直接点击任何一个菜单项,
    也会导致其他(还有自身)菜单接到通知,即 OnStatusChanged() 被调用。所以这些都是在抽象基类里面完成
    的,实体 Element 只需要处理这两个方法就可以了。实体 Mediator 本软件中只有一个,他的实现很简单。

 1我的 WinClock 项目系列之三 (Mediator模式的应用)    // ContextMenuMediator.cs
 2

    为了更好地利用 Visual Studio 的 Designer 设计器,菜单还是在 MainForm 里面用 Designer 生成的,只是在
    MainForm 的构造行函数里面,菜单项被 Element 引用。由于进行了设计,功能都被分散了,MainForm 里面的实体
    代码并不多,看看吧。

  1    }

    这里 Designer 生成的代码没有列出来,其中 SetupMenuItemElements 方法就是完成了实例化 Element 和 Mediator
    具体类的作用, 这样他们都被 medator 引用,所以你不用担心它马上会被垃圾收集干掉。

参考资料: 
    
关机对话框
    李建忠-C#面向对象模式纵横谈第七讲-(行为型模式)  Mediator 中介者模式

      


相关文章:

  • 2022-02-20
  • 2022-12-23
  • 2021-12-05
  • 2021-07-28
  • 2022-01-21
  • 2021-09-20
  • 2021-05-05
猜你喜欢
  • 2022-01-06
  • 2022-02-10
  • 2021-07-15
  • 2022-12-23
  • 2021-09-30
相关资源
相似解决方案