B6) Flyweight(享元模式)
定義:使用共享來(lái)高效的支持大量的細顆粒對象。
似乎不太常用的一個(gè)模式,因為對于要求可能?chē)栏窳艘稽c(diǎn):大量的細顆粒對象,真正運用到這個(gè)層次上的機會(huì )應該不會(huì )太多。享元模式就是將大量對象實(shí)例中相同的部分提取出來(lái),形成一個(gè)原型,這部分稱(chēng)為intrinsic(內部狀態(tài)),是不變的,而會(huì )因外界條件而改變的部分稱(chēng)為extrinsic(外部狀態(tài))。那每次需要一個(gè)新的對象實(shí)例時(shí)候,就從享元共享池(pool)中得到內部狀態(tài)即共享的原型,再根據外部條件,生成外部狀態(tài),這樣如果是大規模數量的對象,就可以節省很多內存空間。是不是很像文件壓縮技術(shù)?那就以壓縮圖像文件的例子來(lái)說(shuō)明一下。首先是BMP文件類(lèi):
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包括文件名、大小、日期等等,這暫時(shí)不考慮,因為對于享元模式,圖片上的成千上萬(wàn)甚至上百萬(wàn)千萬(wàn)的像素(pixel)才是需要考慮的大量的細顆粒對象。像素(pixel)類(lèi),包含顏色和坐標,假設一個(gè)256色的BMP文件,那么顏色是固定的256種,就是內部狀態(tài),而坐標卻會(huì )因為圖片的樣子和大小而變化,就是外部狀態(tài)。如下:
public class Pixel {
private RGB color;
private Position pos;
public Pixel(Position pos, RGB color) {
this.pos = pos;
this.color = color;
}
}
現在開(kāi)始壓縮,假設分析某個(gè)BMP文件后發(fā)現,這個(gè)BMP共包含兩種顏色,黑(RGB:000000)和白(RGB:FFFFFF),圖片大小為100x100。那么,這個(gè)BMP文件大小為10000個(gè)像素x每個(gè)像素的大?。僭O為12個(gè)字節,顏色占用6個(gè),坐標占用6個(gè))+文件信息段(假設為500個(gè)字節),共計120500字節。轉換成壓縮格式,使用享元共享池
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);
}
}
重新來(lái)計算一下新的壓縮后的文件大小,兩個(gè)顏色的像素占用2x6個(gè)字節+坐標占用字節10000x6+文件信息500字節,大約是60512字節,小了一半。就算是256色的BMP,總共的大小也只有256x6+10000x6+500=62036字節。當然,紀錄用的享元池可能還有部分開(kāi)銷(xiāo),但總體來(lái)說(shuō),節省了很大的空間,而且通過(guò)pool得到已有的pixel對象,不用每次創(chuàng )建新的對象,也是非常節省系統資源的。
聯(lián)系客服