Java 享元模式 详解

发布于:2025-04-09 ⋅ 阅读:(25) ⋅ 点赞:(0)

享元模式详解

一、享元模式概述

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术有效地支持大量细粒度的对象。享元模式通过分离对象的内在状态和外在状态,使得可以在多个对象之间共享内在状态,从而减少内存使用。

核心特点

  • 共享对象:相同内在状态的对象被共享
  • 状态分离:区分内在状态(共享)和外在状态(非共享)
  • 减少内存:显著降低大量对象的内存占用
  • 性能优化:适用于对象数量庞大的场景

二、享元模式的结构

主要角色

  1. Flyweight:抽象享元类,定义共享接口
  2. ConcreteFlyweight:具体享元类,实现共享部分
  3. UnsharedConcreteFlyweight:非共享享元类(可选)
  4. FlyweightFactory:享元工厂,创建和管理享元对象
  5. Client:客户端,维护外在状态

三、享元模式的实现

1. 基本实现

// 抽象享元
public interface Flyweight {
    void operation(String extrinsicState);
}

// 具体享元
public class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;
    
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
    
    public void operation(String extrinsicState) {
        System.out.println("内部状态: " + intrinsicState + 
                         ", 外部状态: " + extrinsicState);
    }
}

// 享元工厂
public class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();
    
    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
    
    public int getFlyweightCount() {
        return flyweights.size();
    }
}

// 使用示例
FlyweightFactory factory = new FlyweightFactory();
Flyweight fw1 = factory.getFlyweight("A");
fw1.operation("First Call");

Flyweight fw2 = factory.getFlyweight("A");
fw2.operation("Second Call");

System.out.println("享元对象数量: " + factory.getFlyweightCount());

2. 更复杂的实现

// 字符享元
public class CharacterFlyweight {
    private final char character;
    private final String fontFamily;
    private final int fontSize;
    
    public CharacterFlyweight(char character, String fontFamily, int fontSize) {
        this.character = character;
        this.fontFamily = fontFamily;
        this.fontSize = fontSize;
    }
    
    public void display(int x, int y, String color) {
        System.out.printf("显示字符 '%c' (字体: %s %dpx) 在位置 (%d,%d) 颜色 %s\n",
                        character, fontFamily, fontSize, x, y, color);
    }
}

// 享元工厂
public class CharacterFactory {
    private Map<String, CharacterFlyweight> pool = new HashMap<>();
    
    public CharacterFlyweight getCharacter(char c, String fontFamily, int fontSize) {
        String key = c + fontFamily + fontSize;
        if (!pool.containsKey(key)) {
            pool.put(key, new CharacterFlyweight(c, fontFamily, fontSize));
        }
        return pool.get(key);
    }
}

// 客户端使用
CharacterFactory factory = new CharacterFactory();
CharacterFlyweight char1 = factory.getCharacter('A', "Arial", 12);
char1.display(10, 20, "Red");

CharacterFlyweight char2 = factory.getCharacter('A', "Arial", 12);
char2.display(30, 40, "Blue");

四、享元模式的应用场景

1. 文本编辑器中的字符处理

public class TextEditor {
    private CharacterFactory charFactory = new CharacterFactory();
    private List<CharacterFlyweight> chars = new ArrayList<>();
    private List<Integer> positionsX = new ArrayList<>();
    private List<Integer> positionsY = new ArrayList<>();
    private List<String> colors = new ArrayList<>();
    
    public void addCharacter(char c, String font, int size, int x, int y, String color) {
        CharacterFlyweight charFlyweight = charFactory.getCharacter(c, font, size);
        chars.add(charFlyweight);
        positionsX.add(x);
        positionsY.add(y);
        colors.add(color);
    }
    
    public void render() {
        for (int i = 0; i < chars.size(); i++) {
            chars.get(i).display(positionsX.get(i), positionsY.get(i), colors.get(i));
        }
    }
}

2. 游戏中的粒子系统

// 粒子享元
public class ParticleFlyweight {
    private final String texture;
    private final String particleShape;
    
