享元设计模式






4.60/5 (4投票s)
享元模式是关于创建一个对象池,允许共享已经创建的对象,并导致应用程序消耗更少的内存。
享元设计模式是 GOF 引入的结构型模式之一。享元模式是关于创建一个对象池,允许共享已经创建的对象,并导致应用程序消耗更少的内存。
所以这个模式做了两件事,因为它只创建一次对象,然后将它保存到池中
- 在对象创建方面提高应用程序性能,因为不需要在每个请求都创建一个对象。
- 由于创建的对象已经在内存中,并且没有新的对象池,因此导致应用程序消耗更少的内存。
最终,享元模式使应用程序在内存和处理方面都变得高效。
设计模式的基本 UML 类图
下图显示了基本享元设计模式的类图
IFlyweight
- 派生类型(即具体享元)需要实现的基本契约。
FlyweightFactory
– 这是一个工厂类,客户端类使用它来从具体享元获取数据。此类还负责创建已创建对象的池。因此,当请求的数据已经被请求过时,它会从池中返回数据。
ConcerateSharedFlyweight1
– 这是享元接口的具体实现。顾名思义,此类返回的对象将在其客户端之间共享。
ConcerateUnSharedFlyweight1
– 这是享元接口的具体实现。顾名思义,此类返回的对象将是非共享的,这意味着每次客户端都需要一个新对象。
客户端 – 使用具体实现,它创建 Decorate 的一个实例并使用它的一个功能。
注意
UnSharedFlyweight
并非总是必需的,这取决于需求,但是当您使用享元模式时,总是需要 SharedFlyweight
。
下面的代码是享元设计模式的实现以及上面讨论的类图。
namespace BasicFlyweightPattern
{
#region basic implementation
public class FlyweightFactory
{
public static List<Item> GetStaticItemList(string key)
{
IFlyWeight flyWeight = null;
ICacheManager _objCacheManager = CacheFactory.GetCacheManager();
if (key == "A")
{
if (_objCacheManager.Contains("A"))
{
return _objCacheManager["A"] as List<Item>;
}
else
{
flyWeight = new ConcerateSharedFlyweight1();
}
}
else if (key == "B")
{
if (_objCacheManager.Contains("B"))
{
return _objCacheManager["B"] as List<Item>;
}
else
{
flyWeight = new ConcerateSharedFlyweight2();
}
}
var list = flyWeight.GetList();
_objCacheManager.Add(key, list);
return list;
}
}
interface IFlyWeight
{
List<Item> GetList();
}
public class Item
{
public int id { get; set; }
public string desc { get; set; }
}
public class ConcerateSharedFlyweight1 : IFlyWeight
{
private List<Item> ItemList;
public ConcerateSharedFlyweight1()
{
ItemList = new List<Item>();
}
public List<Item> GetList()
{
ItemList.Add(new Item { id = 1, desc = "A1" });
ItemList.Add(new Item { id = 2, desc = "A2" });
ItemList.Add(new Item { id = 3, desc = "A3" });
return ItemList;
}
}
public class ConcerateSharedFlyweight2 : IFlyWeight
{
private List<Item> ItemList;
public ConcerateSharedFlyweight2()
{
ItemList = new List<Item>();
}
public List<Item> GetList()
{
ItemList.Add(new Item { id = 1, desc = "B1" });
ItemList.Add(new Item { id = 2, desc = "B2" });
ItemList.Add(new Item { id = 3, desc = "B3" });
return ItemList;
}
}
class Program
{
static void Main(string[] args)
{
List<Item> list =FlyweightFactory.GetStaticItemList("A");
//List<Item> list = FlyweightFactory.GetStaticItemList("B");
foreach (var item in list)
{
Console.WriteLine(item.id.ToString() + " " + item.desc );
}
Console.ReadLine();
}
}
}
在上面的代码实现中需要记住的点
- 客户端通过调用
GetStaticItemList
并传递键作为参数来从FlyweightFactory
请求数据,以获取数据。 FlyweightFactory
具有静态方法GetStaticItemList
,如果请求是第一次,它会创建具体实例并获取数据,对于以后的请求,它会返回现有的创建对象。FlyweightFactory
通过使用 Enterprise library 来维护已创建对象的池。缓存块用于在不同的客户端(即不同的对象)之间共享数据。- 在享元的具体实现中,返回的是一个硬编码的列表,但在实际场景中,这将替换为从数据源获取数据。
- Item 是一个类,它是一个 poco 类,该列表从享元具体类返回。此类由不同的项目表示。以下场景提供了更多详细信息。
输出
这里的输出显示了 A 的结果,B 的结果也是如此。如果第二次调用,则数据从缓存中返回。
真实应用程序中的享元设计模式示例
问题陈述
Web 应用程序具有用于显示国家/地区列表、显示州列表、显示产品列表等的下拉列表,并且这些下拉列表是多个屏幕的一部分,多个用户可以访问这些屏幕。
在这种情况下,为了为多个用户请求显示不同类型的列表,服务器需要连接到数据库服务器多个项目,这会降低应用程序的性能,还会消耗内存来创建和存储这些列表。
解决方案
上述问题的解决方案是使用享元设计模式。
以下是在应用程序中使用的享元模式的类图。
与基本实现的映射
IFlyweightManager
等于 IFlyweight
StaticDataListFlyweightFactory
等于 FlyweightFactory
。
CountryStaticListManager
& ProductStaticListManager
等于 ConcerateSharedFlyweight1
& ConcerateSharedFlyweight2
。
StaticItem
等于 Item。
namespace FlyWeightPattern
{
class Program
{
static void Main(string[] args)
{
List<StaticItem> countrylist = StaticDataListFlyWeidhtFactory.GetStaticItemList("Country");
foreach (var item in countrylist)
{
Console.WriteLine(item.id.ToString() + " " + item.Code + " " + item.Description);
}
Console.ReadLine();
}
}
public class StaticDataListFlyWeidhtFactory
{
public static List<StaticItem> GetStaticItemList(string key)
{
IFlyWeightManager manager = null;
ICacheManager _objCacheManager = CacheFactory.GetCacheManager();
if (key == "Country")
{
if (_objCacheManager.Contains("Country"))
{
return _objCacheManager["Country"] as List<StaticItem>;
}
else
{
manager = new CountryStaticListManager();
}
}
else if (key == "ProductType")
{
if (_objCacheManager.Contains("ProductType"))
{
return _objCacheManager["ProductType"] as List<StaticItem>;
}
else
{
manager = new ProductTypeStaticListManager();
}
}
var list = manager.GetList();
_objCacheManager.Add(key, list);
return list;
}
}
interface IFlyWeightManager
{
List<StaticItem> GetList();
}
public class CountryStaticListManager : IFlyWeightManager
{
private List<StaticItem> StaticItemList;
public CountryStaticListManager()
{
StaticItemList = new List<StaticItem>();
}
public List<StaticItem> GetList()
{
StaticItemList.Add(new StaticItem { id = 1, Code = "IND", Description = "India" });
StaticItemList.Add(new StaticItem { id = 2, Code = "SRL", Description = "Sri Lanka" });
StaticItemList.Add(new StaticItem { id = 3, Code = "SA", Description = "South Africa" });
return StaticItemList;
}
}
public class ProductTypeStaticListManager : IFlyWeightManager
{
private List<StaticItem> StaticItemList;
public ProductTypeStaticListManager()
{
StaticItemList = new List<StaticItem>();
}
public List<StaticItem> GetList()
{
StaticItemList.Add(new StaticItem { id = 1, Code = "0123", Description = "Watch" });
StaticItemList.Add(new StaticItem { id = 2, Code = "0234", Description = "Shoes" });
StaticItemList.Add(new StaticItem { id = 3, Code = "0345", Description = "" });
return StaticItemList;
}
}
public class StaticItem
{
public int id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
}
输出
因此,上面的代码的工作方式与模式的基本实现中已经描述的相同。在代码中,通过传递不同的键来获取不同类型的列表。对于此实现,键是 Country 和 Product。在实际应用中,可能不止这些。
上面的实现遵循 SOLID 原则。一个例外是 Factory 类,当想要添加一个新键时需要修改它,因此它违反了单一职责的规则。
注意
在这里,国家/地区和产品列表是硬编码的,但实际上它是从数据库中获取的。
结论
当想要创建一个对象池并在不同的客户端(客户端是软件程序或类或 Web 应用程序,如本例所示)之间共享它时,此模式非常有用。
注意
这是我对模式的看法。如果您发现任何错误,请提供您的反馈。