结构型设计模式之 - 享元模式

133 阅读2分钟
  • 本文已参与「新人创作礼」活动,一起开启掘金创作之路。

什么是享元模式? 📝

享元模式(Flyweight Pattern) 主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

注意: 在应用该模式之前, 你要确定程序中存在与大量类似对象同时占用内存相关的内存消耗问题, 并且确保该问题无法使用其他更好的方式来解决。

理解享元模式 📚

问题

假设你是一名开发工程师,有客户找你开发一个电商类网站,包括一系列的部署以及数据存储。

经过客户介绍,又有几个客户要求做网站,我们代码逻辑实现如下。

static void Main(string[] args)
{
    var websiteA = new WebSite("电商");
    websiteA.Create();
    var websiteB = new WebSite("门户");
    websiteB.Create();
    var websiteC = new WebSite("电商");
    websiteA.Create();
    var websiteD = new WebSite("门户");
    websiteB.Create();
}

public class WebSite{
    private string siteName;
    public WebSite(string SiteName) 
    {
        siteName = SiteName;
    }
    public void Create()=> Console.WriteLine($"创建网站:{siteName}");
}

❌ 同样网站需要多个服务实例,服务器成本、维护成本高。
✔️ 同类型网站使用同一服务实例,使用一些手段进行数据隔离

使用享元模式 ✏️

实现享元:即使用享元工程来判断是否需要复用已有享元或者创建新的对象

  • 创建享元接口实现Create()方法
public interface IWebSite 
{
    void Create();
}
  • 新增具体享元类实现接口
public class WebSite:IWebSite
{
    private string siteName;
    public WebSite(string SiteName) 
    {
        siteName = SiteName;
    }
    public void Create()=> Console.WriteLine($"创建网站:{siteName}");
}
  • 关键:使用享元工程
public class SiteFactory 
{
    // 存储享元
    public Dictionary<string,WebSite> dictionary = new Dictionary<string, WebSite>();
    public WebSite GetInstance(string key) 
    {
        // 判断是否存在享元
        if (!dictionary.ContainsKey(key)) 
        {
            //创建新的对象
            dictionary.Add(key,new WebSite(key));
        }

        return (WebSite)dictionary[key];
    }
    // 获取享元个数
    public int GetCount() 
    {
        return dictionary.Count;
    }
}

享元模式结构中还有一个比较重要的关键
情景 (Context) 类包含原始对象中各不相同的外在状态。

  • 内在状态: 包含不变的、 可在许多对象中重复使用的数据的成员变量。
  • 外在状态: 包含每个对象各自不同的情景数据的成员变量

在上述例子中如果客户需要为不用的网站命名,即是外部状态。

// 情景类包含一些成员变量,这里即是网站名称
public class Context
{
    public Context(string siteName) 
    {
        SiteName = siteName;
    }
    public string SiteName { get; }
}
  • 调用
static void Main(string[] args)
{
    var factory = new SiteFactory();
    WebSite site1 = factory.GetInstance("电商");
    site1.Create(new Context("张三的网站"));
    WebSite site2 = factory.GetInstance("电商");
    site2.Create(new Context("李四的网站"));
    WebSite site3 = factory.GetInstance("门户");
    site3.Create(new Context("王五的网站"));
    WebSite site4 = factory.GetInstance("门户");
    site4.Create(new Context("赵六的网站"));

    factory.GetCount();
    Console.ReadLine();
}
  • 结果

image.png

总结

何时使用享元模式?

  • 系统需要大量的相同对象
  • 数据库连接池

优点:减少大量重复对象创建,减少内存消耗
缺点:需要区分外部状态和内部状态,提高了系统复杂度,还得要考虑线程安全。