今天咱們繼續講述設計模式,今天說起的是享元模式,享——共享。以前不是出現了一系列共享的東西嗎?爲啥呀,還不就是有些東西每一個人都須要,可是每一個人都去買一個又有點浪費。因此出現共享。話費必定的經濟可使用,使用完成以後又歸還。這就是享。分享共享。今天講的享元模式跟這相相似。享元模式——通俗來講也就是共享最小單元的一種模式。咱們就一塊兒看看到底啥是這享元模式吧。html
在軟件系統開發中,咱們確定會出現重複使用同一個對象的狀況,每次使用都new一個對象出來。這樣的話對於內存來講就須要屢次反覆的申請內存了。這樣使用內存也就愈來愈多,這會出現大問題的。那麼能不能建立new一個對象。而後使用的時候就共同使用一個就行了。這也就是享元模式的含義所在了——共享一個對象。設計模式
運用共享技術有效地支持大量細粒度的對象。安全
看上面的案例圖咱們能夠發現享元模式主要包含如下部分:編輯器
享元工廠角色:這個角色主要負責建立和管理享元角色。判斷是否存在符合要求的享元對象,若是存在則直接拿取,若是不存在的話就會建立一個享元對象並保存。ide
抽象享元角色:這個角色是全部享元角色的基類。提供須要實現的公共接口性能
具體享元角色:繼承於抽象享元角色。實現其抽象的接口。this
客戶端:負責調用並處理邏輯,且保存多有享元對象的狀態spa
在咱們平時使用的編輯器中,會出現不少的字,這些字也是會一直重複出現的。那麼咱們如今就試着使用享元模式來對這些字進行處理。這裏暫且使用字母代替:線程
namespace Flyweight_Pattern { class FlyweightPattern { } #region 抽象享元角色——抽象公共接口 public abstract class Flyweight { /// <summary> /// 表述輸出的位置 /// </summary> /// <param name="externalstate">外在的狀態,隨着環境改變而改變</param> public abstract void OutInput(int externalstate); } #endregion #region 具體享元角色——實現其具體 public class SpecificFlyweight : Flyweight { private string Innerstate; /// <summary> /// 內部狀態接收 /// </summary> /// <param name="innerstate">內部狀態</param> public SpecificFlyweight(string innerstate) { this.Innerstate = innerstate; } /// <summary> /// 實現方法 /// </summary> /// <param name="externalstate">外部狀態</param> public override void OutInput(int externalstate) { Console.WriteLine($"內部狀態:{Innerstate}————外部狀態:{externalstate}"); } } #endregion #region 享元工廠角色——對享元角色進行建立及管理的 public class FlyweightFactory { public Dictionary<string, SpecificFlyweight> keyValuePairs = new Dictionary<string, SpecificFlyweight>(); public SpecificFlyweight GetFlyweight(string Key) { SpecificFlyweight specific = null; if (!keyValuePairs.ContainsKey("A")) { Console.WriteLine("暫時未碰見該Key"); keyValuePairs.Add(Key, new SpecificFlyweight(Key)); Console.WriteLine("現已保存該Key"); } else { specific = keyValuePairs[Key] as SpecificFlyweight; } return specific; } } #endregion }
namespace Flyweight_Pattern { class Program { static void Main(string[] args) { ///初始化享元工廠 FlyweightFactory factory = new FlyweightFactory(); while (true) { Console.WriteLine("請輸入字符的位置:"); var indexstring = Console.ReadLine(); if (int.TryParse(indexstring, out int index)) { Console.WriteLine("請輸入字符:"); string str = Console.ReadLine(); ///判斷字符是否建立 Flyweight flyweight = factory.GetFlyweight(str); //若是存在則輸出信息 if (flyweight != null) { flyweight.OutInput(index); } } else { Console.WriteLine("請輸入數字!"); } Console.WriteLine("結束請輸入N"); if (Console.ReadLine()=="N") { break; } } Console.WriteLine("已結束"); Console.ReadLine(); } } }
這裏咱們須要注意的是劃分好外部狀態和內部狀態,不然混淆以後可能引發線程安全問題。同時必不可少的是一個工廠對象進行控制。設計
這裏咱們解釋下在享元模式中的內在狀態和外在狀態:
內在狀態:不隨環境的變化而變化,上面例子中無論位置如何變化,A就是A。字母A就是內在狀態。
外在狀態:會隨着環境的變化而變化,上面例子中位置變化因此輸出的位置也是不一致的。字母A的位置就是外在狀態
對於享元模式來講其使用場景可分如下四點:
一、系統須要大量類似對象
二、建立這些對象須要花費大量資源
三、狀態可分爲內在狀態和外在狀態,能夠根據內在狀態分爲各類組。
四、須要緩衝池的場景
一、享元模式的優勢最主要的是極大的減小了系統中對象的建立,下降了內存使用提升了效率
任何東西來講都是有利有弊的,咱們看下享元模式又存在哪些弊端呢
一、爲了使一些對象共享,對對象區分了內在狀態和外在狀態,使系統邏輯變爲複雜了,使系統更加難於理解了。
咱們再看看享元模式和以前咱們有提到過的原型模式和單例模式的一些區別吧。咱們首先回顧下前面所說的原型模式和單例模式:
原型模式:使用原型實例指定建立對象的種類,而後經過拷貝這些原型來建立新的對象。
單例模式:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
享元模式:運用共享技術有效地支持大量細粒度的對象。
原型模式——享元模式
咱們再來分析,原型模式是經過原型實例指定建立對象。達到類的複用。經過深淺拷貝類來實現複用以節約資源開銷。再看享元模式抽出類似的一些對象,定義其內在狀態和外在狀態來達到對象共享。運用共享的技術來支持大量細粒度的對象。也就是前面更傾向於實現複用,而享元模式更加傾向於共享使用。因此也不適合放一塊兒進行比較的。
單例模式——享元模式
咱們再看單例模式,單例模式保證的是類僅有一個實例,而後提供一個全局訪問點,全部訪問均可以訪問獲得。達到的是一個實例數據的共享。咱們再看享元模式,享元模式經過的是將類似的對象進行共享,而後控制內在狀態和外在狀態來達到變化。享元模式是對象級別的,也就是實現的是多個對象——對象池。而單例模式是一類一個對象的實例。享元模式更加註重的是節約內存空間,提升其性能。然而單例模式注重的是數據的共享。
今天的享元模式就暫時介紹的這麼多,享元模式精髓也就是達到對象的共享,達到共享的話就須要抽出一部分東西達到類似。因此這又區分了內在狀態和外在狀態。內在狀態不隨環境變化而變化,屬於可共享的。而外在狀態隨着環境改變而改變,因此不能共享的。在.Net開發中,咱們常用到的額String類型的實現就採用了享元模式的設計。在string中具備相同字符序列的String對象不會重複建立。具體細節想要研究的能夠自行查詢資料。在咱們使用設計模式的時候有一些點仍是須要屢次強調及注意的。基於原則設計。視狀況採用設計模式。不要爲了使用設計模式而去使用設計模式。一切都是爲了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。
勇敢的面對不必定成功,但你不面對就必定不成功。
歡迎你們掃描下方二維碼,和我一塊兒踏上設計模式的闖關之路吧!