共享之道——享元模式(Python实现)

news2024/11/18 17:42:57

共享之道——享元模式(Python实现)

大家好,今天我们继续来讲结构型设计模式,上一期我们介绍了外观模式,这一期我们来讲享元模式(Flyweight Pattern)。

享元模式(Flyweight Pattern)是一种用于减少内存使用的设计模式,它通过共享尽可能多的数据来减少内存消耗;特别是当程序中存在大量相似对象时,享元模式非常有效。享元模式的核心思想是将那些相似的对象共享起来,避免重复创建相同或相似的对象,从而节省内存和资源,单例模式可以算是享元模式的一种特例。

享元模式简介

享元模式(Flyweight Pattern)是一种用于减少内存使用的设计模式,它通过共享尽可能多的数据来减少内存消耗;特别是当程序中存在大量相似对象时,享元模式非常有效。享元模式的核心思想是将那些相似的对象共享起来,避免重复创建相同或相似的对象,从而节省内存和资源。

享元模式的结构

享元模式通常包括以下几个部分:

  1. Flyweight:享元接口或抽象类,定义了对象的外部状态接口;
  2. ConcreteFlyweight:具体享元类,实现享元接口,并存储内部状态;
  3. FlyweightFactory:享元工厂类,用于创建和管理享元对象,确保合理地共享对象;
  4. Client:客户端类,维护外部状态并使用享元对象。
UML图

../_images/Flyweight.jpg

示意图

享元设计模式

享元模式的Python实现及实际应用

为了更好地理解享元模式,我们来看一个复杂的实际应用场景——假设我们正在开发一个大型多人在线游戏,需要显示大量的游戏角色,每个角色对象包含角色本身(内部状态)和位置、动作、装备等属性(外部状态)。使用享元模式可以显著减少内存消耗,因为相同的角色状态可以共享,以下是享元模式在Python中的一个实现示例:

class GameCharacterFlyweight:
    def __init__(self, character_type, model):
        self.character_type = character_type
        self.model = model

    def render(self, position, action, equipment):
        print(f"Rendering character of type '{self.character_type}' with model '{self.model}' at position {position} with action {action} and equipment {equipment}")

class CharacterFactory:
    def __init__(self):
        self.characters = {}

    def get_character(self, character_type, model):
        key = (character_type, model)
        if key not in self.characters:
            self.characters[key] = GameCharacterFlyweight(character_type, model)
            print(f"Creating new game character flyweight for '{character_type}' with model '{model}'")
        else:
            print(f"Reusing existing game character flyweight for '{character_type}' with model '{model}'")
        return self.characters[key]

# 客户端代码
factory = CharacterFactory()

characters = [
    ("Warrior", "Model1", (10, 10), "Attack", "Sword"),
    ("Mage", "Model2", (20, 20), "Cast Spell", "Staff"),
    ("Warrior", "Model1", (30, 30), "Defend", "Shield"),
    ("Mage", "Model2", (40, 40), "Teleport", "None"),
    ("Warrior", "Model3", (50, 50), "Charge", "Axe"),
    ("Archer", "Model4", (60, 60), "Shoot", "Bow"),
    ("Mage", "Model2", (70, 70), "Heal", "Potion")
]

for character_type, model, position, action, equipment in characters:
    character = factory.get_character(character_type, model)
    character.render(position, action, equipment)

在这个例子中:

  • GameCharacterFlyweight类表示共享的游戏角色对象,包含角色类型和模型等内部状态;
  • CharacterFactory类负责管理和创建这些共享对象,确保同类型同模型的角色对象共享;
  • 客户端代码展示了如何使用享元模式来渲染游戏角色,从而显著减少内存消耗。

享元模式的优缺点

优点:

  1. 减少内存使用:通过共享相似对象,显著减少内存消耗,这在需要创建大量相似对象的场景中尤为重要;
  2. 提高性能:由于减少了对象的数量,可以提高系统的性能,尤其是在内存受限的环境中,这种优化效果尤为明显;
  3. 统一管理:享元工厂集中管理共享对象,使得对象的创建和销毁更加可控。

缺点:

  1. 实现复杂:需要将对象的状态分为内部和外部状态,增加了实现的复杂性,尤其是在处理复杂对象时,需要仔细设计内部和外部状态的划分;
  2. 可能带来线程安全问题:在多线程环境下,共享对象需要注意线程安全问题,需要确保多个线程同时访问共享对象时不会引起数据不一致的问题;
  3. 增加了维护成本:由于实现复杂性和线程安全问题,享元模式的代码维护成本也随之增加。

