本系列文章將向大家介紹一下C#的設計模式,此為第十篇文章,相信對大家會有所幫助的。廢話不多說,繼續來看。
意圖
運用共享技術有效地支持大量細粒度的對象。
場景
在比較底層的系統或者框架級的軟件系統中,通常存在大量細粒度的對象。即使細力度的對象,如果使用的數量級很高的話會占用很多資源。比如,游戲中可能會在無數個地方使用到模型數據,雖然從數量上來說模型對象會非常多,但是從本質上來說,不同的模型可能也就這麼幾個。
此時,我們可以引入享元模式來共享相同的模型對象,這樣就可能大大減少游戲對資源(特別是內存)的消耗。
示例代碼
以下是引用片段:
using System;
using System.Collections;
using System.Text;
using System.IO;
namespace FlyweightExample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(GC.GetTotalMemory(false));
Random rnd = new Random();
ArrayList al = new ArrayList();
for (int i = 0; i < 10000; i++)
{
string modelName = rnd.Next(2).ToString();
Model model = ModelFactory.GetInstance().GetModel(modelName);
//Model model = new Model(modelName);
al.Add(model);
}
Console.WriteLine(GC.GetTotalMemory(false));
Console.ReadLine();
}
}
class Model
{
private byte[] data;
public Model(string modelName)
{
data = File.ReadAllBytes("c:\\" + modelName + ".txt");
}
}
class ModelFactory
{
private Hashtable modelList = new Hashtable();
private static ModelFactory instance;
public static ModelFactory GetInstance()
{
if (instance == null)
instance = new ModelFactory();
return instance;
}
public Model GetModel(string modelName)
{
Model model = modelList[modelName] as Model;
if (model == null)
modelList.Add(modelName, new Model(modelName));
return model;
}
}
}
代碼執行結果如下圖(前面是使用享元模式的結果,後面是沒有使用享元模式的結果):
代碼說明
這裡的ModelFactory就是享元工廠角色。它的作用是創建和管理享元對象。可以看到,每加載一個模型都會在Hashtable中記錄一下,之後如果客戶端還是需要這個模型的話就直接把已有的模型對象返回給客戶端,而不是重新在內存中加載一份模型數據。
ModelFactory本身應用了Singleton,因為如果實例化多個享元工廠是的話就起不到統一管理和分配享元對象的目的了。
Model就是享元角色。在構造方法中傳入modelName,然後它從指定路徑加載模型數據,並且把數據放入字段中。
從代碼的運行結果中可以看到,如果沒有應用享元模式,那麼在內存中就會有10000套模型對象,由於一共就2個模型,所以9998個對象是可以通過享元來消除的。
何時采用
系統中有大量耗費了大量內存的細粒度對象,並且對外界來說這些對沒有任何差別的(或者說經過改造後可以是沒有差別的)。
實現要點
享元工廠維護一張享元實例表。
享元不可共享的狀態需要在外部維護。
按照需求可以對享元角色進行抽象。
注意事項
享元模式通常針對細粒度的對象,如果這些對象比較擁有非常多的獨立狀態(不可共享的狀態),或者對象並不是細粒度的,那麼就不適合運用享元模式。維持大量的外蘊狀態不但會使邏輯復雜而且並不能節約資源。
享元工廠中維護了享元實例的列表,同樣也需要占用資源,如果享元占用的資源比較小或者享元的實例不是非常多的話(和列表元素數量差不多),那麼就不適合使用享元,關鍵還是在於權衡得失。
上一篇:無廢話C#設計模式之九:Proxy
下一篇:無廢話C#設計模式之十一:Composite