PECS原则在装饰器模式中规定:作为生产者(读取)用? extends T,作为消费者(写入)用? super T;LoggingProcessor对delegate用? extends T实现安全读取,DefaultingProcessor则需用? super T保障输入安全,二者不可互换。

Java 中 PECS(Producer Extends, Consumer Super)原则在装饰器模式中用于约束泛型参数类型,核心是:当装饰器需要**读取**被装饰对象的泛型值(即作为生产者),应使用 ? extends T;当装饰器需要**写入**或传入新值(即作为消费者),应使用 ? super T。这确保类型安全,同时保留装饰链的灵活性。
装饰器接口需明确角色:谁产出、谁消费
假设有一个泛型组件接口 Processor<T>:
interface Processor<T> {
T process(T input);
}
装饰器如 LoggingProcessor<T> 既要接收输入(T),又要返回结果(T),此时 T 是**双向角色**,不能直接用通配符——必须保持具体类型一致性。但若你设计的是「只读增强」或「只写增强」的装饰器,则可应用 PECS:
- 若装饰器仅记录输入并委托处理(不修改输入类型),且希望接受更宽泛的输入(如所有
Number子类),则构造时对被装饰对象用Processor<? extends Number>—— 它是Number的生产者(返回Number或子类) - 若装饰器要注入统一的默认值(比如把
null替换为某个T实例),且希望支持向上转型写入(如向Object装饰器中塞String),则被装饰对象类型应声明为Processor<? super String>—— 它是String的消费者
实际装饰器类中如何体现 PECS 约束
以日志装饰器为例,它不改变处理逻辑,只观察输入输出:
立即学习“Java免费学习笔记(深入)”;
class LoggingProcessor<T> implements Processor<T> {
private final Processor<? extends T> delegate; // ✅ delegate 生产 T 或其子类 → 安全读取
LoggingProcessor(Processor<? extends T> delegate) {
this.delegate = delegate;
}
@Override
public T process(T input) {
System.out.println("Before: " + input);
T result = delegate.process(input); // 可安全调用,因为 delegate 至少能处理 T 的子类,而 input 是 T
System.out.println("After: " + result);
return result;
}
}
注意:delegate.process(input) 成立的前提是 input 类型 ≤ delegate 所支持的输入类型。由于 delegate 声明为 Processor<? extends T>,其 process 方法签名实际是 <S extends T> S process(S input)(JLS 推导),因此传入 T 是安全的——这是 PECS 在「生产者位置」保障协变的关键。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
避免反模式:在消费者位置误用 extends
错误示例(编译失败):
class DefaultingProcessor<T> implements Processor<T> {
private final T defaultValue;
private final Processor<? extends T> delegate; // ❌ 错误!这里需要能接收 T 的 delegate
DefaultingProcessor(T defaultValue, Processor<? extends T> delegate) {
this.defaultValue = defaultValue;
this.delegate = delegate;
}
@Override
public T process(T input) {
return delegate.process(input == null ? defaultValue : input); // 编译错误!
// 因为 ? extends T 表示 delegate 输入类型未知(可能是 Integer、Double…),无法保证接受 T
}
}
正确做法是将 delegate 声明为 Processor<? super T>:
-
Processor<? super T>表示该处理器至少能处理T及其所有父类,因此传入T总是安全的 - 但返回类型变为
? super T,即可能返回Object,所以需额外类型检查或限制上界(例如搭配Function<T, R>分离输入/输出)
组合装饰时 PECS 的链式影响
多个装饰器嵌套时,PECS 约束会逐层传导。例如:
Processor<Integer> base = ...; Processor<? extends Number> logged = new LoggingProcessor<>(base); // OK:Integer ⊆ Number Processor<? super Integer> defaulted = new DefaultingProcessor<>(0, logged); // ❌ 编译失败!logged 是 ? extends Number,不是 ? super Integer
原因:PECS 不可逆。? extends Number 不能赋值给 ? super Integer,二者无包含关系。解决方法是统一用具体类型(如 Processor<Integer>)或引入桥接泛型方法:
<U> Processor<U> chain(Processor<? super U> consumer, Processor<? extends U> producer) {
return input -> consumer.process(producer.process(input));
}
这种写法依赖类型推断,适用于简单组合;复杂场景建议用「类型不变」的装饰器基类 + 显式类型参数,而非过度依赖通配符。

















