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

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


一、当继承开始「套娃」

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

想给咖啡加奶加糖,却被迫创建了SugarMilkCoffee、SugarOnlyCoffee等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流中看到层层嵌套时,请向这些优雅的装饰器致敬------正是它们让简单的字节流变成了强大的处理管道!

相关推荐
晨曦中的暮雨8 小时前
限流算法——固定窗口、滑动窗口、漏桶、令牌桶
java·开发语言·算法
喵了几个咪9 小时前
GoWind CMS 拆解:在 Go 里给 TipTap 搭一套 Yjs 协同后端
开发语言·后端·golang
Flynt9 小时前
我把微信运动的排行榜和定点推送复刻了一遍:100万次步数更新只要4秒,坑在别处
redis·后端·性能优化
文丑颜不良啊10 小时前
LeetCode876~900题目解析
java·leetcode
aloha_78910 小时前
Java 基础、集合、异常与 JUnit 5 速查
java·junit·sqlserver
知守观11 小时前
设计模式实战:从真实老项目中看标准模板方法与工厂的落地
java·spring·设计模式
独隅11 小时前
Claude API 实战教程:从入门到完整项目
android·java·数据库·claude·claude code
_孤傲_11 小时前
快速掌握 MySQL 语法
数据库·后端·mysql
Wang's Blog11 小时前
Java 项目实战: 交友项目 - 圈子功能实现:总结
java·开发语言·交友
SL_staff12 小时前
JVS私有化文档系统上线避坑指南:5大运维与业务协同断点及检测加固实践
java·开源·全栈