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

1. 享元模式概述

享元模式(Flyweight Pattern)是一种结构型设计模式,主要用于减少对象的数量,以降低内存占用和提高性能。它通过共享相似对象来避免创建大量相同的实例,适用于需要大量创建重复对象的场景,例如文本编辑器中的字符对象、图形编辑软件中的形状对象等。

享元模式的核心思想:

  • 内部状态(Intrinsic State):可以共享的状态,不会随环境改变,如字体的字形。
  • 外部状态(Extrinsic State):不能共享的状态,需要在运行时传入,如字符的位置。

2. 享元模式的结构

享元模式的典型结构如下:

  • Flyweight(享元接口):定义一个方法用于接收外部状态,并执行相应的逻辑。
  • ConcreteFlyweight(具体享元类):实现享元接口,存储内部状态,并通过外部状态完成功能。
  • FlyweightFactory(享元工厂):用于管理享元对象,提供共享机制,避免重复创建相同对象。
  • Client(客户端):使用享元对象,并传递外部状态。

3. Python 实现享元模式

示例:文字处理系统

假设我们要实现一个文本编辑器,每个字符都有自己的格式(字体、大小、颜色等),但字符的形状是共享的(如‘A’、‘B’等),这正是享元模式的应用场景。

(1) 享元类

class CharacterFlyweight:
    """享元类,存储不可变的内部状态(字符)"""
    
    def __init__(self, char):
        self.char = char  # 共享的内部状态
    
    def display(self, font, size, color, position):
        """显示字符,接收外部状态"""
        print(f"Character: {self.char}, Font: {font}, Size: {size}, Color: {color}, Position: {position}")

(2) 享元工厂

class CharacterFlyweightFactory:
    """享元工厂,管理共享的CharacterFlyweight对象"""
    
    _flyweights = {}  # 享元对象池

    @staticmethod
    def get_flyweight(char):
        """获取享元对象,若不存在则创建"""
        if char not in CharacterFlyweightFactory._flyweights:
            CharacterFlyweightFactory._flyweights[char] = CharacterFlyweight(char)
        return CharacterFlyweightFactory._flyweights[char]

(3) 客户端

class TextEditor:
    """客户端类,使用享元对象并传入外部状态"""
    
    def __init__(self):
        self.characters = []  # 存储字符及其格式信息

    def add_character(self, char, font, size, color, position):
        """添加字符到文本"""
        flyweight = CharacterFlyweightFactory.get_flyweight(char)  # 获取享元对象
        self.characters.append((flyweight, font, size, color, position))

    def render(self):
        """渲染文本"""
        for flyweight, font, size, color, position in self.characters:
            flyweight.display(font, size, color, position)

(4) 测试代码

if __name__ == "__main__":
    editor = TextEditor()
    
    # 添加字符,并指定不同的外部状态
    editor.add_character('A', "Arial", 12, "Black", (0, 0))
    editor.add_character('B', "Times New Roman", 14, "Red", (10, 0))
    editor.add_character('A', "Verdana", 16, "Blue", (20, 0))  # 共享 'A' 对象
    
    editor.render()
    
    # 查看享元对象池
    print("Flyweight Objects in Factory:", list(CharacterFlyweightFactory._flyweights.keys()))

4. 运行结果

Character: A, Font: Arial, Size: 12, Color: Black, Position: (0, 0)
Character: B, Font: Times New Roman, Size: 14, Color: Red, Position: (10, 0)
Character: A, Font: Verdana, Size: 16, Color: Blue, Position: (20, 0)
Flyweight Objects in Factory: ['A', 'B']

可以看到:

  • A 被复用,只创建了一次,而不同外部状态由客户端管理。
  • B 作为新字符被单独创建。
  • 享元工厂管理已创建的字符,并提供共享机制。

5. 享元模式的优缺点

优点

节省内存:减少相同对象的重复创建,降低内存消耗。
提高性能:通过对象复用减少创建时间,提高程序运行效率。
分离状态:内部状态和外部状态分离,增强系统的灵活性。

