用例:假設(shè)公司發(fā)布了一個(gè)公告 需要通過短信 和 郵件分別2種方式 通知員工

 

1:首先我們建立領(lǐng)域模型

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

    /// <summary>
    /// 領(lǐng)域核心基類    /// </summary>
    public abstract class Core
    {        public string Id { set; get; } = Guid.NewGuid().ToString();
    }    public interface ICore
    {

    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

2:消息模型

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 /// <summary>
    /// 通知的領(lǐng)域模型    /// </summary>
    public class Notice : Core
    {        /// <summary>
        /// 通知內(nèi)容        /// </summary>
        public string Message { set; get; }        /// <summary>
        /// 通知發(fā)送時(shí)間        /// </summary>
        public DateTime DateTime { set; get; } = DateTime.Now;
    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 

這個(gè)時(shí)候我們會(huì)想到 建立2個(gè)服務(wù)類 一個(gè)是SmsService 和 EmailService服務(wù) 分別用來發(fā)送短信和Email

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

    public class EmailService
    {        public EmailService() { }        public EmailService(Entity.Notice notice) => Console.WriteLine($"郵件通知:{notice.Message}  發(fā)送時(shí)間:{notice.DateTime}");

    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

  public class SmsService
    {        public SmsService() { }        public SmsService(Entity.Notice notice) => Console.WriteLine($"短信通知:{notice.Message} 發(fā)送時(shí)間:{notice.DateTime}");
    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

static void Main(string[] args)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
           
            Entity.Notice notice = new Entity.Notice() { Message ="明天加班 加班 加班 ~?。。?nbsp;重要的事情說三遍" };            new Service.EmailService(notice);            new Service.SmsService(notice);
        }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance) 
這里主要是因?yàn)?NET CORE中文輸出會(huì)導(dǎo)致亂碼 需要加上編碼配置。也可以換上非Core平臺(tái)

看看運(yùn)行后的效果
Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

運(yùn)行后的效果似乎已經(jīng)滿足了我們的需求 公司公告分別以2種方式發(fā)送出去了
這樣就帶來了一個(gè)問題 如果未來社交發(fā)展需要多平臺(tái)發(fā)送通知呢。。假設(shè)這里有還有QQ 默默 探探 釘釘 微信 等等
這一系列的消息推送方式 那我們的代碼里是不是這樣 ?

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

            Entity.Notice notice = new Entity.Notice() { Message ="明天加班 加班 加班 ~?。。?nbsp;重要的事情說三遍" };            new Service.EmailService(notice);            new Service.SmsService(notice);            new Service.QQService(notice);            new Service.WeiXinService(notice);            new Service.MomoService(notice);            new Service.DingDService(notice);            new Service.TanTanService(notice);

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 這樣寫顯然看起來是一個(gè)非常蛋疼的事。仔細(xì)想想這一系列的消息推送不變的是 事件消息源 也就是Notice對(duì)象

 并且所有發(fā)送消息的方法都是被動(dòng)的接收這個(gè)對(duì)象 , 這樣我們就可以把2者的關(guān)系理解成 消息源是發(fā)布者,

具體處理消息發(fā)送的是訂閱者,從而我們換一個(gè)思路去改造之前的方法

 

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 public interface IEventHandler<T> where T : Entity.Core
    {        /// <summary>
        /// 訂閱對(duì)象的具體實(shí)現(xiàn)        /// </summary>
        /// <param name="entity"></param>
        void Handler(T entity);
    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

定義一個(gè)泛型接口,所有訂閱者必須實(shí)現(xiàn)這個(gè)接口

 

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

    /// <summary>
    /// Email形式處理    /// </summary>
    public class EmailEventHandler : IEventHandler<Entity.Notice>
    {        public void Handler(Notice notice)
        {
            Console.WriteLine($"郵件通知:{notice.Message}  發(fā)送時(shí)間:{notice.DateTime}");
        }
    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 /// <summary>
    /// 短信形式處理    /// </summary>
    public class SmsEventHandler : IEventHandler<Entity.Notice>
    {        public void Handler(Notice notice)
        {
            Console.WriteLine($"短信通知:{notice.Message} 發(fā)送時(shí)間:{notice.DateTime}");
        }    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

這是改造的第一步,改造的目的是讓它能以一種自動(dòng)的方式處理,而不像之前一樣需要一個(gè)一個(gè)對(duì)象的new出來,

做到能像看電視一樣,只要你打開電視就能收看到傳輸過來的畫面

定義一個(gè)消息總線的接口 用來管理 訂閱者的注冊(cè) 以及消息的發(fā)布

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

  public interface IBus
    {        /// <summary>
        /// 默認(rèn)訂閱所有事件消息  啟動(dòng)時(shí)調(diào)用        /// </summary>
        void SubscribeAll();        /// <summary>
        /// 訂閱        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        void Subscribe(Type type, object data);        /// <summary>
        /// 發(fā)布訂閱        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eneity"></param>
        void Publish<T>(T eneity) where T : Entity.Core;
    }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

定義一個(gè)BusManager來實(shí)現(xiàn) IBus

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

        private BusManager()
        {            if (_instance == null)
                Bus = new BusService();
        }        private static object _lock = new object();        private static BusManager _instance;        public static IBus Instance
        {            get
            {                if (_instance == null)
                {                    lock (_lock)
                    {                        if (_instance == null)
                            _instance = new BusManager();
                    }
                }                return _instance;
            }
        }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 

        

 

/// <summary>
        /// 主要是針對(duì) 事件源和具體的事件處理注冊(cè)關(guān)系。ConcurrentDictionary保證了線程的安全        /// </summary>
        private static ConcurrentDictionary<Type, List<object>> _dicHandlers = new ConcurrentDictionary<Type, List<object>>();

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

/// <summary>
        /// 判斷type是否是abs的實(shí)現(xiàn)類或者子類/        /// .net Core中對(duì)反射進(jìn)行了單獨(dú)的處理 反射后一些詳細(xì)屬性都要通過GetTypeInfo獲取 原對(duì)象只保留了一些基本屬性        /// </summary>
        /// <param name="type"></param>
        /// <param name="abs"></param>
        /// <returns></returns>
        private bool IsAssignableFrom(Type type, Type abs)
        {            ///            if ((abs.GetTypeInfo().IsAbstract || abs.GetTypeInfo().IsInterface) && abs.IsAssignableFrom(type))                return true;            else
            {                if (type.GetInterfaces().Any(o => o.GetTypeInfo().IsGenericType && o.GetGenericTypeDefinition() == abs))                    return true;
            }            return false;
        }        /// <summary>
        /// 判斷2個(gè)類型是否相同        /// </summary>
        private Func<object, object, bool> _Equals = (o1, o2) =>
       {           return o1.GetType() == o2.GetType();
       };

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

上述方法都是為了實(shí)現(xiàn)IBus接口所做的鋪墊 如有.Net Core反射疑問的自行Bing

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

        public void Subscribe(Type type, object data)
        {            lock (_lock)
            {                if (_dicHandlers.ContainsKey(type))
                {                    var _handlers = _dicHandlers[type];                    if (!_handlers.Any(o => _Equals(o, data)))
                        _handlers.Add(data);
                }                else
                {
                    _dicHandlers[type] = new List<object>() { data };
                }
            }
        }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

實(shí)現(xiàn)的單個(gè)對(duì)象的加載 Key為具體的發(fā)布對(duì)象類型, Value是具體的訂閱者的行為實(shí)現(xiàn)集合,這里是多個(gè)訂閱者的實(shí)現(xiàn)

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)


ConcurrentDictionary 里的關(guān)系

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

  /// <summary>
        /// 初始化 默認(rèn)的所有實(shí)現(xiàn)都訂閱事件 
        /// </summary>
        public void SubscribeAll()
        {            ///加載程序集,具體的你也可以加載項(xiàng)目路徑下所有的dll或者exe
            var assembly = Assembly.Load(new AssemblyName("ConsoleApp2"));
            assembly.GetTypes().Where(x => x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsInterface).ToList().ForEach(x =>
            {                if (IsAssignableFrom(x, typeof(IEventHandler<>)))
                {                    ///反射創(chuàng)建對(duì)象
                    var entity = Activator.CreateInstance(x);                    ///獲得到泛型參數(shù)的類型
                    var key = x.GetInterfaces().FirstOrDefault().GetGenericArguments().FirstOrDefault();                    this.Subscribe(key, entity);
                }
            });

        }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)


事件源的發(fā)布


Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 /// <summary>
        /// 事件源的發(fā)布        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eneity"></param>
        public void Publish<T>(T eneity) where T : Core
        {            var type = eneity.GetType();            if (_dicHandlers.ContainsKey(type) && _dicHandlers[type] != null)
            {
                _dicHandlers[type].ForEach(o =>
                {                    var eve = o as IEventHandler<T>;
                    eve.Handler(eneity);
                });
            }
        }

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

上面的所有代碼基本上就完成了一個(gè)簡(jiǎn)單的事件總線驅(qū)動(dòng)的模式,
試試最終的運(yùn)行效果。
Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)
是不是感覺很神奇,這就是單純自己理解的事件總線模式。

http://www.cnblogs.com/hfdel/p/7172914.html