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

【设计模式】装饰器模式大白话讲解

装饰器模式大白话讲解

一句话概括

就像给手机加配件:手机本身功能不变,加个壳防摔,加个膜防刮,加个镜头增强拍照
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


现实生活比喻

场景1:手机配件

  • 基础手机:打电话、发短信
  • 加手机壳:还是能打电话,但多了防摔功能
  • 加钢化膜:还是能触摸,但多了防刮功能
  • 加外接镜头:还是能拍照,但效果更好了

场景2:咖啡加料

  • 基础咖啡:黑咖啡
  • 加牛奶:变成拿铁
  • 加糖:变成甜咖啡
  • 加奶油:变成奶油咖啡
  • 可以任意组合:牛奶+糖,牛奶+奶油,糖+奶油,牛奶+糖+奶油…

完整代码示例

场景:咖啡店点餐系统

/*** 装饰器模式 - 咖啡店示例*/
public class Main {public static void main(String[] args) {System.out.println("=== 咖啡店菜单 ===");// 1. 基础咖啡Coffee blackCoffee = new BlackCoffee();System.out.println(blackCoffee.getDescription() + " 价格: ¥" + blackCoffee.cost());// 2. 加配料的咖啡Coffee milkCoffee = new MilkDecorator(new BlackCoffee());System.out.println(milkCoffee.getDescription() + " 价格: ¥" + milkCoffee.cost());Coffee sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new BlackCoffee()));System.out.println(sugarMilkCoffee.getDescription() + " 价格: ¥" + sugarMilkCoffee.cost());// 3. 豪华组合Coffee premiumCoffee = new WhippedCreamDecorator(new ChocolateDecorator(new SugarDecorator(new MilkDecorator(new Espresso()))));System.out.println(premiumCoffee.getDescription() + " 价格: ¥" + premiumCoffee.cost());// 4. 不同基础咖啡的组合Coffee icedCoffee = new IceDecorator(new SugarDecorator(new Latte()));System.out.println(icedCoffee.getDescription() + " 价格: ¥" + icedCoffee.cost());}
}/*** 抽象组件 - 咖啡接口*/
interface Coffee {String getDescription();  // 获取描述double cost();           // 计算价格
}/*** 具体组件 - 基础咖啡种类*/
class BlackCoffee implements Coffee {@Overridepublic String getDescription() {return "黑咖啡";}@Overridepublic double cost() {return 15.0;}
}class Espresso implements Coffee {@Overridepublic String getDescription() {return "浓缩咖啡";}@Overridepublic double cost() {return 18.0;}
}class Latte implements Coffee {@Overridepublic String getDescription() {return "拿铁咖啡";}@Overridepublic double cost() {return 20.0;}
}/*** 抽象装饰器 - 配料基类*/
abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}@Overridepublic String getDescription() {return decoratedCoffee.getDescription();}@Overridepublic double cost() {return decoratedCoffee.cost();}
}/*** 具体装饰器 - 各种配料*/
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 牛奶";}@Overridepublic double cost() {return decoratedCoffee.cost() + 3.0;}
}class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 糖";}@Overridepublic double cost() {return decoratedCoffee.cost() + 1.0;}
}class WhippedCreamDecorator extends CoffeeDecorator {public WhippedCreamDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 奶油";}@Overridepublic double cost() {return decoratedCoffee.cost() + 5.0;}
}class ChocolateDecorator extends CoffeeDecorator {public ChocolateDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 巧克力";}@Overridepublic double cost() {return decoratedCoffee.cost() + 4.0;}
}class IceDecorator extends CoffeeDecorator {public IceDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 冰";}@Overridepublic double cost() {return decoratedCoffee.cost() + 2.0;}
}

运行结果