缺点

增加系统复杂度:享元工厂和对象管理逻辑较复杂,需要维护共享对象池。
适用场景受限:如果对象的内部状态较少或不易分离,享元模式可能不适用。
外部状态管理负担:外部状态由客户端维护,可能导致代码复杂度增加。


6. 适用场景

  • 文本处理:如文字编辑器,每个字符的形状相同但样式不同。
  • 图形系统:如绘图软件,重复绘制相同的形状但不同位置。
  • 游戏开发:如子弹、NPC等对象的复用,提高渲染效率。
  • 数据缓存:如数据库连接池、线程池等,避免重复创建消耗资源。

7. 总结

享元模式是一种优化性能和内存使用的模式,适用于大量重复对象的场景。通过分离内部状态和外部状态,它能有效减少内存占用,提高系统性能。然而,它也会增加系统复杂度,需要权衡使用场景。在 Python 中,利用字典缓存和 .api 调用可以高效地实现享元模式。

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

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

相关文章

RagFlow+Ollama 构建RAG私有化知识库

RagFlowOllama 构建RAG私有化知识库 关于RAG一、什么是RAGFlow一、RAGFlow 安装配置测服已有服务: mysql、redis、elasticsearch 二、RAGFlow 配置 ollama:本地运行大型语言模型的工具软件。用户可以轻松下载、运行和管理各种开源 LLM。降低使用门槛&…

JavaScript(JS)

介绍 JavaScript(简称:JS)是一门跨平台、面向对象的脚本语言。是用来控制网页行为的,它能使网页可交互 JavaScript 和Java 是完全不同的语言,不论是概念还是设计。但是基础语法类似 JS引入方式 内部脚本:将JS代码定义在HTML页面中 JavaScript代码…

LLM 架构

LLM 分类 : 自编码模型 (encoder) : 代表模型 : BERT自回归模型 (decoder) : 代表模型 : GPT序列到序列模型 (encoder-decoder) : 代表模型 : T5 自编码模型 (AutoEncoder model , AE) 代表模型 : BERT (Bidirectional Encoder Representation from Transformers)特点 : Enc…

剑指 Offer II 023. 两个链表的第一个重合节点

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20023.%20%E4%B8%A4%E4%B8%AA%E9%93%BE%E8%A1%A8%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%87%8D%E5%90%88%E8%8A%82%E7%82%B9/README.md 剑指 Offer II 023. 两…

【git-hub项目:YOLOs-CPP】本地实现04:项目简化

项目跑通之后,我们常常还需要对我们没有用到的任何内容进行删除,以简化项目体积,也便于我们阅读和后续部署。如何实现呢?本篇博客教会大家实现! 项目一键下载【⬇️⬇️⬇️】: 精简后:【GitHub跑通项目:YOLOs-CPP】+【计算机视觉】+【YOLOv11模型】+【windows+Cpp+ONN…

R语言用逻辑回归贝叶斯层次对本垒打数据与心脏移植数据后验预测检验模拟推断及先验影响分析|附数据代码...

全文链接:https://tecdat.cn/?p40152 在统计学领域中,层次建模是一种极为强大且实用的工具。它能够巧妙地处理复杂的数据结构,通过分层的方式对数据进行建模。在贝叶斯统计的框架内,层次建模优势尽显,其可以有效地融合…

解锁机器学习核心算法 | 随机森林算法:机器学习的超强武器

一、引言 在机器学习的广阔领域中,算法的选择犹如为一场冒险挑选趁手的武器,至关重要。面对海量的数据和复杂的任务,合适的算法能够化繁为简,精准地挖掘出数据背后隐藏的模式与价值。机器学习领域有十大核心算法,而随…

网络工程师 (43)IP数据报

前言 IP数据报是互联网传输控制协议(Internet Protocol,IP)的数据报格式,由首部和数据两部分组成。 一、首部 IP数据报的首部是控制部分,包含了数据报传输和处理所需的各种信息。首部可以分为固定部分和可变部分。 固定…

部署k8s 集群1.26.0(containerd方式)

