享元模式介紹

享元模式主要在于共享通用物件,減少記憶體的使用,提升系統的訪問效率,而這部分共享物件通常比較耗費記憶體或者需要查詢大量介面或者使用資料庫資源,因此統一抽離作為共享物件使用,
在使用此模式程序中,需要使用享元工廠來進行管理這部分獨立的物件和共享的物件,避免出現執行緒安全的問題,
享元模式設計的思想:減少記憶體的使用提升效率,和之前學習的原型模式通過克隆物件的方式生成復雜物件,減少遠程系統的呼叫,
享元與不可變性
在使用享元模式時,享元物件可在不同情景中是使用,必須確保其狀態不可被修改,也就是說享元物件只能由建構式進行一次性初始化,它不能對其他物件公開其設定器或共有成員變數,
享元工廠
為了更方便的訪問各種享元,可以創建一個工廠方法來管理已有享元物件的快取池,
工廠方法從客戶端處接收目標享元物件的內在狀態作為引數,如果能提前在快取池中找到目標享元,則直接回傳,如果沒有找到,會自動創建一個享元物件,并將其添加到快取池中,
享元模式的結構
-
享元模式只是一種優化,主要應用于與大量類似物件同時占用記憶體相關的記憶體消耗問題時使用,
-
享元 類包含原始物件中部分能在多個物件中共享的狀態,
-
情景類 包含原始物件中各不相同的外在狀態,情景與享元物件組合在一起就能表示原始物件的全部狀態,
-
客戶端 負責計算或存盤享元的外在狀態,
-
享元工廠 會對已有享元的快取池進行管理,
有了工廠后,客戶端無需直接創建享元,它們只需呼叫工廠并向其傳遞目標享元的一些內在狀態即可,工廠會根據引數在之前已創建的享元中進行查找,如果找到滿足的直接回傳,若沒有則進行創建新享元,
僅在程式必須支持大量物件且沒有足夠的記憶體容量時使用享元模式,
- 程式需要生產數量巨大的相似物件
- 這將耗盡目標設備的所有記憶體
- 物件中包含可抽取且能在多個物件間共享的重復狀態
實作方式
1、將需要改寫為享元的類成員變數拆分為兩個部分
- 內在狀態 : 包含不變的,可在許多物件中重復使用的資料的成員變數
- 外在狀態 : 包含每個物件各自不同的情景資料的成員變數
2、保留類中表示內在狀態的成員變數,并將其屬性設定為不可修改,(這些不變的變數只能通過建構式進行初始化操作)
3、找到所有使用外在狀態成員變數的方法,為在方法中所有的每個成員變數新建一個引數,并使用該引數代替成員變數
4、你可以有選擇地創建工廠類來管理享元快取池,它負責在新建享元時檢查已有的享元,如果選擇使用工廠,客戶端就只能通過工廠來請求享元,它們需要將享元的內在狀態作為引數傳遞給工廠
5、客戶端必須存盤和計算外在狀態的數值,因為只有這樣才能呼叫享元物件的方法,外在狀態和參考享元的成員變數可以移動到單獨的情景類中,
優點: 如果程式有很多相似的物件,那么可以節省大量的記憶體,
缺點: 可能犧牲執行速度來換取記憶體、代碼會變的更加復雜,
享元展示了如何生成大量的小型物件,外觀模式則展示了如何用一個物件來代表整個子系統,
Demo
/// <summary>
/// 享元
/// </summary>
public class Flyweight
{
private Car _sharedState;
public Flyweight(Car car)
{
this._sharedState = car;
}
public void Operation(Car uniqueState)
{
string s = JsonConvert.SerializeObject(this._sharedState);
string u = JsonConvert.SerializeObject(uniqueState);
Console.WriteLine("Flyweight:Displaying shared "+s+" and unque "+u+" state");
}
}
/// <summary>
/// 享元工廠
/// 思路:提前在快取池快取物件,取值時先判斷快取池中取,如沒有則創建,同時加入快取池,
/// </summary>
public class FlyweightFactory
{
private List<Tuple<Flyweight,string>> flyweights=new List<Tuple<Flyweight,string>>();
public FlyweightFactory(params Car[] args)
{
foreach (var elem in args)
{
flyweights.Add(new Tuple<Flyweight,string>(new Flyweight(elem),this.getKey(elem)));
}
}
public string getKey(Car key)
{
List<string> elements = new List<string>();
elements.Add(key.Model);
elements.Add(key.Color);
elements.Add(key.Company);
if (key.Owner!=null&& key.Number!=null)
{
elements.Add(key.Number);
elements.Add(key.Owner);
}
elements.Sort();
return string.Join("_",elements);
}
public Flyweight GetFlyweight(Car sharedState)
{
string key = this.getKey(sharedState);
if (flyweights.Where(t=>t.Item2==key).Count()!=0)
{
Console.WriteLine("在享元工廠中,快取中沒有資料");
this.flyweights.Add(new Tuple<Flyweight,string>(new Flyweight(sharedState),key));
}
else
{
Console.WriteLine("緩沖池中有...");
}
return this.flyweights.Where(t => t.Item2 == key).FirstOrDefault().Item1;
}
public void listFlyweights()
{
var count = flyweights.Count;
foreach (var item in flyweights)
{
Console.WriteLine(item.Item2);
}
}
}
public class Car
{
public string Owner { get; set; }
public string Number { get; set; }
public string Company { get; set; }
public string Model { get; set; }
public string Color { get; set; }
}
static void Main(string[] args)
{
var factory = new FlyweightFactory(
new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" },
new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" },
new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" },
new Car { Company = "BMW", Model = "M5", Color = "red" },
new Car { Company = "BMW", Model = "X6", Color = "white" }
);
factory.listFlyweights();
addCarToPoliceDatabase(factory, new Car {
Number = "CL234IR",
Owner = "James Doe",
Company = "BMW",
Model = "M5",
Color = "red"
});
addCarToPoliceDatabase(factory, new Car
{
Number = "CL234IR",
Owner = "James Doe",
Company = "BMW",
Model = "X1",
Color = "red"
});
factory.listFlyweights();
Console.ReadKey();
}
static void addCarToPoliceDatabase(FlyweightFactory factory, Car car)
{
Console.WriteLine("添加一個新Car");
var flyweight = factory.GetFlyweight(new Car
{
Color = car.Color,
Model = car.Model,
Company = car.Company
});
flyweight.Operation(car);
}
對于享元工廠需要特意留意,它是先檢索快取池中的資料總情況,發現不是要找的,那么就新創建物件,
小寄語
人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的,
我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 謝謝,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/294352.html
標籤:ASP.NET
上一篇:WPF 更改 DrawingVisual 的 RenderOpen 用到的物件的內容將持續影響渲染效果
下一篇:【設計模式】外觀
