设计模式之:享元模式

文章目录

什么是享元模式?

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术来有效地支持大量细粒度对象的复用。享元模式通过共享已经存在的对象来减少内存使用,提高系统性能。

核心思想

享元模式的核心思想是:将对象的属性分为内部状态和外部状态,内部状态可以共享,外部状态由客户端维护,从而减少内存中对象的数量。

生活中的享元模式

想象一下字处理软件:

  • 每个字符都有字体、大小、颜色等属性
  • 如果每个字符都存储所有属性,内存会爆炸
  • 实际上,相同格式的字符共享格式信息
  • 只有字符内容和位置是每个字符独有的

这就是享元模式的思想!

模式结构

享元模式包含四个核心角色:

  1. 享元接口(Flyweight):定义享元对象的接口
  2. 具体享元(ConcreteFlyweight):实现享元接口,包含内部状态
  3. 享元工厂(FlyweightFactory):创建和管理享元对象
  4. 客户端(Client):维护外部状态,使用享元对象

基础示例:文字编辑器

1. 享元接口和具体享元

java 复制代码
/**
 * 字符享元接口
 */
public interface CharacterFlyweight {
    /**
     * 显示字符
     * @param externalState 外部状态(位置、颜色等)
     */
    void display(CharacterExternalState externalState);
    
    /**
     * 获取字符内容
     */
    char getCharacter();
    
    /**
     * 获取内部状态
     */
    CharacterInternalState getInternalState();
}

/**
 * 字符内部状态 - 可以共享的部分
 */
class CharacterInternalState {
    private final String fontFamily;
    private final int fontSize;
    private final boolean isBold;
    private final boolean isItalic;
    
    public CharacterInternalState(String fontFamily, int fontSize, 
                                 boolean isBold, boolean isItalic) {
        this.fontFamily = fontFamily;
        this.fontSize = fontSize;
        this.isBold = isBold;
        this.isItalic = isItalic;
    }
    
    // Getter方法
    public String getFontFamily() { return fontFamily; }
    public int getFontSize() { return fontSize; }
    public boolean isBold() { return isBold; }
    public boolean isItalic() { return isItalic; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CharacterInternalState that = (CharacterInternalState) o;
        return fontSize == that.fontSize && 
               isBold == that.isBold && 
               isItalic == that.isItalic && 
               Objects.equals(fontFamily, that.fontFamily);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(fontFamily, fontSize, isBold, isItalic);
    }
    
    @Override
    public String toString() {
        return String.format("字体:%s, 大小:%d, 粗体:%s, 斜体:%s", 
            fontFamily, fontSize, isBold ? "是" : "否", isItalic ? "是" : "否");
    }
}

/**
 * 字符外部状态 - 不可共享的部分
 */
class CharacterExternalState {
    private final int positionX;
    private final int positionY;
    private final String color;
    
    public CharacterExternalState(int positionX, int positionY, String color) {
        this.positionX = positionX;
        this.positionY = positionY;
        this.color = color;
    }
    
    // Getter方法
    public int getPositionX() { return positionX; }
    public int getPositionY() { return positionY; }
    public String getColor() { return color; }
    
    @Override
    public String toString() {
        return String.format("位置(%d,%d), 颜色:%s", positionX, positionY, color);
    }
}

/**
 * 具体字符享元
 */
public class ConcreteCharacter implements CharacterFlyweight {
    private final char character;
    private final CharacterInternalState internalState;
    
    public ConcreteCharacter(char character, CharacterInternalState internalState) {
        this.character = character;
        this.internalState = internalState;
    }
    
    @Override
    public void display(CharacterExternalState externalState) {
        System.out.printf("字符 '%c' [%s] [%s]%n", 
            character, internalState, externalState);
    }
    
    @Override
    public char getCharacter() {
        return character;
    }
    
    @Override
    public CharacterInternalState getInternalState() {
        return internalState;
    }
}

2. 享元工厂

