通俗易懂設計模式解析——享元模式
前言
今天我們繼續講述設計模式,今天提及的是享元模式,享——共享。之前不是出現了一系列共享的東西嗎?為啥呀,還不就是有些東西每個人都需要,但是每個人都去買一個又有點浪費。所以出現共享。話費一定的經濟可以使用,使用完成之後又歸還。這就是享。分享共享。今天講的享元模式跟這相類似。享元模式——通俗來說也就是共享最小單元的一種模式。我們就一起看看到底啥是這享元模式吧。
享元模式介紹
一、來由
在軟體系統開發中,我們肯定會出現重複使用同一個物件的情況,每次使用都new一個物件出來。這樣的話對於記憶體來說就需要多次反覆的申請記憶體了。這樣使用記憶體也就越來越多,這會出現大問題的。那麼能不能建立new一個物件。然後使用的時候就共同使用一個就好了。這也就是享元模式的含義所在了——共享一個物件。
二、 意圖
運用共享技術有效地支援大量細粒度的物件。
三、 案例圖
四、享元模式程式碼示例
看上面的案例圖我們可以發現享元模式主要包含以下部分:
享元工廠角色:這個角色主要負責建立和管理享元角色。判斷是否存在符合要求的享元物件,如果存在則直接拿取,如果不存在的話就會建立一個享元物件並儲存。
抽象享元角色:這個角色是所有享元角色的基類。提供需要實現的公共介面
具體享元角色:繼承於抽象享元角色。實現其抽象的介面。
客戶端:負責呼叫並處理邏輯,且儲存多有享元物件的狀態
在我們平時使用的編輯器中,會出現很多的字,這些字也是會一直重複出現的。那麼我們現在就試著使用享元模式來對這些字進行處理。這裡暫且使用字母代替:
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的位置就是外在狀態
一、 使用場景
對於享元模式來說其使用場景可分以下四點:
1、系統需要大量相似物件
2、建立這些物件需要花費大量資源
3、狀態可分為內在狀態和外在狀態,可以根據內在狀態分為各種組。
4、需要緩衝池的場景
二、 優點
1、享元模式的優點最主要的是極大的減少了系統中物件的建立,降低了記憶體使用提高了效率
三、 缺點
任何東西來說都是有利有弊的,我們看下享元模式又存在哪些弊端呢
1、為了使一些物件共享,對物件區分了內在狀態和外在狀態,使系統邏輯變為複雜了,使系統更加難於理解了。
總結
今天的享元模式就暫時介紹的這麼多,享元模式精髓也就是達到物件的共享,達到共享的話就需要抽出一部分東西達到相似。所以這又區分了內在狀態和外在狀態。內在狀態不隨環境變化而變化,屬於可共享的。而外在狀態隨著環境改變而改變,所以不能共享的。在.Net開發中,我們經常使用到的額String型別的實現就採用了享元模式的設計。在string中具有相同字元序列的String物件不會重複建立。具體細節想要研究的可以自行查詢資料。在我們使用設計模式的時候有一些點還是需要多次強調及注意的。基於原則設計。視情況採用設計模式。不要為了使用設計模式而去使用設計模式。一切都是為了重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。
勇敢的面對不一定成功,但你不面對就一定不成功。
C#設計模式系列目錄
歡迎大家掃描下方二維碼,和我一起踏上設計模式的闖關之路吧!