设计模式11、享元模式Flyweight

解释说明:享元模式(Flyweight Pattern)运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。
抽象享元类(Flyweight):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
具体享元类(ConcreteFlyweight):实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。通常可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
非共享具体享元类(UnsharedConcreteFlyweight):并不是所有抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
享元工厂类(FlyweightFactory):用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),返回新创建的实例并将其存储在享元池中。
优点:
可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。
享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
缺点:
享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
适用场景
一个系统有大量相同或者相似的对象,造成内存的大量耗费。
对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
在使用享元模式时,需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源。因此,应当在需要多次重复使用享元对象时才值得使用享元模式。
#pragma once
#include <iostream>
#include <string>
// 玩家 - 有武器和使命
class IPlayer
{
public:virtual ~IPlayer() {}// 分配武器virtual void assignWeapon(std::string weapon) = 0;// 使命virtual void mission() = 0;
protected:std::string m_task; // 内部状态std::string m_weapon; // 外部状态
};
// 恐怖分子
class Terrorist : public IPlayer
{
public:Terrorist() {m_task = "Plant a bomb";}virtual void assignWeapon(std::string weapon) override {m_weapon = weapon;}virtual void mission() override {std::cout << "Terrorist with weapon " + m_weapon + "," + " Task is " +  m_task << std::endl;}
};
// 反恐精英
class CounterTerrorist : public IPlayer
{
public:CounterTerrorist() {m_task = "Diffuse bomb";}virtual void assignWeapon(std::string weapon) override {m_weapon = weapon;}virtual void mission() override {std::cout << "Counter Terrorist with weapon " + m_weapon + "," + " Task is  " + m_task << std::endl;}
};#pragma once
#include "flyweight.h"
#include <map>
// 用于获取玩家
class PlayerFactory
{
public:// 如果 T/CT 对象存在,则直接从享元池获取;否则,创建一个新对象并添加到享元池中,然后返回。static IPlayer* getPlayer(std::string type){IPlayer* p = NULL;if (m_map.find(type) != m_map.end()) {p = m_map[type];}else {// 创建 T/CT 对象if (type == "T") {std::cout << "Terrorist Created" << std::endl;p = new Terrorist();}else if (type == "CT") {std::cout << "Counter Terrorist Created" << std::endl;p = new CounterTerrorist();}else {std::cout << "Unreachable code!" << std::endl;}// 一旦创建,将其插入到 map 中m_map.insert(std::make_pair(type, p));}return p;}
private:// 存储 T/CT 对象(享元池)static std::map<std::string, IPlayer*> m_map;
};#include "flyweight.h"
#include "flyweight_factory.h"
#include <ctime>
std::map<std::string, IPlayer*> PlayerFactory::m_map = std::map<std::string,  IPlayer*>();
// 玩家类型和武器
static std::string s_playerType[2] = { "T", "CT" };
static std::string s_weapons[4] = { "AK-47", "Maverick", "Gut Knife", "Desert  Eagle" };
#define GET_ARRAY_LEN(array, len) {len = (sizeof(array) / sizeof(array[0]));}
int main()
{srand((unsigned)time(NULL));int playerLen;int weaponsLen;GET_ARRAY_LEN(s_playerType, playerLen);GET_ARRAY_LEN(s_weapons, weaponsLen);// 假设,游戏中有十位玩家for (int i = 0; i < 10; i++) {// 获取随机玩家和武器int typeIndex = rand() % playerLen;int weaponIndex = rand() % weaponsLen;std::string type = s_playerType[typeIndex];std::string weapon = s_weapons[weaponIndex];// 获取玩家IPlayer* p = PlayerFactory::getPlayer(type);// 从武器库中随机分配武器p->assignWeapon(weapon);// 派玩家去执行任务p->mission();}getchar();return 0;
}

 

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

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

相关文章

【记录】IDA|IDA怎么查看当前二进制文件自动分析出来的内存分布情况(内存范围和读写性)

IDA版本&#xff1a;7.6 背景&#xff1a;我之前一直是直接看Text View里面的地址的首尾地址来判断内存分布情况的&#xff0c;似乎是有点不准确&#xff0c;然后才想到IDA肯定自带查看内存分布情况的功能&#xff0c;而且很简单。 可以通过View-Toolbars-Segments&#xff0c…

竞赛选题 机器视觉人体跌倒检测系统 - opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器视觉人体跌倒检测系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&…

Kafka日志索引详解以及生产常见问题分析与总结

文章目录 1、Kafka的Log日志梳理1.1、Topic下的消息是如何存储的&#xff1f;1.1.1、 log文件追加记录所有消息1.1.2、 index和timeindex加速读取log消息日志。 1.2、文件清理机制1.2.1、如何判断哪些日志文件过期了1.2.2、过期的日志文件如何处理 1.3、Kafka的文件高效读写机制…

MySQL-MVCC(Multi-Version Concurrency Control)

MySQL-MVCC&#xff08;Multi-Version Concurrency Control&#xff09; MVCC&#xff08;多版本并发控制&#xff09;&#xff1a;为了解决数据库并发读写和数据一致性的问题&#xff0c;是一种思想&#xff0c;可以有多种实现方式。 核心思想&#xff1a;写入时创建行的新版…

【多任务案例:猫狗脸部定位与分类】

【猫狗脸部定位与识别】 1 引言2 损失函数3 The Oxford-IIIT Pet Dataset数据集4 数据预处理4 创建模型输入5 自定义数据集加载方式6 显示一批次数据7 创建定位模型8 模型训练9 绘制损失曲线10 模型保存与预测 1 引言 猫狗脸部定位与识别分为定位和识别&#xff0c;即定位猫狗…

MacOS怎么安装Nacos(附带:Windows系统)

