前些时候有个想法,想把自己感觉很有意思且方便平时开发的东西合起来,建立一个Framework,它会让开发变得更得心应手,可惜后来随着更多的东西被加入其中,越来越发觉这可能并不是一个开发者需要的东西,因为它太杂了,是的,作为一个Framework,还是单纯点的好,后来工作也忙了,就停滞了。这几天出差广州,夜来无事,便捡个模块来说道说道。
Messenger
在平时的开发中,数据的传递、处理等可以通过事件机制来完成,但是事件机制会引入耦合,当然这种耦合很多时候是合理的,但是却有那么一些时候这种耦合却不是你所需要的,过多的依赖会让你感到困惑,而引入Messenger就是为了解除这种依赖,请看下图。
Figure 1. 类之间的单向依赖
Figure 2. 类之间的双向依赖
Figure 3. 引入Messenger后的依赖关系
Messenger的概念来自MVVM Foundation项目,在看完该项目的源代码后,发现其中的Messenger是个很好的机制,就借鉴这个机制结合实际情况设计了自己的Messenger。
顾名思义,Messenger在这里作为行为的传递者,其职责是预先接受行为的订阅,在需要的时候执行这些行为,即发布。
Figure 4. Messenger类图
从类图上我们看到Messenger提供了订阅、取消订阅和发布行为的能力。Messenger内置一个数据结构用于存储订阅的行为,存储结构描述为Dictionary<T, List<WeakAction>>,T为行为在语义上的含义,作为字典的Key,其对应一组行为,而每个行为都以WeakAction表示,WeakAction会保证Messenger与定义行为的对象之间保持弱引用(WeakRefernce)关系,避免内存泄漏,如此便构成了行为的存储结构MessageToActionMap。
Figure 5. MessageToActionMap类图
Figure 6. WeakAction类图
终于Messenger拥有了订阅和发布行为的能力,为了提供更好的灵活性,Messenger被定义为泛型抽象类型,具体的Messenger通过继承方式扩展,在此,我们定义了几种典型的Messenger实现:
Firgure 7. Messenger实现
Ø GeneralMessenger
GeneralMessenger作为Messenger的一个通用实现,继承自Messenger<object>,适用于大多数场景。
Ø TypeMessenger
TypeMessenger更适用于基于消息驱动的应用场景,在分布式应用中,系统间会互相传递消息,而消息的接收方往往会依据不同的消息类型作出不同的处理,比如Server收到Client的登录请求时会去执行验证行为,而收到登出请求时会作出释放资源行为。当然所有的这些,GeneralMessenger完全可以胜任,只不过TypeMessenger更加方便,后面提到的数据的订阅发布机制便是使用TypeMessenger实现的。
Ø OnceOffMessenger
OnceOffMessenger作为GeneralMessenger的特殊实现,它最特殊的地方便是订阅的行为,在发布后即消亡,适用于处理一次性的行为。
为了适应各种不同的开发场景,Messenger本身是可以创建多个实例的,如果想实现单例模式,可以通过使用SingletonManager.GetInstance<T>方法获取单例。
Firgure 8. SingletonManager类图
TypeMessenger messenger = SingletonManager.GetInstance<TypeMessenger>();
数据的订阅发布机制
发布者的职责是提供数据,而订阅者的职责则是消费数据,即处理数据,当然订阅者可以同时也是发布者,如此可以实现数据的再处理。为此定义了发布接口和订阅接口:
Firgure 9. 订阅发布接口类图
同时提供订阅和发布的标准实现:
Firgure 10. 订阅发布标准实现类图
我们可以看到订阅者同时也是发布者,两者皆是使用TypeMessenger实现订阅发布机制。
SubscriberAdapter<T>的Subscribe方法中订阅T的处理行为为Handle方法:
/// <summary> /// Subscribe the message handler. /// </summary> public void Subscribe() { messenger.Subscribe<T>(new Action<T>(msg => Handle(msg))); }
而在PublisherAdapter的OnMessage和OnMessageAsyn方法中发布数据:
/// <summary> /// Publish the message. /// </summary> /// <param name="message">The message.</param> public virtual void OnMessage(object message) { if (message != null) { messenger.NotifyAll(message); } } /// <summary> /// Publish the message asynchronously. /// </summary> /// <param name="message">The message.</param> public virtual void OnMessageAsyn(object message) { if (message != null) { messenger.NotifyAllAsyn(message); } }
同时在SubscriberAdapter<T>中也可以以类似的方式发布数据,该数据类型的订阅者会处理该数据。
这种设计方式也是借鉴于Apache MINA框架中的过滤器概念,让数据在一个过滤器链中传递,链上的每个过滤器都有机会对数据进行处理和再加工。不过这里的订阅者的数据发布行为只能发布不同于当前类型的数据,否则会进入无限制的死循环,该行为已经通过重载PublisherAdapter的OnMessage和OnMessageAsyn方法实现。
写在后面
事件机制传递数据很方便,也比较简单,只是个人觉得还是这种方式更加灵活,也更加简单。