java 复制代码
import java.util.HashMap;
import java.util.Map;

/**
 * 字符享元工厂
 * 管理字符享元对象的创建和共享
 */
public class CharacterFlyweightFactory {
    private static CharacterFlyweightFactory instance;
    private final Map<String, CharacterFlyweight> characterPool;
    
    private CharacterFlyweightFactory() {
        this.characterPool = new HashMap<>();
    }
    
    public static CharacterFlyweightFactory getInstance() {
        if (instance == null) {
            instance = new CharacterFlyweightFactory();
        }
        return instance;
    }
    
    /**
     * 获取字符享元对象
     */
    public CharacterFlyweight getCharacter(char character, CharacterInternalState internalState) {
        String key = generateKey(character, internalState);
        
        // 如果池中已存在,直接返回
        if (characterPool.containsKey(key)) {
            System.out.printf("✓ 共享字符: '%c' [%s]%n", character, internalState);
            return characterPool.get(key);
        }
        
        // 否则创建新的享元对象并放入池中
        System.out.printf("➤ 创建新字符: '%c' [%s]%n", character, internalState);
        CharacterFlyweight flyweight = new ConcreteCharacter(character, internalState);
        characterPool.put(key, flyweight);
        
        return flyweight;
    }
    
    /**
     * 生成享元对象的键
     */
    private String generateKey(char character, CharacterInternalState internalState) {
        return character + "|" + internalState.hashCode();
    }
    
    /**
     * 获取池中享元对象数量
     */
    public int getPoolSize() {
        return characterPool.size();
    }
    
    /**
     * 显示池中所有享元对象
     */
    public void displayPool() {
        System.out.println("\n📊 字符享元池内容:");
        System.out.println("-".repeat(50));
        characterPool.forEach((key, flyweight) -> {
            ConcreteCharacter character = (ConcreteCharacter) flyweight;
            System.out.printf("键: %s -> 字符: '%c' [%s]%n", 
                key, character.getCharacter(), character.getInternalState());
        });
        System.out.println("总计: " + characterPool.size() + " 个享元对象");
    }
}

3. 客户端使用

java 复制代码
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 文档编辑器 - 客户端
 */
public class DocumentEditor {
    private final List<CharacterContext> documentContent;
    private final CharacterFlyweightFactory factory;
    private final Random random;
    
    public DocumentEditor() {
        this.documentContent = new ArrayList<>();
        this.factory = CharacterFlyweightFactory.getInstance();
        this.random = new Random();
    }
    
    /**
     * 向文档添加字符
     */
    public void addCharacter(char character, CharacterInternalState internalState, 
                           int positionX, int positionY, String color) {
        // 获取享元对象
        CharacterFlyweight flyweight = factory.getCharacter(character, internalState);
        
        // 创建外部状态
        CharacterExternalState externalState = new CharacterExternalState(positionX, positionY, color);
        
        // 保存字符上下文
        CharacterContext context = new CharacterContext(flyweight, externalState);
        documentContent.add(context);
    }
    
    /**
     * 显示文档内容
     */
    public void displayDocument() {
        System.out.println("\n📄 文档内容:");
        System.out.println("=" .repeat(60));
        
        for (CharacterContext context : documentContent) {
            context.display();
        }
        
        System.out.println("=" .repeat(60));
        System.out.printf("文档字符数: %d, 享元对象数: %d, 节省内存: %.1f%%%n",
            documentContent.size(), factory.getPoolSize(),
            (1 - (double) factory.getPoolSize() / documentContent.size()) * 100);
    }
    
