设计模式之装饰器模式(C++)

简介: 设计模式之装饰器模式(C++)

一、装饰器模式是什么?

      装饰器模式是一种结构型的软件设计模式,在不改变原类文件或使用继承的前提下,动态地扩展一个对象,进而达到增强或者增加对象功能的目的。


      装饰器模式的优点:


  1. 灵活性好。相比较继承,装饰模式扩展对象功能更加灵活。
  2. 扩展性好。不同装饰组合,可以创造出各式各样的对象,且避免了类爆炸。
  3. 满足设计模式要求的开闭原则和合成复用原则。
  4. 透明性好。客户端针对抽象操作,对具体实现的内容不可见。

     装饰器模式的缺点:


  1. 复杂性高。装饰模式的设计往往具备较高复杂度,对开发者的水平要求高。


二、装饰器模式

2.1 结构图

      客户端即Main主函数,装饰器和具体构件有共同接口-抽象构件,因此客户端可以给构件添加多层装饰;另外,装饰器中存放了一个抽象构件的指针,可以区分装饰前和装饰后的状态。

2.2 代码示例

      场景描述:我要炒菜,每个菜会有不同的调料添加方案(装饰)。

//Cooking.h
/****************************************************/
#pragma once
#include <iostream>
#include <list>
using namespace std;
// 抽象构件-烹饪
class Cooking
{
public:
  // 构造函数
  Cooking(string name = "") :m_name(name) {};
  // 析构函数
  virtual ~Cooking() {};
  // 获取名字
  virtual string getName() = 0;
protected:
  string m_name;
};
// 具体构件-红烧肉
class SoyBraisedPork :public Cooking
{
public:
  // 构造函数
  explicit SoyBraisedPork() :Cooking("红烧肉") {};
  // 析构函数
  virtual ~SoyBraisedPork() {};
  // 获取名字
  virtual string getName() {
    return m_name;
  }
};
//Seasoning.h
/****************************************************/
#pragma once
#include <iostream>
#include <list>
#include "Cooking.h"
using namespace std;
// 抽象调料
class Seasoning :public Cooking
{
public:
  // 构造函数
  Seasoning(Cooking *cooking){
    m_cooking = cooking;
  };
  // 析构函数
  virtual ~Seasoning() {
    cout << "开始析构。" << endl;
    if (m_cooking != nullptr) {
      cout << "地址:" << m_cooking << endl;
      delete m_cooking;
      m_cooking = nullptr;
    }
    cout << "结束析构。" << endl;
  };
protected:
  Cooking *m_cooking;
};
// 具体调料-盐
class Salt :public Seasoning
{
public:
  // 构造函数
  Salt(Cooking *cooking) :Seasoning(cooking) {};
  // 获取名字
  virtual string getName() {
    m_name = m_cooking->getName() + ",加盐";
    return m_name;
  }
};
// 具体调料-糖
class Sugar :public Seasoning
{
public:
  // 构造函数
  Sugar(Cooking *cooking) :Seasoning(cooking) {};
  // 获取名字
  virtual string getName() {
    m_name = m_cooking->getName() + ",加糖";
    return m_name;
  }
};
//main.cpp
/****************************************************/
#include <iostream>
#include <string>
#include "Seasoning.h"
using namespace std;
int main()
{
  Cooking *cook = new SoyBraisedPork();
  cout << "点菜:" << cook->getName() << endl;
  cout << "地址:" << cook << endl;
  cook = new Salt(cook);
  cout << "点菜:" << cook->getName() << endl;
  cout << "地址:" << cook << endl;
  cook = new Sugar(cook);
  cout << "点菜:" << cook->getName() << endl;
  cout << "地址:" << cook << endl;
  delete cook;
  cook = nullptr;
  return 0;
}

程序结果如下。

      有些同学可能会疑惑这种多层装饰的方法,会不会让new的内存没能释放掉。因此在上述示例中,我特地将每次装饰前的地址做了记录,用于复盘整个流程。其实只要在抽象装饰器中,对存放的抽象构件指针进行释放,即可确保没有内存泄漏。


      地址000001C529820910是Sugar后cook的地址,客户端中对它析构后,它释放的m_cooking其实和Salt同一内容,也就是000001C52981A3F0,所以析构先把这块释放了,释放它的时候,它里面也有一个m_cooking,这个就是起初红烧肉new出来的地址000001C529819510,因而又出现了开始析构的字样,红烧肉析构完就到底了,这样一套下来,你会发现所有new出来的内容都回收了。


      另外,上文介绍的装饰器模式也被成为透明装饰器,也是装饰器标准的样式,客户只操作抽象接口。除此之外,还有一种叫半透明式装饰器,它们的区别在于,半透明装饰器中某些行为是非常规的,这就使得它们无法用同一抽象接口进行迭代,进而无法进行多层装饰,所以在我个人看来,半透明装饰器不具备装饰器模式最特殊的多层装饰属性,文章也就不展开了,大家感兴趣的可以看看其他博主的文章。

三、总结

      我尽可能用较通俗的话语和直观的代码例程,来表述我对装饰器模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解装饰器模式。

      如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

相关文章
|
6月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
138 0
|
1月前
|
设计模式 XML Java
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
29 0
|
6月前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
63 1
|
2月前
|
设计模式 Java
Java设计模式-装饰器模式(10)
Java设计模式-装饰器模式(10)
|
4月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
42 3
|
4月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
54 2
|
6月前
|
设计模式 开发框架 算法
C++中的设计模式:基本概念与应用
C++中的设计模式:基本概念与应用
60 2
|
5月前
|
设计模式 Java
Java设计模式:深入装饰器模式的三种写法(六)
Java设计模式:深入装饰器模式的三种写法(六)
|
5月前
|
设计模式 架构师 安全
设计模式第五讲-装饰器模式和代理模式详解
远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
264 0
|
6月前
|
设计模式 传感器 数据处理
探索设计模式的魅力:为什么你应该了解装饰器模式-代码优化与重构的秘诀
装饰器模式是一种设计模式,它允许在运行时向对象添加额外的职责,而无需修改其代码。这种模式提供了一种动态扩展对象功能的方法,同时保持了对象的单一职责原则。本文介绍了装饰器模式的基本概念、原理、优势、适用场景、实现方法、最佳实践和注意事项。通过装饰器模式,可以将多个行为组合成一个更复杂的行为,而无需使用继承或大量的接口实现。装饰器模式适用于需要对一个对象进行一系列的增强处理的情况,而这些增强处理可以以一种松耦合的方式进行组合。通过使用装饰器模式,可以提高代码的可维护性、可扩展性和灵活性,使系统更加灵活和易于维护
121 1
探索设计模式的魅力:为什么你应该了解装饰器模式-代码优化与重构的秘诀