Mediator模式有一种本事,就是可以让本身需要互相协作的对方,可以不用知道彼此,而把两者之间的联系,转交给Mediator来处理。换句话说,Mediator模式解除了需要互相协调的对象之间的依赖。这也是Mediator(调停者)模式名字的由来。一个颇为形象的例子是***。
进入***的用户总是要彼此通信的,这些对象如果直接进行交互,就会彼此连接,最后织成一张纷繁复杂的大网。要分清彼此之间的关系,真可以说是“剪不断理还乱”了。所以,引入一个***对象来管理用户间的交流,就势成必然。
Mediator模式与Facade模式都是管理复杂对象的行家里手,不过二者在运用上还是有本质的不同。Facade是门面,通过它隔断了客户端与复杂对象之间的直接关系。Mediator是仲裁者,哪里出现纠纷哪里就有它的身影。
Facade对象对于客户端来说是可见的,而隐藏了复杂对象;Mediator对象对于客户端来说则是隐藏的,客户端直接调用复杂对象,而复杂对象之间的关系,则转交给了Mediator。
MVC模式则是职责分离的典范,就好似三权分立一般,各司其职。Model负责提供数据,View则负责显示数据,Controller则负责控制Model与View之间的交互,封装了领域逻辑。这样的职责分离形式,能够有效地解除数据、业务逻辑与UI界面之间的耦合关系。但是,在MVC模式中,由于业务逻辑的问题,很有可能在Controller之间还需要进行交互。这种交互一旦增多,就可能出现在一个Controller中出现不同的Controller,导致代码出现分散,形成霰弹式修改的坏味道。
Marlon在其博客上发表了一篇文章,有效地将MVC模式与Mediator模式两者结合,创造出一种称之为MVC+M的模式,有效地解决了Controller对象之间相互依赖的问题。Marlon实现了一个文件浏览器来展示这一模式。运行程序,当我们点击左边的目录树时,在右边就会显示当前目录下的所有文件。UI如图所示:
左边视图对应的控制对象为DirectorySelectorController,而右边视图对应的则为FileSelectorController对象。Marlon统一定义了一个接口IColleague,作为Mediator模式中参与者的抽象接口,并让相关的Controller实现它。类图如下所示:
每个Controller对象所接收的Mediator对象都是相同的,因为Mediator对象作为BaseController基类的属性存在,并利用了Singleton模式,保证了Mediator对象只能存在一个:
public abstract class BaseController : INotifyPropertyChanged, IColleague
{
static Mediator mediatorInstance = new Mediator();
public Mediator Mediator { get; private set; }
public BaseController()
{
//set the mediator to be the same one for every controller.
Mediator = mediatorInstance;
}
//rest of implementation
}
在子类的构造函数中,通过调用Mediator对象的Register方法,建立了消息与Controller对象之间的映射关系。以FileSelectorController类为例:
public FileSelectorController()
{
Mediator.Register(this, new[]
{
Messages.DirectorySelectedChanged
});
}
Mediator类完成Controller对象之间的协调,其定义如下:
public class Mediator
{
MultiDictionary<string, IColleague> internalList
= new MultiDictionary<string, IColleague>();
public void Register(IColleague colleague, IEnumerable<string> messages)
{
foreach (string message in messages)
internalList.AddValue(message, colleague);
}
public void NotifyColleagues(string message, object args)
{
if (internalList.ContainsKey(message))
{
//forward the message to all listeners
foreach (IColleague colleague in internalList[message])
colleague.MessageNotification(message, args);
}
}
}
Register()方法会将消息与Controller对象的映射注册到内部字典internalList中。而NotifyColleagues()方法则会遍历整个internalList,然后执行Controller对象(体现为IColleague类型)的MessageNotification()方法。通过MessageNotification()方法,每个Controller对象根据传输的消息字符串,做出相应的响应操作。例如在FileSelectorController类中,就是根据Message的值,执行装载文件的业务逻辑:
public override void MessageNotification(string message, object args)
{
switch (message)
{
case Messages.DirectorySelectedChanged:
//load all files for the directory specified
LoadFiles((DirectoryDisplayItem)args);
break;
}
}
如果没有引入Mediator模式,由于需要在点击目录时显示当前目录的文件,因此在DirectorySelectorController类的ItemSelected事件中,必须调用FileSelectorController对象获取文件信息,然后通过对应视图显示这些文件信息。这就导致了DirectorySelectorController和FileSelectorController之间的依赖。现在,在DirectorySelectorController的ItemSelected事件中,就可以通过Mediator来实现文件信息的读取与显示:
//event handler for the selecting changed
void ItemSelected(object sender, RoutedEventArgs e)
{
TreeView treeView = (TreeView)e.OriginalSource;
//Send a message that an item is selected and pass the object selected
Mediator.NotifyColleagues(Messages.DirectorySelectedChanged, treeView.SelectedItem);
}
Marlon实现的MVC+M模式有效地解除了Controller对象之间的耦合关系,其中,他引入了IColleague接口对Controller的相关方法进行了抽象。不过,这样的接口并非必须,正如我在《Strategy模式与Delegate委托》一文中提到的接口与委托之间的关系,我们完全可以用委托来代替IColleague接口的定义,使整个结构变得更加的灵活。由于引入了委托与消息对象的映射关系,因此在Controller类的MessageNotification()方法中,不再需要用switch语句来判断消息的值,而是直接根据映射关系,调用委托对象所指代的方法逻辑。Mediator类可以修改为:
public class Mediator
{
IDictionary<string,Action<object>> m_List = new Dictionary<string,Action<object>>();
public void Register(string message,Action<object> callback)
{
m_List.Add(message,callback);
}
public void NotifyColleagues(string message, object args)
{
if (m_List.ContainsKey(message))
{
m_List[message](args);
}
}
}
与之对应的,FileSelectorController可以修改为:
public FileSelectorController()
{
Mediator.Register(Messages.DirectorySelectedChanged,
(obj) =>
{
LoadFiles((DirectoryDisplayItem)obj);
});
}
至于最初定义在Controller类的MessageNotification()方法,则被匿名函数所代替,已经不再需要了
分享到:
相关推荐
23种设计模式之十八(行为模式)Mediator模式
用一个中介者对象来封装一系列对象的交互,中介和者模式使得各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。
NULL 博文链接:https://gary0416.iteye.com/blog/913462
中介者模式(Mediator) 用意:用一个中介对象来封装一系列对象间的交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。
这是一个运用了中介者设计模式的登录对话框练习题。 该案例改编自结城浩《设计模式-java语言中的应用》一书。 This is a program about a login dialog, wich try to illustrate the design pattern of Mediator. ...
中介者模式的完整代码。 程序默认使用vs开发。其他开发工具可能需要做少许调整。
主要介绍了Java设计模式之中介模式(Mediator模式)介绍,本文讲解了为何使用Mediator模式、如何使用中介模式等内容,需要的朋友可以参考下
C#面向对象设计模式 (行为型模式) Mediator 中介者模式 视频讲座下载
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
一种基于Mediator设计模式的车载多媒体系统设计,宋飞,郭文明,如今,车载多媒体系统已经在汽车产业发展中扮演了越来越重要的角色,而车载系统的设计方式也必将受到越来越多的重视。本文从系统
C#面向对象设计模式纵横谈(17):(行为型模式) Mediator 中介者模式
C++设计模式课件17_Mediator_中介者.pdf
1.2 Smalltalk MVC中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象接口 9 1.6.4 描述对象...
C#面向对象设计模式纵横谈(17):(行为型模式) Mediator 中介者模式 (Level 300)
MVC 模式(MVC Pattern) 业务代表模式(Business Delegate Pattern) 数据访问对象模式(Dao Pattern) 前端控制器模式(Front Controller Pattern) 拦截过滤器模式(Intercepting Filter Pattern) 服务定位...
中介者模式(Mediator Pattern)是一种行为型设计模式,用于减少对象之间的直接相互依赖,使得对象间的交互通过一个中介者对象来进行协调。在中介者模式中,对象之间不再直接相互调用,而是通过中介者对象来传递消息...
设计模式之中介模式的完整代码实现,Java版
设计模式精解-GoF 23 种设计模式解析附 C++实现源码 ...3.6 Mediator模式 3.7 Command模式 3.8 Visitor模式 3.9 Chain of Responsibility模式 3.10 Iterator模式 3.11 Interpreter模式 4 说明
Mediator 模式 Memento 模式 Observer 模式 State 模式 Strategy 模式 Template Method 模式 Visitor 模式 Guarded Suspension 模式 Producer Consumer 模式 Worker Thread 模式 Thread-Per-...
MVC 模式(MVC Pattern) 业务代表模式(Business Delegate Pattern) 组合实体模式(Composite Entity Pattern) 数据访问对象模式(Data Access Object Pattern) 前端控制器模式(Front Controller Pattern) ...