PECS原则在状态机中指导Event泛型使用:Event作为生产者用? extends Event,StateHandler作为消费者用? super Event,Payload定义为T extends Event,跨状态流转采用Function<? super Input, ? extends Output>适配。

在状态机引擎中传递 Event payload 时,PECS 原则直接决定泛型参数的安全性和灵活性——关键不是“能不能用泛型”,而是“用哪种通配符才能既读得准、又写得稳”。
Event 是生产者:用 ? extends Event
当状态机需要从事件队列或监听器中读取事件数据(比如分发、路由、类型判断),Event 就是“生产者”。此时应使用上界通配符:
-
List<? extends Event>可安全接收List<UserLoginEvent>、List<PaymentSuccessEvent>等任意子类列表 - 能调用
get()、stream().map(...),返回类型是Event,可向上转型做统一处理 - 但禁止调用
add()或set()——编译器无法确认你塞进去的到底是哪个具体子类型,防止破坏类型一致性
StateHandler 是消费者:用 ? super Event
当状态处理器需要接收并处理各种具体事件(如 UserLoginEvent、OrderCancelEvent),它本质上是 Event 的“消费者”。这时下界通配符更合适:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
-
Consumer<? super Event>可接受Consumer<Event>、Consumer<Object>,甚至Consumer<Serializable> - 能安全传入任意
Event子类实例,例如handler.accept(new UserLoginEvent()) - 但不能从中
get()出具体子类型——你只知道它至少是Event,但不知道更具体的类型
Payload 泛型字段定义:T extends Event
若状态机内部定义了带泛型的事件载体类(如 StateMachineEvent<T extends Event>),明确限定上界可保证类型收敛:
立即学习“Java免费学习笔记(深入)”;
-
T extends Event表示 payload 必须是Event或其子类,杜绝String、Integer等无关类型混入 - 配合类型擦除,运行时仍保留
getClass()信息,支持基于实际类型的策略分发 - 避免使用裸类型
StateMachineEvent<?>,否则丢失编译期类型约束,易引发 ClassCastException
跨状态流转时的类型适配
状态迁移常涉及事件转换(如 UserLoginEvent → SessionCreatedEvent),此时需组合使用:
- 输入端用
Function<? super UserLoginEvent, ? extends SessionCreatedEvent>:接受任意父类(含UserLoginEvent),产出任意子类(含SessionCreatedEvent) - 避免写成
Function<UserLoginEvent, SessionCreatedEvent>——会卡死泛型扩展性,后续新增事件类型就得改方法签名 - 实际框架(如 Spring Statemachine)内部也按此逻辑设计
Event<T>和StateContext<S, E>中的E extends Event

















