Unity应用架构设计(2)——使用中介者模式解耦ViewModel之间通信
当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件)。越是复杂的页面,被切割出来的子模块就越多,子模块越多,彼此之间需要同步的数据和状态就越频繁,即易产生耦合。那么如何保证在复杂业务情况下,各个子模块之间可以随意通信并保持弱耦合关系,这正是本文所讨论的。
耦合的产生
试想一下,你有这样一下需求,点击 View A中的按钮,View B也需要做出相应的改变。
这不是很简单吗。脑海里迅速出现两种解决方案:
1.View A 主动通知View B做出更新,也就是View A依赖 View B
void Notify()
{
ViewB.Update(color);
}
2.View B监听View A的ColorChanged事件,主动拉取数据并更新,即ViewB 依赖View A
ViewA.OnColorPropertyValueChanged+=(color)=>{
Update(color);**
}
这两种实现毫无疑问是没问题的,至少从结果上来看是正确的。但试想一下,在一个复杂的客户端单页应用程序,这种紧耦合关系会导致程序的复杂度陡然上升。每个View/ViewModel依赖其余对象,而本身又被其他View/ViewModel强引用。这显然不是好的实践方式。
还记得我在上一篇文章的对于MVVM的描述吗?
MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在。ViewModel与ViewModel之间也应该感受不到彼此的存在。
中介者模式的引入
那么如何消除这种紧耦合关系呢?交给中介者设计模式来解决吧。
我们需要添加一个中介者,每个ViewModel Publisher对象都会在自己状态改变时,告诉中介者。每个ViewModel Subscribers 都需要告诉中介者请求来时进行怎样的响应。
在没有中介者之前对象之间都需要彼此认识,互相引用,是一种强耦合关系。有了中介者之后,彻底解耦。
那么现在就需要定义一个中介者,称为MessageAggregator。因为由它来转发消息,所以核心是一个字典,保存了所有需要被转发的消息。它的Key为消息的唯一Id,Value代表一个对该Message的处理程序。
public delegate void MessageHandler<T>(object sender, MessageArgs<T> args);
public class MessageAggregator<T>
{
private readonly Dictionary<string, MessageHandler<T>> _messages = new Dictionary<string, MessageHandler<T>>();
public static readonly MessageAggregator<T> Instance=new MessageAggregator<T>();
private MessageAggregator()
{
}
public void Subscribe(string name, MessageHandler<T> handler)
{
if (!_messages.ContainsKey(name))
{
_messages.Add(name, handler);
}
else
{
_messages[name] += handler;
}
}
public void Publish(string name, object sender, MessageArgs<T> args)
{
if (_messages.ContainsKey(name) && _messages[name] != null)
{
//转发
_messages[name](sender, args);
}
}
}
解耦ViewModel与ViewModel###
通过中介者MessageAggregator对象,ViewModelB Subscribe一个对消息来时的处理函数:
MessageAggregator<object>.Instance.Subscribe("ColorChanged",ToggleHandler);
ViewModel A在自己状态改变时,Pulish状态改变的消息给中介者:
MessageAggregator<object>.Instance.Publish("ColorChanged", this,new MessageArgs<object>("Red"));
小结###
中介者模式常常用来协调相关的GUI组件,可以让对象之间传递的消息变得简单。但如果设计不当,中介者本身会变得过于复杂。
源代码托管在Github上,点击此了解