11 享元(Flyweight)模式

devtools/2025/2/7 13:24:45/

享元模式

1.1 分类

(对象)结构型

1.2 提出问题

做一个车管所系统,将会产生大量的车辆实体,如果每一个实例都保存自己的所有信息,将会需要大量内存,甚至导致程序崩溃。

1.3 解决方案

运用共享技术有效的支持大量细粒度的对象。

1.4 实现类图

在这里插入图片描述

  1. 享元模式只是一种优化。只有存在大量类似对象销毁内存的情况,才考虑使用。
  2. 享元(Flyweight)类包含原始对象中部分能在多个对象中共享的状态。享元中存储的状态被称为“内在状态”。传递给享元方法的状态被称为“外在状态”。
  3. 上下文(Context)类包含原始对象中各不相同的外在状态。上下文与享元对象组合在一起就能表示原始对象的全部状态。
  4. 通常情况下,原始对象的行为保留在享元类中。因此调用享元方法必须提供部分外在状态作为参数。但也可将行为移动到上下文类中,将连入的享元作为单纯的数据对象。
  5. 客户端(Client)负责计算或存储享元的外在状态。在客户端看来,享元是一种可在运行时进行配置的模板对象,具体的配置方式为向其方法中传入一些上下文数据参数。
  6. 享元工厂(Flyweight Factory)会对已有享元的缓存池进行管理。有了工厂后,客户端就无需直接创建享元,只需调用工厂并向其传递目标享元的一些内在状态即可。工厂会根据参数在之前已创建的享元中进行查找,如果找到满足条件的享元就将其返回;如果没有找到就根据参数新建享元。

1.5 示例代码

#include <iostream>
#include <string>
#include <unordered_map>using std::string;
//内部状态
struct SharedState {string m_brand;string m_model;string m_color;SharedState(const string& brand, const string model, const string color):m_brand(brand), m_model(model), m_color(color) {}friend std::ostream& operator<<(std::ostream& os, const SharedState& ss) {return os << "[" << ss.m_brand << "," << ss.m_model << "," << ss.m_color << "]";}
};
//外部状态
struct UniqueState
{std::string m_owner;std::string m_plates;UniqueState(const std::string& owner, const std::string& plates): m_owner(owner), m_plates(plates) {}friend std::ostream& operator<<(std::ostream& os, const UniqueState& us) {return os << "[ " << us.m_owner << " , " << us.m_plates << " ]";}
};//享元,存放共享状态,内部状态
class Flyweight {
private:SharedState m_sharedState;
public:Flyweight(const SharedState sharedState) : m_sharedState(sharedState) {}//使用的时候,使用外部状态作为参数,对整个context做出操作void operation(UniqueState uniqueState) const {std::cout << "Flyweight:显示内部状态("<< m_sharedState << "),显示外部状态:("<< uniqueState << ")\n";}
};
//享元工厂
class FlyweightFactory {
private:std::unordered_map<string, Flyweight> m_Flyweights;string getKey(const SharedState& ss) const {return ss.m_brand + "_" + ss.m_model + "_" + ss.m_color;}
public:FlyweightFactory(std::initializer_list<SharedState> share_states) {for (const SharedState& ss : share_states) {m_Flyweights.insert({ getKey(ss),Flyweight(ss) });}}Flyweight* getFlyWeight(const SharedState& shared_state) {string key = getKey(shared_state);if (m_Flyweights.find(key) == m_Flyweights.end()) {std::cout << "FlyweightFactory:没有找到需要的享元,创建一个新的。\n";m_Flyweights.insert({ key,shared_state });} else {std::cout << "FlyweightFactory:返回一个现有的享元。\n";}return &m_Flyweights.at(key);}void listFlyWeights() const {int count = m_Flyweights.size();std::cout << "\nFlyweightFactory:我有" << count << "个享元:\n";for (std::pair<std::string, Flyweight> item : m_Flyweights) {std::cout << item.first << "\n";}}
};
//上下文
class CarInfoContext {
private:Flyweight* m_flyWeight = nullptr;//内部状态UniqueState m_uniqueState;//外部状态
public:CarInfoContext(Flyweight* flyWeight, const UniqueState * unique_state) :m_flyWeight(flyWeight), m_uniqueState(*unique_state) {}void operation() {m_flyWeight->operation(m_uniqueState);}
};
//Client
class PoliceCarDatabase {
private:std::list<CarInfoContext*> carInfoDatabase;
public:~PoliceCarDatabase() {for (auto item : carInfoDatabase)delete item;}void addCarToPoliceDatabase(FlyweightFactory &ff,const string& owner, const string& plates,const string& brand, const string& model, const string& color) {std::cout << "\n客户端:添加车辆信息到数据库。\n";Flyweight* flyWeight = ff.getFlyWeight({ brand, model, color });//内部状态UniqueState uniqueState(owner, plates);//外部状态carInfoDatabase.push_back(new CarInfoContext(flyWeight, &uniqueState));std::cout << "\n客户端:数据库当前状态:\n";for (auto item : carInfoDatabase) {item->operation();}}
};
int main()
{FlyweightFactory factory({SharedState("奔驰","GLC","白色"),SharedState("奥迪","A7","黑色"),SharedState("宝马","X1","白色")});factory.listFlyWeights();PoliceCarDatabase database;database.addCarToPoliceDatabase(factory,"阿西拜", "赣ABC888", "奔驰", "GLC", "白色");factory.listFlyWeights();database.addCarToPoliceDatabase(factory,"阿西拜", "赣ABC999", "比亚迪", "唐EV", "蓝色");database.addCarToPoliceDatabase(factory,"阿西拜", "赣ABC666", "奔驰", "GLC", "白色");factory.listFlyWeights();
}

1.6 举个栗子

享元模式能有效减少在画布上渲染数百万个树状 对象时所需的内存。
在这里插入图片描述

1.7 总结

