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

设计模式之:装饰器模式

文章目录

    • 什么是装饰器模式?
    • 核心思想
    • 生活中的装饰器模式
    • 模式结构
    • 基础示例:咖啡店系统
      • 1. 组件接口
      • 2. 具体组件
      • 3. 装饰器抽象类
      • 4. 具体装饰器
      • 5. 客户端使用
    • 完整示例:文本处理系统
      • 1. 文本组件接口
      • 2. 具体文本组件
      • 3. 文本装饰器抽象类
      • 4. 具体文本装饰器
      • 5. 文本处理器客户端
    • 实际应用示例:IO流系统
    • 装饰器模式的优点
      • 1. 灵活性高
      • 2. 符合开闭原则
      • 3. 避免类爆炸
    • 装饰器模式的缺点
      • 1. 增加系统复杂度
      • 2. 调试困难
    • 适用场景
    • 最佳实践
      • 1. 保持接口一致性
      • 2. 保持装饰器的简单性
      • 3. 注意装饰顺序
    • 装饰器模式 vs 继承
    • 总结

什么是装饰器模式?

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

核心思想

装饰器模式的核心思想是:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

生活中的装饰器模式

想象一下我们去咖啡店点咖啡:

  • 首先点一杯基础咖啡(被装饰对象)
  • 然后可以添加牛奶(装饰器)
  • 再加糖(另一个装饰器)
  • 再加奶油(又一个装饰器)

每个装饰器都在基础咖啡上添加新的特性,但咖啡的本质没有改变。

模式结构

装饰器模式包含四个核心角色:

  1. 组件接口(Component):定义对象的接口,可以动态地给这些对象添加职责
  2. 具体组件(ConcreteComponent):定义具体的对象,可以给这个对象添加一些职责
  3. 装饰器抽象类(Decorator):继承组件接口,并包含一个组件对象的引用
  4. 具体装饰器(ConcreteDecorator):向组件添加具体的职责

基础示例:咖啡店系统

1. 组件接口

/*** 饮料接口 - 组件接口* 定义所有饮料的共同操作*/
public interface Beverage {/*** 获取饮料描述*/String getDescription();/*** 计算成本*/double cost();/*** 获取完整信息*/default String getFullInfo() {return String.format("%s - ¥%.2f", getDescription(), cost());}
}

2. 具体组件

/*** 浓缩咖啡 - 具体组件*/
public class Espresso implements Beverage {@Overridepublic String getDescription() {return "浓缩咖啡";}@Overridepublic double cost() {return 25.0;}
}/*** 美式咖啡 - 具体组件*/
public class Americano implements Beverage {@Overridepublic String getDescription() {return "美式咖啡";}@Overridepublic double cost() {return 20.0;}
}/*** 拿铁咖啡 - 具体组件*/
public class Latte implements Beverage {@Overridepublic String getDescription() {return "拿铁咖啡";}@Overridepublic double cost() {return 30.0;}
}

3. 装饰器抽象类

/*** 调料装饰器抽象类 - 装饰器* 所有具体装饰器的父类*/
public abstract class CondimentDecorator implements Beverage {// 持有被装饰对象的引用protected Beverage beverage;public CondimentDecorator(Beverage beverage) {this.beverage = beverage;}@Overridepublic abstract String getDescription();@Overridepublic double cost() {return beverage.cost();}
}

4. 具体装饰器

/*** 牛奶装饰器*/
public class MilkDecorator extends CondimentDecorator {public MilkDecorator(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + " + 牛奶";}@Overridepublic double cost() {return beverage.cost() + 5.0;}
}/*** 糖装饰器*/
public class SugarDecorator extends CondimentDecorator {public SugarDecorator(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + " + 糖";}@Overridepublic double cost() {return beverage.cost() + 2.0;}
}/*** 奶油装饰器*/
public class CreamDecorator extends CondimentDecorator {public CreamDecorator(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + " + 奶油";}@Overridepublic double cost() {return beverage.cost() + 8.0;}
}/*** 香草糖浆装饰器*/
public class VanillaSyrupDecorator extends CondimentDecorator {public VanillaSyrupDecorator(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + " + 香草糖浆";}@Overridepublic double cost() {return beverage.cost() + 6.0;}
}/*** 巧克力装饰器*/
public class ChocolateDecorator extends CondimentDecorator {public ChocolateDecorator(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + " + 巧克力";}@Overridepublic double cost() {return beverage.cost() + 7.0;}
}

