当前位置: 首页 > news >正文

Java 设计模式-装饰器模式

Java 设计模式-装饰器模式

模式概述

装饰器模式简介

定义:它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

模式类型:结构型

作用

  • 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
  • 可以在不修改原有代码的情况下,通过组合的方式扩展对象的功能,符合开闭原则(对扩展开放,对修改关闭)。
  • 提供了比继承更有弹性的替代方案,避免了因为子类继承导致的类爆炸问题。

典型应用场景

  • 在图形界面开发中,为组件添加滚动条、边框等装饰
  • Java 的 I/O 流体系中就大量使用了装饰器模式

我认为:装饰器将对象包装,在不改变类的情况下增加其功能,是一种相比继承更灵活的替代方案。

课程目标

  • 理解装饰器模式的核心思想和经典应用场景

  • 识别应用场景,使用装饰器模式解决灵活扩展对象的功能要求

  • 了解装饰器模式的优缺点


核心组件

角色-职责表

角色职责示例类名
抽象组件(Component)定义一个对象接口,可以给这些对象动态地添加职责。Coffee
具体组件(ConcreteComponent)实现了抽象组件的接口,是待装饰的对象。SimpleCoffee
抽象装饰器(Decorator)继承自抽象组件,并持有一个抽象组件的引用。CoffeeDecorator
具体装饰器(ConcreteDecorator)实现了抽象装饰器,负责给具体组件添加具体的职责。MilkDecorator, SugarDecorator

3.2 类图

«interface»
Component
+operation() : void
ConcreteComponent
+operation() : void
«abstract»
Decorator
-component : Component
+operation() : void
+setComponent(Component) : void
ConcreteDecoratorA
-addedState : string
+operation() : void
ConcreteDecoratorB
+addedBehavior() : void
+operation() : void

传统实现 VS 装饰者模式

传统实现(痛点版)

代码实现:

// 传统方式:通过继承扩展功能
public class SimpleCoffee {public double getCost() {return 2.0;}public String getDescription() {return "Simple Coffee";}
}// 加牛奶的咖啡
public class MilkCoffee extends SimpleCoffee {@Overridepublic double getCost() {return super.getCost() + 0.5;}@Overridepublic String getDescription() {return super.getDescription() + ", Milk";}
}// 加糖的咖啡
public class SugarCoffee extends SimpleCoffee {@Overridepublic double getCost() {return super.getCost() + 0.3;}@Overridepublic String getDescription() {return super.getDescription() + ", Sugar";}
}// 加牛奶和糖的咖啡 → 需要创建 MilkAndSugarCoffee,甚至更多组合
public class MilkAndSugarCoffee extends SimpleCoffee {@Overridepublic double getCost() {return super.getCost() + 0.5 + 0.3;}@Overridepublic String getDescription() {return super.getDescription() + ", Milk, Sugar";}
}

痛点总结

  • 类爆炸:每种功能组合都需要一个新类,N 个功能会产生 2^N 个子类。
  • 代码重复:每个子类都要重写 getCost()getDescription(),逻辑重复。
  • 不灵活:无法在运行时动态添加或移除功能。
  • 违反开闭原则:新增功能需要修改父类或增加大量子类。

装饰器模式(优雅版)

代码实现

// 1. 抽象组件
public interface Coffee {double getCost();String getDescription();
}// 2. 具体组件
public class SimpleCoffee implements Coffee {@Overridepublic double getCost() {return 2.0;}@Overridepublic String getDescription() {return "Simple Coffee";}
}// 3. 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {protected Coffee coffee;public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}@Overridepublic double getCost() {return coffee.getCost();}@Overridepublic String getDescription() {return coffee.getDescription();}
}// 4. 具体装饰器
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic double getCost() {return super.getCost() + 0.5;}@Overridepublic String getDescription() {return super.getDescription() + ", Milk";}
}public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic double getCost() {return super.getCost() + 0.3;}@Overridepublic String getDescription() {return super.getDescription() + ", Sugar";}
}// 使用示例
public class Main {public static void main(String[] args) {Coffee coffee = new SimpleCoffee();System.out.println(coffee.getDescription() + " $" + coffee.getCost());coffee = new MilkDecorator(coffee);System.out.println(coffee.getDescription() + " $" + coffee.getCost());coffee = new SugarDecorator(coffee);System.out.println(coffee.getDescription() + " $" + coffee.getCost());// 输出:Simple Coffee, Milk, Sugar $2.8}
}

优势

