【第十节】C++设计模式(结构型模式)-Flyweight( 享元)模式

news2025/2/28 23:23:42

目录

一、问题背景

二、模式选择

三、代码实现

四、总结讨论


一、问题背景

        享元模式(Flyweight Pattern)在对象存储优化中的应用

        在面向对象系统的设计与实现中,创建对象是最常见的操作之一。然而,如果一个应用程序使用了过多的对象,尤其是大量轻量级(细粒度)的对象,可能会导致巨大的存储开销。例如,在文档编辑器的设计中,如果为每个字母创建一个独立的对象,系统中可能会出现大量重复的对象,从而造成存储浪费。例如,字母“a”在文档中可能出现 100,000 次,实际上这 100,000 个“a”可以共享同一个对象。

        然而,由于不同位置的字母“a”可能有不同的显示效果(如字体、大小等),我们可以将对象的状态分为“内部状态”和“外部状态”。内部状态是对象共享的、不变的部分,而外部状态则可以在需要时作为参数传递给对象(例如在显示时传递字体、大小等信息)。

二、模式选择

        上述问题可以通过**享元模式(Flyweight Pattern)**来解决。享元模式的核心思想是通过共享大量细粒度对象来减少存储开销。其典型结构如下:

        FlyweightFactory:类似于工厂模式的对象构造工厂,用于管理对象的创建和共享。
        Flyweight:享元对象的基类,定义了内部状态和外部状态的处理方式。
        ConcreteFlyweight:具体的享元对象实现,包含内部状态。

三、代码实现

        以下是享元模式的完整实现代码,采用 C++ 编写。

代码片段 1:Flyweight.h

#ifndef _FLYWEIGHT_H_
#define _FLYWEIGHT_H_

#include <string>
using namespace std;

class Flyweight {
public:
    virtual ~Flyweight();
    virtual void Operation(const string& extrinsicState); // 外部状态的处理
    string GetIntrinsicState(); // 获取内部状态
protected:
    Flyweight(string intrinsicState); // 构造函数,初始化内部状态
private:
    string _intrinsicState; // 内部状态
};

class ConcreteFlyweight : public Flyweight {
public:
    ConcreteFlyweight(string intrinsicState); // 构造函数
    ~ConcreteFlyweight();
    void Operation(const string& extrinsicState); // 外部状态的处理
};

#endif //~_FLYWEIGHT_H_

代码片段 2:Flyweight.cpp

#include "Flyweight.h"
#include <iostream>
using namespace std;

Flyweight::Flyweight(string intrinsicState) {
    this->_intrinsicState = intrinsicState;
}

Flyweight::~Flyweight() {}

void Flyweight::Operation(const string& extrinsicState) {
    // 默认实现为空
}

string Flyweight::GetIntrinsicState() {
    return this->_intrinsicState;
}

ConcreteFlyweight::ConcreteFlyweight(string intrinsicState) : Flyweight(intrinsicState) {
    cout << "ConcreteFlyweight Build....." << intrinsicState << endl;
}

ConcreteFlyweight::~ConcreteFlyweight() {}

void ConcreteFlyweight::Operation(const string& extrinsicState) {
    cout << "ConcreteFlyweight: 内蕴 [" << this->GetIntrinsicState() << "] 外蕴 [" << extrinsicState << "]" << endl;
}

代码片段 3:FlyweightFactory.h

#ifndef _FLYWEIGHTFACTORY_H_
#define _FLYWEIGHTFACTORY_H_

#include "Flyweight.h"
#include <string>
#include <vector>
using namespace std;

class FlyweightFactory {
public:
    FlyweightFactory();
    ~FlyweightFactory();
    Flyweight* GetFlyweight(const string& key); // 获取享元对象
protected:
private:
    vector<Flyweight*> _fly; // 对象池
};

#endif //~_FLYWEIGHTFACTORY_H_

代码片段 4:FlyweightFactory.cpp

#include "FlyweightFactory.h"
#include <iostream>
#include <cassert>
using namespace std;

FlyweightFactory::FlyweightFactory() {}

FlyweightFactory::~FlyweightFactory() {}

Flyweight* FlyweightFactory::GetFlyweight(const string& key) {
    vector<Flyweight*>::iterator it = _fly.begin();
    for (; it != _fly.end(); it++) {
        // 如果对象已存在,则直接返回
        if ((*it)->GetIntrinsicState() == key) {
            cout << "already created by users...." << endl;
            return *it;
        }
    }
    // 否则创建新对象并加入对象池
    Flyweight* fn = new ConcreteFlyweight(key);
    _fly.push_back(fn);
    return fn;
}

代码片段 5:main.cpp

