07结构型设计模式——装饰器模式

news2024/9/21 16:47:14

一、装饰器模式简介

装饰器模式( Decorator  Pattern)又称包装模式。通过一种面向客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。装饰器模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端可以有选择地、按顺序地使用装饰功能包装对象。

GoF一书对装饰器模式的介绍

二、装饰器模式的用处

        装饰器模式允许在不改变对象结构的情况下,动态地给一个对象添加功能。这种模式通过创建一个装饰类来包装原有类的对象,从而增加新的功能。装饰器模式是面向对象编程中常用的一种设计模式,适用于需要在运行时动态地扩展对象功能的情况。 

  1. 动态扩展功能

    • 装饰器模式允许在不修改原有类的情况下,通过添加装饰器类来动态地扩展对象的功能。这在需要根据不同的需求或条件来增加功能时非常有用。
  2. 增强类的灵活性

    • 通过组合装饰器对象,可以灵活地组合和扩展功能。这种组合的方式比子类化更为灵活,因为它允许在运行时决定具体的功能组合,而不需要修改现有类的代码。
  3. 避免类爆炸

    • 如果每种功能的组合都需要一个新的子类,那么子类数量将会大幅增加,导致类的管理变得困难。装饰器模式可以通过在运行时组合不同的装饰器对象来解决这个问题,从而避免了创建大量的子类。
  4. 遵循开闭原则

    • 装饰器模式遵循了开闭原则,即“对扩展开放,对修改关闭”。通过使用装饰器来增加功能,你可以在不修改原有类的情况下增加新的功能。
  5. 灵活的功能组合

    • 可以在运行时灵活地组合不同的装饰器,这使得功能组合非常灵活。你可以选择不同的装饰器来满足具体的需求,而不需要重新设计整个类层次结构。

三、装饰器模式的设计方法

基础类和装饰器:

  1. 定义基础类Cup:它代表一个基础的水杯。

  2. 定义装饰器基类CupDecorator:继承自Cup,用于装饰基本水杯。

  3. 定义具体装饰器:每个装饰器代表一种调料。

decorator.cpp

#include <iostream>
#include <string>
#include <vector>

// 水杯
class Cup {
public:
    virtual ~Cup() = default;
    virtual std::string getDescription() const {
        return "水杯放入";
    }
    virtual double cost() const {
        return 0.0; // 水杯的成本
    }
};

// 装饰器
class CupDecorator : public Cup {
public:
    CupDecorator(Cup* cup) : cup(cup) {}
    virtual ~CupDecorator() {
        delete cup;
    }
    std::string getDescription() const override {
        return cup->getDescription();
    }
    double cost() const override {
        return cup->cost();
    }

protected:
    Cup* cup;
};

// 调料
class CoffeePowderDecorator : public CupDecorator {
public:
    CoffeePowderDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Coffee Powder";
    }

    double cost() const override {
        return cup->cost() + 2.0; // 咖啡粉的附加费用
    }
};

class BrownSugarDecorator : public CupDecorator {
public:
    BrownSugarDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Brown Sugar";
    }

    double cost() const override {
        return cup->cost() + 1.0; // 红糖的附加费用
    }
};

class LemonSliceDecorator : public CupDecorator {
public:
    LemonSliceDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Lemon Slice";
    }

    double cost() const override {
        return cup->cost() + 0.5; // 柠檬片的附加费用
    }
};

class GojiBerriesDecorator : public CupDecorator {
public:
    GojiBerriesDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Goji Berries";
    }

    double cost() const override {
        return cup->cost() + 1.5; // 枸杞的附加费用
    }
};

class RedDateSlicesDecorator : public CupDecorator {
public:
    RedDateSlicesDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Red Date Slices";
    }

    double cost() const override {
        return cup->cost() + 2.0; // 红枣圈的附加费用
    }
};

class ChrysanthemumDecorator : public CupDecorator {
public:
    ChrysanthemumDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Chrysanthemum";
    }

    double cost() const override {
        return cup->cost() + 1.0; // 菊花的附加费用
    }
};

class YellowTeaDecorator : public CupDecorator {
public:
    YellowTeaDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Yellow Tea";
    }

    double cost() const override {
        return cup->cost() + 2.5; // 黄芽的附加费用
    }
};

class MilkDecorator : public CupDecorator {
public:
    MilkDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Milk";
    }

    double cost() const override {
        return cup->cost() + 2.5; // 牛奶的附加费用
    }
};

class WaterDecorator : public CupDecorator {
public:
    WaterDecorator(Cup* cup) : CupDecorator(cup) {}

    std::string getDescription() const override {
        return cup->getDescription() + ", Water";
    }

    double cost() const override {
        return cup->cost() + 0.0; // 水免费
    }
};

