设计模式-结构型模式之享元模式

news2025/2/28 3:10:35

5. 享元模式

5.1. 模式动机

面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。
  • 享元模式正是为解决这一类问题而诞生的。享元模式通过共享技术实现相同或相似对象的重用

  • 在享元模式中可以共享的相同内容称为内部状态(IntrinsicState),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的

  • 在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。

  • 在享元模式中共享的是享元对象的内部状态,外部状态需要通过环境来设置。在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象。享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。

5.2. 模式定义

享元模式(Flyweight Pattern): 运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

5.3. 模式结构

享元模式包含如下角色:

  • Flyweight: 抽象享元类

  • ConcreteFlyweight: 具体享元类

  • UnsharedConcreteFlyweight: 非共享具体享元类

  • FlyweightFactory: 享元工厂类

5.4. 时序图

5.5. 代码分析

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

int main(int argc, char *argv[])
{
    FlyweightFactory factory;
    Flyweight * fw = factory.getFlyweight("one");
    fw->operation();
    
    Flyweight * fw2 = factory.getFlyweight("two");
    fw2->operation();
    //aready exist in pool
    Flyweight * fw3 = factory.getFlyweight("one");
    fw3->operation();
    return 0;
}
///
//  FlyweightFactory.cpp
//  Implementation of the Class FlyweightFactory
//  Created on:      06-十月-2014 20:10:42
//  Original author: colin
///

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

FlyweightFactory::FlyweightFactory(){

}



FlyweightFactory::~FlyweightFactory(){

}

Flyweight* FlyweightFactory::getFlyweight(string str){
    map<string,Flyweight*>::iterator itr = m_mpFlyweight.find(str);
    if(itr == m_mpFlyweight.end())
    {
        Flyweight * fw = new ConcreteFlyweight(str);
        m_mpFlyweight.insert(make_pair(str,fw));
        return fw;    
    }
    else
    {
        cout << "aready in the pool,use the exist one:" << endl;
        return itr->second;
    }        
}
///
//  ConcreteFlyweight.h
//  Implementation of the Class ConcreteFlyweight
//  Created on:      06-十月-2014 20:10:42
//  Original author: colin
///

#if !defined(EA_C0AF438E_96E4_46f1_ADEC_308EF16E11D1__INCLUDED_)
#define EA_C0AF438E_96E4_46f1_ADEC_308EF16E11D1__INCLUDED_

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

class ConcreteFlyweight : public Flyweight
{

public:
    ConcreteFlyweight(string str);
    virtual ~ConcreteFlyweight();

    virtual void operation();

private:
    string intrinsicState;

};
#endif // !defined(EA_C0AF438E_96E4_46f1_ADEC_308EF16E11D1__INCLUDED_)
///
//  ConcreteFlyweight.cpp
//  Implementation of the Class ConcreteFlyweight
//  Created on:      06-十月-2014 20:10:42
//  Original author: colin
///

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


ConcreteFlyweight::ConcreteFlyweight(string str){
    intrinsicState = str;
}

ConcreteFlyweight::~ConcreteFlyweight(){

}

void ConcreteFlyweight::operation(){
    cout << "Flyweight[" << intrinsicState << "] do operation." << endl; 
}

运行结果:

5.6. 模式分析

享元模式是一个 考虑系统性能的设计模式,通过使用享元模式可以 节约内存空间提高系统的性能

享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态(Internal State)和外部状态(External State)。

  • 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享。

  • 外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的。

5.7. 优点

享元模式的优点

  • 享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。

  • 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

5.8. 缺点

享元模式的缺点

  • 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化

  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长

5.9. 适用环境

在以下情况下可以使用享元模式:

  • 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。

  • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

  • 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。

5.10. 模式应用

享元模式在编辑器软件中大量使用,如在一个文档中多次出现相同的图片,则只需要创建一个图片对象,通过在应用程序中设置该图片出现的位置,可以实现该图片在不同地方多次重复显示。

5.11. 模式扩展

单纯享元模式和复合享元模式

  • 单纯享元模式:在单纯享元模式中,所有的享元对象都是可以共享的,即所有抽象享元类的子类都可共享,不存在非共享具体享元类。

  • 复合享元模式:将一些单纯享元使用组合模式加以组合,可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。

享元模式与其他模式的联用

  • 在享元模式的享元工厂类中通常提供一个静态的工厂方法用于返回享元对象,使用简单工厂模式来生成享元对象。

  • 在一个系统中,通常只有唯一一个享元工厂,因此享元工厂类可以使用单例模式进行设计。

  • 享元模式可以结合组合模式形成复合享元模式,统一对享元对象设置外部状态。

