B6) Flyweight(享元模式) 定義:使用共享來高效的支持大量的細顆粒對象。 似乎不太常用的一個模式,因為對于要求可能嚴格了一點:大量的細顆粒對象,真正運用到這個層次上的機會應該不會太多。享元模式就是將大量對象實例中相同的部分提取出來,形成一個原型,這部分稱為intrinsic(內部狀態(tài)),是不變的,而會因外界條件而改變的部分稱為extrinsic(外部狀態(tài))。那每次需要一個新的對象實例時候,就從享元共享池(pool)中得到內部狀態(tài)即共享的原型,再根據外部條件,生成外部狀態(tài),這樣如果是大規(guī)模數量的對象,就可以節(jié)省很多內存空間。是不是很像文件壓縮技術?那就以壓縮圖像文件的例子來說明一下。首先是BMP文件類: public class BMPFile { private FileInfo info; private Map pixelMap; public Pixel getPixel(Position pos) { return pixelMap.get(pos); } public void setPixel(Position pos, RGB color) { Pixel pixel = new Pixel(pos, color); pixelMap.put(pos, pixel); } } FileInfo包括文件名、大小、日期等等,這暫時不考慮,因為對于享元模式,圖片上的成千上萬甚至上百萬千萬的像素(pixel)才是需要考慮的大量的細顆粒對象。像素(pixel)類,包含顏色和坐標,假設一個256色的BMP文件,那么顏色是固定的256種,就是內部狀態(tài),而坐標卻會因為圖片的樣子和大小而變化,就是外部狀態(tài)。如下: public class Pixel { private RGB color; private Position pos; public Pixel(Position pos, RGB color) { this.pos = pos; this.color = color; } } 現在開始壓縮,假設分析某個BMP文件后發(fā)現,這個BMP共包含兩種顏色,黑(RGB:000000)和白(RGB:FFFFFF),圖片大小為100x100。那么,這個BMP文件大小為10000個像素x每個像素的大?。僭O為12個字節(jié),顏色占用6個,坐標占用6個)+文件信息段(假設為500個字節(jié)),共計120500字節(jié)。轉換成壓縮格式,使用享元共享池 public class PixelPool { private Map pool = new Hashmap(); public Pixel getPixel(RGB color) { Pixel pixel = pool.get(color); if (pixel == null) { pixel = new Pixel(null, color); pool.put(color, pixel); } return pixel; } } 那么,得到的新的壓縮后的文件為: public class CompressedBMPFile extends BMPFile { private PixelPool pool = new PixelPool(); public void setPixel(Position pos, RGB color) { Pixel pixel = pool.getPixel(color); pixel.setPosition(position); pixelMap.put(pos, pixel); } } 重新來計算一下新的壓縮后的文件大小,兩個顏色的像素占用2x6個字節(jié)+坐標占用字節(jié)10000x6+文件信息500字節(jié),大約是60512字節(jié),小了一半。就算是256色的BMP,總共的大小也只有256x6+10000x6+500=62036字節(jié)。當然,紀錄用的享元池可能還有部分開銷,但總體來說,節(jié)省了很大的空間,而且通過pool得到已有的pixel對象,不用每次創(chuàng)建新的對象,也是非常節(jié)省系統(tǒng)資源的。
|