  • 运行时动态扩展:可以在程序运行时自由组合功能。
  • 符合开闭原则:新增功能只需添加新的装饰器类,无需修改已有代码。
  • 避免类爆炸:通过组合而非继承,有效减少子类数量。
  • 职责清晰:每个装饰器只关注一个功能点,符合单一职责原则。

局限

  • ⚠️ 装饰顺序影响结果:如日志装饰器和加密装饰器顺序不同,行为可能不同。
  • ⚠️ 过度使用导致复杂度上升:装饰链过长时,调试和理解成本增加。
  • ⚠️ 仅适用于支持接口/抽象基类的场景:被装饰对象必须有统一接口。

每次调用都是一次递归操作。


模式变体

  • 链式装饰器:通过责任链模式控制处理顺序
  • 优先级装饰器:支持按优先级排序的装饰器
  • 条件装饰器:根据业务规则动态决定是否应用装饰
  • 组合装饰器:将多个装饰器打包成复合装饰器

最佳实践

建议理由
保持单一职责每个装饰器只处理一个业务逻辑
使用工厂模式管理复杂装饰器组合的创建过程
记录装饰日志方便追踪处理流程和调试
限制装饰层级避免过度复杂的装饰链
提供默认实现确保基础功能的完整性

一句话总结

装饰器模式通过优雅的包装机制,实现了来一杯咖啡功能的动态组合与灵活扩展,完美解决了传统实现中的代码臃肿和扩展性难题。

如果关注Java设计模式内容,可以查阅作者的其他Java设计模式系列文章。😊

http://www.dtcms.com/a/331631.html

相关文章:

  • 基于51单片机万年历时钟设计
  • Auto-Coder的CLI 和 Python API
  • 顺序表插入删除
  • React 18/19 新特性 核心 API 深入讲解
  • GraphQL从入门到精通完整指南
  • Scrapy 基础框架搭建教程:从环境配置到爬虫实现(附实例)
  • 开源数据发现平台:Amundsen 第1部分:基础入门与本地环境设置
  • 数据结构:用两个栈模拟队列(Queue Using 2 Stacks)
  • 2025年商协会新运营模式,正在破局
  • NokoPrint:安卓平台上的全能打印解决方案
  • 软件测试之接口测试,接口自动化测试, request
  • 【FreeRTOS】刨根问底4: 优先级反转是啥?咋解决?
  • 系统升级部署中的常见问题与解决方案
  • 京东比价项目开发实录:京东API接口(2025)
  • AI Agent 为什么需要记忆?
  • 我的 LeetCode 日记:Day 37 - 解锁动态规划:完全背包问题
  • 深度解析 Vue 高阶技巧:提升工程化能力的实用方案
  • 使用EvalScope对GPT-OSS-20B进行推理性能压测实战
  • Flink中的水位线
  • STL容器详解:Vector高效使用指南
  • 高效Unicode字符表示:一种创新的词表构建策略分析
  • MCP智能化问答系统实现方案
  • K8S企业级应用与DaemonSet实战解析
  • 【车联网kafka】用钟表齿轮理解 Kafka 时间轮​(第七篇)
  • Java应用快速部署Tomcat指南
  • # 2025全球AI游戏市场研究报告:行业洞察与未来趋势
  • OpenAI 的浏览器将使用 ChatGPT Agent 来控制浏览器
  • 亚马逊FCF计划:破解高单价产品转化困局的金融杠杆
  • RH134 管理基本存储知识点
  • 考研408《计算机组成原理》复习笔记,第四章(1)——指令系统概念(指令字长、N地址指令、定长和变长操作码)