享元模式(Flyweight)
运用共享技术有效地支持大量的细粒度对象
在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行是代价——主要指内存需求方面的代价。
主要思想其实就是设置好一个对象池,如果对象的销毁则返回到池中,需要使用对象则可以从池中获取所需要的对象,进而把创建对象变为一种取用的模式。而避免在在每次使用该对象的时候都重新创建。如此的方案,第一可以解决某个对象数量不可控的问题,第二也可以解决对于某些对象创建过程消耗很大的问题。
代码
以下的代码为一个字处理的系统,把字体看做为一种对象。
严格意义上讲,每个字符都对应着他的字体。但实际在使用的过程中,一篇文章来说也就只有几种字体对象而已,如果为每个对象都创建了一个字体对象,那么会造成字体对象的大量膨胀,并且这样的膨胀也更是没有意义的。
class Font {
private String key;
public Font(final String key){
//...
}
// ... 其他属性方法
};
class FontFactory{
//字体对象池
private Map<String,Font> fontPool;
public Font GetFont(final String key){
// 根据key来在池子中查找字体对象
Font font = fontPool.get(key);
if(font != null){
return font; //查找到的就返回这个字体对象
}
else{
//没有被创建过的对象,则新创建一个,并放入池中
Font tFont = new Font(key);
fontPool.put(key, tFont);
return tFont;
}
}
void clear(){
//...
}
};
通过以上的字体池的问题,可以避免一篇文章具有十万个字符,用到了十万个字体对象,而大量的字体对象都是重复的。FlyWeight共享的对象一旦创建则无法改变,所以该对象应该是只读的。
总结
- 面向对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解决面向的代价问题,一般不触及面向对象的抽象性问题。
- Flyweight采用对象共享的做法来降低系统中的对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对像状态的处理。
- 对象的数量太大,从而导致对像内存开销加大——什么样的数量才算大?这需要我们仔细根据具体应用情况进行评估,而不能凭空臆断。