    /**
     * 生成测试文档
     */
    public void generateTestDocument() {
        System.out.println("🛠️ 生成测试文档...");
        
        // 定义几种格式
        CharacterInternalState[] formats = {
            new CharacterInternalState("宋体", 12, false, false),  // 普通文本
            new CharacterInternalState("黑体", 14, true, false),   // 标题
            new CharacterInternalState("楷体", 12, false, true),   // 强调
            new CharacterInternalState("宋体", 10, false, false)   // 小字
        };
        
        String[] colors = {"黑色", "红色", "蓝色", "绿色"};
        String text = "享元模式通过共享技术来有效地支持大量细粒度对象的复用";
        
        int position = 0;
        for (char c : text.toCharArray()) {
            // 随机选择格式和颜色
            CharacterInternalState format = formats[random.nextInt(formats.length)];
            String color = colors[random.nextInt(colors.length)];
            
            addCharacter(c, format, position * 20, 0, color);
            position++;
        }
    }
}

/**
 * 字符上下文 - 维护外部状态
 */
class CharacterContext {
    private final CharacterFlyweight flyweight;
    private final CharacterExternalState externalState;
    
    public CharacterContext(CharacterFlyweight flyweight, CharacterExternalState externalState) {
        this.flyweight = flyweight;
        this.externalState = externalState;
    }
    
    public void display() {
        flyweight.display(externalState);
    }
    
    public CharacterFlyweight getFlyweight() {
        return flyweight;
    }
    
    public CharacterExternalState getExternalState() {
        return externalState;
    }
}

4. 测试客户端

java 复制代码
/**
 * 享元模式测试客户端
 */
public class FlyweightClient {
    public static void main(String[] args) {
        System.out.println("=== 享元模式演示 - 文字编辑器 ===\n");
        
        DocumentEditor editor = new DocumentEditor();
        
        // 演示1:基础使用
        demonstrateBasicUsage(editor);
        
        // 演示2:性能对比
        demonstratePerformanceComparison();
        
        // 演示3:实际应用场景
        demonstrateRealWorldScenario();
    }
    
    /**
     * 演示基础使用
     */
    private static void demonstrateBasicUsage(DocumentEditor editor) {
        System.out.println("1. 基础使用演示:");
        System.out.println("-".repeat(50));
        
        // 创建几种格式
        CharacterInternalState normal = new CharacterInternalState("宋体", 12, false, false);
        CharacterInternalState bold = new CharacterInternalState("黑体", 14, true, false);
        CharacterInternalState italic = new CharacterInternalState("楷体", 12, false, true);
        
        // 添加一些字符
        editor.addCharacter('H', bold, 0, 0, "红色");
        editor.addCharacter('e', normal, 20, 0, "黑色");
        editor.addCharacter('l', normal, 40, 0, "黑色");
        editor.addCharacter('l', normal, 60, 0, "黑色"); // 重复字符,应该共享
        editor.addCharacter('o', italic, 80, 0, "蓝色");
        editor.addCharacter('!', bold, 100, 0, "红色");
        
        // 显示文档
        editor.displayDocument();
        
        // 显示享元池
        CharacterFlyweightFactory.getInstance().displayPool();
    }
    
    /**
     * 演示性能对比
     */
    private static void demonstratePerformanceComparison() {
        System.out.println("\n2. 性能对比演示:");
        System.out.println("-".repeat(50));
        
        // 测试不使用享元模式
        long startTime = System.currentTimeMillis();
        testWithoutFlyweight();
        long withoutFlyweightTime = System.currentTimeMillis() - startTime;
        
        // 测试使用享元模式
        startTime = System.currentTimeMillis();
        testWithFlyweight();
        long withFlyweightTime = System.currentTimeMillis() - startTime;
        
        System.out.println("\n⏱️ 性能对比结果:");
        System.out.printf("不使用享元模式: %d ms%n", withoutFlyweightTime);
        System.out.printf("使用享元模式: %d ms%n", withFlyweightTime);
        System.out.printf("性能提升: %.1f%%%n", 
            (1 - (double) withFlyweightTime / withoutFlyweightTime) * 100);
    }
    