5. 客户端使用

/*** 咖啡店客户端*/
public class CoffeeShop {public static void main(String[] args) {System.out.println("=== 咖啡店订单系统 ===\n");// 订单1:浓缩咖啡 + 牛奶 + 糖System.out.println("订单1:");Beverage order1 = new Espresso();          // 浓缩咖啡order1 = new MilkDecorator(order1);        // 加牛奶order1 = new SugarDecorator(order1);       // 加糖System.out.println(order1.getFullInfo());// 订单2:拿铁 + 奶油 + 巧克力 + 香草糖浆System.out.println("\n订单2:");Beverage order2 = new Latte();             // 拿铁order2 = new CreamDecorator(order2);       // 加奶油order2 = new ChocolateDecorator(order2);   // 加巧克力order2 = new VanillaSyrupDecorator(order2);// 加香草糖浆System.out.println(order2.getFullInfo());// 订单3:美式咖啡 + 牛奶System.out.println("\n订单3:");Beverage order3 = new Americano();         // 美式咖啡order3 = new MilkDecorator(order3);        // 加牛奶System.out.println(order3.getFullInfo());// 显示所有订单总价System.out.println("\n=== 订单汇总 ===");double total = order1.cost() + order2.cost() + order3.cost();System.out.printf("总金额: ¥%.2f%n", total);}
}

完整示例:文本处理系统

让我们通过一个更复杂的文本处理系统来深入理解装饰器模式。

1. 文本组件接口

/*** 文本组件接口*/
public interface TextComponent {/*** 获取文本内容*/String getContent();/*** 获取文本长度*/int getLength();/*** 显示文本信息*/default void display() {System.out.println("内容: " + getContent());System.out.println("长度: " + getLength());}
}

2. 具体文本组件

/*** 基础文本 - 具体组件*/
public class PlainText implements TextComponent {private final String content;public PlainText(String content) {this.content = content;}@Overridepublic String getContent() {return content;}@Overridepublic int getLength() {return content.length();}
}/*** 加密文本 - 具体组件*/
public class EncryptedText implements TextComponent {private final String content;public EncryptedText(String content) {this.content = encrypt(content);}@Overridepublic String getContent() {return decrypt(content);}@Overridepublic int getLength() {return decrypt(content).length();}private String encrypt(String text) {// 简单的加密:字符偏移char[] chars = text.toCharArray();for (int i = 0; i < chars.length; i++) {chars[i] = (char) (chars[i] + 1);}return new String(chars);}private String decrypt(String encrypted) {// 解密:字符偏移还原char[] chars = encrypted.toCharArray();for (int i = 0; i < chars.length; i++) {chars[i] = (char) (chars[i] - 1);}return new String(chars);}
}

3. 文本装饰器抽象类

/*** 文本装饰器抽象类*/
public abstract class TextDecorator implements TextComponent {protected TextComponent textComponent;public TextDecorator(TextComponent textComponent) {this.textComponent = textComponent;}@Overridepublic String getContent() {return textComponent.getContent();}@Overridepublic int getLength() {return textComponent.getLength();}
}

4. 具体文本装饰器

/*** HTML装饰器 - 给文本添加HTML标签*/
public class HtmlDecorator extends TextDecorator {public HtmlDecorator(TextComponent textComponent) {super(textComponent);}@Overridepublic String getContent() {return "<html><body>" + textComponent.getContent() + "</body></html>";}@Overridepublic int getLength() {return getContent().length();}@Overridepublic void display() {System.out.println("HTML格式:");System.out.println(getContent());}
}/*** 大写装饰器 - 将文本转换为大写*/
public class UpperCaseDecorator extends TextDecorator {public UpperCaseDecorator(TextComponent textComponent) {super(textComponent);}@Overridepublic String getContent() {return textComponent.getContent().toUpperCase();}
}/*** 小写装饰器 - 将文本转换为小写*/
public class LowerCaseDecorator extends TextDecorator {public LowerCaseDecorator(TextComponent textComponent) {super(textComponent);}@Overridepublic String getContent() {return textComponent.getContent().toLowerCase();}
}/*** 压缩装饰器 - 移除多余空格*/
public class CompressDecorator extends TextDecorator {public CompressDecorator(TextComponent textComponent) {super(textComponent);}@Overridepublic String getContent() {return textComponent.getContent().replaceAll("\\s+", " ").trim();}@Overridepublic int getLength() {return getContent().length();}
}/*** 前缀装饰器 - 添加前缀*/
public class PrefixDecorator extends TextDecorator {private final String prefix;public PrefixDecorator(TextComponent textComponent, String prefix) {super(textComponent);this.prefix = prefix;}@Overridepublic String getContent() {return prefix + textComponent.getContent();}@Overridepublic int getLength() {return getContent().length();}
}/*** 后缀装饰器 - 添加后缀*/
public class SuffixDecorator extends TextDecorator {private final String suffix;public SuffixDecorator(TextComponent textComponent, String suffix) {super(textComponent);this.suffix = suffix;}@Overridepublic String getContent() {return textComponent.getContent() + suffix;}@Overridepublic int getLength() {return getContent().length();}
}/*** 颜色装饰器 - 添加颜色标记*/
public class ColorDecorator extends TextDecorator {private final String color;public ColorDecorator(TextComponent textComponent, String color) {super(textComponent);this.color = color;}@Overridepublic String getContent() {return String.format("[颜色:%s]%s[/颜色]", color, textComponent.getContent());}@Overridepublic int getLength() {// 颜色标记不计入内容长度return textComponent.getLength();}
}/*** 边框装饰器 - 给文本添加边框*/
public class BorderDecorator extends TextDecorator {private final char borderChar;public BorderDecorator(TextComponent textComponent, char borderChar) {super(textComponent);this.borderChar = borderChar;}@Overridepublic String getContent() {String content = textComponent.getContent();String borderLine = String.valueOf(borderChar).repeat(content.length() + 4);return borderLine + "\n" +borderChar + " " + content + " " + borderChar + "\n" +borderLine;}@Overridepublic int getLength() {return getContent().length();}
}

5. 文本处理器客户端

/*** 文本处理器客户端*/
public class TextProcessor {public static void main(String[] args) {System.out.println("=== 文本处理系统 ===\n");// 示例1:基础文本处理demonstrateBasicTextProcessing();// 示例2:格式化文本demonstrateTextFormatting();// 示例3:加密文本处理demonstrateEncryptedText();// 示例4:复杂装饰组合demonstrateComplexDecoration();}/*** 演示基础文本处理*/private static void demonstrateBasicTextProcessing() {System.out.println("1. 基础文本处理演示:");System.out.println("-".repeat(40));// 创建基础文本TextComponent text = new PlainText("   Hello,   Decorator  Pattern!   ");System.out.println("原始文本:");text.display();// 添加压缩装饰器text = new CompressDecorator(text);System.out.println("\n压缩后:");text.display();// 添加大写装饰器text = new UpperCaseDecorator(text);System.out.println("\n大写后:");text.display();// 添加前缀后缀text = new PrefixDecorator(text, ">>> ");text = new SuffixDecorator(text, " <<<");System.out.println("\n添加前后缀:");text.display();}/*** 演示文本格式化*/private static void demonstrateTextFormatting() {System.out.println("\n2. 文本格式化演示:");System.out.println("-".repeat(40));TextComponent text = new PlainText("装饰器模式很实用");// 添加颜色和边框text = new ColorDecorator(text, "红色");text = new BorderDecorator(text, '*');System.out.println("格式化文本:");System.out.println(text.getContent());}/*** 演示加密文本处理*/private static void demonstrateEncryptedText() {System.out.println("\n3. 加密文本处理演示:");System.out.println("-".repeat(40));// 创建加密文本TextComponent secretText = new EncryptedText("机密信息:项目预算100万");System.out.println("加密内容: " + secretText.getContent());System.out.println("解密后长度: " + secretText.getLength());// 对加密文本进行装饰secretText = new UpperCaseDecorator(secretText);secretText = new BorderDecorator(secretText, '#');System.out.println("\n装饰后的加密文本:");System.out.println(secretText.getContent());}/*** 演示复杂装饰组合*/private static void demonstrateComplexDecoration() {System.out.println("\n4. 复杂装饰组合演示:");System.out.println("-".repeat(40));// 创建复杂的文本处理流水线TextComponent text = new PlainText("   Welcome to Java Design Patterns   ");System.out.println("原始文本:");text.display();// 构建处理流水线text = new CompressDecorator(text);        // 压缩空格text = new UpperCaseDecorator(text);       // 转大写text = new PrefixDecorator(text, "🚀 ");   // 添加前缀text = new SuffixDecorator(text, " 🎯");   // 添加后缀text = new ColorDecorator(text, "蓝色");   // 添加颜色text = new BorderDecorator(text, '═');     // 添加边框System.out.println("\n经过完整处理流水线:");System.out.println(text.getContent());System.out.println("最终长度: " + text.getLength());}
}

实际应用示例:IO流系统

Java的IO流系统是装饰器模式的经典应用:

import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;/*** Java IO流装饰器模式示例*/
public class IOStreamExample {public static void main(String[] args) {System.out.println("=== Java IO流装饰器模式示例 ===\n");// 示例1:基础文件读写demonstrateBasicFileIO();// 示例2:缓冲流装饰器demonstrateBufferedStream();// 示例3:数据流装饰器demonstrateDataStream();// 示例4:压缩流装饰器demonstrateCompressionStream();}/*** 演示基础文件读写*/private static void demonstrateBasicFileIO() {System.out.println("1. 基础文件IO:");try {// 文件输出流 - 具体组件FileOutputStream fos = new FileOutputStream("test.txt");// 使用装饰器添加功能BufferedOutputStream bos = new BufferedOutputStream(fos);PrintStream ps = new PrintStream(bos);ps.println("Hello, Decorator Pattern!");ps.println("This is a test message.");ps.close();System.out.println("文件写入完成");} catch (IOException e) {e.printStackTrace();}}/*** 演示缓冲流装饰器*/private static void demonstrateBufferedStream() {System.out.println("\n2. 缓冲流装饰器:");try {// 读取文件:FileInputStream -> BufferedInputStream -> DataInputStreamFileInputStream fis = new FileInputStream("test.txt");BufferedInputStream bis = new BufferedInputStream(fis);System.out.println("读取文件内容:");int data;while ((data = bis.read()) != -1) {System.out.print((char) data);}bis.close();System.out.println("\n文件读取完成");} catch (IOException e) {e.printStackTrace();}}/*** 演示自定义装饰器*/public static void demonstrateDataStream() {System.out.println("\n3. 数据流装饰器:");try {// 写入数据FileOutputStream fos = new FileOutputStream("data.bin");BufferedOutputStream bos = new BufferedOutputStream(fos);DataOutputStream dos = new DataOutputStream(bos);dos.writeInt(123);dos.writeUTF("装饰器模式");dos.writeDouble(3.14);dos.close();System.out.println("数据写入完成");// 读取数据FileInputStream fis = new FileInputStream("data.bin");BufferedInputStream bis = new BufferedInputStream(fis);DataInputStream dis = new DataInputStream(bis);System.out.println("读取数据:");System.out.println("Int: " + dis.readInt());System.out.println("String: " + dis.readUTF());System.out.println("Double: " + dis.readDouble());dis.close();} catch (IOException e) {e.printStackTrace();}}/*** 演示压缩流装饰器*/public static void demonstrateCompressionStream() {System.out.println("\n4. 压缩流装饰器:");try {// 压缩写入FileOutputStream fos = new FileOutputStream("compressed.gz");GZIPOutputStream gzos = new GZIPOutputStream(fos);BufferedOutputStream bos = new BufferedOutputStream(gzos);String text = "这是一个被压缩的文本内容,使用GZIP装饰器进行压缩处理。";bos.write(text.getBytes());bos.close();System.out.println("压缩文件写入完成");} catch (IOException e) {e.printStackTrace();}}
}

装饰器模式的优点

1. 灵活性高

// 可以动态组合功能
Beverage coffee = new Espresso();
coffee = new MilkDecorator(coffee);    // 随时添加牛奶
coffee = new SugarDecorator(coffee);   // 随时添加糖
// 不需要修改原有类

2. 符合开闭原则

// 对扩展开放,对修改关闭
// 新增装饰器不需要修改现有代码
public class NewCondimentDecorator extends CondimentDecorator {// 新增装饰器,不影响其他类
}

3. 避免类爆炸

// 不使用装饰器模式需要:
// EspressoWithMilk, EspressoWithSugar, EspressoWithMilkAndSugar...
// 使用装饰器模式只需要:Espresso + 各种装饰器组合

装饰器模式的缺点

1. 增加系统复杂度

// 多层装饰可能使代码难以理解
TextComponent text = new BorderDecorator(new ColorDecorator(new UpperCaseDecorator(new PlainText("hello")), "red"), '*'
);

2. 调试困难

// 多层包装使得调试时难以确定问题所在
// 需要逐层检查装饰器

适用场景

