ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

装饰器模式(Decorator)在 Java 中的动态扩展实战——基于 java-design-patterns 仓库的巨魔武装示例

2026/10/1 8:28:35 拓冰建站 浏览量
装饰器模式(Decorator)在 Java 中的动态扩展实战——基于 java-design-patterns 仓库的巨魔武装示例 示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载装饰器模式Decorator Pattern又称 Wrapper 封装器是 GoF 结构型设计模式之一它允许在不修改现有代码的前提下通过“包裹”对象的方式在运行时动态添加或移除职责是对继承的一种更灵活的替代方案。本文以 java-design-patterns 仓库中decorator模块的“武装巨魔”示例为主线完整讲解装饰器模式的意图、类图、源码实现、测试验证、适用场景与权衡取舍读完即可在真实 Java 项目中独立落地该模式。模式概述为什么需要装饰器装饰器模式的核心目标可以概括为一句话为单个对象动态地、透明地添加额外职责而无需影响同一类的其他对象。这里有两个关键词动态职责的添加发生在运行时new ClubbedTroll(troll)而非编译期继承透明装饰器与被装饰对象实现相同的接口调用方无需感知对象是否被装饰过。从设计原则看装饰器模式天然契合两条 SOLID 原则单一职责原则SRP把不同关注点的功能拆分到不同类中每个装饰器只负责一项扩展开闭原则OCP类的功能可以被扩展通过新增装饰器类而无需修改已有类。在面向对象编程中装饰器模式是一种允许向单个对象静态或动态地添加行为、而不影响同类其他对象行为的设计模式。它常用于遵循单一职责原则将功能拆分到关注点各异的类中也用于遵循开闭原则在无需修改类的前提下扩展其功能。 —— 引自 装饰器英文文档真实世界类比武装巨魔与定制咖啡山丘附近住着一只愤怒的巨魔平时赤手空拳但有时会手持武器。要给巨魔武装起来并不需要创造一只新巨魔而是用合适的武器动态地装饰它。 —— 引自 阿拉伯语文档这个例子非常直观SimpleTroll是那只赤手空拳的巨魔ClubbedTroll持棒巨魔不是巨魔的新物种而是给同一只巨魔加了一根狼牙棒。装饰前后巨魔的“身份”没变都还是Troll但行为攻击、逃跑和属性攻击力发生了叠加。另一个经典类比是咖啡店定制基础咖啡对象可以依次被“加牛奶”“加糖”“加奶油”等装饰器包裹每层装饰都动态地为咖啡新增风味或配料这正是装饰器在现实世界的缩影。仓库中的类结构四个核心角色在 decorator 模块中装饰器模式的四个经典角色一应俱全全部位于包com.iluwatar.decorator角色类/接口仓库文件职责抽象组件ComponentTroll接口Troll.java定义统一契约attack()、getAttackPower()、fleeBattle()具体组件ConcreteComponentSimpleTrollSimpleTroll.java被装饰的基础对象攻击力 10装饰器基类可选本示例直接实现接口—更复杂的场景可抽象出TrollDecorator基类复用委托逻辑具体装饰器ConcreteDecoratorClubbedTrollClubbedTroll.java持有被装饰对象攻击力在原值上 10并追加“挥棒攻击”日志类图关系源自 decorator.urm.puml非常清晰SimpleTroll与ClubbedTroll都实现Troll接口..|ClubbedTroll通过字段decorated: Troll聚合一个Troll对象--。时序逻辑见 时序图展示了装饰器在运行时如何把调用链式地委托给被装饰对象源码级拆解三个核心文件1. 抽象组件Troll接口/** Interface for trolls. */ public interface Troll { void attack(); int getAttackPower(); void fleeBattle(); }该接口定义了装饰双方共用的契约是“透明性”的基石客户端无论持有SimpleTroll还是ClubbedTroll都以Troll类型编程完全无感知。2. 具体组件SimpleTrollSlf4j public class SimpleTroll implements Troll { Override public void attack() { LOGGER.info(The troll tries to grab you!); } Override public int getAttackPower() { return 10; } Override public void fleeBattle() { LOGGER.info(The troll shrieks in horror and runs away!); } }SimpleTroll直接实现接口是“基础巨魔”攻击力恒为 10。Slf4j是 Lombok 注解自动生成LOGGER字段用于输出行为日志。3. 具体装饰器ClubbedTrollSlf4j RequiredArgsConstructor public class ClubbedTroll implements Troll { private final Troll decorated; Override public void attack() { decorated.attack(); LOGGER.info(The troll swings at you with a club!); } Override public int getAttackPower() { return decorated.getAttackPower() 10; } Override public void fleeBattle() { decorated.fleeBattle(); } }这是装饰器的标准模板请重点记忆它的三个编写套路持有被装饰对象通过构造器注入一个Troll类型的decorated字段RequiredArgsConstructor为final字段自动生成构造器增强before/after 包装attack()先委托给decorated.attack()再追加自己的“挥棒攻击”日志getAttackPower()在委托结果上10透传透明委托fleeBattle()不做任何增强原样转发给被装饰对象保证装饰器的“透明”特性。运行时演示App入口与程序输出App.java 是模块的程序入口它依次展示了“未装饰”与“已装饰”两种状态下巨魔的行为差异public static void main(String[] args) { // simple troll LOGGER.info(A simple looking troll approaches.); var troll new SimpleTroll(); troll.attack(); troll.fleeBattle(); LOGGER.info(Simple troll power: {}.\n, troll.getAttackPower()); // change the behavior of the simple troll by adding a decorator LOGGER.info(A troll with huge club surprises you.); var clubbedTroll new ClubbedTroll(troll); clubbedTroll.attack(); clubbedTroll.fleeBattle(); LOGGER.info(Clubbed troll power: {}.\n, clubbedTroll.getAttackPower()); }注意同一个troll对象被直接传入new ClubbedTroll(troll)完成“武装”全程没有创建新的巨魔——这正是装饰器“动态改变行为”的直观证据。程序运行输出如下A simple looking troll approaches. The troll tries to grab you! The troll shrieks in horror and runs away! Simple troll power: 10. A troll with huge club surprises you. The troll tries to grab you! The troll swings at you with a club! The troll shrieks in horror and runs away! Clubbed troll power: 20.对比两组输出可以发现三个关键变化攻击力从 10 提升到 20getAttackPower()被叠加攻击时多出一条“挥棒攻击”日志attack()被增强且基础攻击日志依然保留证明委托链生效逃跑行为完全不变fleeBattle()被透传证明装饰器可以选择性增强。本地运行与验证仓库采用 Maven 多模块结构decorator模块的构建说明位于其 pom.xml。在仓库根目录下可执行# 运行装饰器示例程序 ./mvnw -pl decorator exec:java # 运行装饰器模块的全部单元测试 ./mvnw -pl decorator test前提本机已安装 JDK 与 Maven或使用仓库自带的mvnw包装脚本。测试验证装饰器行为的可证明性仓库为装饰器模式提供了两个单元测试从测试角度印证了“增强 透传”的语义ClubbedTrollTest.java使用 Mockito 的spy监视被装饰的SimpleTrollfinal var simpleTroll spy(new SimpleTroll()); final var clubbed new ClubbedTroll(simpleTroll); assertEquals(20, clubbed.getAttackPower()); // 攻击力被叠加为 20 verify(simpleTroll, times(1)).getAttackPower(); clubbed.attack(); // 攻击被委托给被装饰对象 verify(simpleTroll, times(1)).attack(); clubbed.fleeBattle(); // 逃跑同样被委托 verify(simpleTroll, times(1)).fleeBattle(); verifyNoMoreInteractions(simpleTroll);该测试精准锁定了装饰器的三个语义getAttackPower()返回叠加后的 20attack()、fleeBattle()都被委托给被装饰对象且各调用一次。SimpleTrollTest.java验证基础组件的独立行为攻击力恒为 10attack()与fleeBattle()各输出一条日志且日志内容与预期完全一致。适用场景什么时候该用装饰器根据 阿拉伯语文档 与 英文文档装饰器模式适用于以下情况需要动态、透明地为单个对象添加职责且不能影响其他对象职责可以被撤销装饰器可以随时换一层或拆掉一层用子类扩展不切实际当存在大量相互独立的扩展维度时子类组合会引发“子类爆炸”。例如有 3 种基础组件 × N 种扩展用继承需要 N 个排列组合子类而用装饰器只需 N 个装饰器类自由组合类的定义被隐藏或不可用于继承例如 final 类或无法访问源码的第三方类。真实世界中的已知应用Java 标准库本身就是装饰器模式的最佳教科书I/O 流体系java.io.InputStream、OutputStream、Reader、Writer系列例如new BufferedInputStream(new FileInputStream(file))就是一层层“装饰”java.util.Collections的包装方法synchronizedXXX()为集合加线程安全包装、unmodifiableXXX()返回不可修改视图、checkedXXX()类型安全检查视图全部通过装饰器动态添加职责。GUI 工具包也常使用装饰器为组件动态附加滚动条、边框、布局管理等行为。收益与权衡装饰器的两面性收益Benefits比静态继承更灵活职责可以在运行时组合、叠加、移除避免在继承体系高层的类中塞满各种特性feature-laden classes装饰器与组件无需是同一对象职责可独立演化完全遵循开闭原则加新功能 加新装饰器类旧代码零改动。代价Trade-offs类型测试会失效装饰器与组件不是同一个对象instanceof这类类型判断会失败小对象泛滥多层装饰会产生大量外观相似的小对象配置复杂时难以一眼看出最终结构过度使用会使代码结构复杂化大量细粒度装饰器类增加理解与维护成本。与其他模式的关联装饰器在 GoF 家族中与三个模式关系密切引自 英文文档适配器模式Adapter装饰器改变对象的职责适配器改变对象的接口组合模式Composite装饰器可视为只含一个组件的“退化的组合”但装饰器目的是添加额外职责而非聚合对象策略模式Strategy一句话概括——装饰器改变对象的“皮肤”外部行为包装策略改变对象的“内脏”内部算法替换。总结装饰器模式以“接口契约 构造器注入 委托转发”三件套实现了运行时无侵入的行为扩展。本文所依据的 decorator 模块 用 4 个 Java 文件Troll、SimpleTroll、ClubbedTroll、App加 3 个测试文件完整呈现了该模式的最小可运行形态攻击力 10 → 20 的叠加、攻击日志的追加、逃跑行为的透传无不指向同一个结论——装饰器让你在不重写、不继承、不修改的前提下为对象“穿上一层又一层能力”。当你面对“子类爆炸”或“第三方类无法继承”的困境时装饰器就是那个值得优先考虑的答案。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐java-design-patterns 中的 Decorator装饰器模式在 Java 中动态扩展对象职责的完整实战指南java design patterns 中的 Decorator装饰器模式在 Java 中动态扩展对象职责的完整实战指南 本指南以 java desig示例工程教程Java 桥接模式Bridge Pattern源码级解析基于 java-design-patterns 的武器与附魔组合示例Java 桥接模式Bridge Pattern源码级解析基于 java design patterns 的武器与附魔组合示例 本篇技术指南以 java d示例工程教程Java 适配器模式实战解析以 java-design-patterns 仓库的 FishingBoatAdapter 为例Java 适配器模式实战解析以 java design patterns 仓库的 FishingBoatAdapter 为例 导读 本文以当前仓库 java示例工程教程上一篇Mumble 连接建立协议详解从 TCP 握手、TLS 认证到 ServerSync 的完整时序下一篇CANN Ascend C SIMT API half精度转换函数创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考