享元设计模式
享元模式(Flyweight Pattern)是一种用于减少对象创建数量、节省内存的设计模式,核心是通过共享 “细粒度对象” 来避免重复创建。它适用于存在大量相似对象的场景,比如游戏中的士兵、文本编辑器中的字符等。
使用场景:对象的状态可以外部化,即对象的部分状态可以独立于对象本身存在。
假设你在开发一款战争游戏,屏幕上需要显示 1000 个相同造型的士兵(比如都是 “步兵”),每个士兵会在不同位置移动、攻击。
如果不用享元模式,你可能会为每个士兵创建一个独立对象,每个对象里包含:
- 士兵的造型(如 “步兵” 的图片、武器模型)
- 士兵的当前位置(x 坐标、y 坐标)
- 士兵的血量、攻击力(假设所有步兵属性相同)
问题来了:
1000 个士兵中,“造型”“血量”“攻击力” 是完全一样的(固定属性),但每个士兵的 “位置” 不同(动态变化)。如果每个对象都存储这些重复的固定属性,会浪费大量内存(1000 个对象重复存储相同的图片、模型数据)。
用享元模式优化:
拆分状态为 “内部状态” 和 “外部状态”:
内部状态(共享):所有士兵都一样的属性,比如 “造型”“血量”“攻击力”,只需要保存一份,让所有士兵共享。
外部状态(外部化):每个士兵独有的属性,比如 “位置”,不存储在共享对象里,而是单独记录(比如存在一个 “位置列表” 中)。
具体实现:
定义一个 “步兵享元对象”(InfantryFlyweight),只包含内部状态:
class InfantryFlyweight {private String model; // 模型(如“步兵_01”)private int hp; // 血量(如100)private int attack; // 攻击力(如10)// 构造方法初始化内部状态(只创建一次)public InfantryFlyweight(String model, int hp, int attack) {this.model = model;this.hp = hp;this.attack = attack;}
}
用一个 “享元工厂” 管理这个共享对象(确保只创建一次):
class SoldierFactory {private static Map<String, InfantryFlyweight> flyweights = new HashMap<>();// 获取共享的步兵对象(相同模型只创建一次)public static InfantryFlyweight getInfantry() {String key = "infantry_01"; // 唯一标识if (!flyweights.containsKey(key)) {// 第一次创建时初始化内部状态flyweights.put(key, new InfantryFlyweight("步兵_01", 100, 10));}return flyweights.get(key);}
}
外部状态(位置)单独存储,使用时结合享元对象:
// 1000个士兵的位置(外部状态,单独存储)
List<Position> positions = new ArrayList<>();
for (int i = 0; i < 1000; i++) {positions.add(new Position(i * 10, 0)); // 不同的x坐标
}// 渲染士兵时,共享同一个享元对象,搭配不同的外部状态
InfantryFlyweight sharedInfantry = SoldierFactory.getInfantry();
for (Position pos : positions) {// 用共享的士兵模型,加上当前位置,渲染到屏幕render(sharedInfantry, pos);
}
