浮华过后,真金始现

一切问题最终都是时间问题,一切烦恼其实都是自寻烦恼
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

【插件式框架探索系列】建立基于委托的订阅发布机制

Posted on 2010-05-10 00:10  Kolor  阅读(2947)  评论(8编辑  收藏  举报

前些时候有个想法,想把自己感觉很有意思且方便平时开发的东西合起来,建立一个Framework,它会让开发变得更得心应手,可惜后来随着更多的东西被加入其中,越来越发觉这可能并不是一个开发者需要的东西,因为它太杂了,是的,作为一个Framework,还是单纯点的好,后来工作也忙了,就停滞了。这几天出差广州,夜来无事,便捡个模块来说道说道。

Messenger

在平时的开发中,数据的传递、处理等可以通过事件机制来完成,但是事件机制会引入耦合,当然这种耦合很多时候是合理的,但是却有那么一些时候这种耦合却不是你所需要的,过多的依赖会让你感到困惑,而引入Messenger就是为了解除这种依赖,请看下图。

clip_image002[4]

Figure 1. 类之间的单向依赖

clip_image004[4]

Figure 2. 类之间的双向依赖

clip_image006[4]

Figure 3. 引入Messenger后的依赖关系

Messenger的概念来自MVVM Foundation项目,在看完该项目的源代码后,发现其中的Messenger是个很好的机制,就借鉴这个机制结合实际情况设计了自己的Messenger。

顾名思义,Messenger在这里作为行为的传递者,其职责是预先接受行为的订阅,在需要的时候执行这些行为,即发布。

clip_image008[4]

Figure 4. Messenger类图

从类图上我们看到Messenger提供了订阅、取消订阅和发布行为的能力。Messenger内置一个数据结构用于存储订阅的行为,存储结构描述为Dictionary<T, List<WeakAction>>,T为行为在语义上的含义,作为字典的Key,其对应一组行为,而每个行为都以WeakAction表示,WeakAction会保证Messenger与定义行为的对象之间保持弱引用(WeakRefernce)关系,避免内存泄漏,如此便构成了行为的存储结构MessageToActionMap。

clip_image010[4]

Figure 5. MessageToActionMap类图

clip_image012[4]

Figure 6. WeakAction类图

终于Messenger拥有了订阅和发布行为的能力,为了提供更好的灵活性,Messenger被定义为泛型抽象类型,具体的Messenger通过继承方式扩展,在此,我们定义了几种典型的Messenger实现:

clip_image014[4]

Firgure 7. Messenger实现

Ø GeneralMessenger

GeneralMessenger作为Messenger的一个通用实现,继承自Messenger<object>,适用于大多数场景。

Ø TypeMessenger

TypeMessenger更适用于基于消息驱动的应用场景,在分布式应用中,系统间会互相传递消息,而消息的接收方往往会依据不同的消息类型作出不同的处理,比如Server收到Client的登录请求时会去执行验证行为,而收到登出请求时会作出释放资源行为。当然所有的这些,GeneralMessenger完全可以胜任,只不过TypeMessenger更加方便,后面提到的数据的订阅发布机制便是使用TypeMessenger实现的。

Ø OnceOffMessenger

OnceOffMessenger作为GeneralMessenger的特殊实现,它最特殊的地方便是订阅的行为,在发布后即消亡,适用于处理一次性的行为。

为了适应各种不同的开发场景,Messenger本身是可以创建多个实例的,如果想实现单例模式,可以通过使用SingletonManager.GetInstance<T>方法获取单例。

clip_image016[4]

Firgure 8. SingletonManager类图

TypeMessenger messenger = SingletonManager.GetInstance<TypeMessenger>();

 

数据的订阅发布机制

发布者的职责是提供数据,而订阅者的职责则是消费数据,即处理数据,当然订阅者可以同时也是发布者,如此可以实现数据的再处理。为此定义了发布接口和订阅接口:

clip_image018[4]

Firgure 9. 订阅发布接口类图

同时提供订阅和发布的标准实现:

clip_image020[5]

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方法实现。

写在后面

事件机制传递数据很方便,也比较简单,只是个人觉得还是这种方式更加灵活,也更加简单。

下载代码