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

目录

一、问题背景

二、模式选择

三、代码实现

四、总结讨论


一、问题背景

        享元模式(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 种设计模式解析

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

macOS - 使用 tmux

文章目录 安装 tmux使用更多快捷键说明 安装 tmux brew install tmux使用 在终端输入 tmux 进入 tmux 界面&#xff0c;然后 输入 Control Option B 进入交互模式 输入 % 左右分栏&#xff0c;" 上下分割 上一个窗格&#xff1a;{&#xff0c;下一个&#xff1a;} PS…

【洛谷贪心算法题】P1094纪念品分组

该题运用贪心算法&#xff0c;核心思想是在每次分组时&#xff0c;尽可能让价格较小和较大的纪念品组合在一起&#xff0c;以达到最少分组的目的。 【算法思路】 输入处理&#xff1a;首先读取纪念品的数量n和价格上限w&#xff0c;然后依次读取每件纪念品的价格&#xff0c;…

16. LangChain实战项目2——易速鲜花内部问答系统

需求简介 易束鲜花企业内部知识库如下&#xff1a; 本实战项目设计一个内部问答系统&#xff0c;基于这些内部知识&#xff0c;回答内部员工的提问。 在前面课程的基础上&#xff0c;需要安装的依赖包如下&#xff1a; pip install docx2txt pip install qdrant-client pip i…

Minio搭建并在SpringBoot中使用完成用户头像的上传

Minio使用搭建并上传用户头像到服务器操作,学习笔记 Minio介绍 minio官网 MinIO是一个开源的分布式对象存储服务器&#xff0c;支持S3协议并且可以在多节点上实现数据的高可用和容错。它采用Go语言开发&#xff0c;拥有轻量级、高性能、易部署等特点&#xff0c;并且可以自由…

Spring AI:让AI应用开发更简单

文章目录 引言什么是Spring AI&#xff1f;核心特性 Spring AI的核心组件ChatClient&#xff1a;聊天模型示例代码图示 ImageClient&#xff1a;图像生成示例代码图示 Prompt Templates&#xff1a;提示词模板示例代码 Spring AI的优势示例项目&#xff1a;智能机票助手代码实现…

【C】链式二叉树算法题1 -- 单值二叉树

leetcode链接https://leetcode.cn/problems/univalued-binary-tree/description/ 1 题目描述 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时&#xff0c;才返回 true&#xff1b;否则返回 false。 示例 1&#xff1…

什么是最终一致性,它对后端系统的意义是什么

最终一致性(Eventual Consistency)是分布式系统中的一种一致性模型。与传统的强一致性模型不同,最终一致性并不要求系统在任何时刻都保持一致,而是保证在足够的时间后,所有节点的数据最终会达到一致的状态。换句话说,系统允许短时间内出现数据的不一致性,但最终会通过某…

掌握大模型高效任务流搭建(一):构建LangChain任务流

前言&#xff1a; 在LangChain框架中&#xff0c;“链”占据着核心地位。它允许我们将众多任务模块串联起来&#xff0c;构建出富有弹性的任务流。借助这种链式结构&#xff0c;我们能够处理复杂的逻辑&#xff0c;并实现任务的自动化。在实际场景里&#xff0c;链式操作极大地…

目标检测——数据处理

1. Mosaic 数据增强 Mosaic 数据增强步骤: (1). 选择四个图像&#xff1a; 从数据集中随机选择四张图像。这四张图像是用来组合成一个新图像的基础。 (2) 确定拼接位置&#xff1a; 设计一个新的画布(输入size的2倍)&#xff0c;在指定范围内找出一个随机点&#xff08;如…

塑造网络安全的关键事件

注&#xff1a;本文为 “网络安全” 相关文章合辑。 机翻&#xff0c;未校。 Timeline of Cyber Security: Key Events that Shaped the Field 网络安全时间表&#xff1a;塑造该领域的关键事件 October 29, 2023 Cyberattacks are an everyday threat, always changing. T…

题解 | 牛客周赛82 Java ABCDEF

目录 题目地址 做题情况 A 题 B 题 C 题 D 题 E 题 F 题 牛客竞赛主页 题目地址 牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 做题情况 A 题 判断字符串第一个字符和第三个字符是否相等 import java.io.*; import java.math.*; import java.u…

Redis 高可用性:如何让你的缓存一直在线,稳定运行?

&#x1f3af; 引言&#xff1a;Redis的高可用性为啥这么重要&#xff1f; 在现代高可用系统中&#xff0c;Redis 是一款不可或缺的分布式缓存与数据库系统。无论是提升访问速度&#xff0c;还是实现数据的高效持久化&#xff0c;Redis 都能轻松搞定。可是&#xff0c;当你把 …

uniapp-原生android插件开发摘要

uni-app在App侧的原生扩展插件&#xff0c;支持使用java、object-c等原生语言编写&#xff0c;从HBuilderX 3.6起&#xff0c;新增支持了使用uts来开发原生插件。 基础项目 UniPlugin-Hello-AS工程请在App离线SDK中查找 基础项目(App离线SDK)已经配置好了自定义插件所需要的…

【定昌Linux系统】部署了java程序,设置开启启动

将代码上传到相应的目录&#xff0c;并且配置了一个.sh的启动脚本文件 文件内容&#xff1a; #!/bin/bash# 指定JAR文件的路径&#xff08;如果JAR文件在当前目录&#xff0c;可以直接使用文件名&#xff09; JAR_FILE"/usr/local/java/xs_luruan_client/lib/xs_luruan_…

SpringBoot源码解析(十):应用上下文AnnotationConfigServletWebServerApplicationContext构造方法

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext SpringBoot源码解析(三)&#xff1a;启动开始阶段 SpringBoot源码解析(四)&#xff1a;解析应用参数args Sp…

Unity小功能实现:鼠标点击移动物体

1、功能描述 当玩家点击鼠标时&#xff0c;场景中的物体会移动到鼠标点击的位置。这个功能可以用于控制角色移动、放置物体等场景。 2、实现步骤 创建Unity项目&#xff1a;首先&#xff0c;打开Unity并创建一个新的3D项目。 添加3D物体&#xff1a;在场景中创建一个3D物体&am…

游戏引擎学习第127天

仓库:https://gitee.com/mrxiao_com/2d_game_3 为本周设定阶段 我们目前的渲染器已经实现了令人惊讶的优化&#xff0c;经过过去两周的优化工作后&#xff0c;渲染器在1920x1080分辨率下稳定地运行在60帧每秒。这个结果是意料之外的&#xff0c;因为我们没有预计会达到这样的…

Opencv 图像基本操作

1.1 数据读取-图像 opencv读取的格式是BGR而不是RGB import cv2 import matplotlib.pyplot as plt import numpy as np %matplotlib inline # 在Notebook的输出单元格内嵌入绘制的图形&#xff0c;而不在新窗口中显示img cv2.imread(cat.jpg) # cv2.IMREAD_COLOR&#xff1a…

【微知】ssh如何指定免密的2种简单方式?(vim ~/.ssh/authorized_keys、ssh-copy-id)

背景 ssh通过存储公钥到远端服务器&#xff0c;可以完成本端访问远端服务器的时候免密。免密原理是本端使用私钥&#xff0c;远端公钥&#xff0c;远端可以进行鉴权 方法1&#xff1a; vim ~/.ssh/authorized_keys 将本地电脑的pub的key直接copy到远端 ~/.ssh/authorized_ke…

Skywalking介绍,Skywalking 9.4 安装,SpringBoot集成Skywalking

一.Skywalking介绍 Apache SkyWalking是一个开源的分布式追踪与性能监视平台&#xff0c;特别适用于微服务架构、云原生环境以及基于容器&#xff08;如Docker、Kubernetes&#xff09;的应用部署。该项目由吴晟发起&#xff0c;并已加入Apache软件基金会的孵化器&#xff0c;…