GOF:運用共用技術有效地支援大量細粒度的對象。
解釋一下概念:也就是說在一個系統中如果有多個相同的對象,那麼只共用一份就可以了,不必每個都去執行個體化一個對象。比如說(這裡引用GOF書中的例子)一個文本系統,每個字母定一個對象,那麼大小寫字母一共就是52個,那麼就要定義52個對象。如果有一個1M的文本,那麼字母是何其的多,如果每個字母都定義一個對象那麼記憶體早就爆了。那麼如果要是每個字母都共用一個對象,那麼就大大節約了資源。
在Flyweight模式中,由於要產生各種各樣的對象,所以在Flyweight(享元)模式中常出現Factory模式。Flyweight的內部狀態是用來共用的,Flyweight factory負責維護一個Object Storage Service池(Flyweight Pool)來存放內部狀態的對象。Flyweight模式是一個提高程式效率和效能的模式,會大大加快程式的運行速度.應用場合很多,下面舉個例子:
先定義一個抽象的Flyweight類:
| package Flyweight; public abstract class Flyweight ... { public abstract void operation(); }//end abstract class Flyweight |
在實現一個具體類:
| package Flyweight; public class ConcreteFlyweight extends Flyweight ... { private String string; public ConcreteFlyweight(String str) ... { string = str; }//end ConcreteFlyweight(...) public void operation() ... { System.out.println("Concrete---Flyweight : " + string); }//end operation() }//end class ConcreteFlyweight |
實現一個Factory 方法類:
package Flyweight; import java.util.Hashtable;public class FlyweightFactory ... { private Hashtable flyweights = new Hashtable();//----------------------------1 public FlyweightFactory() ...{} public Flyweight getFlyWeight(Object obj) ... { Flyweight flyweight = (Flyweight) flyweights.get(obj);//----------------2 if(flyweight == null) ...{//---------------------------------------------------3 //產生新的ConcreteFlyweight flyweight = new ConcreteFlyweight((String)obj); flyweights.put(obj, flyweight);//--------------------------------------5 } return flyweight;//---------------------------------------------------------6 }//end GetFlyWeight(...) public int getFlyweightSize() ... { return flyweights.size(); } }//end class FlyweightFactory |
這個Factory 方法類非常關鍵,這裡詳細解釋一下:
在1處定義了一個Hashtable用來儲存各個對象;在2處選出要執行個體化的對象,在6處將該對象返回,如果在Hashtable中沒有要選擇的對象,此時變數flyweight為null,產生一個新的flyweight儲存在Hashtable中,並將該對象返回。
最後看看Flyweight的調用:
package Flyweight; import java.util.Hashtable;public class FlyweightPattern ...{ FlyweightFactory factory = new FlyweightFactory(); Flyweight fly1; Flyweight fly2; Flyweight fly3; Flyweight fly4; Flyweight fly5; Flyweight fly6; /** *//** Creates a new instance of FlyweightPattern */ public FlyweightPattern() ...{ fly1 = factory.getFlyWeight("Google"); fly2 = factory.getFlyWeight("Qutr"); fly3 = factory.getFlyWeight("Google"); fly4 = factory.getFlyWeight("Google"); fly5 = factory.getFlyWeight("Google"); fly6 = factory.getFlyWeight("Google"); }//end FlyweightPattern() public void showFlyweight() ... { fly1.operation(); fly2.operation(); fly3.operation(); fly4.operation(); fly5.operation(); fly6.operation(); int objSize = factory.getFlyweightSize(); System.out.println("objSize = " + objSize); }//end showFlyweight() public static void main(String[] args) ... { System.out.println("The FlyWeight Pattern!"); FlyweightPattern fp = new FlyweightPattern(); fp.showFlyweight(); }//end main(...) }//end class FlyweightPattern |
下面是運行結果:
Concrete---Flyweight : Google Concrete---Flyweight : Qutr Concrete---Flyweight : Google Concrete---Flyweight : Google Concrete---Flyweight : Google Concrete---Flyweight : Google objSize = 2 |
我們定義了6個對象,其中有5個是相同的,按照Flyweight模式的定義“Google”應該共用一個對象,在實際的對象數中我們可以看出實際的對象卻是只有2個。
下面給出一個簡易的UML圖:
總結:
Flyweight(享元)模式是如此的重要,因為它能幫你在一個複雜的系統中大量的節省記憶體空間。在GOF的書中舉了文本處理的例子,我覺得非常恰當。那麼,在Java中String這個類型比較特殊,為什麼呢,看下面的例子:
String a = "hello"; String b = "hello"; if(a == b) System.out.println("OK"); else System.out.println("Error"); |
輸出結果是:OK。稍有經驗的人都可以看出if條件比較的是兩a和b的地址,也可以說是記憶體空間。那麼Sting的實現是不是使用了Flyweight模式呢,不得而知,到現在還沒有研究過。