享元模式 & 基于享元模式的对象池设计与开发应用(设计模式与开发实践 P12)

文章目录

享元模式(flyweight)是一种进行性能优化的模式,通过共享技术来支持大量细粒度的对象

如果系统中创建了大量相似的对象,我们就可以通过享元模式节省内存

反例

服装厂生产了一堆衣服,需要模特拍照片,假设有 100 个衣服被生产,就 new 了 100 个模特出来给衣服拍照片,显然内存要爆炸

这时我们把模特抽象出来,通过 更新他身上的衣服执行拍照方法 ,就避免了过多的内存消耗,这个步骤将对象的属性划分成了内部 状态和外部状态,每个对象都有拍照这个内部属性,穿的衣服、性别都是外部属性,减少了共享对象的数量~

  • 内部状态 存储在对象内部
  • 内部状态 可以被一些对象共享
  • 内部状态 独立于场景,一般不会改变
  • 外部状态 取决于场景,根据场景变化

虽然修改外部状态也需要花费一定时间,但总比新建一个对象要好,所以这是一种时间换空间的优化方式,上面的例子中,衣服就是外部属性,拍照就是内部属性~

应用

上面的修改是基于享元模式的一个小改动,完整的享元模式还应该包含一个享元模式对象工厂,下面是 Unity 中一个常见的情景

正常来说我们用 new 创建 100 个粒子,性能可能不受影响,但 10000 个有可能就得爆炸了!

看下面的代码理解享元模式的好处在哪:

csharp 复制代码
using System;
using System.Collections.Generic;

// 享元接口
interface IParticle
{
    void Move(int x, int y);
    void Draw();
}

// 具体享元类
class Particle : IParticle
{
    private string color;

    public Particle(string color)
    {
        this.color = color;
    }

    public void Move(int x, int y)
    {
        Console.WriteLine($"Moving particle to ({x}, {y})");
    }

    public void Draw()
    {
        Console.WriteLine($"Drawing particle with color: {color}");
    }
}

// 享元工厂类
class ParticleFactory
{
    private Dictionary<string, IParticle> particles = new Dictionary<string, IParticle>();

    public IParticle GetParticle(string color)
    {
        if (particles.ContainsKey(color))
        {
            return particles[color];
        }
        else
        {
            IParticle particle = new Particle(color);
            particles.Add(color, particle);
            return particle;
        }
    }
}

// 游戏场景类
class GameScene
{
    private ParticleFactory particleFactory = new ParticleFactory();
    private List<IParticle> particles = new List<IParticle>();

    public void AddParticle(string color, int x, int y)
    {
        IParticle particle = particleFactory.GetParticle(color);
        particle.Move(x, y);
        particles.Add(particle);
    }

    public void RenderScene()
    {
        foreach (var particle in particles)
        {
            particle.Draw();
        }
    }
}

// 测试
class Program
{
    static void Main(string[] args)
    {
        GameScene scene = new GameScene();
        
        // 添加红色粒子到不同位置
        scene.AddParticle("red", 10, 20);
        scene.AddParticle("red", 30, 40);
        scene.AddParticle("red", 50, 60);

        // 添加蓝色粒子到不同位置
        scene.AddParticle("blue", 70, 80);
        scene.AddParticle("blue", 90, 100);

        // 渲染场景
        scene.RenderScene();
    }
}

对象池

对象池 维护一个 装有空闲对象 的池子,如果需要对象的时候,不是直接 new,而是从对象池里获取,如果池里没有则创建一个新的

原理很好理解,我们班人手买一本 C++ Primer Plus 可能不是那么划算,大部分时间都是闲置的,如果我们创建一个池,需要看的就去拿,看完了就还回来,不够了马上从图书馆借一本出来,这就很节约了

HTTP 连接数据库连接池 都是对象池技术的应用

对象池应用

我们举个例子,某某地图 APP 上有很多个标记 ABCDEFG,如果我们搜索兰州拉面,就会弹出来 4 个附近的兰州拉面标记,这时候如果我们换个地方搜索,弹出来了 6 个兰州拉面标记:

  • 销毁前面的兰州拉面标记重新创建
  • 利用对象池技术,前面的 4 个标记放回池里,再创建 2 个出来用

再看看上面 Unity 的例子,是否能理解为什么 享元模式 & 对象池技术在特殊的场景下是优秀的

相关推荐
淬渊阁8 分钟前
Go package
java·开发语言
CoderCodingNo17 分钟前
【GESP】C++二级真题 luogu-B4259 [GESP202503 二级] 等差矩阵
java·c++·矩阵
佳腾_31 分钟前
【Web应用服务器_Tomcat】二、Tomcat 核心配置与集群搭建
java·前端·中间件·tomcat·web应用服务器
聂 可 以31 分钟前
IntelliJ IDEA修改实体类成员变量的名称(引入了该实体类的全部文件也会自动更新变量的名称)
java·ide·intellij-idea
冰茶_33 分钟前
C#中常见的设计模式
java·开发语言·microsoft·设计模式·微软·c#·命令模式
.似水1 小时前
2025.4.22_C_可变参数列表
java·c语言·算法
禅与Bug的修复艺术1 小时前
JAVA后端开发常用的LINUX命令总结
java·linux·面试·java面试·后端开发·java后端·面试经验
佩奇的技术笔记1 小时前
Java学习手册:Java开发常用的内置工具类包
java
Niuguangshuo1 小时前
Python 设计模式:访问者模式
python·设计模式·访问者模式
triticale1 小时前
【蓝桥杯】P12165 [蓝桥杯 2025 省 C/Java A] 最短距离
java·蓝桥杯