    private static void testWithoutFlyweight() {
        List<SimpleCharacter> characters = new ArrayList<>();
        CharacterInternalState format = new CharacterInternalState("宋体", 12, false, false);
        
        // 创建10000个字符对象
        for (int i = 0; i < 10000; i++) {
            char c = (char) ('A' + (i % 26));
            characters.add(new SimpleCharacter(c, format, i * 10, 0, "黑色"));
        }
    }
    
    private static void testWithFlyweight() {
        DocumentEditor editor = new DocumentEditor();
        CharacterInternalState format = new CharacterInternalState("宋体", 12, false, false);
        
        // 创建10000个字符,但共享享元对象
        for (int i = 0; i < 10000; i++) {
            char c = (char) ('A' + (i % 26));
            editor.addCharacter(c, format, i * 10, 0, "黑色");
        }
    }
    
    /**
     * 演示实际应用场景
     */
    private static void demonstrateRealWorldScenario() {
        System.out.println("\n3. 实际应用场景演示:");
        System.out.println("-".repeat(50));
        
        DocumentEditor editor = new DocumentEditor();
        editor.generateTestDocument();
        editor.displayDocument();
        CharacterFlyweightFactory.getInstance().displayPool();
    }
}

/**
 * 简单字符类 - 用于对比测试
 */
class SimpleCharacter {
    private char character;
    private CharacterInternalState internalState;
    private int positionX;
    private int positionY;
    private String color;
    
    public SimpleCharacter(char character, CharacterInternalState internalState,
                          int positionX, int positionY, String color) {
        this.character = character;
        this.internalState = internalState;
        this.positionX = positionX;
        this.positionY = positionY;
        this.color = color;
    }
}

完整示例:围棋游戏

让我们通过一个更复杂的围棋游戏示例来深入理解享元模式。

1. 围棋棋子享元

java 复制代码
import java.util.HashMap;
import java.util.Map;

/**
 * 围棋棋子享元接口
 */
public interface GoPiece {
    /**
     * 显示棋子
     * @param externalState 外部状态(位置)
     */
    void display(PieceExternalState externalState);
    
    /**
     * 获取棋子颜色
     */
    String getColor();
}

/**
 * 棋子内部状态
 */
class PieceInternalState {
    private final String color; // 颜色是内部状态,可以共享
    private final String shape; // 形状(圆形)
    
    public PieceInternalState(String color) {
        this.color = color;
        this.shape = "圆形";
    }
    
    public String getColor() { return color; }
    public String getShape() { return shape; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PieceInternalState that = (PieceInternalState) o;
        return Objects.equals(color, that.color) && 
               Objects.equals(shape, that.shape);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(color, shape);
    }
    
    @Override
    public String toString() {
        return color + shape;
    }
}

/**
 * 棋子外部状态
 */
class PieceExternalState {
    private final int x;
    private final int y;
    
    public PieceExternalState(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public int getX() { return x; }
    public int getY() { return y; }
    
    @Override
    public String toString() {
        return String.format("位置(%d,%d)", x, y);
    }
}

/**
 * 具体围棋棋子
 */
class ConcreteGoPiece implements GoPiece {
    private final PieceInternalState internalState;
    
    public ConcreteGoPiece(PieceInternalState internalState) {
        this.internalState = internalState;
    }
    
    @Override
    public void display(PieceExternalState externalState) {
        System.out.printf("○ %s棋子 %s%n", internalState.getColor(), externalState);
    }
    
    @Override
    public String getColor() {
        return internalState.getColor();
    }
    
    public PieceInternalState getInternalState() {
        return internalState;
    }
}

/**
 * 围棋棋子工厂
 */
class GoPieceFactory {
    private static GoPieceFactory instance;
    private final Map<String, GoPiece> piecePool;
    
    private GoPieceFactory() {
        this.piecePool = new HashMap<>();
    }
    
    public static GoPieceFactory getInstance() {
        if (instance == null) {
            instance = new GoPieceFactory();
        }
        return instance;
    }
    