void printService(Cup* cup) {
    std::cout << "Description: " << cup->getDescription() << std::endl;
    std::cout << "Cost: $" << cup->cost() << std::endl;
}

// 纯水套餐
void servicePureWater() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    printService(myCup);
    delete myCup;
}

// 咖啡套餐
void serviceCoffee() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    myCup = new CoffeePowderDecorator(myCup);
    myCup = new BrownSugarDecorator(myCup);
    myCup = new MilkDecorator(myCup);
    printService(myCup);
    delete myCup;
}

// 饮料套餐
void serviceDrink() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    myCup = new LemonSliceDecorator(myCup);
    myCup = new ChrysanthemumDecorator(myCup);
    printService(myCup);
    delete myCup;
}

// 养生套餐
void serviceHealth() {
    Cup* myCup = new Cup();
    myCup = new WaterDecorator(myCup);
    myCup = new YellowTeaDecorator(myCup);
    myCup = new GojiBerriesDecorator(myCup);
    myCup = new RedDateSlicesDecorator(myCup);
    printService(myCup);
    delete myCup;
}

int main() {
    servicePureWater();
    serviceCoffee();
    serviceDrink();
    serviceHealth();
    return 0;
}

 运行效果

四、总结

通过装饰器模式(Decorator Pattern)可以灵活地组合各种调料,而不需要修改基础Cup类的代码去继承或者依赖什么的,只需要添加装饰器和要装饰的功能即可。装饰器模式的优点在于它提供了一种非常灵活的方式来扩展对象的功能。即通过装饰器动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2051673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

求前n项和5.3.1

求他的前n项和 #include <stdio.h>int main() {int n;int i;double sum0.0;scanf("%d", &n);for(i1; i<n; i){sum1.0/i;}printf("%f", sum);return 0; } 一个变量是输入的变量 一个变量要表达递增的 另外一个变量把他们加起来表示总和…

整数分解5.3.2

题 前面写过逆序的 最后一个数后面不要有空格 #include <stdio.h>int main() {int x;scanf("%d",&x);int d;do{dx%10;printf("%d",d);if(x>10){printf(" ");}x/10;}while(x>0);printf("\n");return 0; } 现在这个是…

0818---算法

牛牛快递 如何输入一个字符&#xff1f; java中Scanner类没有.nextChar import java.utol.Scanner; Scanner in new Scanner(System.in); char b in.next().charAt(0);思路&#xff1a; 创建一个Scanner对象&#xff0c;调用Scanner对象的next()方法获取控制台输入的字符串…

Java二十三种设计模式-备忘录模式(19/23)

本文深入探讨了备忘录模式&#xff0c;从定义、组成、实现到使用场景、优缺点、与其他模式的比较&#xff0c;以及最佳实践和替代方案&#xff0c;全面解析了如何在软件开发中有效地保存和恢复对象状态&#xff0c;以支持复杂的撤销操作和历史状态管理。 备忘录模式&#xff1a…

【JAVA OOP】Day09 抽象方法、抽象类、接口、引用类型数组

Day09目标&#xff1a; 理解抽象方法、抽象类的应用场景&#xff1b; 掌握抽象方法、抽象类的语法&#xff1b; 理解接口的应用场景&#xff1b; 掌握接口的语法、应用&#xff1b; 掌握引用类型数组的用法&#xff1b; 代码量&#xff1a;课上120行&#xff0c;课下240行…

AvaloniaChat—从源码构建指南

AvaloniaChat介绍 一个使用大型语言模型进行翻译的简单应用。 我自己的主要使用场景 在看英文文献的过程中&#xff0c;比较喜欢对照着翻译看&#xff0c;因此希望一边是英文一边是中文&#xff0c;虽然某些软件已经自带了翻译功能&#xff0c;但还是喜欢大语言模型的翻译&…

2-69 基于matlab的三坐标雷达目标跟踪数据融合

基于matlab的三坐标雷达目标跟踪数据融合,采用的是概率数据关联算法和EKF&#xff0c;展示了目标的真实轨迹和跟踪滤波轨迹&#xff0c;以及数据融合的轨迹。程序已调通&#xff0c;可直接运行。 2-69 三坐标雷达目标跟踪数据融合 - 小红书 (xiaohongshu.com)

『 Linux 』利用UDP套接字简单进行网络通信

文章目录 Socket常见API转网络字节序网络数据传输的读网络数据传输的写 简单的UDP网络程序服务端基本结构Init() 服务端的初始化Run() 服务端的运行服务端启动及测试 简单的UDP网络程序客户端服务端客户端相互通信测试服务端通过传入命令处理实现远程命令执行参考代码 Socket常…

STM32————串口发送和接收数据包

