GoF设计模式之十一 Flyweight- -

来源:百度文库 编辑:神马文学网 时间:2024/04/28 06:50:04

 

                                      

    B6) Flyweight(享元模式)
    定义:使用共享来高效的支持大量的细颗粒对象。
    似乎不太常用的一个模式,因为对于要求可能严格了一点:大量的细颗粒对象,真正运用到这个层次上的机会应该不会太多。享元模式就是将大量对象实例中相同的部分提取出来,形成一个原型,这部分称为intrinsic(内部状态),是不变的,而会因外界条件而改变的部分称为extrinsic(外部状态)。那每次需要一个新的对象实例时候,就从享元共享池(pool)中得到内部状态即共享的原型,再根据外部条件,生成外部状态,这样如果是大规模数量的对象,就可以节省很多内存空间。是不是很像文件压缩技术?那就以压缩图像文件的例子来说明一下。首先是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种,就是内部状态,而坐标却会因为图片的样子和大小而变化,就是外部状态。如下:
    public class Pixel {
        private RGB color;
        private Position pos;
        public Pixel(Position pos, RGB color) {
            this.pos = pos;
            this.color = color;
        }
    }
    现在开始压缩,假设分析某个BMP文件后发现,这个BMP共包含两种颜色,黑(RGB:000000)和白(RGB:FFFFFF),图片大小为100x100。那么,这个BMP文件大小为10000个像素x每个像素的大小(假设为12个字节,颜色占用6个,坐标占用6个)+文件信息段(假设为500个字节),共计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);
        }
    }

    重新来计算一下新的压缩后的文件大小,两个颜色的像素占用2x6个字节+坐标占用字节10000x6+文件信息500字节,大约是60512字节,小了一半。就算是256色的BMP,总共的大小也只有256x6+10000x6+500=62036字节。当然,纪录用的享元池可能还有部分开销,但总体来说,节省了很大的空间,而且通过pool得到已有的pixel对象,不用每次创建新的对象,也是非常节省系统资源的。