Skip to content

享元

更新: 6/22/2025 字数: 0 字 时长: 0 分钟

定义

享元模式 (Flyweight Pattern) 运用共享技术有效地支持大量细粒度对象的复用。通过分离对象的内在状态(可共享)和外在状态(不可共享),享元模式显著减少内存占用,提高系统性能。

角色

  • 享元接口 (Flyweight):声明对象操作接口
  • 具体享元 (Concrete Flyweight):实现享元接口,存储内在状态
  • 非共享具体享元 (Unshared Concrete Flyweight):不共享的具体实现
  • 享元工厂 (Flyweight Factory):创建和管理享元对象
  • 客户端 (Client):维护外在状态,使用享元对象

实现

文本编辑器字符示例

java
// 享元接口
public interface Character {
    void display(int position);
}

// 具体享元:字符对象
public class CharacterImpl implements Character {
    private char symbol; // 内在状态(可共享)
    
    public CharacterImpl(char symbol) {
        this.symbol = symbol;
    }
    
    @Override
    public void display(int position) {
        System.out.println("字符 '" + symbol + "' 在位置:" + position);
    }
}

// 享元工厂
public class CharacterFactory {
    private Map<Character, Character> characters = new HashMap<>();
    
    public Character getCharacter(char symbol) {
        Character character = characters.get(symbol);
        if (character == null) {
            character = new CharacterImpl(symbol);
            characters.put(symbol, character);
        }
        return character;
    }
}

// 客户端:文档
public class Document {
    private List<Character> chars = new ArrayList<>();
    private CharacterFactory factory = new CharacterFactory();
    
    public void addChar(char symbol, int position) {
        Character character = factory.getCharacter(symbol);
        chars.add(character);
        character.display(position);
    }
    
    public void saveToFile(String filename) {
        // 保存文档(只存储字符和位置)
    }
}

// 使用示例
public class TextEditor {
    public static void main(String[] args) {
        Document doc = new Document();
        doc.addChar('H', 1);
        doc.addChar('e', 2);
        doc.addChar('l', 3);
        doc.addChar('l', 4); // 重用'l'享元
        doc.addChar('o', 5);
    }
}

游戏粒子系统示例

java
// 内在状态(可共享)
public class ParticleType {
    private String name;
    private String texture;
    private Color color;
    
    public ParticleType(String name, String texture, Color color) {
        this.name = name;
        this.texture = texture;
        this.color = color;
    }
    
    public void draw(Particle particle) {
        // 使用内在状态绘制粒子
        System.out.printf("绘制 %s 粒子:位置 (%d,%d), 速度 (%d,%d)%n", 
            name, particle.getX(), particle.getY(), 
            particle.getVelX(), particle.getVelY());
    }
}

// 外在状态(不可共享)
public class Particle {
    private int x, y; // 位置
    private int velX, velY; // 速度
    private ParticleType type; // 享元引用
    
    public Particle(int x, int y, int velX, int velY, ParticleType type) {
        this.x = x;
        this.y = y;
        this.velX = velX;
        this.velY = velY;
        this.type = type;
    }
    
    public void move() {
        x += velX;
        y += velY;
    }
    
    public void draw() {
        type.draw(this);
    }
    
    // getters...
}

// 享元工厂
public class ParticleFactory {
    private Map<String, ParticleType> particleTypes = new HashMap<>();
    
    public ParticleType getParticleType(String name, String texture, Color color) {
        String key = name + texture + color.toString();
        ParticleType type = particleTypes.get(key);
        if (type == null) {
            type = new ParticleType(name, texture, color);
            particleTypes.put(key, type);
        }
        return type;
    }
}

// 粒子系统(客户端)
public class ParticleSystem {
    private List<Particle> particles = new ArrayList<>();
    private ParticleFactory factory = new ParticleFactory();
    
    public void addParticle(int x, int y, int velX, int velY, 
                           String typeName, String texture, Color color) {
        ParticleType type = factory.getParticleType(typeName, texture, color);
        particles.add(new Particle(x, y, velX, velY, type));
    }
    
    public void animate() {
        for (Particle particle : particles) {
            particle.move();
            particle.draw();
        }
    }
}

优缺点

优点:

  1. 大幅减少内存占用
  2. 减少对象创建开销
  3. 集中管理共享状态
  4. 提高系统性能(尤其大量重复对象场景)

缺点:

  1. 增加系统复杂度
  2. 需要分离内外状态(增加设计难度)
  3. 共享对象线程安全问题
  4. 可能引入查找开销(工厂查找)

应用场景

  1. 大量相似对象占用过多内存
  2. 对象状态可分离为内在和外在
  3. 不依赖对象标识的操作
  4. 文本编辑器(字符处理)
  5. 游戏开发(粒子、地形、NPC)
  6. 图形系统(图标、光标)
  7. 数据库连接池

与其他模式的关系

  • 与组合模式:享元可作为组合中的叶子节点
  • 与单例模式:享元工厂常使用单例
  • 与状态模式:状态对象可实现为享元
  • 与策略模式:策略对象可实现为享元
  • 与对象池模式:对象池管理生命周期,享元关注状态共享

JDK 中的享元模式

  1. Java 字符串常量池
  2. java.lang.Integer#valueOf()(-128~127 缓存)
  3. java.lang.Boolean#valueOf()(TRUE/FALSE 缓存)
  4. Swing 中的Border实现
  5. Java 线程池(线程复用)

注意事项

  1. 仔细分析对象状态(区分内在/外在)
  2. 控制享元对象数量(避免工厂膨胀)
  3. 考虑线程安全(共享状态访问)
  4. 避免过早优化(只在必要时使用)
  5. 注意享元对象生命周期管理
  6. 平衡内存节省与性能开销

贡献者

The avatar of contributor named as LI SIR LI SIR
The avatar of contributor named as wkwbk wkwbk

页面历史