=== 咖啡店菜单 ===
黑咖啡 价格: ¥15.0
黑咖啡 + 牛奶 价格: ¥18.0
黑咖啡 + 牛奶 + 糖 价格: ¥19.0
浓缩咖啡 + 牛奶 + 糖 + 巧克力 + 奶油 价格: ¥31.0
拿铁咖啡 + 糖 + 冰 价格: ¥23.0

更实用的例子:IO流系统

/*** Java IO流就是装饰器模式的经典应用*/
public class IOExample {public static void main(String[] args) {// Java IO流中的装饰器模式// InputStream就是抽象组件// FileInputStream、ByteArrayInputStream就是具体组件// BufferedInputStream、DataInputStream就是装饰器System.out.println("=== Java IO流中的装饰器模式 ===");// 模拟Java IO的使用方式try {// 基础文件流InputStream fileStream = new FileInputStream("data.txt");System.out.println("基础文件流: 只能按字节读取");// 加缓冲装饰器InputStream bufferedStream = new BufferedInputStream(fileStream);System.out.println("缓冲流: 可以批量读取,提高效率");// 加数据装饰器InputStream dataStream = new DataInputStream(bufferedStream);System.out.println("数据流: 可以读取各种数据类型");// 组合使用InputStream advancedStream = new DataInputStream(new BufferedInputStream(new FileInputStream("data.txt")));System.out.println("组合流: 既有缓冲又有数据类型支持");} catch (Exception e) {e.printStackTrace();}}
}// 模拟Java IO的装饰器结构
interface InputStream {int read();void close();
}class FileInputStream implements InputStream {private String filename;public FileInputStream(String filename) {this.filename = filename;}@Overridepublic int read() {System.out.println("从文件 " + filename + " 读取一个字节");return 0;}@Overridepublic void close() {System.out.println("关闭文件流");}
}// 抽象装饰器
abstract class FilterInputStream implements InputStream {protected InputStream in;public FilterInputStream(InputStream in) {this.in = in;}@Overridepublic int read() {return in.read();}@Overridepublic void close() {in.close();}
}// 具体装饰器
class BufferedInputStream extends FilterInputStream {public BufferedInputStream(InputStream in) {super(in);}@Overridepublic int read() {System.out.println("从缓冲区读取数据...");return super.read();}public int read(byte[] buffer) {System.out.println("批量读取 " + buffer.length + " 字节到缓冲区");return buffer.length;}
}class DataInputStream extends FilterInputStream {public DataInputStream(InputStream in) {super(in);}@Overridepublic int read() {return super.read();}public int readInt() {System.out.println("读取int类型数据");return 0;}public double readDouble() {System.out.println("读取double类型数据");return 0.0;}
}

装饰器模式的核心结构

      Component(抽象组件)↑
ConcreteComponent(具体组件) ← Decorator(抽象装饰器)↑ConcreteDecorator(具体装饰器)

关键特征:

  • 相同接口:装饰器和被装饰对象实现相同接口
  • 组合关系:装饰器包含被装饰对象的引用
  • 透明装饰:客户端不知道是否被装饰
  • 动态添加:运行时动态添加功能

装饰器 vs 继承

继承方式(不灵活):

class Coffee { ... }
class MilkCoffee extends Coffee { ... }
class SugarCoffee extends Coffee { ... }
class MilkSugarCoffee extends Coffee { ... } // 类爆炸!

装饰器方式(灵活):

Coffee coffee = new MilkDecorator(new SugarDecorator(new BlackCoffee()));
// 任意组合,无需创建新类

适用场景(大白话版)

适合用装饰器的场景:

  1. 动态添加功能

    // 运行时决定加什么功能
    if (userWantsMilk) {coffee = new MilkDecorator(coffee);
    }
    if (userWantsSugar) {coffee = new SugarDecorator(coffee);
    }
    
  2. 避免类爆炸

    // 如果有10种配料,继承需要2^10=1024个类
    // 装饰器只需要10个装饰器类,任意组合
    
  3. 不影响原有对象