5.12. 总结

  • 享元模式运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用,它是一种对象结构型模式

  • 享元模式包含四个角色抽象享元类声明一个接口,通过它可以接受并作用于外部状态;具体享元类实现了抽象享元接口,其实例称为享元对象;非共享具体享元是不能被共享的抽象享元类的子类;享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。

  • 享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态和外部状态。其中内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享;外部状态是随环境改变而改变的、不可以共享的状态。

  • 享元模式主要优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;其缺点是使得系统更加复杂,并且需要将享元对象的状态外部化,而读取外部状态使得运行时间变长

  • 享元模式适用情况包括:一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;对象的大部分状态都可以外部化,可以将这些外部状态传入对象中;多次重复使用享元对象

[上一节]设计模式-结构型模式之外观模式

[下一节]设计模式-结构型模式之代理模式

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

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

相关文章

GoF代理模式

在java中代理模式的作用: 1.一个对象需要受到保护的时候&#xff0c;可以考虑使用代理对象取完成某个行为. 2.需要给某个对象的功能进行功能增强的时候&#xff0c;可以考虑找一个代理进行增强 3.A对象无法和B对象无法直接沟通&#xff0c;也可以使用代理模式解决 代理模式有三…

WPF mvvm框架Stylet使用教程-窗体交互用法

窗体操作 打开窗体 在stylet框架中&#xff0c;要打开一个窗口或者对话框&#xff0c;只需要直接使用窗口管理器 在要使用的ViewModel中注入IWindowManager&#xff0c;然后使用他的方法操作窗口。 ShowDialog(object viewModel)模态显示ShowWindow(object viewModel) 非模…

修改OPNET帮助文档的默认打开浏览器 给Edge浏览器配置IE Tab插件

我在使用 OPENT Modeler 软件时经常会用到帮助文档&#xff0c;但是其默认打开的是 IE 浏览器&#xff0c;想要其在 Edge 浏览器中打开&#xff0c;但是会出现网页无法打开的情况&#xff0c;这时需要给 Edge 浏览器安装一个 IE Tab 插件。 IE Tab 插件是专门针对浏览器而开发的…

vue3的介绍和两种创建方式(cli和vite)

目录 一、vue3的介绍 &#xff08;一&#xff09;vue3的简介 &#xff08;二&#xff09;vue3对比vue2带来的性能提升 二、vue3的两种创建方式 方式一&#xff1a;使用vue-cli创建&#xff08;推荐--全面&#xff09; 操作步骤 方式二&#xff1a;使用vite创建 操作步…

Spring是什么?关于Spring家族

初识Spring 什么是Spring&#xff1f; Spring是一个开源的Java企业级应用程序开发框架&#xff0c;由Rod Johnson于2003年创建&#xff0c;并在接下来的几年里得到了广泛的发展和应用。它提供了一系列面向对象的编程和配置模型&#xff0c;支持开发各种类型的应用程序&#x…

黑客网站攻击的主要手段

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 黑客与白帽子 有的童鞋觉得黑客和白帽子是同一回事儿&#xff0c;其实不然&#xff1b;而且&#xff0c;他们的工作方式与目标也有很大的差异。 黑客是指一群专门使用计算机…

9.2 变量的指针和指向变量的指针变量

9.2 变量的指针和指向变量的指针变量 一.指针变量的定义二.指针变量的引用三.整理至https://appd872nnyh9503.pc.xiaoe-tech.com/index的笔记 一.指针变量的定义 变量的指针 就是变量的地址。 我们可以定义一个指向 变量 的指针变量。 这种指针变量&#xff0c;我们在定义的时…

信创办公–基于WPS的EXCEL最佳实践系列 (筛选重要数据)

信创办公–基于WPS的EXCEL最佳实践系列 &#xff08;筛选重要数据&#xff09; 目录 应用背景操作步骤1、筛选2、高级筛选 应用背景 在WPS里&#xff0c;筛选有两种&#xff0c;一种是筛选&#xff0c;另外一种则是高级筛选。 操作步骤 1、筛选 可以根据学号、准考证号、考…

MyBatisPlus基础入门学习

系列文章目录 MyBatisPlus基础入门学习 文章目录 系列文章目录前言一、MyBatisPlus简介1.入门案例2.MyBatisPlus概述 二、标准数据层开发1.标准数据层CRUD功能2.分页功能 三、DQL控制1.条件查询方式2.查询投影3.查询条件设定4.字段映射与表名映射 四、DML控制1.Insert2.Delete…