#include "Flyweight.h"
#include "FlyweightFactory.h"
#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
    FlyweightFactory* fc = new FlyweightFactory();
    Flyweight* fw1 = fc->GetFlyweight("hello"); // 获取享元对象
    Flyweight* fw2 = fc->GetFlyweight("world!"); // 获取享元对象
    Flyweight* fw3 = fc->GetFlyweight("hello"); // 获取享元对象
    return 0;
}

代码说明

        享元模式在实现过程中,主要是为共享对象提供一个存放的“仓库”(对象池)。这里通过 C++ STL 中的 `vector` 容器来实现对象池的管理。需要注意的是,对象池的管理策略(查找、插入等)对性能有很大影响。这里使用了简单的顺序遍历来查找对象,但实际应用中可以使用更高效的索引策略,例如哈希表。

四、总结讨论

        享元模式通过共享细粒度对象,有效地减少了系统中的对象数量,从而降低了存储开销。它特别适用于需要创建大量相似对象的场景,如文档编辑器、游戏中的粒子系统等。通过合理使用享元模式,可以显著提高系统的性能和资源利用率。

        在以后讲到的状态模式(State Pattern)和策略模式(Strategy Pattern)中,可能会产生大量的对象,因此可以通过享元模式来优化存储开销。享元模式的核心思想是共享对象,从而减少系统中对象的数量,降低存储和计算资源的消耗。

参考学习:设计模式精解-GoF 23 种设计模式解析

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

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

相关文章

AORO M6北斗短报文终端:将“太空黑科技”转化为安全保障

在卫星导航领域&#xff0c;北斗系统作为我国自主研发的全球卫星导航系统&#xff0c;正以其独特的短报文通信功能引发全球范围内的广泛关注。这一突破性技术不仅使北斗系统在全球四大导航系统中独树一帜&#xff0c;具备了双向通信能力&#xff0c;更通过遨游通讯推出的AORO M…

深度生成模型(二)——基本概念与数学建模

上一篇笔记中提到了端到端模型底层核心采用了深度生成模型&#xff0c;先简单梳理一下 生成式人工智能&#xff08;Artificial Intelligence Generated Content&#xff0c;AIGC&#xff09;经历了从早期基于概率模型和规则系统的方法到现代深度生成模型的跨越式发展 深度神经…

Mac本地部署Deep Seek R1

Mac本地部署Deep Seek R1 1.安装本地部署大型语言模型的工具 ollama 官网&#xff1a;https://ollama.com/ 2.下载Deepseek R1模型 网址&#xff1a;https://ollama.com/library/deepseek-r1 根据电脑配置&#xff0c;选择模型。 我的电脑&#xff1a;Mac M3 24G内存。 这…

项目——仿RabbitMQ实现消息队列

1.项目介绍 曾经在学习Linux的过程中&#xff0c;我们学习过阻塞队列 (BlockingQueue) 。 当时我们说阻塞队列最大的用途, 就是用来实现生产者消费者模型。 生产者消费者模型是后端开发的常用编程方式&#xff0c; 它存在诸多好处&#xff1a; 解耦合支持并发支持忙闲不均削峰…

【nextjs官方demo】Chapter 6连接数据库报错

问题&#xff1a;跟着demo创建完成postgres数据库&#xff0c;并修改了env文件&#xff0c;需要访问/seed去初始化数据的时候&#xff1a; 报错信息如下&#xff0c;看信息就是bcrypt模块有问题&#xff1a; 排除了你的环境问题后&#xff0c;就看下面这句话&#xff1a; 它的…

Nginx的反向代理(超详细)

正向代理与反向代理概念 1.概念&#xff1a; 反向代理服务器位于用户与目标服务器之间&#xff0c;但对用户而言&#xff0c;反向代理服务器就相当于目标服务器&#xff0c;即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时&#xff0c;用户不需要知道目标服务…

Plantsimulation中机器人怎么通过阻塞角度设置旋转135°

创建一个这样的简单模型。 检查PickAndPlace的角度表。源位于180的角位置&#xff0c;而物料终结位于90的角位置。“返回默认位置”选项未被勾选。源每分钟生成一个零件。启动模拟时&#xff0c;Plant Simulation会选择两个位置之间的最短路径。示例中的机器人无法绕135的角位…

Docker数据卷容器实战

数据卷容器 数据共享 上面讲述的是主机和容器之间共享数据&#xff0c;那么如何实现容器和容器之间的共享数据呢&#xff1f;那就是创建 创建数据卷容器。 命名的容器挂载数据卷&#xff0c;其他容器通过挂载这个&#xff08;父容器&#xff09;实现数据共享&#xff0c;挂载…

【Rust中级教程】2.13. 结语(杂谈):我学习Rust的心路历程

