C++实现设计模式---享元模式 (Flyweight)

news/2025/1/17 19:38:22/

享元模式 (Flyweight)

享元模式 是一种结构型设计模式,它通过共享对象来减少内存使用和对象创建的开销。当系统中有大量相似对象时,享元模式可以避免重复创建相同对象,从而节省内存。


意图

  • 通过共享相同对象来减少内存消耗。
  • 用于系统中存在大量相似对象的场景。

使用场景

  1. 大量相似对象

    • 系统中存在许多共享的对象,这些对象的状态大部分是相同的。
  2. 状态可以分为内部状态和外部状态

    • 内部状态:可以被共享的部分,不会随上下文变化。
    • 外部状态:特定于场景的部分,不可共享,需要由客户端管理。
  3. 节约内存

    • 系统需要大量创建对象,但内存开销成为瓶颈。

参与者角色

  1. 享元接口 (Flyweight)

    • 定义共享对象的公共接口。
  2. 具体享元 (ConcreteFlyweight)

    • 实现享元接口,存储可以共享的内部状态。
  3. 非共享享元 (UnsharedFlyweight)

    • 不可以共享的子类,通常会组合共享的享元对象。
  4. 享元工厂 (FlyweightFactory)

    • 创建并管理享元对象,确保共享对象的唯一性。
  5. 客户端 (Client)

    • 负责管理外部状态,并将外部状态与享元对象结合使用。

示例代码

以下代码展示了如何使用享元模式来共享图形对象,例如圆形。

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>// 享元接口:图形
class Shape {
public:virtual ~Shape() = default;virtual void draw(const std::string& color) const = 0; // 外部状态为颜色
};// 具体享元类:圆形
class Circle : public Shape {
private:int radius; // 内部状态:半径public:Circle(int r) : radius(r) {}void draw(const std::string& color) const override {std::cout << "Drawing a circle with radius " << radius << " and color " << color << std::endl;}
};// 享元工厂:管理享元对象
class ShapeFactory {
private:std::unordered_map<int, std::shared_ptr<Shape>> shapes; // 缓存共享对象public:std::shared_ptr<Shape> getCircle(int radius) {if (shapes.find(radius) == shapes.end()) {shapes[radius] = std::make_shared<Circle>(radius);std::cout << "Creating a circle with radius " << radius << std::endl;}return shapes[radius];}
};// 客户端代码
int main() {ShapeFactory factory;// 获取共享的圆形对象auto circle1 = factory.getCircle(5);auto circle2 = factory.getCircle(10);auto circle3 = factory.getCircle(5); // 共享对象// 使用享元对象绘制circle1->draw("red");   // 外部状态:红色circle2->draw("blue");  // 外部状态:蓝色circle3->draw("green"); // 外部状态:绿色return 0;
}

代码解析

1. 享元接口 (Shape)
  • 定义了 draw 方法,用于绘制图形,并接收外部状态作为参数:
class Shape {
public:virtual ~Shape() = default;virtual void draw(const std::string& color) const = 0;
};
2. 具体享元类 (Circle)
  • 实现了 Shape 接口,存储可以共享的内部状态(如半径):
class Circle : public Shape {
private:int radius; // 内部状态public:Circle(int r) : radius(r) {}void draw(const std::string& color) const override {std::cout << "Drawing a circle with radius " << radius << " and color " << color << std::endl;}
};
3. 享元工厂 (ShapeFactory)
  • 负责管理享元对象,保证相同的内部状态只创建一个对象:
class ShapeFactory {
private:std::unordered_map<int, std::shared_ptr<Shape>> shapes; // 缓存共享对象public:std::shared_ptr<Shape> getCircle(int radius) {if (shapes.find(radius) == shapes.end()) {shapes[radius] = std::make_shared<Circle>(radius);std::cout << "Creating a circle with radius " << radius << std::endl;}return shapes[radius];}
};
4. 客户端
  • 客户端通过 ShapeFactory 获取共享对象,并将外部状态与内部状态结合:
auto circle1 = factory.getCircle(5); // 创建新对象
auto circle3 = factory.getCircle(5); // 复用已有对象
circle1->draw("red");   // 绘制红色圆形
circle3->draw("green"); // 绘制绿色圆形

优缺点