享元模式的应用场景

  1. 系统中存在大量相似对象,导致内存消耗较大:例如图形界面系统中的字符显示、地图应用中的地图元素、游戏中的角色等;
  2. 对象的大部分状态可以外部化,可以将其移出对象:即对象的状态可以分为共享的内部状态和不共享的外部状态;
  3. 应用程序不依赖于对象标识:即对象的标识可以由其他数据来代替,而不需要依赖于对象本身的唯一标识。

总结

享元模式通过共享对象来减少内存消耗,在需要创建大量相似对象的场景中非常有效;理解和应用享元模式可以显著提高程序的性能和资源利用率,在实际项目中,正确识别和应用享元模式的场景,可以使系统更加高效和可维护。

希望本文能帮助你更好地理解享元模式及其在Python中的实现,并能在实际项目中灵活应用这一设计模式!如果你有任何疑问或想法,欢迎在下方留言!别忘了关注我们的公众号,获取更多有趣的编程知识和实用的代码技巧,我们期待与你的交流与分享!
在这里插入图片描述

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

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

相关文章

超实用 不再担心猫咪掉毛 一文教你养宠家庭空气净化器怎么选

一到夏天,家中的猫咪给你带来的不仅仅是温暖的陪伴,还有那挥之不去的宠物异味。普通空气净化器虽然能够应对一般的空气净化需求,但对于养猫家庭特有的挑战,如宠物毛发、皮屑和异味等,它们往往难以胜任。专业的宠物空气…

【LLM大模型】大模型Prompt Engineering提示词工程

目录: 1、提示工程简介 2、如何写好提示词 2.1 描述清晰2.2 角色扮演2.3 提供示例2.4 复杂任务分解2.5 使用格式符区分语义2.6 情感和物质激励2.7 使用英语2.8 结构化提示词 1、提示工程简介 1.1 什么是Prompt 提示词? 不论是文生图应用,…

STM32-门电路-储存器-寄存器-STM32f1-MCU-GPIO-总线-keil5-点led

1、门电路 门电路组成简单加法器: 二进制对电路的影响: 0和1代表无和有; 以下图例,演示与门:左1右1输出1; 电平标准:使用不同的电压表示数字0和1; 高电平:1&#xff1…

【CSS】文字交融展开

实现如下效果,仅需一个动画几行代码 首先给文本元素添加动画 letter-spacing:初始文本堆在一起,结束展开文本filter:初始模糊,结束清晰 然后给文本的父元素设置对比度,简单理解为亮的更亮暗的更暗。 以…

vue3 项目部署到线上环境,初始进入系统,页面卡顿大概一分钟左右,本地正常无卡顿。localStorage缓存1MB数据导致页面卡顿。

使用vue3进行项目开发,前端框架使用jeecg-boot进行开发,项目初期,打包部署到生产环境,无异常。某天,进行前端项目打包部署到生产环境,突然出现异常情况,部署到线上环境,初始进入系统…

专题十一_字符串

目录 14. 最长公共前缀 解析 题解 5. 最长回文子串 解析 题解 67. 二进制求和 解析 题解 43. 字符串相乘 解析 题解 14. 最长公共前缀 14. 最长公共前缀 - 力扣(LeetCode) 解析 题解 解法一:两两比较,横向比较 clas…

苹果手机录屏没有声音怎么办?2招教你快速解决

今天,录屏功能已成为了我们工作和娱乐中的得力助手。苹果手机凭借其卓越的性能和丰富的功能,自然也在录屏方面有着不俗的表现。苹果手机自带的录屏功能简单直观,能够轻松记录屏幕的精彩瞬间。 然而,有时候苹果手机录屏没有声音怎…

案例:使用Haproxy搭建Web集群

目录 Haproxy Haproxy和LVS的区别 LVS Haproxy 代理和调度的区别 Haproxy调度算法原理 案例 拓扑图 Web服务器配置 Haproxy配置 安装Haproxy Haproxy初步设置 Haproxy配置 配置文件各行说明 监听项配置 启动Haproxy 测试 配置Haproxy日志 Haproxy Haproxy是…

定点数的实现

定点数实现的是float转PEint /// 浮点数有很多问题 多个平台一些运算结果不一致 /// 定点数 运算 (把浮点数转为定点数进行运算,保证所有平台结果的一致性) //因为要把float转化为整形来操作 //float是一个结构体 所以我们这里也是…