    public ParticleFlyweight(String texture, String shape) {
        this.texture = texture;
        this.particleShape = shape;
    }
    
    public void render(int x, int y, String color, int speed) {
        System.out.printf("渲染 %s 粒子 (纹理: %s) 在 (%d,%d) 颜色 %s 速度 %d\n",
                        particleShape, texture, x, y, color, speed);
    }
}

// 粒子工厂
public class ParticleFactory {
    private Map<String, ParticleFlyweight> particles = new HashMap<>();
    
    public ParticleFlyweight getParticle(String texture, String shape) {
        String key = texture + "_" + shape;
        if (!particles.containsKey(key)) {
            particles.put(key, new ParticleFlyweight(texture, shape));
        }
        return particles.get(key);
    }
}

3. 数据库连接池

public class ConnectionPool {
    private static final int POOL_SIZE = 5;
    private List<Connection> pool = new ArrayList<>();
    
    public ConnectionPool(String url, String user, String password) {
        for (int i = 0; i < POOL_SIZE; i++) {
            pool.add(createConnection(url, user, password));
        }
    }
    
    public Connection getConnection() {
        for (Connection conn : pool) {
            if (!conn.isInUse()) {
                conn.setInUse(true);
                return conn;
            }
        }
        throw new RuntimeException("连接池已满");
    }
    
    public void releaseConnection(Connection conn) {
        conn.setInUse(false);
    }
    
    private Connection createConnection(String url, String user, String password) {
        // 创建实际连接
        return new Connection(url, user, password);
    }
}

五、享元模式的变体

1. 复合享元模式

public class CompositeFlyweight implements Flyweight {
    private Map<String, Flyweight> flyweights = new HashMap<>();
    
    public void add(String key, Flyweight flyweight) {
        flyweights.put(key, flyweight);
    }
    
    public void operation(String extrinsicState) {
        for (Flyweight flyweight : flyweights.values()) {
            flyweight.operation(extrinsicState);
        }
    }
}

2. 带缓存清理的享元工厂

public class ManagedFlyweightFactory {
    private Map<String, WeakReference<Flyweight>> cache = new HashMap<>();
    
    public Flyweight getFlyweight(String key) {
        synchronized (cache) {
            WeakReference<Flyweight> ref = cache.get(key);
            Flyweight flyweight = (ref != null) ? ref.get() : null;
            
            if (flyweight == null) {
                flyweight = new ConcreteFlyweight(key);
                cache.put(key, new WeakReference<>(flyweight));
            }
            return flyweight;
        }
    }
}

六、享元模式的优缺点

优点

  1. 减少内存使用:共享相同内在状态的对象
  2. 提高性能:减少对象创建和垃圾回收开销
  3. 集中管理:享元工厂统一管理共享对象
  4. 扩展性好:可以轻松增加新的共享对象

缺点

  1. 增加复杂度:需要区分内在和外在状态
  2. 线程安全问题:共享对象需要考虑线程安全
  3. 不适用所有场景:仅当对象数量庞大且内在状态可共享时有效

七、最佳实践

  1. 合理划分状态:明确区分内在和外在状态
  2. 使用工厂管理:集中管理享元对象的创建和共享
  3. 考虑线程安全:多线程环境下确保共享对象安全
  4. 性能监控:监控享元池的大小和效果
  5. 避免过度使用:仅在确实需要优化内存时使用

八、总结

享元模式是优化大量细粒度对象内存使用的有效方案,特别适用于:

  • 系统需要创建大量相似对象
  • 对象的大部分状态可以外部化
  • 内存占用是系统瓶颈
  • 需要集中管理共享资源

在实际开发中,享元模式常见于:

  • 文本/图形编辑器
  • 游戏开发(粒子、角色等)
  • 数据库连接池
  • 浏览器DOM节点管理

正确使用享元模式可以显著降低内存消耗,但需要注意不要过早优化,应在性能分析确认内存是瓶颈后再考虑使用此模式。


网站公告

今日签到

点亮在社区的每一天
去签到