给代码穿上品如的衣服:装饰器模式的套娃艺术

给代码穿上品如的衣服:装饰器模式的套娃艺术


一、当继承开始「套娃」

你是否经历过这样的崩溃?

想给咖啡加奶加糖,却被迫创建了SugarMilkCoffeeSugarOnlyCoffee等48个子类;

要给游戏角色装备皮肤,结果代码里长出了RedHatBlueSwordArmorHero这样的类名...

这时你需要装饰器模式------它像品如的衣柜,让对象可以随时随地换皮肤,还能把十层Buff叠得比千层饼还优雅。


二、俄罗斯套娃的设计图(UML图)

java 复制代码
          ┌─────────────┐
          │  Component  │
          ├─────────────┤
          │ +operation()│
          └──────△──────┘
                 │
   ┌─────────────┴─────────────┐
   │                           │
┌─────────────┐        ┌─────────────┐
│ Concrete    │        │ Decorator   │
│ Component   │        ├─────────────┤
└─────────────┘        │ -component  │
                       │ +operation()│
                       └──────△──────┘
                              │
                 ┌────────────┴────────────┐
                 │                         │
          ┌─────────────┐          ┌─────────────┐
          │ Concrete    │          │ Concrete    │
          │ DecoratorA  │          │ DecoratorB  │
          └─────────────┘          └─────────────┘
  • 素颜女神(Component):定义核心功能
  • 基础款(ConcreteComponent):实现基础功能
  • 美妆博主(Decorator):持有组件引用,提供增强接口
  • 彩妆单品(ConcreteDecorator):具体增强实现

三、咖啡店の魔法时刻(代码实战)

1. 基础咖啡(素颜版)
java 复制代码
// 咖啡接口(Component)
interface Coffee {
    String getDesc();
    double cost();
}

// 基础咖啡(ConcreteComponent)
class SimpleCoffee implements Coffee {
    public String getDesc() { return "咖啡"; }
    public double cost() { return 8.0; }
}
2. 魔法装饰器(美妆版)
java 复制代码
// 装饰器基类(Decorator)
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    public String getDesc() {
        return decoratedCoffee.getDesc();
    }
    
    public double cost() {
        return decoratedCoffee.cost();
    }
}

// 摩卡魔法(具体装饰器)
class MochaDecorator extends CoffeeDecorator {
    public MochaDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDesc() {
        return super.getDesc() + "+摩卡";
    }
    
    @Override
    public double cost() {
        return super.cost() + 3.0;
    }
}

// 香草咒语(具体装饰器)
class VanillaDecorator extends CoffeeDecorator {
    public VanillaDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDesc() {
        return super.getDesc() + "+香草";
    }
    
    @Override
    public double cost() {
        return super.cost() + 2.5;
    }
}
3. 点一杯魔法咖啡
java 复制代码
Coffee myCoffee = new SimpleCoffee();
myCoffee = new MochaDecorator(myCoffee);  // 叠加摩卡
myCoffee = new VanillaDecorator(myCoffee);// 叠加香草

System.out.println(myCoffee.getDesc());  // 咖啡+摩卡+香草
System.out.println("价格:" + myCoffee.cost()); // 13.5元

四、装饰器 vs 继承:美颜相机 vs 整容医院

维度 装饰器模式 继承
扩展方式 动态组合 静态编译
类数量 线性增长(N+M) 指数爆炸(M^N)
灵活性 运行时自由搭配 编译时确定
代码复用 装饰器可重复使用 每个组合都是新类
现实类比 乐高积木 石膏雕像

选型指南

  • 需要动态增减功能 → 装饰器
  • 功能组合固定 → 继承
  • 不确定时 → 选装饰器保平安

五、现实世界的叠Buff艺术

  1. Java IO流

    java 复制代码
    // 经典套娃三连
    new BufferedReader(
        new InputStreamReader(
            new FileInputStream("data.txt")
        )
    );
  2. Web中间件:身份验证+日志记录+缓存装饰器链

  3. 游戏装备系统:武器基础属性+宝石强化+皮肤特效

  4. 前端高阶组件:Redux的connect()装饰React组件

  5. Spring AOP:通过装饰器模式实现切面增强

冷知识

Java的Collections.unmodifiableList()其实是个装饰器,给集合套上「只读盔甲」。


六、防套娃翻车指南

  1. 控制嵌套层数

    java 复制代码
    // 错误示范:套娃十连击
    coffee = new Mocha(new Milk(new Sugar(...(new SimpleCoffee()))));
  2. 保持装饰器透明

    java 复制代码
    // 好的装饰器应该像透明滤镜
    // 不要偷偷修改对象核心状态
  3. 避免循环装饰

    java 复制代码
    // 禁止:装饰器A装饰装饰器B,B又装饰A
    // 这会导致代码进入莫比乌斯环
  4. 优先接口装饰

    java 复制代码
    // 装饰器应该面向接口
    // 而不是具体实现类
  5. 警惕性能损耗

    java 复制代码
    // 每个装饰器都是包装盒
    // 套太多会影响性能

七、品如の衣柜总结大会

装饰器模式就像代码界的奇迹暖暖:

  • :用于动态增强对象功能
  • :保持装饰器单一职责
  • 不要:把装饰器当继承用
  • 不要:忘记装饰器带来的复杂度

当你在Java IO流中看到层层嵌套时,请向这些优雅的装饰器致敬------正是它们让简单的字节流变成了强大的处理管道!

相关推荐
一路向北North1 小时前
IDEA加载项目时依赖无法更新
java·ide·intellij-idea
uhakadotcom2 小时前
Python 量化计算入门:基础库和实用案例
后端·算法·面试
小萌新上大分2 小时前
SpringCloudGateWay
java·开发语言·后端·springcloud·springgateway·cloudalibaba·gateway网关
uhakadotcom2 小时前
使用Python获取Google Trends数据:2025年详细指南
后端·面试·github
uhakadotcom2 小时前
使用 Python 与 Google Cloud Bigtable 进行交互
后端·面试·github
程序员沉梦听雨2 小时前
原型模式详解
设计模式·原型模式
直视太阳3 小时前
springboot+easyexcel实现下载excels模板下拉选择
java·spring boot·后端
Code成立3 小时前
《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》第2章 Java内存区域与内存溢出异常
java·jvm·jvm内存模型·jvm内存区域
追逐时光者3 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 33 期(2025年4.1-4.6)
后端·.net
灼华十一3 小时前
Golang系列 - 内存对齐
开发语言·后端·golang