    public GoPiece getPiece(String color) {
        // 如果池中已存在,直接返回
        if (piecePool.containsKey(color)) {
            System.out.printf("✓ 共享%s棋子%n", color);
            return piecePool.get(color);
        }
        
        // 否则创建新的享元对象
        System.out.printf("➤ 创建新%s棋子%n", color);
        PieceInternalState internalState = new PieceInternalState(color);
        GoPiece piece = new ConcreteGoPiece(internalState);
        piecePool.put(color, piece);
        
        return piece;
    }
    
    public int getPoolSize() {
        return piecePool.size();
    }
    
    public void displayPool() {
        System.out.println("\n🎲 棋子享元池:");
        piecePool.forEach((color, piece) -> {
            System.out.printf("颜色: %s -> %s%n", color, piece.getColor());
        });
        System.out.println("总计: " + piecePool.size() + " 种棋子");
    }
}

2. 围棋棋盘

java 复制代码
import java.util.ArrayList;
import java.util.List;

/**
 * 围棋棋盘
 */
public class GoBoard {
    private final List<PieceContext> pieces;
    private final GoPieceFactory factory;
    private static final int BOARD_SIZE = 19;
    
    public GoBoard() {
        this.pieces = new ArrayList<>();
        this.factory = GoPieceFactory.getInstance();
    }
    
    /**
     * 在棋盘上放置棋子
     */
    public void placePiece(String color, int x, int y) {
        if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE) {
            System.out.println("❌ 无效位置: (" + x + "," + y + ")");
            return;
        }
        
        // 检查位置是否已有棋子
        if (hasPieceAt(x, y)) {
            System.out.println("❌ 位置 (" + x + "," + y + ") 已有棋子");
            return;
        }
        
        // 获取棋子享元
        GoPiece piece = factory.getPiece(color);
        
        // 创建外部状态
        PieceExternalState externalState = new PieceExternalState(x, y);
        
        // 保存棋子上下文
        PieceContext context = new PieceContext(piece, externalState);
        pieces.add(context);
        
        System.out.printf("✅ 在(%d,%d)放置%s棋子%n", x, y, color);
    }
    
    /**
     * 检查位置是否有棋子
     */
    private boolean hasPieceAt(int x, int y) {
        return pieces.stream().anyMatch(context -> 
            context.getExternalState().getX() == x && 
            context.getExternalState().getY() == y);
    }
    
    /**
     * 显示棋盘状态
     */
    public void displayBoard() {
        System.out.println("\n🎯 棋盘状态:");
        System.out.println("=" .repeat(40));
        
        for (PieceContext context : pieces) {
            context.display();
        }
        
        System.out.println("=" .repeat(40));
        System.out.printf("棋盘棋子数: %d, 享元对象数: %d%n", 
            pieces.size(), factory.getPoolSize());
    }
    
    /**
     * 模拟一局围棋
     */
    public void simulateGame() {
        System.out.println("🎮 开始模拟围棋对局...");
        
        // 黑棋先行
        placePiece("黑", 3, 3);
        placePiece("黑", 4, 4);
        placePiece("黑", 5, 5);
        
        // 白棋应对
        placePiece("白", 3, 4);
        placePiece("白", 4, 3);
        placePiece("白", 5, 4);
        
        // 继续对局
        placePiece("黑", 6, 6);
        placePiece("白", 6, 5);
        placePiece("黑", 7, 7);
        placePiece("白", 7, 6);
        
        // 尝试在已有位置放置棋子
        placePiece("黑", 3, 3); // 应该失败
        
        System.out.println("\n对局结束!");
    }
}

/**
 * 棋子上下文
 */
class PieceContext {
    private final GoPiece piece;
    private final PieceExternalState externalState;
    
    public PieceContext(GoPiece piece, PieceExternalState externalState) {
        this.piece = piece;
        this.externalState = externalState;
    }
    
    public void display() {
        piece.display(externalState);
    }
    
    public GoPiece getPiece() {
        return piece;
    }
    
    public PieceExternalState getExternalState() {
        return externalState;
    }
}

3. 游戏客户端

