C++设计模式_13_Flyweight享元模式

news2024/9/23 11:26:04

Flyweight享元模式仍然属于“对象性能”模式。

文章目录

  • 1. 动机(Motivation)
  • 2. 模式定义
  • 3. 结构( Structure)
  • 4. 代码演示
  • 5. 要点总结
  • 6. 其他参考

1. 动机(Motivation)

在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价一一主要指内存需求方面的代价。

通常不用担心对象数量问题,但是存在倍乘效应的情况下就会占用很大的内存需求,常见的优化方法是共享技术,共享技术是面向对象里经常用来解决性能问题的手段,这也是Flyweight的核心思想。

如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?

2. 模式定义

运用共享技术有效地支持大量细粒度的对象。
–《设计模式》GoF

比如说字符串,字符串在系统中使用的量是非常大的,占用的内存也是比较大的,常见的系统包括stl等都用了一定的共享技术,java和C#会在编译器层面用一些共享技术。除了字符串,线程也是一类例子。

3. 结构( Structure)

在这里插入图片描述

GoF中面向对象的一种描述方法。从上面的类图可以看到FlyweightFactory的工厂,本来创建对象是一个个new,但是这种方式会导致应该共享的却没有共享,利用享元的工厂GetFlyweight(key),用key做判断对象是否创建,如果已经创建直接返回,如果对象之前没有创建,那么先创建一个,加到对象池中,然后再返回。右下角的可以忽略UnsharedConcreteFlyweight,因为有些对象是支持共享,有些是不支持的。

4. 代码演示

以下为示意性代码,比如说要设计一个字处理系统,里面具有很多的假设,你将字体类型实现为一个对象,以下使用Font类来描述字体

class Font {
private:

    //unique object key
    string key;
    
    //object state
    //....
    
public:
    Font(const string& key){
        //...
    }
};

字体对象的量很大,一个系统中每一个字符都有一个字体,实际上十页文章,真正使用的字体也就是四五种左右,而不是每一个字符的字体对象都不一样。如果不加区分的给每一个字符创建一个字体对象,系统将很难承受。这个时候就需要利用享元的方式实现。

字体一般能确定一个key,比如string key;可以load到相关的资源,利用key来构造对象。

真正推荐的Flyweight享元模式创建方式如下:

class FontFactory{
private:
    map<string,Font* > fontPool;
    
public:
    Font* GetFont(const string& key){

        map<string,Font*>::iterator item=fontPool.find(key);
        
        if(item!=footPool.end()){
            return fontPool[key];
        }
        else{
            Font* font = new Font(key);
            fontPool[key]= font;
            return font;
        }

    }
    
    void clear(){
        //...
    }
};

设定一个FontFactory的字体工厂,用到map<string,Font* > fontPool;维持一个字体对象池fontPool, Font* GetFont(const string& key)传递一个key字符串,map<string,Font*>::iterator item=fontPool.find(key);查找key,如果找到key,判断迭代器不等于end,直接返回,说明之前创建过,如果没有找到说明这种对象没有创建,首先进行创建Font* font = new Font(key);,创建之后,fontPool[key]= font;添加到对象池中,再将对象返回。

大家可以看到,同一种key永远只有一个字体对象对应,只创建了一个字体对象,不会有很多,当然Key是有限的,可能你有10万个字符,但只有10种key及对应的字体对象,这样的话只是维持了10个字体对象,也就是维持了map,每次get的时候取。

实现起来各种各样,但是核心的思想就是共享的方式,有就返回,没有就创建返回。

整体代码

class Font {
private:

    //unique object key
    string key;
    
    //object state
    //....
    
public:
    Font(const string& key){
        //...
    }
};
ß

class FontFactory{
private:
    map<string,Font* > fontPool;
    
public:
    Font* GetFont(const string& key){

        map<string,Font*>::iterator item=fontPool.find(key);
        
        if(item!=footPool.end()){
            return fontPool[key];
        }
        else{
            Font* font = new Font(key);
            fontPool[key]= font;
            return font;
        }

    }
    
    void clear(){
        //...
    }
};

5. 要点总结

  • 面向对象很好地解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解决面向对象的代价问题,一般不触发面向对象的抽象性问题

  • Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理