2.13.1. 【Rust自学】专栏的缘起 笔者我在去年12月份之前对Rust还一无所知&#xff0c;后来看到JetBrains推出了Rust Rover&#xff0c;想着自己毕竟是买的全产品证书就下载下来玩了一下。原本就是看看&#xff0c;都打算卸载了&#xff0c;后来去网上查才发现Rust这门语言挺牛…

【备赛】点亮LED

LED部分的原理图 led前面有锁存器&#xff0c;这是为了防止led会受到lcd的干扰&#xff08;lcd也需要用到这些引脚&#xff09;。 每次想要对led操作&#xff0c;就需要先打开锁存器&#xff0c;再执行操作&#xff0c;最后关闭锁存器。 这里需要注意的是&#xff0c;引脚配置…

cpp中的继承

一、继承概念 在cpp中&#xff0c;封装、继承、多态是面向对象的三大特性。这里的继承就是允许已经存在的类&#xff08;也就是基类&#xff09;的基础上创建新类&#xff08;派生类或者子类&#xff09;&#xff0c;从而实现代码的复用。 如上图所示&#xff0c;Person是基类&…

[Java基础] JVM常量池介绍(BeanUtils.copyProperties(source, target)中的属性值引用的是同一个对象吗)

文章目录 1. JVM内存模型2. 常量池中有什么类型&#xff1f;3. 常量池中真正存储的内容是什么4. 判断一个字符串(引用)是否在常量池中5. BeanUtils.copyProperties(source, target)中的属性值引用的是同一个对象吗&#xff1f;6. 获取堆内存使用情况、非堆内存使用情况 1. JVM内…

NocoBase 本周更新汇总:新增路由管理

汇总一周产品更新日志&#xff0c;最新发布可以前往我们的博客查看。 NocoBase 目前更新包括的版本更新包括三个分支&#xff1a;main &#xff0c;next和 develop。 main &#xff1a;截止目前最稳定的版本&#xff0c;推荐安装此版本。 next&#xff1a;包含即将发布的新功…

【数据结构】(12) 反射、枚举、lambda 表达式

一、反射 1、反射机制定义及作用 反射是允许程序在运行时检查和操作类、方法、属性等的机制&#xff0c;能够动态地获取信息、调用方法等。换句话说&#xff0c;在编写程序时&#xff0c;不需要知道要操作的类的具体信息&#xff0c;而是在程序运行时获取和使用。 2、反射机制…

ONES 功能上新|ONES Copilot、ONES Project 新功能一览

ONES Copilot 智能 AI 助手模型可配置多种类型模型&#xff0c;服务提供方 Dashscope 的模型列表中新增 DeepSeek V3 与 DeepSeek R1&#xff1b;选择自定义模型配置时&#xff0c;填写私有部署的 DeepSeek 模型相关参数即可。 应用场景&#xff1a; 企业内部自部署或在模型服务…

STM32寄存器控制引脚高低电平

一. 引子 最近在学习32代码的过程当中&#xff0c;虽然在学习IMX6ULL开发板的过程中接触过很多寄存器&#xff0c;最近在返回去看32的时候&#xff0c;在研究代码的时候发现自己对于寄存器的有些特性理解的不够深刻&#xff0c;所以下来的时候去查了资料&#xff0c;以及问了一…

SOC-ATF 安全启动BL1流程分析(1)

一、ATF 源码下载链接 1. ARM Trusted Firmware (ATF) 官方 GitHub 仓库 GitHub 地址: https://github.com/ARM-software/arm-trusted-firmware 这是 ATF 的官方源码仓库&#xff0c;包含最新的代码、文档和示例。 下载方式&#xff1a; 使用 Git 克隆仓库&#xff1a; git…

TDesign:Cascader 级联选择器(省市区三级联动)

Cascader 级联选择器API 参考官方示例代码 在自己的模板中使用&#xff1a;view import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import package:get/get.dart; import package:tdesign_flutter/tdesign_flutter.dart;import i…

linux中安装部署Jenkins,成功构建springboot项目详细教程

参考别人配置Jenkins的git地址为https&#xff0c;无法连上github拉取项目&#xff0c;所以本章节介绍通过配置SSH地址来连github拉取项目 目录&#xff1a; 1、springboot项目 1.1 创建名为springcloudproject的springboot项目工程 1.2 已将工程上传到github中&#xff0c;g…

2025系统架构师(一考就过):案例之四:架构复用、架构评估、特定架构(DSSA)、架构开发方法(ABSD)

二、软件架构复用 ◆软件产品线是指一组软件密集型系统&#xff0c;它们共享一个公共的、可管理的特性集&#xff0c;满足某个特定市场或任务的具体需要&#xff0c;是以规定的方式用公共的核心资产集成开发出来的。即围绕核心资产库进行管理复用、集成新的系统。 ◆软件架构…