泛型是保障领域事件驱动器类型安全的核心,多态仅提供统一入口;通过泛型约束事件处理器、只读协变集合、泛型注册方法及typetoken运行时类型封装,实现事件可扩展、处理器可插拔与编译期类型安全。

多态本身不提供类型安全,它只保证“能调用父类声明的方法”;泛型才是加固层——关键在于用泛型约束多态的边界,让编译器在调用前就排除非法操作。标准领域事件驱动器的核心诉求是:事件可扩展、处理器可插拔、分发过程类型明确、上下游不因新增事件而编译失败。这需要多态提供统一入口,泛型划定行为边界。
定义事件基类与泛型事件接口
先建立清晰的继承体系,再用泛型固化语义:
- 定义抽象基类 DomainEvent(含时间戳、ID、版本等通用字段),所有具体事件如
OrderPlaced、PaymentProcessed都继承它 - 声明泛型接口 IEventHandler
where TEvent : DomainEvent ,强制每个处理器只处理一种确定事件类型 - 避免裸接口
IEventHandler—— 它会导致运行时类型擦除,无法阻止把OrderPlaced误传给本该处理UserRegistered的处理器
事件分发器使用上界约束确保只读安全
分发器接收多个处理器,但绝不允许往里塞非法类型:
- 用
IReadOnlyList<ieventhandler extends domainevent>></ieventhandler>(Java)或readonly Array<ieventhandler>></ieventhandler>(TypeScript)存储处理器列表 - 这种协变声明意味着你可以传入
[new OrderHandler(), new UserHandler()],但编译器禁止你向该列表 add 任意新处理器——因为它是只读视图,符合“生产者”语义 - 若用
List<ieventhandler>></ieventhandler>,反而可能在运行时混入不兼容处理器,破坏类型契约
泛型方法替代泛型类,提升事件注册粒度
注册动作本身不需要整个驱动器泛型化,只需方法级约束:
- 提供
<t extends domainevent> void registerHandler(Class<t> eventType, IEventHandler<t> handler)</t></t></t> - 这样每次注册都绑定具体事件类型,比如
registerHandler(OrderPlaced.class, new OrderPlacedHandler()),编译器自动推导T = OrderPlaced - 相比
EventDispatcher<orderplaced></orderplaced>这种单类型实例,泛型方法支持同一驱动器管理数十种事件,且无状态固化开销
避免反射与泛型混用,用 TypeToken 封装运行时类型
当需序列化/反序列化事件时,类型擦除会带来风险:
- 不要依赖
event.getClass().getGenericSuperclass()解析泛型参数——它脆弱、不可靠、难调试 - 改用
TypeToken<orderplaced>()</orderplaced>(Java)或typeof<orderplaced></orderplaced>(TypeScript)显式携带类型信息 - 例如反序列化时:
fromJson(json, new TypeToken<orderplaced>() {})</orderplaced>,确保返回对象精确为OrderPlaced,而非模糊的DomainEvent











