pecs原则在模板方法钩子函数中仅作用于泛型参数设计:入参作为消费者应声明为? super t,返回值或产出容器作为生产者应声明为? extends t;非泛型钩子无需考虑pecs。

PECS(Producer Extends, Consumer Super)原则在模板方法模式中不直接作用于钩子函数本身,而是影响其参数类型的设计——尤其当钩子方法接收泛型集合或回调上下文作为输入时。
钩子函数参数常需作为“消费者”处理数据
钩子方法(如 shouldExecute()、beforeProcess(T context))通常用于干预流程,其入参往往是运行时传入的具体上下文对象。此时参数是被模板方法“消费”的,应遵循 Consumer Super:
- 若钩子方法需兼容多种子类型上下文(如
BaseContext及其子类OrderContext、PaymentContext),声明为beforeProcess(? super BaseContext)更安全; - 避免写成
beforeProcess(? extends BaseContext)——这会让方法只能接收更宽泛的父类型(如Object),失去类型约束,实际无法使用子类特有字段; - 典型场景:抽象模板中定义
protected void beforeSubmit(Request> request),子类覆盖时可接受任意Request子类实例,无需强制泛型协变。
返回值或泛型容器参数可能涉及“生产者”视角
少数情况下,钩子方法返回一个泛型结果(如 List> 或 Optional<t></t>),或接收一个用于填充结果的容器参数:
- 若钩子负责生成某种结果(如
collectMetrics()返回指标列表),返回类型宜用List extends Metric>(Producer Extends),方便子类返回LatencyMetric等具体子类; - 若钩子接收一个待填充的集合(如
addExtraHeaders(List<string> headers)</string>),参数应声明为List super String>,确保能向任意String容器(如ArrayList<charsequence></charsequence>)安全写入; - 但实践中,这类设计较少见——钩子方法更倾向无参、布尔返回或简单上下文入参,过度泛化反而降低可读性。
多数钩子无需泛型,PECS 仅在必要时介入
标准模板方法中的钩子(如 boolean shouldSkip()、void afterSave())本身不带泛型参数,PECS 不生效。只有当钩子明确参与泛型数据流转时才需考虑:
- 优先用具体类型(如
beforeValidate(OrderRequest req)),清晰且类型安全; - 仅当框架需高度通用(如统一处理各类
Event<t></t>),才引入通配符,并严格按 PECS 判定方向; - 误用
extends作入参会导致编译错误(无法调用子类特有方法),误用super作返回值会限制子类自由度(只能返回Object等顶层类型)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











