FlyweightPattern-享元模式

ZHIZRL / 2023-08-21 / 原文

在C#中,享元模式(Flyweight Pattern)是一种结构型设计模式,它旨在通过共享对象来最大程度地减少内存使用和提高性能。享元模式适用于需要创建大量相似对象的情况,通过共享相同数据的方式来减少对象的数量。

享元模式有以下几个关键角色:

Flyweight(享元):定义共享对象的接口,通常包含公共状态的操作方法。享元对象在内部不存储具体的状态,而是依赖外部传入的状态。

ConcreteFlyweight(具体享元):实现享元接口,并为内部状态添加具体实现。具体享元对象可以被共享。

FlyweightFactory(享元工厂):负责创建和管理享元对象。它维护一个享元池,用于存储已经创建的享元对象,以便在需要时进行共享。

下面是一个示例,展示如何使用享元模式在C#中实现一个简单的字体管理器:

namespace FlyweightPattern_享元模式
{
    internal class Program
    {
        // Flyweight
        public interface IFont
        {
            void SetFont(string fontName, int size);
            void Render(string text);
        }

        // ConcreteFlyweight
        public class Font : IFont
        {
            private string fontName;
            private int size;

            public void SetFont(string fontName, int size)
            {
                this.fontName = fontName;
                this.size = size;
            }

            public void Render(string text)
            {
                Console.WriteLine("Rendering text: " + text + " with font " + fontName + " and size " + size);
            }
        }
        // FlyweightFactory
        public class FontManager
        {
            private Dictionary<string, IFont> fonts = new Dictionary<string, IFont>();
            private readonly static object FlyweightFactoryLock = new object();
            public IFont GetFont(string key)
            {
                if (!fonts.ContainsKey(key))
                //是为了优化性能,避免对象已经被初始化后,再次请求还需要等待锁
                {
                    lock (FlyweightFactoryLock)//Monitor.Enter,保证方法体只有一个线程可以进入
                    {
                        if (!fonts.ContainsKey(key))
                        {
                            fonts.Add(key, new Font());
                        }
                    }
                }
                return fonts[key];
            }
        }
        static void Main(string[] args)
        {
            FontManager fontManager = new FontManager();

            // 获取并使用字体对象
            IFont font1 = fontManager.GetFont("Arial");
            font1.SetFont("Arial", 12);
            font1.Render("Hello, world!");

            // 再次获取字体对象
            IFont font2 = fontManager.GetFont("Arial");
            font2.Render("Flyweight pattern");

            // 验证字体对象是否相同
            Console.WriteLine(object.ReferenceEquals(font1, font2)); // 输出:True
            Console.Read();
        }
    }
}

在上述示例中,使用享元模式实现了一个字体管理器。IFont是享元接口,定义了设置字体和渲染文本的方法。Font是具体享元对象,实现了享元接口,并保存了具体的字体名称和大小。FontManager是享元工厂,负责创建和管理享元对象。它在内部维护了一个字典,用于存储已经创建的享元对象。当客户端请求一个字体时,如果字体已经存在于字典中,则直接返回现有的享元对象;否则,创建一个新的享元对象并将其存储在字典中。

通过使用享元模式,可以在需要大量相似对象时节省大量内存,并提高性能。具体享元对象可以被多个客户端共享,避免了重复创建相同的对象。而享元工厂负责创建和管理享元对象,确保同一个对象只会被创建一次。