設計模式:享元(FlyWeight)模式
設計模式:享元(FlyWeight)模式
一、前言
享元(FlyWeight)模式顧名思義,既是輕量級的,原因就是享元,共享元素,這裏的元素指的是對象。如何共享對象,那就是在檢測對象產生的時候,如果產生的是同一個對象,那麽直接使用已經產生的,聽起來很像是單例模式,其實享元模式的內部實現就是很類似與單例模式的懶漢模式。享元的好處就是,在某些場景下可以節省內存,從而使得程序的性能得到提升。
那麽到底什麽對象是可以共享的呢?!比如操作系統安裝的時候就已經自動保存的圖標、字體等等東西,這些東西是可以共享的,我們可以拿來直接使用,比如說word上面的字體,這些都是享元,因為不會發生改變,屬於intrinsic(固有的,內在的,本質的),而有的對象是不能共享的,被稱為extrinsic(外在的),本例之中自己使用TXT文檔創建了幾個字體,分別表示0,1,2...然後使用程序讀取這些字體生成一個對象,這樣的對象不能改變,因此可以用來共享。學過計算機高級結構的都知道,共享的內存一定要保證一致性,發生改變的時候也同步更新,而這裏的享元從始至終都沒有發生過改變,因此可以作為共享變量。
二、代碼
文本文件:
BigChar類:(單個字符所表達的類)
1 package zyr.dp.flyweight; 2 3 import java.io.BufferedReader; 4 import java.io.FileNotFoundException; 5 import java.io.FileReader; 6 import java.io.IOException; 7 8 public class BigChar { 9 10 private char charname; 11 private String frontData;12 public BigChar(char charname){ 13 this.charname=charname; 14 try { 15 BufferedReader br=new BufferedReader(new FileReader("big"+charname+".txt")); 16 StringBuffer sb=new StringBuffer(); 17 String line; 18 while((line=br.readLine())!=null){ 19 sb.append(line+"\n"); 20 } 21 br.close(); 22 frontData=sb.toString(); 23 } catch (FileNotFoundException e) { 24 e.printStackTrace(); 25 } catch (IOException e) { 26 // TODO Auto-generated catch block 27 e.printStackTrace(); 28 } 29 } 30 public void print(){ 31 System.out.println(frontData); 32 } 33 }
BigCharFactory 類:
1 package zyr.dp.flyweight; 2 3 import java.util.HashMap; 4 5 public class BigCharFactory { 6 7 private HashMap pool=new HashMap(); 8 9 private static BigCharFactory bigCharFactory=new BigCharFactory(); 10 11 private BigCharFactory(){ 12 13 } 14 15 public static BigCharFactory getInstance(){ 16 return bigCharFactory; 17 } 18 19 public synchronized BigChar getBigChar(char name){ 20 BigChar bigchar=(BigChar)pool.get(""+name); 21 if(bigchar==null){ 22 bigchar=new BigChar(name); 23 pool.put(""+name, bigchar); 24 } 25 return bigchar; 26 } 27 public BigChar getBigCharNotUsed(char name){ 28 return new BigChar(name); 29 } 30 31 }
BigString類:
1 package zyr.dp.flyweight; 2 3 public class BigString { 4 5 private BigChar [] bigchars; 6 public BigString(String word,boolean isUsed){ 7 if(isUsed == true){ 8 bigchars=new BigChar[word.length()]; 9 BigCharFactory bf=BigCharFactory.getInstance(); 10 for(int i=0;i<word.length();i++){ 11 bigchars[i]=bf.getBigChar(word.charAt(i)); 12 } 13 }else{ 14 bigchars=new BigChar[word.length()]; 15 BigCharFactory bf=BigCharFactory.getInstance(); 16 for(int i=0;i<word.length();i++){ 17 bigchars[i]=bf.getBigCharNotUsed(word.charAt(i)); 18 } 19 } 20 } 21 22 public void print(){ 23 for(int i=0;i<bigchars.length;i++){ 24 bigchars[i].print(); 25 } 26 } 27 }
Main類:
1 package zyr.dp.flyweight; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 String name="221100"; 7 testMemory( name, false); 8 testMemory( name, true); 9 } 10 public static void testMemory(String name,boolean isUsed){ 11 System.out.println("是否使用輕量級:"+isUsed); 12 BigString bs=new BigString(name,isUsed); 13 bs.print(); 14 countMemory(); 15 System.out.println("================="); 16 } 17 public static void countMemory(){ 18 Runtime.getRuntime().gc(); 19 System.out.println("已使用內存:"+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())); 20 } 21 }
運行結果:
是否使用輕量級:false ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- 已使用內存:879440 ================= 是否使用輕量級:true ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- 已使用內存:876928 =================運行結果
三、總結
在我們的程序中,使用了單例模式,同時為了享元,我們使用了類似於單例模式中的懶漢模式,加入synchronized是為了防止多線程中出現誤入,當然在本例中是沒有多線程的,加不加鎖無所謂。同時,我們對比了沒有使用享元的例子,(對比之前先啟動GC回收一次內存)可以發現所占用的內存空間,明顯使用了享元的占用的內存小,而沒有使用享元的占用的內存多。並且這裏我們要註意垃圾回收機制,在工廠類中,使用了HashMap來將BigChar對象保存起來,這樣就形成了一個DAC(有向無環圖),只要pool變量不被釋放,我們使用的共享單元是不會被釋放的。這樣就保證了BigChar對象數組不被釋放,在使用享元模式的時候一定要特別註意這種情況,因為垃圾回收器(GC)在內存占用過多的時候被喚醒,然後清理那些被再被使用的內存,采用的方式就是DAC。
設計模式:享元(FlyWeight)模式