首先进行实验&#xff0c;对于代码在上一节的基础上&#xff0c;先定义新变量以及增加一个发送数据包函数&#xff1a; 本代码设置FF为包头&#xff0c;FE为包尾&#xff0c;中间为需要传输的数据&#xff0c;一次为4个&#xff0c;之后是接收数据包的函数 当标志位为1代表接收…

SpringBoot+Vue实现大文件上传(分片上传)

SpringBootVue实现大文件上传&#xff08;分片上传&#xff09; 1 环境 SpringBoot 3.2.1&#xff0c;Vue 2&#xff0c;ElementUI 2 问题 前几篇文章&#xff0c;可以用于较小文件的上传&#xff0c;对于较大文件来说&#xff0c;为了提高上传效率和可靠性&#xff0c;可以采…

LeetCode题练习与总结:二叉树的右视图--199

一、题目描述 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,4]示例 2: 输入: [1,null,3] 输出: [1,3]示例 3: 输入: [] 输出…

判别回形针的方向(clip.hdev)

1.1应用示例思路 (1) 利用Blob分析(一般步骤&#xff1a;图像阈值分割、获取连通区域、计算Blob的相关几何特征)&#xff0c;获取目标区域。 (2) 求目标区域的中心坐标和方向。 1.2应用实例代码 * clip.hdev: Orientation of clips*是否必须在活动的图形窗口中显示图标对象…

“论面向服务架构设计及其应用”写作框架,软考高级,系统架构设计师

论文真题 面向服务架构&#xff08;Service-Oriented Architecture, SOA&#xff09; 是一种应用框架&#xff0c;将日常的业务应用划分为单独的业务功能服务和流程&#xff0c;通过采用良好定义的接口和标准协议将这些服务关联起来。通过实施基于SOA的系统架构&#xff0c;用…

GPT-5 惊涛来袭:铸就智能新传奇

目录 引言&#xff1a; 正文&#xff1a; 方向一&#xff1a;人工智能发展现状 方向二&#xff1a;GPT-5技术突破预测 方向三&#xff1a;智能系统人类协作 方向四&#xff1a;迎接AI技术变革策略 结束语&#xff1a; 引言&#xff1a; 在科技浩渺浪潮澎湃翻涌的时代&…

ThinkPHP5 5.0.23 远程代码执行漏洞

目录 1、启动环境 2、漏洞利用 3、更改传参方式 4、修改参数 5、发送数据 1、启动环境 docker-compose up -d 2、访问靶机ip端口号8080 2、漏洞利用 使用burpsuite抓包软件抓包 3、更改传参方式 将 GET传参改为POST传参 4、修改参数 url参数 /index.php?scaptcha post参…

聚星文社,绘唐科技AI工具

聚星文社是一个文学创作社区&#xff0c;为广大创作者提供了一个交流和展示作品的平台。绘唐科技是一家AI技术公司&#xff0c;专注于开发人工智能工具和解决方案。绘唐科技与聚星文社合作&#xff0c;为聚星文社的创作者提供了一款AI工具&#xff0c;帮助创作者提升创作效率和…

ES+FileBeat+Kibana日志采集搭建体验

1.环境准备 需要linux操作系统&#xff0c;并安装了docker环境 此处使用虚拟机演示。&#xff08;虚拟机和docker看参考我之前写的文章&#xff09; VirtualBox安装Oracle Linux 7.9全流程-CSDN博客 VirtualBox上的Oracle Linux虚拟机安装Docker全流程-CSDN博客 简单演示搭建ES…

高可用集群keepalived 详细讲解

一&#xff1a;高可用集群keepalived LB&#xff1a;Load Balance 负载均衡 负载均衡&#xff0c;其含义就是指将负载&#xff08;工作任务&#xff09;进行平衡、分摊到多个操作单元上进行运行&#xff0c;例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器…

git详细命令

git常用命令&#xff0c;待 1. 前言2. Git安装3. 公钥3.1 生成公钥3.2 配置SSH 密钥 4. 配置用户名和邮箱5. git常用命令5.1 创建仓库命令5.1.1 git init命令5.1.2 git clone[url] 命令 5.2 add 增加 / 删除文件 &#xff08;跟踪文件&#xff09;5.3 代码提交5.4 分支5.5 标签…

性能优化理论篇 | Cache VS Buffer,傻傻分不清 ?

性能优化系列目录&#xff1a; 性能优化理论篇 | 彻底弄懂系统平均负载 性能优化理论篇 | swap area是个什么东西 从free命令开始 free 命令是一个在类 Unix 操作系统中用于显示内存使用情况的工具。它的输出包含了系统内存的不同方面&#xff0c;如总内存、已用内存、空闲内存…