java 复制代码
/**
 * 围棋游戏客户端
 */
public class GoGameClient {
    public static void main(String[] args) {
        System.out.println("=== 享元模式演示 - 围棋游戏 ===\n");
        
        GoBoard board = new GoBoard();
        
        // 演示围棋游戏
        board.simulateGame();
        board.displayBoard();
        
        // 显示享元池
        GoPieceFactory.getInstance().displayPool();
        
        // 演示内存节省
        demonstrateMemorySaving();
    }
    
    /**
     * 演示内存节省效果
     */
    private static void demonstrateMemorySaving() {
        System.out.println("\n💾 内存节省演示:");
        System.out.println("-".repeat(40));
        
        int totalPieces = 1000;
        GoPieceFactory factory = GoPieceFactory.getInstance();
        
        System.out.println("模拟放置 " + totalPieces + " 个棋子:");
        
        // 重置工厂
        // 在实际应用中,我们不会这样重置,这里只是为了演示
        System.out.println("创建黑白两种棋子享元...");
        
        // 模拟大量棋子放置
        GoPiece blackPiece = factory.getPiece("黑");
        GoPiece whitePiece = factory.getPiece("白");
        
        System.out.printf("实际创建的享元对象: %d 个%n", factory.getPoolSize());
        System.out.printf("内存节省: %d 个对象 -> %d 个享元, 节省 %.1f%% 内存%n",
            totalPieces, factory.getPoolSize(),
            (1 - (double) factory.getPoolSize() / totalPieces) * 100);
    }
}

实际应用示例:数据库连接池

java 复制代码
import java.util.HashMap;
import java.util.Map;

/**
 * 数据库连接池 - 享元模式实际应用
 */
public class ConnectionPool {
    private static ConnectionPool instance;
    private final Map<String, DatabaseConnection> connectionPool;
    private final int maxPoolSize;
    
    private ConnectionPool(int maxPoolSize) {
        this.connectionPool = new HashMap<>();
        this.maxPoolSize = maxPoolSize;
        System.out.println("初始化数据库连接池,最大连接数: " + maxPoolSize);
    }
    
    public static ConnectionPool getInstance(int maxPoolSize) {
        if (instance == null) {
            instance = new ConnectionPool(maxPoolSize);
        }
        return instance;
    }
    
    /**
     * 获取数据库连接
     */
    public DatabaseConnection getConnection(String databaseUrl, String username) {
        String key = databaseUrl + "|" + username;
        
        // 如果连接已存在且可用,直接返回
        if (connectionPool.containsKey(key) && connectionPool.get(key).isAvailable()) {
            System.out.println("✓ 复用数据库连接: " + key);
            return connectionPool.get(key);
        }
        
        // 如果连接池已满,等待或抛出异常
        if (connectionPool.size() >= maxPoolSize) {
            System.out.println("❌ 连接池已满,无法创建新连接");
            return null;
        }
        
        // 创建新连接
        System.out.println("➤ 创建新数据库连接: " + key);
        DatabaseConnection connection = new DatabaseConnection(databaseUrl, username);
        connectionPool.put(key, connection);
        
        return connection;
    }
    
    /**
     * 获取连接池状态
     */
    public void displayPoolStatus() {
        System.out.println("\n📊 连接池状态:");
        System.out.println("当前连接数: " + connectionPool.size());
        System.out.println("最大连接数: " + maxPoolSize);
        System.out.println("使用率: " + (connectionPool.size() * 100 / maxPoolSize) + "%");
    }
}

/**
 * 数据库连接 - 享元对象
 */
class DatabaseConnection {
    private final String databaseUrl;
    private final String username;
    private boolean inUse;
    
    public DatabaseConnection(String databaseUrl, String username) {
        this.databaseUrl = databaseUrl;
        this.username = username;
        this.inUse = false;
        System.out.println("建立到 " + databaseUrl + " 的连接,用户: " + username);
    }
    
