模式实战指南:用组合替代继承动态扩展对象职责)
示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载装饰器Decorator模式是 GoF 提出的经典结构性设计模式其核心思想是动态地为对象附加额外职责用对象组合替代子类继承来扩展功能。本文以 java-design-patterns 仓库中的decorator模块为骨架通过完整的巨魔Troll实战示例、源码调用链与单元测试讲解装饰器模式的定义、四类角色、实现要点、适用场景及 JDK 中的真实应用。读完本文你将能够独立实现一个符合单一职责原则、支持运行时动态叠加职责的装饰器组件。或称包装器Wrapper装饰器模式在业界常被称为包装器因为它本质上就是用一个装饰类对象把目标对象包装起来装饰类与目标实现同一接口内部持有目标对象的引用对外透明地转发调用并在转发前后插入额外的行为。目的动态地为对象附加额外的职责。装饰器为子类提供了一种灵活的替代方案以扩展功能。动态职责的叠加发生在运行时而非编译期透明对调用方来说装饰后的对象与原始对象使用方式完全一致同一接口替代继承避免为了每种功能组合创建大量子类。真实世界例子愤怒的巨魔附近的山丘上住着一个愤怒的巨魔。通常它是徒手的但有时它有武器。为了武装巨魔不必创建新的巨魔而是用合适的武器动态地装饰它。通俗地说装饰器模式让你可以在运行时通过把对象包装进一个装饰类对象中来动态改变一个对象的行为。维基百科给出的定义更加严谨在面向对象的编程中装饰器模式是一种设计模式它允许将行为静态或动态地添加到单个对象中而不会影响同一类中其他对象的行为。装饰器模式通常对于遵守单一责任原则很有用因为它允许将功能划分到具有唯一关注领域的类之间。模式角色与类图从 decorator/etc/decorator.urm.puml 中的 PlantUML 定义可以看出本模块共有四个参与者正好对应装饰器模式的四个标准角色角色本模块实现类职责抽象构件ComponentTroll接口定义业务方法attack()、getAttackPower()、fleeBattle()具体构件ConcreteComponentSimpleTroll实现接口的原始对象被装饰的目标装饰DecoratorClubbedTroll持有Troll decorated引用实现同一接口转发调用并叠加行为客户端ClientApp运行时组装具体构件与装饰器装饰器模式类图Troll 接口由 SimpleTroll 与 ClubbedTroll 实现ClubbedTroll 通过组合持有被装饰的 Troll 引用类图中的关键关系SimpleTroll ..| Troll具体构件实现接口ClubbedTroll ..| Troll装饰器也实现同一接口保证类型透明ClubbedTroll -- -decorated Troll装饰器组合而非继承目标对象这是整个模式能够动态叠加职责的根基。程序示例从徒手到持棒下面以巨魔为例从源码层面完整走一遍装饰器模式的实现。第一步抽象构件——巨魔接口首先定义一个简单的巨魔接口它声明了巨魔的全部行为。对应源码 decorator/src/main/java/com/iluwatar/decorator/Troll.javapublic interface Troll { void attack(); int getAttackPower(); void fleeBattle(); }第二步具体构件——徒手巨魔然后创建一个简单的巨魔直接实现Troll接口初始攻击力为 10。对应源码 decorator/src/main/java/com/iluwatar/decorator/SimpleTroll.javaSlf4j 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!); } }注意这里使用了 Lombok 的Slf4j注解生成日志对象日志框架为 SLF4J Logback依赖声明可见 decorator/pom.xml。第三步装饰器——持棒巨魔接下来我们想为巨魔添加一根球棒。按照装饰器模式不修改SimpleTroll也不为它创建子类而是新建一个ClubbedTroll装饰器它实现Troll接口通过构造器注入被装饰的巨魔并在转发调用时叠加行为。对应源码 decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.javaSlf4j 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(); } }这里RequiredArgsConstructor为final字段decorated自动生成构造器。逐方法分析装饰器的行为attack()先调用decorated.attack()转发原始攻击再追加挥棒日志——这是典型的前置/后置增强getAttackPower()返回decorated.getAttackPower() 10——把攻击力从 10 增强到 20fleeBattle()原样转发不做任何增强——装饰器可以选择性增强部分方法。第四步客户端组装——实战演示程序入口 decorator/src/main/java/com/iluwatar/decorator/App.java 演示了先徒手作战、再动态装备球棒的完整过程// simple troll var troll new SimpleTroll(); troll.attack(); // The troll tries to grab you! troll.fleeBattle(); // The troll shrieks in horror and runs away! LOGGER.info(Simple troll power: {}.\n, troll.getAttackPower()); // 10 // change the behavior of the simple troll by adding a decorator var clubbedTroll new ClubbedTroll(troll); clubbedTroll.attack(); // The troll tries to grab you! The troll swings at you with a club! clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away! LOGGER.info(Clubbed troll power: {}.\n, clubbedTroll.getAttackPower()); // 20两个关键观察点运行时动态装饰troll对象本身从未被修改ClubbedTroll只是把它包了一层包装前后troll的行为完全不变而clubbedTroll的行为被增强了原始对象可复用同一个SimpleTroll实例既能独自作战也能被任意多个装饰器反复包装不影响同一类中其他对象的行为。运行与测试验证编译运行本模块是一个独立的 Maven 工程可通过 Maven 直接运行主类查看日志输出主类com.iluwatar.decorator.App已在 decorator/pom.xml 的maven-assembly-plugin中配置mvn -pl decorator compile exec:java -Dexec.mainClasscom.iluwatar.decorator.App或在模块目录内直接执行mvn package java -cp target/decorator-*.jar com.iluwatar.decorator.App单元测试验证仓库为装饰器模块提供了三个测试从不同角度验证了模式行为SimpleTrollTest.java验证具体构件的行为。断言getAttackPower()返回 10attack()与fleeBattle()分别输出对应日志通过自定义InMemoryAppender捕获 Logback 日志并断言共产生 2 条日志。ClubbedTrollTest.java这是最有说服力的测试使用 Mockito 的spy验证委托关系与增强逻辑final var simpleTroll spy(new SimpleTroll()); final var clubbed new ClubbedTroll(simpleTroll); assertEquals(20, clubbed.getAttackPower()); // 增强10 10 verify(simpleTroll, times(1)).getAttackPower(); // 委托增强基于原对象 clubbed.attack(); // 转发原始攻击 verify(simpleTroll, times(1)).attack(); clubbed.fleeBattle(); // 原样转发逃跑 verify(simpleTroll, times(1)).fleeBattle(); verifyNoMoreInteractions(simpleTroll);测试明确印证了装饰器的两个核心语义增强逻辑确实发生在原对象结果之上20 10 10且所有调用都被委托给被装饰对象装饰器自身没有引入额外状态。AppTest.java验证主方法App.main可无异常执行保证示例可运行。适用性什么时候使用装饰器根据原文档并结合源码结构在以下场景中应当考虑使用装饰器模式动态透明地向单个对象添加职责即不影响其他对象——如上例给一个巨魔加球棒不影响其他徒手巨魔对于可以撤销的职责——装饰可以随时解除去掉包装即恢复原对象职责的叠加顺序也可控当通过子类化进行扩展不切实际时——有时可能存在大量独立的扩展若为每种组合都建立子类会产生组合爆炸。例如功能 A、B、C 的任意组合需要 2³ 种子类而用装饰器只需要 3 个装饰类即可在运行时任意叠加。此外当类定义被隐藏或无法用于子类化时装饰器是唯一可行的扩展手段。装饰器在 Java 世界中的真实案例原文档列出了装饰器模式在标准 JDK 中的经典应用这些都是可以随时打开源码验证的实例java.io体系java.io.InputStream、java.io.OutputStream、java.io.Reader、java.io.Writer 及其子类体系——例如BufferedInputStream、DataInputStream都是装饰器层层包装同一抽象输入流逐层叠加缓冲、类型化读取等能力java.util.Collections的视图方法Collections#synchronizedXXX()——为任意集合动态附加线程安全能力Collections#unmodifiableXXX()——为任意集合动态附加只读保护Collections#checkedXXX()——为任意集合动态附加类型检查。这三个系列的共同特征是传入一个普通集合返回一个行为被改变但接口相同的包装集合且原集合本身不受影响——与巨魔示例的机制完全一致。实现要点与设计权衡结合源码 ClubbedTroll.java 可以总结出四条可复用的实现准则装饰器与构件必须实现同一接口Troll这是透明的前提客户端无需感知对象是否被装饰用组合而非继承装饰器持有final Troll decorated引用在构造器中注入保证职责可在运行时动态组合转发与增强分离需要增强的方法先decorated.xxx()再追加逻辑如attack()需要原样传递的方法直接转发如fleeBattle()增强逻辑保持单一职责、互不干扰注意顺序敏感性与洋葱结构多个装饰器叠加时呈层层包裹的洋葱结构调用顺序即包装顺序叠加职责过多时调试成本会上升因此装饰器应保持小而专一。总结装饰器模式用一个包装器类解决了子类组合爆炸与运行时扩展两大痛点SimpleTroll负责核心行为ClubbedTroll只负责加球棒这一单一职责两者通过Troll接口松耦合客户端在运行时自由组装。从 java-design-patterns 的 decorator 模块源码 及其 测试用例 可以确认增强基于委托结果、调用透明转发、原对象零侵入——这正是装饰器模式在 JDK IO 流与 Collections 工具类中被广泛采用的底层原因。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐java-design-patterns 装饰器模式Decorator Pattern深度解析用动态包装替代继承实现对象扩展java design patterns 装饰器模式Decorator Pattern深度解析用动态包装替代继承实现对象扩展 本文基于 java desi示例工程教程java-design-patterns 中的 Decorator装饰器模式在 Java 中动态扩展对象职责的完整实战指南java design patterns 中的 Decorator装饰器模式在 Java 中动态扩展对象职责的完整实战指南 本指南以 java desig示例工程教程java-design-patterns 项目中的装饰器模式Decorator在 Java 中动态扩展对象职责的实战指南java design patterns 项目中的装饰器模式Decorator在 Java 中动态扩展对象职责的实战指南 装饰器模式Decorator示例工程教程上一篇5个简单步骤如何用LangFlow可视化界面快速构建AI应用下一篇如何 3 分钟搞定 scrcpy 安卓投屏一份面向新手的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考