享元模式是什么?
享元模式(Flyweight Pattern)是一种结构型的设计模式,它的思想是摒弃在每个对象中保存所有数据的方式,通过共享多个对象共有的相同状态,使我们能够在有限的内存容量中更快地载入更多的对象。
相信大家都玩过超级马里奥这款游戏,游戏中马里奥的冒险之旅会碰到各种怪物的干扰,一旦马里奥被这些怪物碰触到,游戏就以失败结束了。游戏中会出现大量的怪物,每出现一个怪物时,我们就得创建一个对象来表示。游戏画面在渲染怪物时,得将表示该怪物的图片加载内存中,这个过程不仅耗时也很耗内存。
对于同一种怪物,比如蘑菇怪,渲染它们的图片是一样的并且是不会改变的。这种只能读取但不能修改的常量属性,我们称之为内在状态。而值会变化的属性,则称之为外在状态,比如怪物的坐标,它会随着怪物移动而变化。所以,我们其实可以将一个对象分成两个部分,包含内在状态的部分,以及包含外在状态的部分。仅包含内在状态的部分称之为享元。
为了能方便地维护各种享元对象,我们可以创建一个缓存池来管理已有的享元对象。当要获取一个享元对象时,先从缓存池中查找,如果找到了,就将其返回;如果找不到,则新建一个享元对象,并将其添加到缓存池中。
案例
让我们通过模拟马里奥游戏来进一步理解享元模式。首先,我们定义一个 Monster 类来表示怪物。
public class Monster {
private MonsterType monsterType;
private Position position;
private Image image;
public void render() {
// Our code for rendering the monster
}
// other methods
}
现在,我们知道 image 属性是 Monster 对象的内部状态,所以我们不会每创建一个 Monster 对象就跟着 new 一个 Image 对象。我们会用一个缓存池来管理 Image 对象,并提供一个工厂方法负责对象的创建、获取。
public class ImageFactory {
private static Map<String, Image> imageCache = new HashMap<String, Image>();
public static Image createImage(String path) {
Image image;
if (imageCache.containsKey(path)) {
image = imageCache.get(path);
} else {
image = new Image(path);
imageCache.put(path, image);
}
return image;
}
}
为了更好地维护 Monster 对象的创建,我们同样也是提供一个工厂方法。在创建 Monster 对象时,image 享元对象是通过 ImageFactory 获取的,而不是 new 得到的。
public class MonsterFactory {
private static Map<MonsterType, String> monsterImagePathMap = new HashMap<>();
static {
monsterImagePathMap.put(MonsterType.MUSHROOM, "/images/monster/mushroom.png");
monsterImagePathMap.put(MonsterType.TORTOISE, "/images/monster/tortoise.png");
// ...
}
public static Monster createMonster(MonsterType monsterType, Position position) {
Monster monster = new Monster();
monster.setMonsterType(monsterType);
monster.setPosition(position);
Image image = ImageFactory.createImage(monsterImagePathMap.get(monsterType));
monster.setImage(image);
return monster;
}
}
案例源码
可在 GitHub 上查看上述案例的完整代码。
参考资料
本文参考的资料如下: