ABP之事件总线(2)

时间:2023-03-08 23:48:19
ABP之事件总线(2)

在上一篇文章中,我们复习了一下事件的经典的发布订阅模式,同时对是事件源和时间处理逻辑进行抽象统一,用起来也没有问题。但是还是有很多的问题,比如说我们Handle方法其实是违背了单一性的原则的,里面混杂了各个EventData的处理逻辑,这个方法将会越来越大,越来越慢,看着越来越难受。好,那么先解决今天的第一个问题。既然我们前面为了单一化原则,分别定义了不同的xxEventData,那么我们可以同样的定义不同的xxEventHandler.

创建不同的Handler

        public class FishingEventHandler : IEventHandler<FishEventData>
{
public void Handle(FishEventData eventData)
{
Console.WriteLine("小猫说:");
Console.WriteLine("我吃了{0}斤鱼",eventData.FishWeight);
}
}
public class MouseEventHandler : IEventHandler<MouseEventData>
{
public void Handle(MouseEventData eventData)
{
Console.WriteLine("小猫说:");
Console.WriteLine("我抓到了{0}老鼠", eventData.MouseName);
}
}

实现猫捉老鼠

  static void Main(string[] args)
{ Cat c1 = new Cat();
Mouse m1 = new Mouse("1号老鼠"); //订阅事件
// m1.selfEventHandler += c1.Handle;
m1.selfEventHandler += new MouseEventHandler().Handle;
//触发事件
m1.Comming(m1.Name); Console.ReadLine();
}

到了这里,可能会感到疑问了,我们做了这么多的工作,又回到了最初的起点???事件的处理逻辑还是得重新写。。。。但是!!!!有没有发现一个问题,我们把事件整个的脱离出来了,不再依赖于猫(订阅者),而是直接订阅事件,关键是还有一个关键的发现,那就是我们统一了事件的处理逻辑方法的名称,统一为Handle。这样大大方便了我们的开发,以后我们编写事件的时候,只需要编写对应的xxxEventData和xxxEventHandler就可以了,是不是很方便!是不是有一种解除耦合的感觉!

ABP之事件总线(2)

上面的这行代码是我们手动注册我们的事件处理逻辑,现在问题来了刚才我们写的是猫捉老鼠的处理逻辑,现在来了,狗捉老鼠,牛捉老鼠,大象捉老鼠。。。。此时创建了DogMouseEventHandler:IEventHandler<MouseEventData>、NiuMouseEventHandler:IEventHandler<MouseEventData>、ElephantMouseEventHandler:IEventHandler<MouseEventData>

 m1.selfEventHandler += new DogMouseEventHandler().Handle;
 m1.selfEventHandler += new NiuMouseEventHandler().Handle;
 m1.selfEventHandler += new ElephantMouseEventHandler().Handle;
如果我们再动态的添加很多,此时我们的代码还是需要修改。。。。。那么如何解决这个问题呢?也就是如何代替显示的注册,而是直接自动的动态的注册。那就只能从程序集入手了。。。用到的技术也就是我们常说的反射。 所以我们重新修改Mouse类
    public  class Mouse
{ //声明事件委托
public event MouserEventHandler selfEventHandler;
public Mouse(string name)
{
this.Name = name;
var asm = Assembly.GetExecutingAssembly();
foreach (var type in asm.GetTypes())
{
//判断当前的类型是否实现了IEventHandler接口
if (typeof(IEventHandler).IsAssignableFrom(type))
{
//获取该type实现了泛型的IEventhandler接口
var handlerInterface = type.GetInterface("IEventHandler`1");
if (handlerInterface == null)
continue;
var arg = handlerInterface.GetGenericArguments()[];
if (arg.Equals(typeof(MouseEventData)))
{
var handler = Activator.CreateInstance(type) as IEventHandler<MouseEventData>;
this.selfEventHandler += handler.Handle;
}
}
}
}
public void Comming(string name )
{
Console.WriteLine("老鼠说:\n"); Console.WriteLine("我的名字是{0},I am Comming!", name);
//触发事件
selfEventHandler(new MouseEventData() { MouseName = name});
}
public string Name { get; set; } }

上面的代码中我们将Mouse类的构造函数进行重写,在构造函数中使用反射的方式实现事件逻辑的注册。

ABP之事件总线(2)

上面标注的地方由两个需要注意的地方:1.必须是IEventHandler`1,而不是IEventHandler,如果使用IEventHander,那么IEventHandler<TEventData>也将会被获取到,此时获取参数是没有的,所以会出现索引超出的错误

2.IEventHandler`1,这是固定的获取泛型接口的方法

ABP之事件总线(2)

此时我们的猫捉老鼠

    class Program
{
static void Main(string[] args)
{ Cat c1 = new Cat();
Mouse m1 = new Mouse("1号老鼠"); //订阅事件
// m1.selfEventHandler += c1.Handle;
// m1.selfEventHandler += new MouseEventHandler().Handle;
//触发事件
m1.Comming(m1.Name); Console.ReadLine();
} }

运行一下:

ABP之事件总线(2)

今天那就先到这里了。