MacOS安装Nacos&#xff08;一定要配置JDK的环境变量&#xff0c;后面告诉你为什么&#xff1f;&#xff09; &#xff08;1&#xff09;进入Nacos官网&#xff0c;前往githubhomehomehttp://nacos.io/zh-cn/ &#xff08;2&#xff09;点击右下角的releases 然后点击Tags 选择…

代码随想录算法训练营第五十七天 | 392.判断子序列 115.不同的子序列

1. 判断子序列 392. 判断子序列 - 力扣&#xff08;LeetCode&#xff09; dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度。 class Solution {public boolean isSubsequence(String s, String t) {//dp[i][j] 表示…

Redis7的数据结构

Redis以键-值对的形式存储数据 一、键 1、键的特点 键是一个字符串&#xff0c;这个字符串的内容可以是数字、字符序列&#xff0c;也可以是一个文件的字节序列&#xff0c;甚至空字符串也可以做为key。 在一个数据库中键必须是唯一的。 键最大可以达到512M&#xff0c;但太…

通用收藏管理器Koillection

什么是 Koillection &#xff1f; Koillection 是一个自托管的收藏管理器&#xff0c;旨在跟踪任何类型的物理&#xff08;主要&#xff09;收藏&#xff0c;如书籍、DVD、邮票、游戏……&#xff0c;由于 Koillection 旨在用于任何类型的收藏&#xff0c;它不支持自动下载元数…

STM32 DMA从存储器发送数据到串口

1.任务描述 &#xff08;1&#xff09;ds18b20测量环境温度存储到存储器&#xff08;数组&#xff09;中。 &#xff08;2&#xff09;开启DMA将数组中的内容&#xff0c;通过DMA发送到串口 存在问题&#xff0c;ds18b20读到的数据是正常的&#xff0c;但是串口只是发送其低…

Redis最常见的5种应用场景

Redis作为当今最流行的内存数据库&#xff0c;已经成为服务端加速的必备工具之一。对于Redis为什么那么快&#xff1f;以及Redis采用单线程&#xff0c;但为什么反而获得更高的性能的疑问&#xff0c;在之前的Redis为什么那么快&#xff1f;一文中&#xff0c;已经有所介绍。 …

全新UI彩虹外链网盘系统源码(前后端美化模板)

全新UI彩虹外链网盘系统源码前后端美化模板&#xff0c;支持所有格式文件的上传、生成文件外链、图片外链、音乐视频外链等功能&#xff0c;同时还可以自动生成相应的 UBB 代码和 HTML 代码&#xff0c;支持文本、图片、音乐、视频在线预览。这不仅仅是一个网盘&#xff0c;更是…

证书显示未受信任,生成的证书过期

此时若是导入证书后&#xff0c;证书显示未受信任&#xff0c;则说明我们缺失最新的AppleWWDRCA证书 解决方案&#xff1a; 重新下载AppleWWDRCA并安装。即下载最新的AppleWWDRCA证书&#xff0c;双击安装到“登录”项的钥匙串下&#xff1b;然后再安装你的开发证书或者发布证书…

WebSocket实战之六心跳重连机制

一、前言 WebSocket应用部署到生产环境&#xff0c;我们除了会碰到因为经过代理服务器无法连接的问题&#xff08;注&#xff1a;该问题可以通过搭建WSS来解决&#xff0c;具体配置请看 WebSocket实战之四WSS配置 &#xff09;&#xff0c;另外一个问题就是外网环境不稳定经常…

Appium开发

特点 开源免费支持多个平台 IOS(苹果)、安卓App的自动化都支持 支持多种类型的自动化 支持苹果、安卓应用原生界面的自动化支持应用内嵌网络视图的自动化支持手机浏览器(Chrome)中的web网站自动化支持flutter应用的自动化 支持多种编程语言 像selenium一样&#xff0c;可以用多…

react.js在visual code 下的hello World

想学习reacr.js &#xff0c;就开始做一个hello world。 我的环境是visual code &#xff0c;所以我找这个环境下的例子。参照&#xff1a; https://code.visualstudio.com/docs/nodejs/reactjs-tutorial 要学习react.js &#xff0c;还得先安装node.js&#xff0c;我在visual …

面试打底稿④ 专业技能的第四部分

简历原文 抽查部分 了解Python的使用&#xff08;第一篇关于Python升级版本bug解决的文章斩获6W阅读&#xff09;&#xff0c;用python实现了几篇图像信息隐藏领 域论文的复现&#xff08;博客中有提及&#xff09;&#xff1b; 了解Django基本框架&#xff0c;写过Django框架的…

【软考】4.2 关系代数

《 关系代数 》 表和表之间的逻辑运算 笛卡尔积&#xff1a;S1 x S2 投影&#xff1a;π&#xff1b;选择某一列&#xff08;属性&#xff09;&#xff1b;一个关系R的投影操作结果也是一个关系&#xff0c;记作Πa&#xff0c;它由从关系R中选出的A列元素构成&#xff1b;选择…

测开 | Vue速查知识点

文章目录 Vue知识1. Vue 概述2. Vue 代码格式3. Vue 指令3.1 v-bind & v-model3.2 v-on3.3 v-if和v-show3.4 v-for 4. 生命周期 Vue知识 1. Vue 概述 简介&#xff1a; Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09; 是一套构建用户界面的 渐进式框架。与其他…

CodeCraft-21 and Codeforces Round 711 (Div. 2)A-F

1.Problem - A - Codeforces &#xff08;1&#xff09;题意 求一个大于等于n的整数x&#xff0c;满足gcd(x,sum(dig(x)) > 1&#xff0c;dig表示x的各个数位。 &#xff08;2&#xff09;思路 考虑最差是满足gcd(x,sum(dig(x)) 2,因此不会枚举很多&#xff0c;直接暴力枚…