  1. 在不影响其他对象的情况下,动态、透明地给单个对象添加职责
  2. 处理那些可以撤销的职责
  3. 当不能采用继承的方式对系统进行扩充时

最佳实践

1. 保持接口一致性

public abstract class Decorator implements Component {// 装饰器要实现相同的接口// 这样对客户端来说,装饰器和具体组件没有区别
}

2. 保持装饰器的简单性

public class SimpleDecorator extends Decorator {// 每个装饰器只负责一个单一的功能// 避免一个装饰器做太多事情
}

3. 注意装饰顺序

// 装饰顺序可能影响最终结果
TextComponent text = new PlainText("hello");
text = new UpperCaseDecorator(text);   // 先大写
text = new BorderDecorator(text);      // 后加边框
// 与反向顺序结果可能不同

装饰器模式 vs 继承

特性继承装饰器模式
扩展方式编译时静态扩展运行时动态扩展
灵活性低,继承关系在编译时确定高,可以在运行时组合
类数量容易产生类爆炸类数量可控
维护性修改父类影响所有子类装饰器之间相互独立

总结

装饰器模式就像给对象"穿衣服",可以一层一层地添加功能,而且可以随意搭配。

核心价值:

  • 动态添加功能,无需修改原有代码
  • 功能组合灵活,避免类爆炸
  • 符合开闭原则,易于扩展

使用场景:

  • 需要动态、透明地给对象添加功能时
  • 需要为对象添加的功能可能经常变化时
  • 不能使用继承或继承会导致类爆炸时

简单记忆:

想要新功能,包装一下就行!
就像给咖啡加调料,想加什么就加什么。

掌握装饰器模式,能够让你的代码像搭积木一样灵活组合各种功能,创造出无限可能!

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

相关文章:

  • 用户态和内核态切换开销详解(了解即可)
  • Android触屏TP驱动事件上报以及多点触摸
  • 上海微信小程序网站建设教做西餐的网站
  • 一文读懂YOLOv4:目标检测领域的技术融合与性能突破
  • 深圳企业网站建设报价泰安建设网站
  • vllm系统架构图解释
  • 上海做网站公司做网站的公司免费域名注册工具
  • 博客安全攻防演练技术指南
  • IMX8MP交叉编译QT 5.12.9
  • 通过datax将mysql数据导入到clickhouse
  • 湛江网站网站建设长沙网络推广平台
  • 平顶山市网站建设校际凡科平台是干什么的
  • 突破机房边界!VMware虚拟机结合cpolar远程协作实战指南
  • 微算法科技(NASDAQ MLGO)创建企业级区块链双层共识算法:融合优化DPoS与动态BFT的协同机制设计
  • Redis深度探索
  • 做金融的看哪些网站店铺设计分析
  • 【机器学习07】 激活函数精讲、Softmax多分类与优化器进阶
  • 香水推广软文seo入门教学
  • AI一周事件(2025年10月15日-10月21日)
  • 从零搭建 RAG 智能问答系统 5:多模态文件解析与前端交互实战
  • H618-实现基于RTMP推流的视频监控
  • vue 项目中 components、views、layout 各个目录规划,组件、页面、布局如何实现合理搭配,实现嵌套及跳转合理,使用完整说明
  • 网站建设彩铃短信营销
  • 公司网站建设管理办法汉中网络推广
  • 深度学习(14)-Pytorch torch 手册
  • 喜讯|中国质量认证中心(CQC)通过个人信息保护合规审计服务认证
  • iOS原生与Flutter的交互编程
  • 【研究生随笔】Pytorch中的线性回归
  • OCR 识别:电子保单的数字化助力
  • 好看的网站哪里找网站免费软件