    public void executeQuery(String sql) {
        if (!inUse) {
            inUse = true;
            System.out.println("执行查询: " + sql);
            // 模拟查询执行
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            inUse = false;
        } else {
            System.out.println("连接正在使用中,无法执行查询");
        }
    }
    
    public boolean isAvailable() {
        return !inUse;
    }
    
    public String getConnectionInfo() {
        return databaseUrl + " (" + username + ")";
    }
}

享元模式的优点

1. 大幅减少内存使用

java 复制代码
// 没有享元模式:创建1000个独立对象
// 使用享元模式:只创建2个享元对象(黑白棋子)
// 内存节省:998个对象!

2. 提高性能

java 复制代码
// 对象创建和垃圾回收开销大大减少
// 特别适合大量细粒度对象的场景

3. 更好的对象管理

java 复制代码
// 通过工厂统一管理享元对象
// 可以轻松实现对象池等功能

享元模式的缺点

1. 增加系统复杂度

java 复制代码
// 需要区分内部状态和外部状态
// 增加了设计和实现的难度

2. 可能引入线程安全问题

java 复制代码
// 如果享元对象有状态,需要考虑线程安全
// 外部状态需要由客户端正确管理

适用场景

  1. 系统中有大量相似对象时
  2. 对象的大部分状态可以外部化时
  3. 需要缓冲池的场景
  4. 需要实现对象共享的场景

最佳实践

1. 合理划分内部状态和外部状态

java 复制代码
// 内部状态:不变的、可共享的
// 外部状态:变化的、不可共享的

2. 使用工厂管理享元对象

java 复制代码
public class FlyweightFactory {
    // 统一管理享元对象的创建和获取
    // 确保对象的正确共享
}

3. 考虑线程安全性

java 复制代码
// 如果享元对象有状态变化,需要同步控制
public synchronized Flyweight getFlyweight(String key) {
    // 线程安全的获取方式
}

享元模式 vs 其他模式

模式 目的 特点
享元模式 对象共享 减少内存使用,提高性能
单例模式 唯一实例 确保一个类只有一个实例
原型模式 对象复制 通过复制现有对象创建新对象

总结

享元模式就像是"资源共享中心",让相同的资源可以被多次使用,避免重复创建。

核心价值:

  • 大幅减少内存中对象的数量
  • 提高系统性能
  • 更好地管理相似对象

使用场景:

  • 系统中有大量相似对象时
  • 对象创建开销很大时
  • 需要实现对象池功能时

简单记忆:

大量对象不用愁,享元模式来帮忙!

内部状态可共享,外部状态客户端扛。

掌握享元模式,能够让你在处理大量相似对象时游刃有余,显著提升系统性能!

相关推荐
杯莫停丶3 小时前
设计模式之:组合模式
设计模式·组合模式
遥远_3 小时前
Java微服务无损发布生产案例
java·spring·微服务·优雅停机·java微服务无损发布
苹果醋34 小时前
学习札记-Java8系列-1-Java8新特性简介&为什么要学习Java8
java·运维·spring boot·mysql·nginx
武子康4 小时前
Java-159 MongoDB 副本集容器化 10 分钟速查卡|keyfile + –auth + 幂等 init 附 docker-compose
java·数据库·mongodb·docker·性能优化·nosql·1024程序员节
m0_748233644 小时前
C++ 模板初阶:从函数重载到泛型编程的优雅过渡
java·c++·算法·1024程序员节
以己之4 小时前
11.盛最多水的容器
java·算法·双指针·1024程序员节
摇滚侠4 小时前
全面掌握PostgreSQL关系型数据库,设置远程连接,笔记05,笔记06
java·数据库·笔记·postgresql
shepherd1265 小时前
破局延时任务(上):为什么选择Spring Boot + DelayQueue来自研分布式延时队列组件?
java·spring boot·后端·1024程序员节
机灵猫5 小时前
微服务中的服务熔断、降级与限流
java·数据库·微服务