[图解]阿西莫夫·台球杀人事件-《分析模式》漫谈

1 00:00:00,470 --> 00:00:02,510 今天的《分析模式》漫谈 2 00:00:02,760 --> 00:00:06,700 我们来说一个有趣的台球杀人事件 3 00:00:08,640 --> 00:00:09,630 还是第一章 4 00:00:09,920 --> 00:00:12,020 这里有一句,you would 5 00:00:12,030 …

【docker快捷部署系列二】用docker-compose快速配置多个容器,docker部署Springboot+Vue项目和mysql数据库

1、思路 docker部署项目是将项目的不同程序放入不同容器中运行,这样可以方便管理不同程序。我的项目有Springboot、Vue、mysql三部分,Vue用nginx代理,因为nodejs太占空间了。一开始我是用Dockerfile创建镜像再运行容器的,但发现它…

uniapp点击图片预览,关闭预览图片后自动触发onshow生命周期,怎么解决?

第一,页面的数据会实时更新,所以接口请求需要在onshow中,变量figh初始为true,数据列表信息可直接调用获取 当点击查看图片时改变,变量figh为false,此时onshow里面的this.postlist()不触发。 此时&#xff0…

Linux/C 高级——Linux命令

从这里开始,我们展开对Linux/c 高级的学习,首先介绍的是在Linux/c高级中,Linux的部分 目录 1.Linux简介 1.1Linux起源 1.2查看系统版本命令 1.3分层结构 1.4系统关机重启命令 2.Linux安装工具 2.1软件包安装 2.1.1软件包的管理机制 …

FastAdmin默认表单中显示列表

FastAdmin表单中又列表&#xff0c;例如订单下有好几个商品需要进行显示&#xff0c;其他字段用系统默认表单样式。 <div class"form-group"><label class"control-label col-xs-12 col-sm-2">{:__(商品详情)}:</label><div class&qu…

升级 chatGPT plus 成功丨出海笔记

有图有真相(升级了速度真的爽)&#xff0c;这个过程说简单不简单&#xff0c;说难不难&#xff0c;废话不说&#xff0c;直接上干货&#xff1a; 支付的时候老说你的卡decline或者被拒绝&#xff0c;就是环境原因。 关键点 换什么IP都没用&#xff0c;本地环境怎么切换都不行&…

java——泛型和JUnit

1、泛型的理解和好处 1.1、使用传统方法的问题分析 1、不能对加入到集合 ArrayList中的数据类型进行约束(不安全) 2、遍历的时候&#xff0c;需要进行类型转换,如果集合中的数据量较大&#xff0c;对效率有影响 1.2、泛型的好处 1、编译时&#xff0c;检查添加元素的类型&…

FreeRTOS学习 -- 事件标志组

一、事件标志组简介 1、事件位&#xff08;事件标志&#xff09; 事件位用来表明某个事件是否发生&#xff0c;事件位通常用作事件标志&#xff0c;比如下面的几个例子&#xff1a; 当收到一条消息并且把这条消息处理掉以后就可以将某个位&#xff08;标志&#xff09;置1&a…

阅读台灯什么品牌好?一文带你了解热门阅读台灯推荐

阅读台灯最终都绕不开护眼这个话题。护眼灯作为保护视力的辅助工具&#xff0c;以有效护眼的价值深受大众青睐。学生长时间用眼&#xff0c;普通台灯的伤害大&#xff0c;而阅读台灯的出现&#xff0c;通过其先进的技术和设计&#xff0c;能为学生提供了一个既舒适又健康的照明…

十三、代理模式

文章目录 1 基本介绍2 案例2.1 Sortable 接口2.2 BubbleSort 类2.3 SortTimer 类2.4 Client 类2.5 Client 类的运行结果2.6 总结 3 各角色之间的关系3.1 角色3.1.1 Subject ( 主体 )3.1.2 RealObject ( 目标对象 )3.1.3 Proxy ( 代理 )3.1.4 Client ( 客户端 ) 3.2 类图 4 动态…

vue3学习day04-provide和inject、defineOptions、defineModel、Pinia、pinia持久化

15、provide和inject &#xff08;1&#xff09;作用&#xff1a;顶层组件向任意的底层组件传递数据和方法&#xff0c;实现跨层组件通信 &#xff08;2&#xff09;语法&#xff1a; 1&#xff09;顶层组件通过provide函数提供数据 2&#xff09;底层函数提供inject获取数据…