需要注意,对象创建出来之后,不能更改对象状态,往往这种对象创建出来之后就是只读的,像java和c#中的字符串是只读的,而C++标准中字符串不是只读的,这是因为背后使用了prototype的设计模式解决copy and write问题,总体来讲这样的对象出去最好是只读的,否则共享就不成立了,共享后被更改,其他对象共享的也就被更改了。

  • 对象的数量太大从而导致对象内存开销加大,–什么样的数量才算大?这需要我们存细的根据具体应用情况进行评估,而不能凭空臆断

简单的说明,一个对象到底占多大,使用sizeof和根据类内的数据类型,对齐,虚函数表指针(32位为4byte)等加起来之后就是对象的size,再看对象有多少个来计算占用内存。

6. 其他参考

C++设计模式——享元模式

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

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

相关文章

Web攻防05_MySQL_二次注入堆叠注入带外注入

文章目录 MYSQL-二次注入-74CMS思路描述&#xff1a;注入条件&#xff1a;案例&#xff1a;74CMS个人中心简历功能 MYSQL-堆叠注入-CTF强网思路描述注入条件案例&#xff1a;2019强网杯-随便注&#xff08;CTF题型&#xff09; MYSQL-带外注入-DNSLOG注入条件使用平台带外应用场…

代碼隨想錄算法訓練營|第四十九天|139.单词拆分、关于多重背包、背包问题总结。刷题心得(c++)

目录 讀題 139.单词拆分 自己看到题目的第一想法 看完代码随想录之后的想法 139.单词拆分 - 實作 思路 Code 關於多重背包 與01背包與完全背包的差別 轉化成01背包問題 背包问题总结 背包問題分類 背包問題 - 遞推公式 最多裝多少/能否裝滿 最大價值 裝滿背包有…

OpenFeign实现分析、源码解析

什么是openfeign? 是springcloud全家桶的组件之一&#xff0c;其核心作用是为Rest API提供高效简洁的rpc调用方式。 为什么只定义接口而没有实现类&#xff1f; 源码解读&#xff08;省略&#xff09; 总结&#xff1a; 源码分析&#xff1a;如何发送http请求&#xff1f; …

基于单片机设计的智能窗帘控制系统

一、前言 智能家居技术在近年来取得了巨大的发展&#xff0c;并逐渐成为人们日常生活中的一部分。智能家居系统带来了便利、舒适和高效的生活体验&#xff0c;拥有广泛的应用领域&#xff0c;其中之一就是智能窗帘控制系统。 传统窗帘需要手动操作&#xff0c;打开或关闭窗帘…

微服务-Ribbon负载均衡

文章目录 负载均衡原理流程原理源码分析负载均衡流程 负载均衡策略饥饿加载总结 负载均衡原理 流程 原理 LoadBalanced 标记RestTemplate发起的http请求要被Ribbon进行拦截和处理 源码分析 ctrlshiftN搜索LoadBalancerInterceptor&#xff0c;进入。发现实现了ClientHttpRequ…

Snipaste--强大的截图贴图软件--非常实用

一.软件介绍&#xff1a; Snipaste 是一个简单但强大的截图工具&#xff0c;也可以让你将截图贴回到屏幕上&#xff01;下载并打开Snipaste&#xff0c;按下 F1 来开始截图&#xff0c;再按 F3&#xff0c;截图就在桌面置顶显示了。就这么简单&#xff01;你还可以将剪贴板里的…

SK-Net eca注意力机制应用于ResNet (附代码)

resnet发展历程 论文地址&#xff1a;https://arxiv.org/pdf/1903.06586.pdf 代码地址&#xff1a;https://github.com/pppLang/SKNet 1.是什么&#xff1f; SK-net网络是一种增加模块嵌入到一些网络中的注意力机制&#xff0c;它可以嵌入和Resnet中进行补强&#xff0c;嵌入…

composer安装thinkphp6报错

composer安装thinkphp6报错&#xff0c; 查看是否安装了对应的PHP扩展&#xff0c;我这边使用的是宝塔的环境&#xff0c;全程可以可视化操作 这样就可以安装完成了

linux工具篇

文章目录 linux工具篇1. linux 软件包管理器-yum1.1 什么是软件包1.2 yum的使用1.3 yum源 2. linux编辑器-vim2.1 vim概念2.2 vim各个模式切换2.3 vim正常模式命令汇总2.4 vim底行模式各命令汇总2.5 vim的简单配置 3. Linux编译器-gcc/g使用3.1 复习程序编译过程(1) 预处理(2) …

