设计模式的征途—12.享元(Flyweight)模式
現(xiàn)在在大力推行節(jié)約型社會,“浪費可恥,節(jié)儉光榮”。在軟件系統(tǒng)中,有時候也會存在資源浪費的情況,例如,在計算機內(nèi)存中存儲了多個完全相同或者非常相似的對象,如果這些對象的數(shù)量太多將導致系統(tǒng)運行代價過高。那么,是否存在一種技術可以用于節(jié)約內(nèi)存使用空間,實現(xiàn)對這些相同或者相似對象的共享訪問呢?答案是肯定的,這種技術就是享元模式。
| 享元模式(Flyweight) | 學習難度:★★★★☆ | 使用頻率:★☆☆☆☆ |
一、圍棋棋子的設計
M公司開發(fā)部欲開發(fā)一個圍棋軟件,其界面效果如下圖所示:
M公司開發(fā)人員通過對圍棋軟件進行分析,發(fā)現(xiàn)在圍棋棋盤中包含大量的黑子和白子,它們的形狀、大小都一模一樣,只是出現(xiàn)的位置不同而已。如果將每一個棋子都作為一個獨立的對象存儲在內(nèi)存中,將可能導致該圍棋軟件在運行時所需要的內(nèi)存空間較大。
如何降低運行代價、提高系統(tǒng)性能是M公司開發(fā)人員需要解決的一個問題。為此,M公司開發(fā)人員決定使用享元模式來設計該軟件。
二、享元模式概述
2.1 享元模式簡介
享元(Flyweight)模式:運用共享技術有效地支持大量細粒度對象的復用。系統(tǒng)只使用少量的對象,而這些對象都很相似,狀態(tài)變化很小,可以實現(xiàn)對象的多次復用。由于享元模式要求能夠共享的對象必須是細粒度對象,因此它又稱為輕量級模式,是一種結(jié)構型模式。
2.2 享元模式結(jié)構
享元模式的結(jié)構較為復雜,一般結(jié)合工廠模式一起使用,在其結(jié)構圖中包含了一個享元工廠類,如下圖所示:
由上圖可以看出,它包含了以下4個角色:
(1)Flyweight(抽象享元類):一個接口或抽象類,聲明了具體享元類的公共方法。
(2)ConcreteFlyweight(具體享元類):實現(xiàn)了抽象享元類,其實例稱為享元對象。
(3)UnsharedConcreteFlyweight(非共享具體享元類):并不是所有的抽象享元類的子類都需要被共享,不能被共享的子類可設計為費共享具體享元類。
(4)FlyweightFactory(享元工廠類):用于創(chuàng)建并管理享元對象,一般設計為一個存儲“Key-Value”鍵值對的集合(可以結(jié)合工廠模式設計)。其作用就在于:提供一個用于存儲享元對象的享元池,當用戶需要對象時,首先從享元池中獲取,如果享元池中不存在,那么則創(chuàng)建一個新的享元對象返回給用戶,并在享元池中保存該新增對象。=> 想想.NET中的各種資源池的設計?
三、重構后的圍棋棋子方案
3.1 重構后的設計
M公司開發(fā)人員采用了享元模式進行設計,如下圖所示:
其中,IgoChessman充當抽象享元類,BlackIgoChessman和WhiteIgoChessman充當具體享元類,IgoChessmanFactory充當享元工廠類。
3.2 具體代碼實現(xiàn)
(1)抽象享元類:IgoChessman
public abstract class IgoChessman{public abstract string GetColor();public void Display(Coordinates coord){Console.WriteLine("棋子顏色:{0},棋子位置:{1}", GetColor(), coord.X + "," + coord.Y);}}/// <summary>/// 外部狀態(tài):棋子坐標/// </summary>public class Coordinates{public int X { get; set; }public int Y { get; set; }public Coordinates(){}public Coordinates(int x, int y){this.X = x;this.Y = y;}}(2)具體享元類:BlackIgoChessman、WhiteIgoChessman
// 具體享元類Apublic class BlackIgoChessman : IgoChessman{public override string GetColor(){return "黑色";}}// 具體享元類Bpublic class WhiteIgoChessman : IgoChessman{public override string GetColor(){return "白色";}}(3)享元工廠類:IgoChessmanFactory
/// <summary>/// 享元工廠類/// </summary>public class IgoChessmanFactory{private static readonly IgoChessmanFactory instance = new IgoChessmanFactory(); // 使用單例模式實現(xiàn)享元private static Hashtable ht; // 使用Hashtable來存儲享元對象,充當享元池private IgoChessmanFactory(){ht = new Hashtable();IgoChessman blackChess = new BlackIgoChessman();ht.Add("b", blackChess);IgoChessman whiteChess = new WhiteIgoChessman();ht.Add("w", whiteChess);}public static IgoChessmanFactory GetInstance(){return instance;}public IgoChessman GetIgoChessman(string color){IgoChessman chess = ht[color] as IgoChessman;return chess;}}(4)客戶端調(diào)用
public class Program{public static void Main(string[] args){// 獲取享元工廠IgoChessmanFactory chessFactory = IgoChessmanFactory.GetInstance();// 通過享元工廠獲取3顆黑子IgoChessman blackChess1 = chessFactory.GetIgoChessman("b");IgoChessman blackChess2 = chessFactory.GetIgoChessman("b");IgoChessman blackChess3 = chessFactory.GetIgoChessman("b");Console.WriteLine("判斷兩顆黑子是否相同:{0}", object.ReferenceEquals(blackChess1, blackChess2));// 通過享元工廠獲取2顆白子IgoChessman whiteChess1 = chessFactory.GetIgoChessman("w");IgoChessman whiteChess2 = chessFactory.GetIgoChessman("w");Console.WriteLine("判斷兩顆白子是否相同:{0}", object.ReferenceEquals(whiteChess1, whiteChess2));// 顯示棋子blackChess1.Display(new Coordinates(1,2));blackChess2.Display(new Coordinates(3, 4));blackChess3.Display(new Coordinates(1, 3));whiteChess1.Display(new Coordinates(2, 5));whiteChess2.Display(new Coordinates(2, 4));Console.ReadKey();}}運行結(jié)果如下圖所示:
從運行結(jié)果可以看出,在每次調(diào)用Display()方法時,都設置了不同的外部狀態(tài)-坐標值,因此相同的棋子雖然具有相同的顏色,但是它們的坐標值不同,將顯示在棋盤的不同位置。
四、享元模式總結(jié)
4.1 主要優(yōu)點
可以極大減少內(nèi)存中對象的數(shù)量,使得相同或相似對象在內(nèi)存中只有一份 => 節(jié)省系統(tǒng)資源,提高系統(tǒng)性能!棒棒噠!
4.2 主要缺點
為了使對象可以共享,享元模式需要將享元對象的部分狀態(tài)外部化,而讀取外部狀態(tài)將使得運行時間變長!
4.3 應用場景
(1)一個系統(tǒng)有大量相同或相似的對象,造成了系統(tǒng)內(nèi)存的大量損耗 => 趕緊使用享元模式吧!
(2)對象的大部分狀態(tài)都可以外部化,可以將這些外部狀態(tài)傳入對象中。
(3)要維護享元模式,需要耗費一定的系統(tǒng)資源,因為在需要時會多次重復使用才值得使用享元模式了!
參考資料
劉偉,《設計模式的藝術—軟件開發(fā)人員內(nèi)功修煉之道》
?
作者:周旭龍
出處:http://edisonchou.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
轉(zhuǎn)載于:https://www.cnblogs.com/edisonchou/p/7148258.html
總結(jié)
以上是生活随笔為你收集整理的设计模式的征途—12.享元(Flyweight)模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [导入]给家人补补钙!双莲炖腔骨
- 下一篇: java中对象模型与数据库中的关系模型