for-each不支持自动装饰,需预先将原始对象包装为装饰后实例再遍历;若让装饰器实现iterable接口,可在iterator()中即时装饰每个元素。

Java 中 for-each 本身不支持“自动应用装饰器”,它只是语法糖,用于简化对 Iterable 或数组的遍历。所谓“配合自定义装饰器模式遍历被增强后的对象列表”,核心在于:**先完成装饰(即创建被增强的对象实例),再用 for-each 遍历这些已装饰好的对象**——而不是在 for-each 循环体内动态装饰。
装饰器对象需提前构造好
装饰器模式要求被装饰对象与装饰器实现同一接口(或继承同一抽象类)。for-each 只关心元素类型是否兼容,不参与增强逻辑。因此,你必须在遍历前,把原始对象包装成装饰后的实例。
- 原始列表:
List<widget> rawWidgets = ...;</widget> - 装饰后列表:
List<widget> decoratedWidgets = rawWidgets.stream().map(EnhancedWidget::new).collect(Collectors.toList());</widget> - 然后才能安全使用 for-each:
for (Widget w : decoratedWidgets) { ... }
让装饰器自身支持 Iterable(进阶技巧)
若希望“一个装饰器实例”能代表整个增强后的集合(例如统一添加日志、计时、权限校验等横切行为),可让装饰器实现 Iterable 接口,内部委托给原始集合,并在 iterator() 返回的迭代器中对每个元素做即时包装。
示例关键代码:
public class LoggedWidgetList implements Iterable<widget> {
private final List<widget> delegate;
public LoggedWidgetList(List<widget> delegate) {
this.delegate = delegate;
}
@Override
public Iterator<widget> iterator() {
return new Iterator<widget>() {
private final Iterator<widget> it = delegate.iterator();
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public Widget next() {
Widget w = it.next();
System.out.println("[LOG] Accessing widget: " + w.getId());
return new LoggedWidget(w); // 即时装饰
}
};
}
}</widget></widget></widget></widget></widget></widget>
此时可直接 for-each:for (Widget w : new LoggedWidgetList(rawWidgets)) { ... }
避免常见误区
- 不要在 for-each 循环内重复 new 装饰器:这会导致每次访问都新建对象,可能引发状态错乱或性能问题(如重复打开资源)。
-
装饰器必须与 for-each 的目标类型一致:如果 for-each 声明为
for (EnhancedWidget e : list),那 list 的泛型必须是EnhancedWidget或其父类/接口,否则编译失败。 - 注意装饰器的不可变性与线程安全:若装饰器持有共享状态(如计数器、缓存),在多线程遍历时需同步,否则结果不可预测。
实用建议:结合工厂方法提升可读性
将装饰逻辑封装为静态工厂方法,让意图更清晰:
public class WidgetDecorators {
public static Widget withLogging(Widget w) {
return new LoggedWidget(w);
}
public static Widget withCaching(Widget w) {
return new CachedWidget(w);
}
}
// 使用时:
List<widget> enhanced = widgets.stream()
.map(WidgetDecorators::withLogging)
.map(WidgetDecorators::withCaching)
.collect(Collectors.toList());
for (Widget w : enhanced) {
w.render(); // 已同时具备日志和缓存能力
}</widget>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