  1. 优点:如果程序中有很多相似对象,那么你将可以节省大量内存。
  2. 缺点:可能需要牺牲执行速度来换取内存,因为他人每次调用享元方法时都需要重新计算部分情景数据。

http://www.ppmy.cn/devtools/156815.html

相关文章

.net的一些知识点

1.public,protected,private的区别 从访问权限来说是 public>protecd>private 翻译成汉字&#xff1a;公有的>受保护的>私有的 但是在拿那种旧版本(2017及之前)的vs创建class的时候&#xff0c;这个类是没有修饰符的。现在vs2022版本创建带了默认修饰符&#x…

大模型高级工程师实践 - 将课程内容转为音频

音频内容可以随时随地播放&#xff0c;让学习变得更加灵活和便捷。本节课程介绍如何借助文本生成模型 Qwen-Max、语音合成模型 CosyVoice 和视频编辑和处理 moviepy&#xff0c;将课程内容快速转换为音频&#xff0c;并生成对应的字幕 1. 原理介绍 除了之前用到的 Qwen-Max&a…

Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)

文章目录 一、环境准备二、安装Ollama2.1 访问Ollama官方网站2.2 下载适用于Windows的安装包2.3 安装Ollama安装包2.4 指定Ollama安装目录2.5 指定Ollama的大模型的存储目录 三、选择DeepSeek R1模型四、下载并运行DeepSeek R1模型五、常见问题解答六、使用Chatbox进行交互6.1 …

概念RAG

RAG&#xff08;Retrieval-Augmented Generation&#xff09;是一种结合了信息检索&#xff08;Retrieval&#xff09;和生成&#xff08;Generation&#xff09;技术的人工智能框架&#xff0c;旨在提高生成内容的准确性和相关性。RAG 通过在生成过程中引入外部知识库或数据库…

python中的lambda function(ChatGPT回答)

Python 中的 lambda 函数是一个匿名函数&#xff0c;它没有名字&#xff0c;通常用于定义简单的、一次性使用的函数。它可以接受任意数量的参数&#xff0c;但只能有一个表达式&#xff0c;并且该表达式的结果就是返回值。 lambda 函数的语法是&#xff1a; lambda 参数1, 参…

Mybatis篇

1&#xff0c;什么是Mybatis &#xff08; 1 &#xff09;Mybatis 是一个半 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了 JDBC&#xff0c;开发时只需要关注 SQL 语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁…

Spring容器初始化扩展点:ApplicationContextInitializer

目录 一、什么是ApplicationContextInitializer&#xff1f;1、核心作用2、适用场景 二、ApplicationContextInitializer的使用方式1、实现ApplicationContextInitializer接口2、注册初始化器 三、ApplicationContextInitializer的执行时机四、实际应用案例1、动态设置环境变量…

2023年总结感悟

农民用铁锹挖土&#xff0c;和工程师用电流表测试电流其实是一样的。肌肉力量是男孩信息的源泉74岁时一个门槛&#xff0c;老人看一面就少看一面对于老人来说可以自己吃饭&#xff0c;自己走路已经很不错了&#xff0c;若是由于疾病预后很差&#xff0c;不如有尊严的离开世界护…