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


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

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

    反例

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

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

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

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

    应用

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

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

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

    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    对象池

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

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

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

    对象池应用

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

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

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

  • 相关阅读:
    Unity可视化Shader工具ASE介绍——6、通过例子说明ASE节点的连接方式
    JDBC操作BLOB类型字段
    最大异或对 c++实现
    俄罗斯网络间谍组织在有针对性的攻击中部署LitterDrifter USB蠕虫
    (选专业)你适合国际贸易类专业吗?
    PCL可视化只有顶点彩色信息的OBJ文件
    高防CDN有什么作用?
    npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
    向量化实现矩阵运算优化(一)
    剑指offer 20. 调整数组顺序使奇数位于偶数前面
  • 原文地址:https://blog.csdn.net/Littlelumos/article/details/133630666