12.NET观察者模式,发布与订阅

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。 ——发布订阅模式

发布订阅模式主要有两个角色:
1.发布方(Publisher):也称为被观察者,当状态改变时负责通知所有订阅者。
2.订阅方(Subscriber):也称为观察者,订阅事件并对接收到的事件进行处理。
发布订阅模式有两种实现方式:
1.简单的实现方式:由Publisher维护一个订阅者列表,当状态改变时循环遍历列表通知订阅者。
2.委托的实现方式:由Publisher定义事件委托,Subscriber实现委托。

 

简单地实现发布订阅案例
public class Dog
{
    public void Roar()
    {
        Console.WriteLine("汪汪汪!再不走咬你了");
    }
}
public class Person
{
    public void Roar()
    {
        Console.WriteLine("小偷,哪里跑");
    }
}

 

发布:

/// <summary>
/// 小偷
/// </summary>
public class Thief
{
    public delegate void StealDelegate();//委托
    /// <summary>
    /// 偷盗事件
    /// </summary>
    public event StealDelegate StealEvent;//事件

    /// <summary>
    ////// </summary>
    public void Steal()
    {
        Console.WriteLine("哇,好多钱呀");
        StealEvent.Invoke(); // 触发事件,发布
    }
}

订阅:

Thief thief = new();

// 狗和主人,同时订阅偷盗,并观察有没有小偷进来
thief.StealEvent+= new Dog().Roar;
thief.StealEvent+=new Person().Roar;

// 开始偷盗
thief.Steal();

Console.ReadKey();

 

 
如何实现自动订阅发布
发布订阅模式下,无非就涉及到三种实体:
1.事件发布者(EventBus)
2.事件处理者/订阅者(EventHandler)
3.事件源(EventData, 用于传参)
 
事件源,参数:
/// <summary>
/// 事件源
/// </summary>
public class EventData
{
    /// <summary>
    /// 事件源
    /// </summary>
    public object? Sender { get; set; }

    /// <summary>
    /// 事件发布的时间
    /// </summary>
    public DateTime CreateTime { get; set; } = DateTime.Now;
}

 

订阅接口:

/// <summary>
/// 事件处理者(所有的订阅者都需要继承只接口)
/// 还有一个作用:凡是继承了这个接口的人,都是订阅者
/// </summary>
public interface IEventHandler<in TEventData> where TEventData:EventData
{
    /// <summary>
    /// 事件处理的方法
    /// </summary>
    void Handler(TEventData data);
}

 

发布接口:

/// <summary>
/// 事件发布者
/// </summary>
public interface IEventBus<in TEventData> where TEventData:EventData
{
    void Publish(TEventData data);
}

 

实现IEventBus

/// <summary>
/// 事件总线实现者(所有的发布者都用它)
/// 这个类需要实现两个功能:
/// 1. 自动订阅
/// 2. 订阅者需要自动触发
/// </summary>
public class EventBus<TEventData>:IEventBus<TEventData> where TEventData:EventData
{
    public delegate void EventBusHandler(TEventData data);
    public event EventBusHandler EventBusEvent;

    /// <summary>
    /// 每种EventData 可能对应一组EventHandler(订阅者)
    /// </summary>
    private static readonly Dictionary<Type, List<Type>> EventHandlerMapping = new();
    
    static EventBus()
    {
        // 获取所有实现了IEventHandler<>接口的子类
        var list = (from type in Assembly.GetExecutingAssembly().GetTypes()
            from intf in type.GetInterfaces()
            where intf.IsGenericType && intf.GetGenericTypeDefinition() == typeof(IEventHandler<>)
            select type).ToList();
        foreach (var t in list)
        {
            //获取该类实现的泛型接口
            Type? handlerInterface = t.GetInterface("IEventHandler`1"); 
            if (handlerInterface != null)
            {
                // 获取泛型接口指定的EventData参数类型
                Type eventDataType = handlerInterface.GetGenericArguments()[0]; 
                if (EventHandlerMapping.ContainsKey(eventDataType))
                {
                    List<Type> handlerTypes = EventHandlerMapping[eventDataType];
                    handlerTypes.Add(t);
                    EventHandlerMapping[eventDataType] = handlerTypes;
                }
                else
                {
                    var handlerTypes = new List<Type> {t};
                    EventHandlerMapping[eventDataType] = handlerTypes;
                }
            }
        }

    }
    
    /// <summary>
    /// 发布事件, 订阅者自动触发
    /// </summary>
    /// <param name="data"></param>
    /// <exception cref="NotImplementedException"></exception>
    public void Publish(TEventData data)
    {
        var eventHandlerList = EventHandlerMapping[data.GetType()];
        foreach (var t in eventHandlerList)
        {
            // 自动订阅事件
            EventBusEvent +=  (Activator.CreateInstance(t) as IEventHandler<TEventData>)!.Handler;
        }
        // 触发事件
        EventBusEvent?.Invoke(data);
    }
}

 

案列1,无参订阅

public class Dog:IEventHandler<EventData>
{
    public void Handler(EventData data)
    {
        Console.WriteLine("汪汪汪,再不走就咬你");
    }
}
public class Person:IEventHandler<EventData>
{
    public void Handler(EventData data)
    {
        Console.WriteLine("小偷哪里逃");
    }
}

实现:

Console.WriteLine("Hello, World!");
// 事件源
EventData data = new();
// 创建发布者
IEventBus<EventData> bus = new EventBus<EventData>();
// 发布事件
bus.Publish(data);

 

案例2,有参订阅:

参数类

/// <summary>
/// 消息通知 事件参数
/// </summary>
public class NotifyEventData:EventData
{
    /// <summary>
    /// 通知接收者
    /// </summary>
    public string Receiver { get; set; } = null!;
}

 

订阅,发送Email

public class EmailEventHandler:IEventHandler<NotifyEventData>
{
    public void Handler(NotifyEventData data)
    {
        Console.WriteLine($"{data.Receiver} 收到了邮件通知");
    }
}

 

订阅,发送短信

public class SmsEventHandler:IEventHandler<NotifyEventData>
{
    public void Handler(NotifyEventData data)
    {
        Console.WriteLine($"{data.Receiver} 收到了短信通知");
    }
}

 

发布

Console.WriteLine("Hello, World!");

IEventBus<NotifyEventData> bus2 = new EventBus<NotifyEventData>();
bus2.Publish(new NotifyEventData {Receiver = "张三"});

 

posted @ 2024-02-27 11:20  野码  阅读(114)  评论(0编辑  收藏  举报