10 设计模式之装饰模式

一、什么是装饰模式?

1.装饰模式(Decorator Pattern)

是一种结构型设计模式,用于动态地向对象添加新的功能,而无需修改其原始代码。它通过创建一系列装饰类,将功能封装在一个对象中,从而实现功能的灵活扩展。

2.核心思想:

在不改变对象本身的情况下,通过包装(组合)的方式,动态地叠加或增强对象的行为。


二、装饰模式的结构

装饰模式包含以下几个关键角色:

  1. Component(抽象组件):定义了对象的接口,具体组件和装饰器都实现该接口。
  2. ConcreteComponent(具体组件):实现了组件接口,表示被装饰的对象。
  3. Decorator(抽象装饰器):实现组件接口,内部持有一个组件实例(即被装饰对象的引用)。
  4. ConcreteDecorator(具体装饰器):继承抽象装饰器,实现具体的功能扩展。

三、装饰模式的优缺点

优点:

  1. 符合开闭原则:无需修改已有代码即可扩展新功能。
  2. 灵活组合功能:通过装饰器类的嵌套,可以动态叠加不同的功能。
  3. 易于维护:功能模块化,扩展性强。

缺点:

  1. 增加了系统的复杂性,可能出现过多的装饰器类。
  2. 对于深度嵌套的装饰器链,调试和排查问题可能较为困难。

四、装饰模式的实现案例

我们以一个制作咖啡的场景为例,展示如何使用装饰模式动态叠加功能。

1. 定义组件接口

java 复制代码
// 抽象组件:定义了咖啡的接口
interface Coffee {
    String getDescription(); // 获取描述
    double cost();           // 获取价格
}

2. 定义具体组件

java 复制代码
// 具体组件:浓缩咖啡
class EspressoCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }

    @Override
    public double cost() {
        return 5; // 浓缩咖啡的价格
    }
}

// 具体组件:美式咖啡
class AmericanoCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "美式咖啡";
    }

    @Override
    public double cost() {
        return 8; // 美式咖啡的价格
    }
}

3. 定义抽象装饰器

java 复制代码
// 抽象装饰器:实现 Coffee 接口并组合一个 Coffee 实例
abstract class Decorator implements Coffee {
    protected Coffee coffee; // 被装饰对象

    public Decorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription(); // 调用被装饰对象的方法
    }

    @Override
    public double cost() {
        return coffee.cost();
    }
}

4. 定义具体装饰器

java 复制代码
// 具体装饰器:添加牛奶
class MilkDecorator extends Decorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + " 加奶";
    }

    @Override
    public double cost() {
        return super.cost() + 2; // 牛奶价格为 2 元
    }
}

// 具体装饰器:添加巧克力
class ChocolateDecorator extends Decorator {
    public ChocolateDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + " 加热巧";
    }

    @Override
    public double cost() {
        return super.cost() + 3; // 巧克力价格为 3 元
    }
}

// 具体装饰器:添加糖
class SugarDecorator extends Decorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + " 加糖";
    }

    @Override
    public double cost() {
        return super.cost() + 1; // 糖价格为 1 元
    }
}

5. 测试装饰模式

java 复制代码
public class TestDecorate {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee coffee = new AmericanoCoffee();

        // 添加牛奶装饰
        coffee = new MilkDecorator(coffee);

        // 添加巧克力装饰
        coffee = new ChocolateDecorator(coffee);

        // 添加糖装饰
        coffee = new SugarDecorator(coffee);

        // 打印结果
        System.out.println("描述: " + coffee.getDescription());
        System.out.println("总价: " + coffee.cost() + " 元");
    }
}

五、输出结果

描述: 美式咖啡 加奶 加热巧 加糖 总价: 14.0 元


六、总结

  1. 装饰模式的核心在于"组合":通过将对象嵌套包装,动态地叠加新功能。
  2. 典型使用场景:
    • 动态扩展类的功能,例如日志系统、IO流等。
    • 替代类继承,避免创建过多的子类。
  3. 注意事项:
    • 装饰器链条不宜过长,避免维护困难。
    • 选择合适的抽象层次,确保装饰器的功能明确。

通过这个咖啡店的案例,我们学习了如何使用装饰模式动态地叠加功能,轻松实现了个性化的饮品搭配。装饰模式不仅提高了代码的灵活性,还能让程序更具扩展性,是一个非常实用的设计模式。

相关推荐
卡尔特斯1 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源1 小时前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole1 小时前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫2 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide2 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261352 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源2 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
晨米酱3 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
CoovallyAIHub3 小时前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
Java中文社群3 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试