文章目录 概念概述 解决了什么 区别与联系 享元模式的某个例子的细节分析
概念概述
ECS(Entity-Component-System) 1、Entity(实体):唯一标识符。 2、Component(组件):纯数据容器(提一嘴UI实例,UI实例的引用可以作为数据放这里,system便可以使用)。 3、System(系统):负责逻辑处理。 享元模式(Flyweight Pattern) 1、核心思想:通过共享技术来高效地支持大量细粒度对象的复用。 2、它通过将对象的内在状态(不变部分)和外在状态(可变部分)分离,减少内存占用和对象创建开销。 对象池(Object-Pool) 1、维护一组可复用的对象实例。 2、使用从池中取用完放回,避免频繁创建和销毁对象。
解决了什么
解耦与灵活性 性能优化 代码可维护性 传统面向对象继承会导致复杂的类层次结构(如 Monster -> FlyingMonster -> BossMonster ) 数据连续性:同类型组件在内存中连续存储,适合批量处理(如所有 PhysicsComponent 一起更新) 逻辑集中在 System 中,避免分散在多个类里 ECS 通过组合(Component)替代继承,动态组装实体行为(如给实体添加 FlyComponent 即可飞行) 多线程友好:不同 System 可以并行处理(如渲染和物理计算分离) 新增功能只需添加新组件和系统,无需修改现有代码。
slfnte:ui&btl_uni_one_frm.
interface UIComponent { uiInstance : Laya. Sprite; isVisible : boolean;
}
复杂类设计关键区别说明
特性 容器类设计 ECS设计 实体表示 包含组件的对象 简单的数字ID 组件访问 character.health components.health.get(id) 系统处理 对象调用自己的方法 系统批量处理所有同类组件 内存布局 组件分散存储 同类型组件连续存储 添加组件 需要修改类定义 动态注册到组件Map
内存消耗问题 对象创建性能问题 数据冗余问题 当需要创建大量相似对象时(如游戏中的树木、子弹、NPC等),直接实例化会导致内存爆炸。 频繁创建/销毁对象会引发GC压力(如JavaScript的垃圾回收) 多个对象包含重复数据(如相同纹理、模型) 享元方案:共享相同的内在状态,仅存储一份。 享元方案:通过对象池复用已有实例。 享元方案:将重复数据提取为共享部分
性能开销问题 内存碎片问题 实时性要求 问题 频繁实例化和销毁对象(如子弹、敌人、粒子效果)会导致高CPU和内存开销(尤其是构造函数复杂或GC压力大的语言)。 反复分配/释放内存可能引发内存碎片(尤其在C++等手动管理内存的语言中) 游戏或实时系统中,突发需求(如爆炸产生100颗爆炸碎片)可能导致瞬时卡顿。 解决 通过复用已有对象,减少 new/delete 或 instantiate/destroy 调用 对象池保持内存块连续,提升内存访问效率 预初始化对象池,确保快速响应。
区别与联系
特性 享元模式 对象池 目标 共享不可变数据 复用可回收完整对象 适用场景 纹理、配置、模型等静态资源/共同的逻辑函数 子弹、敌人等动态游戏对象 状态管理 分离内在/外在状态 对象完全一致,无状态分离/对象需重置后复用
高频复杂大量可复用对象=> ECS+对象池+享元模式 === [王炸]
享元模式的某个例子的细节分析
侧重记录这部分是因为思考是被享元模式引起的 享元模式与普通的继承模式对比节省内存的例子之一分析如下:
场景:
需要100个精灵实例,每个精灵实例有n个属性和3个函数 方式1:通过继承模式组织类(有1个ExtCls1 方式2:通过享元模式+组合关系(有一个ExtCls2和一个享元类ThreeMthCls,ExtCls2引用了ThreeMthCls
对比依据(V8 需要为每个实例维护方法访问路径):
纯继承模式 继承+引用享元类模式 指针 vs 方法副本 100 个 24 字节方法引用包装 100 个 8 字节指针 实例创建 100个ExtCls1 100个ExtCls2 + 共同引用1个ThreeMthCls
说明:虽然继承后创建的实例的函数时共享原型链上的,但是每个实例都要维护对应的方法访问路径(消耗38 * 100 =2400(B));分离后只需要共享1个内在状态类即可(消耗1 8*100=800(B))