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

10 设计模式之装饰模式

一、什么是装饰模式?

1.装饰模式(Decorator Pattern)

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

2.核心思想:

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


二、装饰模式的结构

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

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

三、装饰模式的优缺点

优点:

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

缺点:

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

四、装饰模式的实现案例

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

1. 定义组件接口

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

2. 定义具体组件

// 具体组件:浓缩咖啡
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. 定义抽象装饰器

// 抽象装饰器:实现 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. 定义具体装饰器

// 具体装饰器:添加牛奶
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. 测试装饰模式

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. 注意事项:
    • 装饰器链条不宜过长,避免维护困难。
    • 选择合适的抽象层次,确保装饰器的功能明确。

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


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

相关文章:

  • 006 MATLAB编程基础
  • rest-assured multiPart上传中文名称文件,文件名乱码
  • 永磁同步电机谐波抑制算法(11)——基于矢量比例积分调节器(vector PI controller,VPI controller)的谐波抑制策略
  • 【Linux内核】ashmem pin/unpin
  • 【时时三省】tessy 新建工程 复用 旧工程用例
  • Spring Task和WebSocket使用
  • 全面解析 C++ STL 中的 set 和 map
  • 各类 AI API获取方法,GPT | Claude | Midjourney等
  • 【论文复现】DETR[端到端目标检测]
  • 网络安全与基础总复习
  • React Native 组件详解之SectionList、StatusBar、Switch、Text 、 TextInput
  • Python基础可能经常出现的异常类型
  • 身份证 OCR 识别 API 接口的应用场景
  • JVM_总结详解
  • 大模型开发和微调工具Llama-Factory-->LoRA合并
  • 本地部署开源趣味艺术画板Paint Board结合内网穿透跨网络多设备在线绘画
  • Axios与FastAPI结合:构建并请求用户增删改查接口
  • qt QRadialGradient详解
  • 读《Effective Java》笔记 - 条目15
  • 数据结构与算法学习笔记----堆
  • day32|leetcode 509.斐波那契数,70.爬楼梯,746.使用最小花费爬楼梯
  • 什么是隐式类型转换?隐式类型转换可能带来哪些问题? 显式类型转换(如强制类型转换)有哪些风险?
  • 人工智能技术在外骨骼机器人中的应用,发展历程与原理介绍
  • 普及组集训--图论最短路径
  • 婚礼照片分享平台WeddingShare
  • Java NIO 全面详解:初学者入门指南