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

装饰器模式 (Decorator Pattern)

装饰器模式 (Decorator Pattern)

装饰器模式是一种 结构型设计模式,它允许动态地向对象添加新的功能,同时又不改变其结构。这种模式通过对象组合来实现,比通过继承扩展功能更加灵活。


原理

  1. 核心思想:通过将对象包装在一系列装饰器中,增强或修改对象的功能,而无需更改对象本身的代码。
  2. 适用场景
    • 希望动态地扩展一个类的功能,而不使用继承。
    • 需要为一个对象提供多种行为组合,且行为的数量动态变化。
  3. 参与角色
    • Component(抽象组件):定义一个对象接口,可以动态地为其添加职责。
    • ConcreteComponent(具体组件):实现抽象组件的类,是被装饰的对象。
    • Decorator(装饰器):实现抽象组件,并持有一个具体组件的引用。
    • ConcreteDecorator(具体装饰器):扩展装饰器,提供额外的功能。

优点

  1. 动态扩展功能:无需修改原始类和其他装饰器类即可扩展功能。
  2. 遵循开闭原则:通过添加新装饰器类来实现功能扩展。
  3. 灵活组合:装饰器可以任意组合使用。

缺点

  1. 复杂性增加:过多的装饰器可能导致系统变得复杂。
  2. 调试困难:在装饰器链中定位问题可能较为困难。

示例代码

场景描述

假设有一个咖啡订单系统,不同的咖啡可以加不同的调料(如牛奶、糖)。咖啡本身和调料的价格需要动态组合计算,且系统应具备良好的扩展性。


1. 定义抽象组件
// 抽象组件
public interface Coffee {
    String getDescription(); // 获取描述
    double getCost();        // 获取价格
}

2. 创建具体组件
// 具体组件:基础咖啡
public class BasicCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Basic Coffee";
    }

    @Override
    public double getCost() {
        return 5.0;
    }
}

3. 创建装饰器抽象类
// 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee; // 持有组件的引用

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

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

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

4. 创建具体装饰器
// 牛奶装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 1.5; // 牛奶价格
    }
}

// 糖装饰器
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 0.5; // 糖价格
    }
}

5. 客户端代码
public class DecoratorPatternExample {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee coffee = new BasicCoffee();
        System.out.println(coffee.getDescription() + " -> $" + coffee.getCost());

        // 加牛奶的咖啡
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " -> $" + coffee.getCost());

        // 加牛奶和糖的咖啡
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " -> $" + coffee.getCost());
    }
}

输出结果
Basic Coffee -> $5.0
Basic Coffee, Milk -> $6.5
Basic Coffee, Milk, Sugar -> $7.0

UML 类图

         +----------------+         +--------------------+
         |    Coffee      |<>------>|  CoffeeDecorator   |
         +----------------+         +--------------------+
         |+ getDescription()        |+ getDescription()  |
         |+ getCost()               |+ getCost()         |
         +----------------+         +--------------------+
                ^                           ^
                |                           |
   +--------------------+         +--------------------+
   |   BasicCoffee      |         | MilkDecorator      |
   +--------------------+         +--------------------+
   |+ getDescription()  |         |+ getDescription()  |
   |+ getCost()         |         |+ getCost()         |
   +--------------------+         +--------------------+

使用场景

  1. 需要动态地增加功能:如图形编辑器中为图形对象添加功能(边框、阴影)。
  2. 功能组合的场景:如不同装饰效果的叠加。
  3. 避免继承扩展:用装饰器动态扩展功能而不引入过多的子类。

总结

  • 装饰器模式是一种灵活的设计模式,可以在运行时动态地为对象添加功能。
  • 它有效避免了类爆炸问题,特别适合需要灵活组合的场景。
  • 通过对象组合,装饰器模式实现了强大的扩展能力,符合 开闭原则

http://www.kler.cn/a/406896.html

相关文章:

  • Python 快速入门(上篇)❖ Python基础知识
  • 2023年9月GESPC++一级真题解析
  • 前端-react(class组件和Hooks)
  • 真题-桂城2018年六年级
  • 嵌入式硬件实战基础篇(二)-稳定输出3.3V的太阳能电池-无限充放电
  • Go-RPC关键指标分析与企业实践
  • 设计模式-创建型-单例模式
  • ssm面向品牌会员的在线商城小程序
  • 【SQL Server】华中农业大学空间数据库实验报告 实验四 完整性约束
  • IDEA2024 maven构建跳过测试
  • 【跳线帽】是什么?怎么用?
  • AIVA 技术浅析(五):使用的自然语言处理(NLP)技术浅析
  • mac homebrew国内镜像源安装
  • SpringBoot社团管理:数据驱动的解决方案
  • uniapp、js判断输入的内容是整数
  • 动态规划子数组系列一>最长湍流子数组
  • 旋转向量v和旋转矩阵R
  • 抓包 127.0.0.1 (loopback) 使用 tcpdump+wireshark
  • java计算机毕设课设—企业采购信息管理系统(附源码、文章、相关截图、部署视频)
  • netstat -tuln | grep 27017(显示所有监听状态的 TCP 和 UDP 端口,并且以数字形式显示地址和端口号)
  • R语言p值矫正整的方法
  • 全面解析 JMeter 后置处理器:概念、工作原理与应用场景
  • HCIA考试内容多吗?HCIA数通学什么?
  • go interface(接口)使用
  • HashMap底层原理
  • 24.11.23 Ajax