什么是享元模式?
享元模式是一种结构型设计模式,它通过共享技术来有效地支持大量细粒度的对象。享元模式通过共享已经存在的对象来减少创建对象的数量,从而减少内存占用和提高性能。
享元模式包含以下角色:
- 享元接口(Flyweight):声明一个接口,通过它可以接受并作用于外部状态
- 具体享元类(ConcreteFlyweight):实现享元接口,并为内部状态增加存储空间
- 非共享具体享元类(UnsharedConcreteFlyweight):不需要共享的Flyweight子类
- 享元工厂(FlyweightFactory):创建并管理flyweight对象,确保合理地共享flyweight
享元模式的优缺点
优点:
- 减少内存使用:通过共享对象,大量减少对象的创建,节省内存空间
- 提高性能:减少对象创建和垃圾回收的开销
- 系统资源优化:有效利用系统资源,提高系统整体性能
缺点: - 增加复杂性:需要区分内部状态和外部状态,增加了系统复杂性
- 线程安全问题:共享对象可能带来线程安全问题,需要额外处理
- 状态管理复杂:需要仔细管理对象的内部状态和外部状态
什么场景下使用享元模式
- 系统中有大量相似对象
- 这些对象的大部分状态都可以外部化
- 按照内部状态分成很多组,当把对象作为组来处理时,同一组的对象可以被共享
- 需要缓冲池的场景
- 对象创建开销大,但可以共享的场景
代码举例
// 享元接口 - 地形类型
interface Terrain {void render(int x, int y, String instanceData);boolean isWalkable();int getMovementCost();
}// 具体享元类 - 草地地形(内部状态:类型属性)
class GrassTerrain implements Terrain {private static final String TYPE = "Grass";private static final boolean WALKABLE = true;private static final int MOVEMENT_COST = 1;@Overridepublic void render(int x, int y, String instanceData) {System.out.printf("渲染草地地形在(%d,%d),实例数据:%s%n", x, y, instanceData);}@Overridepublic boolean isWalkable() {return WALKABLE;}@Overridepublic int getMovementCost() {return MOVEMENT_COST;}
}// 具体享元类 - 水域地形
class WaterTerrain implements Terrain {private static final String TYPE = "Water";private static final boolean WALKABLE = false;private static final int MOVEMENT_COST = Integer.MAX_VALUE;@Overridepublic void render(int x, int y, String instanceData) {System.out.printf("渲染水域地形在(%d,%d),实例数据:%s%n", x, y, instanceData);}@Overridepublic boolean isWalkable() {return WALKABLE;}@Overridepublic int getMovementCost() {return MOVEMENT_COST;}
}// 具体享元类 - 山地形
class MountainTerrain implements Terrain {private static final String TYPE = "Mountain";private static final boolean WALKABLE = false;private static final int MOVEMENT_COST = Integer.MAX_VALUE;@Overridepublic void render(int x, int y, String instanceData) {System.out.printf("渲染山地形在(%d,%d),实例数据:%s%n", x, y, instanceData);}@Overridepublic boolean isWalkable() {return WALKABLE;}@Overridepublic int getMovementCost() {return MOVEMENT_COST;}
}// 具体享元类 - 道路地形
class RoadTerrain implements Terrain {private static final String TYPE = "Road";private static final boolean WALKABLE = true;private static final int MOVEMENT_COST = 1;@Overridepublic void render(int x, int y, String instanceData) {System.out.printf("渲染道路地形在(%d,%d),实例数据:%s%n", x, y, instanceData);}@Overridepublic boolean isWalkable() {return WALKABLE;}@Overridepublic int getMovementCost() {return MOVEMENT_COST;}
}// 享元工厂
class TerrainFactory {private static final Map<String, Terrain> terrainTypes = new HashMap<>();static {terrainTypes.put("grass", new GrassTerrain());terrainTypes.put("water", new WaterTerrain());terrainTypes.put("mountain", new MountainTerrain());terrainTypes.put("road", new RoadTerrain());}public static Terrain getTerrain(String type) {Terrain terrain = terrainTypes.get(type.toLowerCase());if (terrain == null) {throw new IllegalArgumentException("未知的地形类型: " + type);}return terrain;}public static int getTerrainTypeCount() {return terrainTypes.size();}
}// 地形实例(包含外部状态)
class TerrainTile {private int x, y;private Terrain terrain;private String variation; // 外部状态:地形变种private boolean hasResource; // 外部状态:是否有资源public TerrainTile(int x, int y, Terrain terrain, String variation, boolean hasResource) {this.x = x;this.y = y;this.terrain = terrain;this.variation = variation;this.hasResource = hasResource;}public void render() {String instanceData = String.format("变种:%s, 资源:%s", variation, hasResource ? "有" : "无");terrain.render(x, y, instanceData);}public boolean isWalkable() {return terrain.isWalkable();}public int getMovementCost() {return terrain.getMovementCost();}// getterspublic int getX() { return x; }public int getY() { return y; }public String getVariation() { return variation; }public boolean hasResource() { return hasResource; }
}// 游戏地图类
class GameMap {private List<TerrainTile> tiles = new ArrayList<>();private int width, height;public GameMap(int width, int height) {this.width = width;this.height = height;}public void addTile(int x, int y, String terrainType, String variation, boolean hasResource) {if (x >= 0 && x < width && y >= 0 && y < height) {Terrain terrain = TerrainFactory.getTerrain(terrainType);tiles.add(new TerrainTile(x, y, terrain, variation, hasResource));}}public void render() {System.out.println("=== 渲染游戏地图 ===");System.out.println("地图大小: " + width + "x" + height);System.out.println("地形类型数量: " + TerrainFactory.getTerrainTypeCount());System.out.println("地形实例数量: " + tiles.size());for (TerrainTile tile : tiles) {tile.render();}}public List<TerrainTile> getWalkableTiles() {List<TerrainTile> walkableTiles = new ArrayList<>();for (TerrainTile tile : tiles) {if (tile.isWalkable()) {walkableTiles.add(tile);}}return walkableTiles;}
}// 客户端使用示例
public class GameMapDemo {public static void main(String[] args) {GameMap gameMap = new GameMap(100, 100);// 创建大量地形实例,但只有几种地形类型Random random = new Random();String[] terrainTypes = {"grass", "water", "mountain", "road"};String[] variations = {"light", "dark", "normal"};// 模拟创建一个大地图的地形for (int i = 0; i < 1000; i++) {int x = random.nextInt(100);int y = random.nextInt(100);String terrainType = terrainTypes[random.nextInt(terrainTypes.length)];String variation = variations[random.nextInt(variations.length)];boolean hasResource = random.nextDouble() < 0.1; // 10%概率有资源gameMap.addTile(x, y, terrainType, variation, hasResource);}// 渲染地图gameMap.render();// 获取可行走的地形List<TerrainTile> walkableTiles = gameMap.getWalkableTiles();System.out.println("\n可行走的地形数量: " + walkableTiles.size());// 显示前10个可行走地形System.out.println("\n前10个可行走地形:");for (int i = 0; i < Math.min(10, walkableTiles.size()); i++) {TerrainTile tile = walkableTiles.get(i);System.out.printf("位置(%d,%d), 变种:%s%n", tile.getX(), tile.getY(), tile.getVariation());}}
}