优点
  1. 减少内存使用
    • 通过共享对象,避免了重复创建相同对象,节省了内存。
  2. 提高系统性能
    • 减少了对象创建的时间和空间开销。
  3. 灵活性高
    • 外部状态与内部状态分离,可以独立管理。
缺点
  1. 复杂性增加
    • 系统需要额外的享元工厂来管理共享对象。
  2. 外部状态的管理困难
    • 客户端需要显式传递外部状态,增加了使用复杂性。

适用场景

  1. 系统有大量相似对象

    • 如文字处理系统中的字符对象,每个字符对象可以共享其字体、大小等内部状态。
  2. 内存消耗成为瓶颈

    • 系统中对象数量庞大,通过共享来减少内存占用。
  3. 对象的状态可以分为内部状态和外部状态

    • 内部状态可以共享,外部状态由客户端管理。

总结

享元模式通过共享相似对象来减少内存使用,是一种优化性能的重要模式。它适用于对象数量庞大且状态大部分可以共享的场景。


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

相关文章

排序算法(C语言版)

直接插入排序 #include<stdio.h> #include<stdlib.h> #define MAXSIZE 100 //定义顺序表结构体 typedef struct { int key;//这里可以根据实际需求添加其他数据成员 }RedType; typedef struct { RedType r[MAXSIZE 1];//r[0]闲置或用作哨兵 int length; }…

Swift语言的数据库编程

Swift语言的数据库编程 引言 在现代应用程序的开发中&#xff0c;数据的存储和管理是一个至关重要的环节。无论是移动应用、Web服务还是桌面软件&#xff0c;数据库都扮演着数据存储和检索的核心角色。随着Swift语言在iOS和macOS开发中的普及&#xff0c;越来越多的开发者开始…

mobaxterm内置编辑器中文出现乱码如何解决:直接更换编辑器为本地编辑器

诸神缄默不语-个人CSDN博文目录 使用场景是我需要用mobaxterm通过SSH的方式登录服务器&#xff0c;进入服务器之后我就直接打开代码文件&#xff0c;mobaxterm会直接用内置的编辑器&#xff08;MobaTextEditor&#xff09;打开&#xff0c;但这会导致中文编程乱码。 我一开始是…

【Mysql进阶知识】Mysql 程序的介绍、选项在命令行配置文件的使用、选项在配置文件中的语法

目录 一、程序介绍 二、mysqld--mysql服务器介绍 三、mysql - MySQL 命令行客户端 3.1 客户端介绍 3.2 mysql 客户端选项 指定选项的方式 mysql 客户端命令常用选项 在命令行中使用选项 选项(配置)文件 使用方法 选项文件位置及加载顺序 选项文件语法 使用举例&am…

Conda的一些常用命令

以下是Conda的一些常用命令&#xff1a; pip freeze > requirements.txt pip install -r requirements.txt 基本信息查看类 查看conda版本&#xff1a; conda -V 或 conda --version 可以查看当前安装的conda版本。 查看conda帮助信息&#xff1a; conda -h 或 conda --he…

第九章:演示文稿软件PPT

文章目录&#xff1a; 一&#xff1a;界面 1.介绍 2.选项卡 2.1 开始 2.2 插入 2.3 设计 2.4 切换 2.5 动画 2.6 放映 2.7 审阅 2.8 视图 2.9 音频工具 2.10 视频工具 二&#xff1a;基础 三&#xff1a;设计 1.静态 2.动态 四&#xff1a;放映 一&#xff1…

Linux——信号的创建、保存和处理

Linux——进程信号-CSDN博客 文章目录 目录 文章目录 前言 一、创建进程的信号 1、键盘输入方式 2、系统接口 3、指令获得信号 4、硬件异常产生信号 5、软件条件产生信号 二、信号的保存 1、pending表 2、阻塞信号&#xff08;block位图表&#xff09; 信号集&#xff1a;&…

使用vnstat监控网络流量和带宽占用

使用vnstat监控网络流量和带宽占用 简介 vnstat是个Linux下基于shell终端的网络流量监控工具&#xff0c;可帮助用户在不同时间段内监视&#xff0c;记录和查看网络统计信息。它提供了各种网络接口的汇总&#xff0c;允许用户以详细表或命令行统计视图的形式查看小时&#xf…