【Oracle】Navicat Premium 连接 Oracle的两种方式

Navicat Premium 使用版本说明 Navicat Premium 版本 11.2.16 (64-bit) 一、配置OCI 1.1 配置OCI环境变量 1.1.2 设置\高级系统设置 1.1.2 系统属性\高级\环境变量(N) 1.1.3 修改/添加系统变量 ORACLE_HOME ORACLE_HOME D:\app\root\product\12.1.0\dbhome_11.1.4 添加系…

Redis快速上手篇(一)(安装与配置)

NoSQL NoSQL 是 Not Only SQL 的缩写&#xff0c;意即"不仅仅是 SQL"的意思&#xff0c;泛指非关系型的数据库。强调 Key-Value Stores 和文档数据库的优点。 NoSQL 产品是传统关系型数据库的功能阉割版本&#xff0c;通过减少用不到或很少用的功能&#xff0c;来大…

vue3中使用svg并封装成组件

打包svg地图 安装插件 yarn add vite-plugin-svg-icons -D # or npm i vite-plugin-svg-icons -D # or pnpm install vite-plugin-svg-icons -D使用插件 vite.config.ts import { VantResolver } from unplugin-vue-components/resolvers import { createSvgIconsPlugin } from…

【C语言初阶】switch语句的基本语法

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《速学C语言》《数据结构篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言&#x1f4ac; switch语句的介绍&#x1f4ac; switch语句的语法形式&#x1f4ad; 在switch语句中的 break&…

景联文科技提供4D-BEV标注工具:提升自动驾驶感知能力的精准数据支持

4D-BEV标注是一种用于自动驾驶领域的数据标注方法。在3D空间的基础上&#xff0c;加入了时间维度&#xff0c;形成了四个维度。这种方法通过精准地跟踪和记录动态对象&#xff08;如车辆、行人&#xff09;的运动轨迹、姿势变化以及速度等信息&#xff0c;全面理解和分析动态对…

JWT的登录认证与自校验原理分析

目录 一、JWT的概述 1.什么是JWT&#xff1f; 2.JWT的用户认证 3.JWT解决了什么问题&#xff1f; 4.关于JWT中的签名如何理解&#xff1f; 5.JWT的优势 二、JWT的结构 1.令牌的组成&#xff1a; 2.JWT的工具类 3.JWT所需的依赖 4.JWT登录生成Token的原理 三、JWT的自…

Linux中关于glibc包导致的服务器死机或者linux命令无法使用的情况

glibc是gnu发布的libc库&#xff0c;即c运行库。glibc是linux系统中最底层的api&#xff0c;几乎其它任何运行库都会依赖于glibc。glibc除了封装linux操作系统所提供的系统服务外&#xff0c;它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX …

智能巡检系统可以应用在哪些地方?巡检系统有什么优势?

智能巡检系统可以广泛应用于学校、物业、工厂、酒店和民宿、运维商以及能源行业等不同领域的巡检管理之中&#xff0c;为用户提供了巡检任务安排管理、签到打卡、工单上报处理以及数据统计分析等多种功能。 一、巡检系统的应用场景   1、学校&#xff1a;为了确保学校各项设施…

【抓包分析】通过ChatGPT解密还原某软件登录算法实现绕过手机验证码登录

文章目录 &#x1f34b;前言实现效果广告抓包分析一、定位加密文件二、编辑JS启用本地替换 利用Chatgpt进行代码转换最后 &#x1f34b;前言 由于C站版权太多&#xff0c;所有的爬虫相关均为记录&#xff0c;不做深入&#xff01; 今天发现github上没有这个东西&#xff0c;抓…

Centos7 防火墙的关闭

Centos7 防火墙的关闭 Centos7默认使用的是firewall作为防火墙&#xff1b; 查看防火墙状态&#xff1a;firewall-cmd --state 停止防火墙&#xff1a;systemctl stop firewalld.service; 禁止防火墙开机启动&#xff1a;systemctl disable firewalld.service; 放行端口…

项目总结-新增商品-Pagehelper插件分页查询

&#xff08;1&#xff09;新增商品 工具类&#xff1a; /** * Title: FileUtils.java * Package com.qfedu.common.utils * Description: TODO(用一句话描述该文件做什么) * author Feri * date 2018年5月29日 * version V1.0 */ package com.gdsdxy.common.u…