1. 程式人生 > >設計模式:享元(FlyWeight)模式

設計模式:享元(FlyWeight)模式

例子 清理 什麽 public == lean http 變量 --

設計模式:享元(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)模式