随着k8s版本逐步更新,在不支持docker环境的情况下,需要使用containerd方式作为容器引擎。为了更好的个人学习使用,需要重新部署一套1.26.0版本的k8s集群,并且使用containerd方式作为容器引擎,版本为1.6.33。在部署过程…

移动通信发展史

概念解释 第一代网络通信 1G 第二代网络通信 2G 第三代网络通信 3G 第四代网络通信 4G 4g网络有很高的速率和很低的延时——高到500M的上传和1G的下载 日常中的4G只是用到了4G技术 运营商 移动-从民企到国企 联通-南方教育口有人 电信 铁通:成立于 2000 年…

HarmonyOS进程通信及原理

大家好,我是学徒小z,最近在研究鸿蒙中一些偏底层原理的内容,今天分析进程通信给大家,请用餐😊 文章目录 进程间通信1. 通过公共事件(ohos.commonEventManager)公共事件的底层原理 2. IPC Kit能…

openCV中如何实现滤波

图像滤波用于去除噪声和图像平滑,OpenCV 提供了多种滤波器: 1.1. 均值滤波: import cv2# 读取图像 image cv2.imread("example.jpg")# 均值滤波 blurred_image cv2.blur(image, (5, 5)) # (5, 5) 是滤波核的大小 滤波核大小的…

Linux网络 | 多路转接Reactor

前言:本节内容结束Linux网络部分。本节将要简单实现一下多路转接Reactor的代码,制作一个多路转接版本的四则运算计算器服务器。Reactor的代码相当困难,除了350多行新代码, 还要用到我们之前写的许多文件, 比如之前写的…

数控机床设备分布式健康监测与智能维护系统MTAgent

数控机床设备分布式健康监测与智能维护系统MTAgent-v1.1融合了目前各种先进的信号处理以及信息分析算法以算法工具箱的方式,采用了一种开发的、模块化的结构实现信号各种分析处理,采用Python编程语言,满足不同平台需求(包括Windows、Linux)。…

Opencv项目实战:26 信用卡号码识别与类型判定

项目介绍 在日常生活中,信用卡的使用越来越普遍。本项目的主要目标是通过图像处理技术自动识别信用卡号码,并根据信用卡号码的第一个数字判定信用卡的类型(如Visa、MasterCard等)。项目结合了图像预处理、轮廓检测、模板匹配等技…

利用websocket检测网络连接稳定性

浏览器中打开F12,控制台中输入以下内容 > 回车 > 等待结果 连接关闭 表示断网 let reconnectDelay 1000; // 初始重连间隔 let pingInterval null; let socketManuallyClosed false; // 标志是否手动关闭function createWebSocket() {if (socketManuallyCl…

WPF9-数据绑定进阶

目录 1. 定义2. 背景3. Binding源3.1. 使用Data Context作为Binding的源3.2. 使用LINQ检索结果作为Binding的源 4. Binding对数据的转换和校验4.1. 需求4.2. 实现步骤4.3. 值转换和校验的好处4.3.1. 数据转换的好处 4.4. 数据校验的好处4.5. 原理4.5.1. 值转换器原理4.5.2. 数据…

【Unity Shader编程】之图元装配与光栅化

执行方式:自动完成 图元装配自动化流程 顶点坐标存入装配区 → 按绘制模式连接顶点 → 生成完整几何图元 示例:gl.drawArrays(gl.TRIANGLES, 0, 3)自动生成三角形 会自动自动裁剪超出屏幕范围(NDC空间外)的三角形,仅保…

ssm121基于ssm的开放式教学评价管理系统+vue(源码+包运行+LW+技术指导)

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

网工项目理论1.11 网络出口设计

本专栏持续更新,整一个专栏为一个大型复杂网络工程项目。阅读本文章之前务必先看《本专栏必读》。 一.网络出口接入技术 二.单一出口网络结构 三.同运营商多出口结构 四.多运营商多出口结构——出向流量 五.多运营商多出口结构——服务器访问流量 六.多运营商多出口…