在上一篇文章中,我们复习了一下事件的经典的发布订阅模式,同时对是事件源和时间处理逻辑进行抽象统一,用起来也没有问题。但是还是有很多的问题,比如说我们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就可以了,是不是很方便!是不是有一种解除耦合的感觉!
上面的这行代码是我们手动注册我们的事件处理逻辑,现在问题来了刚才我们写的是猫捉老鼠的处理逻辑,现在来了,狗捉老鼠,牛捉老鼠,大象捉老鼠。。。。此时创建了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()[0]; if (arg.Equals(typeof(MouseEventData))) { var handler = Activator.CreateInstance(type) as IEventHandler<MouseEventData>; this.selfEventHandler += handler.Handle; } } } } public void Comming(string name ) { Console.WriteLine("老鼠说: "); Console.WriteLine("我的名字是{0},I am Comming!", name); //触发事件 selfEventHandler(new MouseEventData() { MouseName = name}); } public string Name { get; set; } }
上面的代码中我们将Mouse类的构造函数进行重写,在构造函数中使用反射的方式实现事件逻辑的注册。
上面标注的地方由两个需要注意的地方:1.必须是IEventHandler`1,而不是IEventHandler,如果使用IEventHander,那么IEventHandler<TEventData>也将会被获取到,此时获取参数是没有的,所以会出现索引超出的错误
2.IEventHandler`1,这是固定的获取泛型接口的方法
此时我们的猫捉老鼠
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(); } }
运行一下:
今天那就先到这里了。