在我们的开发过程中,我们经常会遇到这样的场景就是一个对象的其中的一些状态依赖于另外的一个对象的状态,而且这两个对象之间彼此是没有关联的,及两者之间的耦合性非常低,特别是在这种基于容器模型的开发中遇到的会非常多,比如Prism框架或者MEF这种框架中,而我们会发现在这样的系统中我们经常使用一种Publish和Subscribe的模式来进行交互,这种交互有什么好处呢?基于带着这些问题的思考,我们来一步步来剖析!
首先第一步就是定义一个叫做IEventAggregator的接口,里面定义了一些重载的Subscribe和Publish方法,我们具体来看一看这个接口:
////// Enables loosely-coupled publication of and subscription to events. /// public interface IEventAggregator { ////// Gets or sets the default publication thread marshaller. /// ////// The default publication thread marshaller. /// ActionPublicationThreadMarshaller { get; set; } /// /// Subscribes an instance to all events declared through implementations of /// The instance to subscribe for event publication. void Subscribe(object instance); ////// /// Unsubscribes the instance from all events. /// /// The instance to unsubscribe. void Unsubscribe(object instance); ////// Publishes a message. /// /// The message instance. ////// Uses the default thread marshaller during publication. /// void Publish(object message); ////// Publishes a message. /// /// The message instance. /// Allows the publisher to provide a custom thread marshaller for the message publication. void Publish(object message, Actionmarshal); }
有了这个接口,接下来就是怎样去实现这个接口中的各种方法,我们来看看具体的实现过程。
////// Enables loosely-coupled publication of and subscription to events. /// public class EventAggregator : IEventAggregator { ////// The default thread marshaller used for publication; /// public static ActionDefaultPublicationThreadMarshaller = action => action(); readonly List handlers = new List (); /// /// Initializes a new instance of the public EventAggregator() { PublicationThreadMarshaller = DefaultPublicationThreadMarshaller; } ///class. /// /// Gets or sets the default publication thread marshaller. /// ////// The default publication thread marshaller. /// public ActionPublicationThreadMarshaller { get; set; } /// /// Subscribes an instance to all events declared through implementations of /// The instance to subscribe for event publication. public virtual void Subscribe(object instance) { lock(handlers) { if (handlers.Any(x => x.Matches(instance))) { return; } handlers.Add(new Handler(instance)); } } ////// /// Unsubscribes the instance from all events. /// /// The instance to unsubscribe. public virtual void Unsubscribe(object instance) { lock(handlers) { var found = handlers.FirstOrDefault(x => x.Matches(instance)); if (found != null) { handlers.Remove(found); } } } ////// Publishes a message. /// /// The message instance. ////// Does not marshall the the publication to any special thread by default. /// public virtual void Publish(object message) { Publish(message, PublicationThreadMarshaller); } ////// Publishes a message. /// /// The message instance. /// Allows the publisher to provide a custom thread marshaller for the message publication. public virtual void Publish(object message, Actionmarshal) { Handler[] toNotify; lock (handlers) { toNotify = handlers.ToArray(); } marshal(() => { var messageType = message.GetType(); var dead = toNotify .Where(handler => !handler.Handle(messageType, message)) .ToList(); if(dead.Any()) { lock(handlers) { foreach(var handler in dead) { handlers.Remove(handler); } } } }); } protected class Handler { readonly WeakReference reference; readonly Dictionary supportedHandlers = new Dictionary (); public Handler(object handler) { reference = new WeakReference(handler); var interfaces = handler.GetType().GetInterfaces() .Where(x => typeof(IHandle).IsAssignableFrom(x) && x.IsGenericType); foreach(var @interface in interfaces) { var type = @interface.GetGenericArguments()[0]; var method = @interface.GetMethod("Handle"); supportedHandlers[type] = method; } } public bool Matches(object instance) { return reference.Target == instance; } public bool Handle(Type messageType, object message) { var target = reference.Target; if(target == null) return false; foreach(var pair in supportedHandlers) { if(pair.Key.IsAssignableFrom(messageType)) { pair.Value.Invoke(target, new[] { message }); return true; } } return true; } } }
首先在EventAggregator的内部维护了一个LIst
我们会发现在每一次当执行这个Subscribe的方法的时候,会将当前object类型的参数instance传入到Handler这个对象中,在Handler这个类的构造函数中,首先将这个instance放入到一个弱引用中去,然后再获取这个对象所有继承的接口,并查看是否继承了IHandle
public interface IHandle {} ////// Denotes a class which can handle a particular type of message. /// ///The type of message to handle. public interface IHandle: IHandle { /// /// Handles the message. /// /// The message. void Handle(TMessage message); }
在看完了Subscribe这个方法后,后面我们就来看看Unsubscribe方法吧,这个思路其实很简单就是找到List
////// Publishes a message. /// /// The message instance. /// Allows the publisher to provide a custom thread marshaller for the message publication. public virtual void Publish(object message, Actionmarshal) { Handler[] toNotify; lock (handlers) { toNotify = handlers.ToArray(); } marshal(() => { var messageType = message.GetType(); var dead = toNotify .Where(handler => !handler.Handle(messageType, message)) .ToList(); if(dead.Any()) { lock(handlers) { foreach(var handler in dead) { handlers.Remove(handler); } } } }); }
我们看到,在发布一个object类型的message的时候,必然对应着另外的一个对象来处理这个消息,那么怎样找到这个消息的处理这呢?
对,我们在Subscribe一个对象的时候不是已经通过反射将订阅这个消息的对象及方法都存在了一个List
这里面还有一个要点就是,如果执行的方法返回了false,就是执行不成功,那么就从当前的List
1 所有消息订阅的对象必须实现统一的接口IHandle
2 整个EventAggregator必须是单实例或者是静态的,这样才能够在统一的集合中去实现上述的各种操作。
最后还是按照之前的惯例,最后给出一个具体的实例来做相关的说明,请点击此处进行下载,在下篇中我们将介绍一种简单版的基于事件的发布和订阅模式的例子。
以上就是C# 基于消息发布订阅模型的示例(上)的详细内容,更多关于c# 发布订阅模型的资料请关注脚本之家其它相关文章!