pecs原则在状态机中指导event泛型使用:event作为生产者用? extends event,statehandler作为消费者用? super event,payload定义为t extends event,跨状态流转采用function

在状态机引擎中传递 Event payload 时,PECS 原则直接决定泛型参数的安全性和灵活性——关键不是“能不能用泛型”,而是“用哪种通配符才能既读得准、又写得稳”。
Event 是生产者:用 ? extends Event
当状态机需要从事件队列或监听器中读取事件数据(比如分发、路由、类型判断),Event 就是“生产者”。此时应使用上界通配符:
-
List extends Event>可安全接收List<userloginevent></userloginevent>、List<paymentsuccessevent></paymentsuccessevent>等任意子类列表 - 能调用
get()、stream().map(...),返回类型是Event,可向上转型做统一处理 - 但禁止调用
add()或set()——编译器无法确认你塞进去的到底是哪个具体子类型,防止破坏类型一致性
StateHandler 是消费者:用 ? super Event
当状态处理器需要接收并处理各种具体事件(如 UserLoginEvent、OrderCancelEvent),它本质上是 Event 的“消费者”。这时下界通配符更合适:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
-
Consumer super Event>可接受Consumer<event></event>、Consumer<object></object>,甚至Consumer<serializable></serializable> - 能安全传入任意
Event子类实例,例如handler.accept(new UserLoginEvent()) - 但不能从中
get()出具体子类型——你只知道它至少是Event,但不知道更具体的类型
Payload 泛型字段定义:T extends Event
若状态机内部定义了带泛型的事件载体类(如 StateMachineEvent<t extends event></t>),明确限定上界可保证类型收敛:
-
T extends Event表示 payload 必须是Event或其子类,杜绝String、Integer等无关类型混入 - 配合类型擦除,运行时仍保留
getClass()信息,支持基于实际类型的策略分发 - 避免使用裸类型
StateMachineEvent>,否则丢失编译期类型约束,易引发 ClassCastException
跨状态流转时的类型适配
状态迁移常涉及事件转换(如 UserLoginEvent → SessionCreatedEvent),此时需组合使用:
- 输入端用
Function super UserLoginEvent, ? extends SessionCreatedEvent>:接受任意父类(含UserLoginEvent),产出任意子类(含SessionCreatedEvent) - 避免写成
Function<userloginevent sessioncreatedevent></userloginevent>——会卡死泛型扩展性,后续新增事件类型就得改方法签名 - 实际框架(如 Spring Statemachine)内部也按此逻辑设计
Event<t></t>和StateContext<s e></s>中的E extends Event
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










