设计模式——装饰模式

news/2024/12/29 9:14:15/

文章目录

  • 1.定义
  • 2. 结构组成
  • 3. 组合模式结构
  • 4. 示例代码
  • 5. 模式优势
  • 6. 应用场景

1.定义

装饰模式就像是给你的对象穿上不同的 “时尚服装”,在程序运行时,你可以随意地给对象搭配各种 “服装” 来增加新的功能,而且完全不用对对象本身的 “身材”(类结构)进行修改。这是一种很巧妙的设计模式,能够让对象在不改变自身本质的情况下,变得更加 “华丽”。

2. 结构组成

  • Component(组件):
    • 这就好比是一个标准的 “衣架”,它定义了所有可以被装饰的对象的基本 “穿搭风格”(行为)。在装饰模式里,这个 “衣架” 接口有一个 “execute ()” 方法,这就像是所有衣服(具体组件和装饰器)都要能挂在这个衣架上的基本要求。
  • Concrete Component(具体组件):
    • 这是一件最基础的 “衣服”,它按照 “衣架”(Component)的标准制作出来,提供了最基础的 “穿搭效果”(实现了 “execute ()” 方法),代表了对象最原始的功能。
  • Base Decorator(基础装饰器):
    • 这是一个特别的 “衣架外套”,它本身也是按照 “衣架” 的标准制作的(实现了 Component 接口)。它里面还藏着一个对其他 “衣服”(Component 对象)的引用,当你穿上这个 “衣架外套” 时,它会把里面的 “衣服” 也展示出来(在其 “execute ()” 方法中调用 “wrappee” 的 “execute ()” 方法)。
  • Concrete Decorators(具体装饰器):
    • 这些就像是各种各样的 “时尚配饰”,它们都继承自 “衣架外套”(Base Decorator)。当你把这些 “配饰” 挂在 “衣架” 上时,它们可以在展示里面 “衣服”(调用被装饰对象的方法)的前后,添加一些额外的 “时尚元素”(额外的行为)。

3. 组合模式结构

在这里插入图片描述

  • 创建基础对象:就像你要开始搭配穿搭一样,首先你有了一件基础的 “衣服”(客户端创建一个具体组件对象,例如a = new ConcComponent()),这是最基础的穿搭风格。
  • 添加装饰器:接着,你可以给这件基础 “衣服” 搭配上一件 “衣架外套”,比如 “时尚配饰 1”(b = new ConcDecorator1(a),这里 “ConcDecorator1” 是一个具体装饰器,它包装了基础对象 “a”)。
    你还可以继续在外面添加更多的 “时尚配饰”,像 “时尚配饰 2”(c = new ConcDecorator2(b),这里 “ConcDecorator2” 又包装了 “b”,形成了一个装饰器链),让你的穿搭变得更加独特。
  • 执行操作: 最后,当你穿上这套精心搭配的 “衣服”(调用最外层装饰器的 “execute ()” 方法,如c.execute())时,会按照从外到内的顺序展示出每一件 “衣服” 和 “配饰” 的效果:
    • 首先,“时尚配饰 2”(“ConcDecorator2”)会展示它的 “时尚元素”,它可能会在展示里面 “衣服”(调用被装饰对象 “b” 的方法)之前或之后添加一些独特的风格。
    • 然后,“时尚配饰 1”(“ConcDecorator1”)也会展示它的特色,同样可能添加额外的时尚效果。
    • 最后,基础的 “衣服”(“a”)的效果会被展示出来,完成整个 “时尚穿搭秀”(操作)。

4. 示例代码


#include <iostream>
#include <memory>using namespace std;class Component{
public:Component(){cout << "Component Constructor " <<endl;}   virtual ~Component(){cout << "Component Destructor " <<endl;}   virtual string Operation() const = 0;
};class ConcreteComponent : public Component{
public:ConcreteComponent(){cout << "ConcreteComponent Constructor " <<endl;}   ~ConcreteComponent(){cout << "ConcreteComponent Destructor " <<endl;}string Operation() const override{return "ConcreteComponent";}
};class Decorator : public Component{
protected:shared_ptr<Component> component_;
public:Decorator(shared_ptr<Component> component) : component_ (component){cout << "Decorator Constructor " <<endl;}   ~Decorator(){cout << "Decorator Destructor " <<endl;}string Operation() const override{return component_->Operation();}
};class ConcreteDecoratorA : public Decorator{
public:ConcreteDecoratorA(shared_ptr<Component> component) : Decorator (component){cout << "ConcreteDecoratorA Constructor " <<endl;}   ~ConcreteDecoratorA(){cout << "ConcreteDecoratorA Destructor " <<endl;}string Operation() const override{return "ConcreteDecoratorA(" + Decorator::Operation() + ")";}
};class ConcreteDecoratorB : public Decorator{
public:ConcreteDecoratorB(shared_ptr<Component> component) : Decorator(component){cout << "ConcreteDecoratorB Constructor " <<endl;}   ~ConcreteDecoratorB(){cout << "ConcreteDecoratorB Destructor " <<endl;}string Operation() const override{return "ConcreteDecoratorB(" + Decorator::Operation() + ")";}
};void ClientCode(shared_ptr<Component> component){cout<< component->Operation() <<endl;
}int main()
{shared_ptr<Component> simple = make_shared<ConcreteComponent>();cout << "Client: I've got a simple component:\n";ClientCode(simple);cout << "\n\n";shared_ptr<Component> decorator1 = make_shared<ConcreteDecoratorA>(simple);shared_ptr<Component> decorator2 = make_shared<ConcreteDecoratorB>(decorator1);cout << "Client: Now I've got a decorated component:\n";ClientCode(decorator2);std::cout << "\n";return 0;
}