    // 只是包装,不修改原对象
    // 可以多次装饰,层层包装
    

不适合的场景:

  1. is-a关系:如果确实是"是一种"的关系,用继承
  2. 功能变化很大:如果要彻底改变接口,用适配器
  3. 简单扩展:如果只需要简单扩展,直接修改类可能更简单

优缺点

优点:

  • 灵活扩展:可以动态添加功能
  • 符合开闭原则:不修改原有代码就能扩展
  • 避免类爆炸:组合代替继承
  • 职责清晰:每个装饰器只负责一个功能

缺点:

  • 复杂度增加:多层装饰理解起来有点绕
  • 调试困难:调用链较长,调试不太直观
  • 对象识别:被装饰后的对象类型发生变化

与其它模式对比

模式目的关键区别
装饰器模式动态添加功能保持接口,增强功能
适配器模式接口转换改变接口,功能不变
策略模式算法替换整体替换算法
组合模式部分-整体树形结构,统一操作

总结

装饰器模式就是:

  • 包装纸:一层层包装,每层增加一点功能
  • 俄罗斯套娃:大娃套小娃,功能叠加
  • 乐高积木:基础块+装饰块,任意组合

核心口诀:

功能扩展要动态,
继承爆炸很头痛。
装饰模式来包装,
层层叠加真轻松!

就像现实中的:

  • 咖啡加料:基础咖啡+牛奶+糖+奶油…
  • 📦 礼品包装:礼物+包装纸+彩带+贺卡
  • 🎮 游戏装备:基础角色+武器+防具+饰品
  • 🏠 房屋装修:毛坯房+水电+墙面+家具

记住:当你需要动态、透明地给对象添加功能,并且不想使用继承时,考虑装饰器模式!

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

相关文章:

  • GitLab 版本控制系统
  • Apifox 10 月更新|支持实时预览在线文档个性化配置的效果、性能优化、测试能力升级!
  • 基于HTML5、阿里云播放SDK、腾讯云播放SDK开发的M3U8在线播放器
  • 2025年10月AI科技领域周报(10.20-10.26):多模态技术突破 具身智能开启机器人新纪元
  • 生产管理系统详解:高离散制造 – 生产订单数据库设计表(核心表结构)
  • C语言字符串连接实现详解:掌握自定义strcat函数
  • 代码随想录第53天 | 图论二三题
  • 搜索引擎 网站地图做网站需要招聘内容
  • 具身智能3D数字人开放平台「星云」发布:魔珐科技让AI第一次拥有“身体”
  • 世冠科技受邀参加第三十二届中国汽车工程学会年会暨展览会
  • 服装网站的建设背景建设网站可选择的方案
  • 上传视频网站源码全国可信网站
  • 《Muduo网络库:实现TcpServer类终章》
  • 三数之和:用Java思路分析
  • 企业有没有必要自建一套培训考试
  • 测试开发话题06---测试分类(1)
  • 【Agentic RL专题】一、LLM agent 与 agentic RL
  • 使用Java做URL短连接还原长链接获取参数
  • 自己网站做电子签章有效么有哪些网站做汽车周边服务
  • 做网站去哪好在线表单 wordpress
  • 从信号零损耗到智能协同:高清混合矩阵全链路技术拆解,分布式可视化系统十大趋势重塑行业
  • 【超详细】MySQL事务面试题
  • Ubuntu(③vsftpd)
  • Ubuntu 25.10 发布,各种衍生版也发布
  • HUAWEI A800I A2 aarch64架构Ubuntu服务器鲲鹏920开启 IOMMU/SMMU 硬件虚拟化功能
  • GitHub 发布 Agent HQ:欢迎回家,智能体们
  • 使用 Python 将 PowerPoint 转换为 Word 文档
  • 怎么成立自己的网站公司网站建设案例
  • 做数码后期上数码网站企业推广文章
  • iOS 抓包工具实战 开发者的工具矩阵与真机排查流程