原创文章生成器在线版-ai写作生成器

随着人工智能技术的迅猛发展&#xff0c;越来越多的人开始意识到&#xff0c;利用AI可以实现许多以前不可能想象的事情。其中&#xff0c;一种最能体现人工智能技术优势的应用就是“ai原创文章生成器”。它可以为营销从业者提供一种全新的营销推广方式。 那么&#xff0c;什么是…

AIGC技术赋能下 CRM将迎来怎样的变革?

今年以来&#xff0c;随着ChatGPT的爆火&#xff0c;人工智能&#xff08;AI&#xff09;迎来新一轮的热潮&#xff0c;开始更多地走入人们的视野。如果说2016年“阿尔法狗”&#xff08;Alpha Go&#xff09;大战围棋世界冠军还只是人工智能的“昙花一现”&#xff0c;那么Cha…

在 FPGA 上如何实现双线性插值的计算?

作者 | 殷庆瑜 责编 | 胡巍巍 目录 一、概述 二、What&#xff1f;什么是双线性插值&#xff1f; 二、Why&#xff1f;为什么需要双线性插值&#xff1f; 三、How&#xff1f;怎么实现双线性插值&#xff1f; 关键点1 像素点选择 关键点2 权重计算 升级1 通过查表减少…

深入分析Linux网络丢包

1、背景&#xff1a; 从图中你可以看出&#xff0c;可能发生丢包的位置&#xff0c;实际上贯穿了整个网络协议栈。换句话说&#xff0c;全程都有丢包的可能。 在两台 VM 连接之间&#xff0c;可能会发生传输失败的错误&#xff0c;比如网络拥塞、线路错误等&#xff1b;在网卡…

大数据实战 --- 淘宝用户行为

目录 开发环境 数据描述 功能需求 数据准备 数据清洗 用户行为分析 找出有价值的用户 开发环境 HadoopHiveSparkHBase 启动Hadoop&#xff1a;start-all.sh 启动zookeeper&#xff1a;zkServer.sh start 启动Hive&#xff1a; nohup hiveserver2 1>/dev/null 2>…

计算机体系结构基本概念,指令系统

Amdahl定律 这个定律告诉我们去优化系统中最重要&#xff08;占比最大&#xff09;的部分&#xff0c;作业有个问题&#xff0c;是系统中有多个部件可以改进&#xff0c;可改进部分比例的分母是整个任务&#xff0c;并不是独属于部件 i i i的任务&#xff0c;因此扩展的Amdahl定…

kubespray 部署 kubernetes 排错细节仅供参考

文章目录 1. TASK [kubernetes/preinstall : Hosts | create list from inventory]2: TASK [container-engine/containerd : containerd Create registry directories]3. TASK [kubernetes/control-plane : kubeadm | Initialize first master]4. reslov.conf 权限无法修改5. i…

LeetCode算法小抄 -- 环检测算法 和 拓扑排序算法

LeetCode算法小抄 -- 环检测算法 和 拓扑排序算法 环检测算法(DFS)[207. 课程表](https://leetcode.cn/problems/course-schedule/) 拓扑排序算法(DFS)[210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) 环检测算法(BFS)拓扑排序算法(BFS) ⚠申明&#xff1…

第四章-图像加密与解密

加密与加密原理 使用异或运算实现图像加密及解密功能。 异或运算规则(相同为0,不同为1) 运算数相同,结果为0;运算数不同,结果为1任何数(0/1)与0异或,结果仍为自身任何数(0/1)与1异或,结果为另外一个数,即0变1, 1变0任何数和自身异或,结果为0 同理到图像加密解密 加密过程:…

Stable Diffusion成为生产力工具(六):制作一张庆祝五一劳动节的海报

S&#xff1a;AI能取代设计师么&#xff1f; I &#xff1a;至少在设计行业&#xff0c;目前AI扮演的主要角色还是超级工具&#xff0c;要顶替&#xff1f;除非甲方对设计效果无所畏惧~~ 预先学习&#xff1a; 安装webui《Windows安装Stable Diffusion WebUI及问题解决记录》。…

JS逆向 - 破解oklink加密参数及加密数据

版权声明&#xff1a;原创不易&#xff0c;本文禁止抄袭、转载&#xff0c;侵权必究&#xff01; 目录 一、JS逆向目标-会当临绝顶二、JS逆向分析-不识庐山真面目三、JS逆向测试-只缘身在此山中四、JS反逆向-柳暗花明又一村五、oklink逆向完整代码下载六、作者Info 一、JS逆向目…