5. 模式优势

  • 灵活性高
    • 这种模式就像你的时尚穿搭可以随时变化一样,在程序运行时,你可以动态地给对象添加或移除各种 “时尚元素”(功能),完全不用改变对象本身的 “身材”(结构)。比如,你可以根据当天的心情或者场合,随意地给对象搭配不同的功能。
  • 可扩展性好
    • 当你想要一种新的 “时尚风格”(功能)时,只需要轻松地设计一个新的 “时尚配饰”(装饰器)就可以了,完全符合程序设计中的 “开闭原则”。这就好比你想要一种新的穿搭风格,只需要买一个新的配饰,而不用重新设计一件衣服。
  • 复用性强
    • 无论是基础的 “衣服”(组件)还是各种 “时尚配饰”(装饰器),都可以被重复使用,大大减少了代码的重复。就像你可以用同一件基础衣服搭配不同的配饰,或者把同一个配饰用在不同的穿搭上。

6. 应用场景

  • 动态添加功能
    • 当你在程序中需要像在穿搭中根据心情或场合动态地给对象添加新功能时,装饰模式就非常有用了。例如,在图形用户界面(GUI)中,你可以像给窗口搭配不同的 “时尚元素” 一样,给窗口添加边框、滚动条等装饰。
  • 避免类爆炸
    • 当你发现如果用传统的继承方式来给对象添加功能,会导致像衣柜里堆满了各种相似但又略有不同的衣服一样(类爆炸),装饰模式就可以通过像搭配穿搭一样的组合方式来替代继承,更加灵活地扩展功能。
  • 多特性组合
    • 当你有很多像时尚配饰一样的特性需要组合到一个对象上,而且这些特性可以像穿搭一样动态地添加或移除时,装饰模式就派上用场了。比如在咖啡制作系统中,咖啡就像基础的衣服,而糖、奶、巧克力等配料就像各种时尚配饰,每种配料都可以看作是一个装饰器,你可以根据自己的口味随意搭配。

http://www.ppmy.cn/news/1559034.html

相关文章

PyAudio库基本知识详解——为自制PCM音频播放器做准备

前言 结合前段时间我们做的音频编解码器&#xff0c;这样我们就可以将获取到的ADPCM数据&#xff0c;转换成PCM数据&#xff0c;然后播放出来&#xff0c;得到一个完整的音频数据&#xff0c;因此&#xff0c;接下来几篇文章中&#xff0c;我们想做一个播放PCM格式的音频播放器…

嵌入式硬件面试题

1、请问什么是通孔、盲孔和埋孔&#xff1f;孔径多大可以做机械孔&#xff0c;孔径多小必须做激光孔&#xff1f;请问激光微型孔可以直接打在元件焊盘上吗&#xff0c;为什么&#xff1f; 通孔是贯穿整个PCB的过孔&#xff0c;盲孔是从PCB表层连接到内层的过孔&#xff0c;埋孔…

路由器RIP动态路由配置

路由器RIP动态路由配置 目录 实验目的 实验背景 技术原理 配置RIP动态路由的一般步骤 学习任务 实验设备 实验拓扑 实验步骤 实验目的 掌握RIP协议的配置方法&#xff1a;掌握查看通过动态路由协议RIP学习产生的路由&#xff1b;熟悉广域网线缆的链接方式&#xff1b;…

xdoj 分别计算奇数和偶数之和

问题描述 接受用户输入的正整数 n&#xff0c;用程序实现 1 到正整数 n 之间的奇数和偶数之和。 输入说明 正整数 n 输出说明 分别输出 1 到 n 之间的奇数和偶数之和&#xff08;第一个数为奇数之和&#xff0c;第二个数为偶数之和&#xff0c;两个 数之间用空格间隔&…

Word论文交叉引用一键上标

Word论文交叉引用一键上标 1.进入Microsoft word使用CtrlH快捷键或单击替换按钮 2.在查找内容中输入[^#] 3.鼠标点击&#xff0c;标签为“替换为&#xff1a;”的文本框&#xff0c;注意光标一定要打在图红色方框圈中的文本框中&#xff01; 4.点击格式选择字体 5.勾选上标…

突发!GitLab(国际版)将停止对中国区用户提供 GitLab.com 账号服务

消息称&#xff1a; 目前&#xff0c;为了更加严格的遵循中国网络数据安全管理的相关要求&#xff0c;GitLab SaaS&#xff08;国际版&#xff09;已逐步停止向国内用户提供服务与支持&#xff0c;国内用户亦无法注册或使用 GitLab SaaS&#xff08;国际版&#xff09;。自您的…

什么是数据库的锁?怎么实现?

数据库的锁是数据库管理系统&#xff08;DBMS&#xff09;用来控制多个并发事务访问共享数据的一种机制。它通过限制对数据的访问&#xff0c;确保在并发环境下数据的完整性和一致性。锁的主要目的是防止多个事务在同一时间对相同的数据进行修改&#xff0c;避免出现数据冲突和…

Linux(Centos 7.6)目录结构详解

Linux(Centos 7.6)是一个操作系统&#xff0c;其核心设计理念是将一切资源抽象为文件&#xff0c;即一切皆文件。比如系统中的硬件设备硬盘、网络接口等都被视为文件。Windows系统一般是分为C、D、E盘。而Linux(Centos 7.6)是以斜线"/"作为文件系统的开始目录&#x…