项目简介
本项目是基于 .NET Framework 框架的Winform项目, 实现一键发布博客到各个平台(如WordPress站点、博客园等)的功能
项目结构与定位
Core 项目
这是整个解决方案的核心层,主要负责定义跨模块的通用契约。
- IEvent 接口(所有事件的基类接口)
- EventBus(事件的统一发布与订阅中心)
- 一些基础的事件类型定义(如 AddPublishConfigEvent)
- Core 不包含业务逻辑实现,保证可以被 UI 层、服务层等模块安全依赖。
事件总线(EventBus)
- 采用 发布-订阅模式(Pub/Sub)实现解耦,用于UI项目与Core项目。
- // 订阅事件 public void SubscribeEvent(Action handler) where TEvent : IEvent, new(); // 发布事件 public void PublishEvent(TEvent _event) where TEvent : IEvent, new();
复制代码
- 强类型事件:事件处理函数的参数就是泛型类型参数,因此事件类型可以在编译期检查,而不是运行时靠字符串或反射。
事件体系
- public interface IEvent { bool IsSuccess { get; set; } Exception Exception { get; set; } }
复制代码
- 作用:传递一个发布配置对象,不带返回结果。
- 泛型 T 代表具体的配置类型,比如 WordPressConfig、CnblogsConfig 等。
- 用途:通知系统“有一个新的平台发布配置被添加”。
问题介绍
项目中所使用的强类型事件发布订阅模式有以下特点:
- 每个事件类既是事件参数,也是事件种类的唯一标识。
- 这样一来,事件在编译期就是类型安全的。
但是,这样就会出现一个问题:
UI 层要把“具体的发布配置对象”传递到 Core 层(通过事件总线),那事件类怎么设计才能优雅地传递类型参数?
两种初始思路
方案一:为每种配置写一个事件类
比如 AddWordPressPublishConfigEvent、AddCNBlogPublishConfigEvent ……
这样做直观,但问题也很明显:
- 要支持更多平台,就得定义更多事件类。
- ApplicationService 也要增加更多处理方法,代码臃肿。
- public class AddWordPressPublishConfigEvent { ... } public class AddCNBlogPublishConfigEvent { ... } ... // 后续适配更多平台需要定义更多事件类 // Core层负责接受事件消息的类中 private void OnAddWordPressPublishConfig(AddWordPressConfigEvent _event){ ... } private void OnAddCNBlogPublishConfig(AddCNBlogPublishConfigEvent _event){ ... } ... // 后续适配更多平台需要定义更多事件处理方法
复制代码 方案二:事件类改为泛型
设计一个 AddPublishConfigEvent,类型参数 T 就是配置类。
优点是事件类可以复用,不需要为每个平台重复造轮子。
但问题在于:事件处理方法也得是泛型方法,而且还需要针对不同 T 类型订阅事件,看起来依然繁琐。- // 定义泛型事件类,无需定义大量的事件了 public class AddPublishConfigEvent : IEvent where T : IPublishConfig, new() { public T PublishConfig {get; set;} // T 类型约束于实现了IPublishConfig接口的类,便于传递配置信息 public bool IsSuccess { get; set; } public Exception Exception { get; set; } } // Core层负责接受事件消息的类中 private void OnAddPublishConfig(AddPublishConfigEvent _event){ ... } private void OnAddPublishConfig(AddPublishConfigEvent _event){ ... } ... // 后续适配更多平台仍然需要定义更多事件处理方法
复制代码 最终解法
为了尽可能地减少后续开发的负担,在权衡了两种方案的维护成本与类型安全后,经过讨论和尝试,我在方案二的基础上进行了修改,选择了 泛型事件类 + 泛型事件处理方法 的组合:- // 泛型事件,直接携带具体的配置对象 // 定义泛型事件类,无需定义大量的事件了 public class AddPublishConfigEvent :IEvent where T : class, IPublishConfig, new() { public T PublishConfig { get; set; } public bool IsSuccess { get; set; } public Exception Exception { get; set; } } // Core层负责接受事件消息的类中 // 只需要定义一个方法就兼容所有的平台了 private void OnAddPublishConfig(AddPublishConfigEvent e) where T : class, IPublishConfig, new() { _publishConfigService.Add(e.PublishConfig); }
复制代码 这样带来的好处是:
- 事件类高度复用:只要是配置类,都能用 AddPublishConfigRequestEvent 携带。
- 减少类型转换:不需要先用 IPublishConfig 再强转成具体实现类。
- 编译期安全:方法的参数类型和事件类的泛型参数保持一致。
唯一的缺点是:
- 初始化时仍然需要订阅不同配置类型的事件(例如 WordPressConfig、CNBlogConfig)。
- 不过这一步只在程序启动时做一次,可以用反射简化,性能不是问题。
总结
这个问题其实本质上是:如何在强类型事件系统中优雅地传递泛型参数。
- 如果走“为每个平台写事件类”的路子,代码会越来越多。
- 如果使用“泛型事件+泛型方法”,则能保证 类型安全、代码复用性高。
最终我采用了第二种方式,并且通过订阅时的反射处理把繁琐步骤封装掉,既解决了类型参数传递的问题,又让事件流保持简洁。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |