设计模式——享元模式

享元模式 (Flyweight Pattern)

什么是享元模式?

享元模式是一种结构型设计模式,它允许你通过共享对象来减少内存使用。享元模式通过共享相似对象的固有状态来减少内存占用。

简单来说:享元模式就是"共享对象",让多个对象共享同一个实例。

生活中的例子

想象一下:

  • 五子棋:棋盘上的棋子可以共享,只有位置不同
  • 文字编辑器:相同的字符可以共享,只有位置不同
  • 游戏中的树:森林中的树可以共享,只有位置不同

为什么需要享元模式?

传统方式的问题

java 复制代码
// 创建大量相似对象
for (int i = 0; i < 10000; i++) {
    Tree tree = new Tree("松树", "绿色");
    tree.setPosition(i, i);
}

问题

  1. 内存浪费:大量相似对象占用大量内存
  2. 性能下降:创建和销毁大量对象影响性能

享元模式的优势

java 复制代码
// 共享对象
TreeFactory factory = new TreeFactory();
for (int i = 0; i < 10000; i++) {
    Tree tree = factory.getTree("松树", "绿色");
    tree.setPosition(i, i);
}

优势

  1. 减少内存:通过共享对象减少内存使用
  2. 提高性能:减少对象的创建和销毁

享元模式的结构

复制代码
┌─────────────────────┐
│    Flyweight        │  享元接口
├─────────────────────┤
│ + operation(): void │
└──────────┬──────────┘
           │ 实现
           │
┌──────────┴──────────┐
│  ConcreteFlyweight  │  具体享元
├─────────────────────┤
│ - intrinsicState    │
│ + operation(): void │
└─────────────────────┘

┌─────────────────────┐
│   FlyweightFactory  │  享元工厂
├─────────────────────┤
│ - flyweights: Map   │
│ + getFlyweight():   │
│   Flyweight         │
└─────────────────────┘

代码示例

1. 定义享元接口

java 复制代码
/**
 * 享元接口:树
 */
public interface Tree {
    /**
     * 显示树
     * @param x x坐标
     * @param y y坐标
     */
    void display(int x, int y);
}

2. 定义具体享元

java 复制代码
/**
 * 具体享元:树
 */
public class ConcreteTree implements Tree {
    private String type;
    private String color;
    
    public ConcreteTree(String type, String color) {
        this.type = type;
        this.color = color;
    }
    
    @Override
    public void display(int x, int y) {
        System.out.println(type + "树(" + color + ") 在位置 (" + x + ", " + y + ")");
    }
}

3. 定义享元工厂

java 复制代码
/**
 * 享元工厂:树工厂
 */
public class TreeFactory {
    private Map<String, Tree> trees = new HashMap<>();
    
    /**
     * 获取树
     */
    public Tree getTree(String type, String color) {
        String key = type + "-" + color;
        Tree tree = trees.get(key);
        
        if (tree == null) {
            tree = new ConcreteTree(type, color);
            trees.put(key, tree);
            System.out.println("创建新的" + type + "树(" + color + ")");
        }
        
        return tree;
    }
    
    /**
     * 获取树对象数量
     */
    public int getTreeCount() {
        return trees.size();
    }
}

4. 使用享元

java 复制代码
/**
 * 享元模式测试类
 * 演示如何使用享元模式减少内存使用
 */
public class FlyweightTest {
    
    public static void main(String[] args) {
        System.out.println("=== 享元模式测试 ===\n");
        
        TreeFactory factory = new TreeFactory();
        
        // 创建10000棵树
        System.out.println("--- 创建10000棵树 ---");
        for (int i = 0; i < 10000; i++) {
            Tree tree = factory.getTree("松树", "绿色");
            tree.display(i, i);
        }
        
        System.out.println("\n实际创建的树对象数量: " + factory.getTreeCount());
        
        // 创建不同类型的树
        System.out.println("\n--- 创建不同类型的树 ---");
        Tree tree1 = factory.getTree("松树", "绿色");
        Tree tree2 = factory.getTree("松树", "绿色");
        Tree tree3 = factory.getTree("柳树", "绿色");
        Tree tree4 = factory.getTree("枫树", "红色");
        
        tree1.display(0, 0);
        tree2.display(1, 1);
        tree3.display(2, 2);
        tree4.display(3, 3);
        
        System.out.println("\n实际创建的树对象数量: " + factory.getTreeCount());
        
        System.out.println("\n=== 享元模式的优势 ===");
        System.out.println("1. 减少内存:通过共享对象减少内存使用");
        System.out.println("2. 提高性能:减少对象的创建和销毁");
        System.out.println("3. 资源共享:多个对象可以共享资源");
        
        System.out.println("\n=== 实际应用场景 ===");
        System.out.println("1. 字符串常量池:Java中的字符串常量池");
        System.out.println("2. Integer缓存:Java中的Integer缓存");
        System.out.println("3. 游戏开发:游戏中的角色、道具等");
        System.out.println("4. 图形处理:共享相同的图形对象");
        
        System.out.println("\n=== 内存节省示例 ===");
        System.out.println("如果不使用享元模式:");
        System.out.println("  - 创建10000棵树需要10000个对象");
        System.out.println("使用享元模式:");
        System.out.println("  - 创建10000棵树只需要" + factory.getTreeCount() + "个对象");
        System.out.println("  - 节省了 " + (10000 - factory.getTreeCount()) + " 个对象");
    }
}

享元模式的优点

  1. 减少内存:通过共享对象减少内存使用
  2. 提高性能:减少对象的创建和销毁
  3. 资源共享:多个对象可以共享资源

享元模式的缺点

  1. 增加复杂度:引入了额外的类
  2. 状态分离:需要分离内部状态和外部状态

适用场景

  1. 大量相似对象:需要创建大量相似对象
  2. 内存敏感:对内存使用敏感
  3. 对象可共享:对象可以被共享

常见应用场景

  • 字符串常量池:Java中的字符串常量池
  • Integer缓存:Java中的Integer缓存
  • 游戏开发:游戏中的角色、道具等

使用建议

  • 大量相似对象:使用享元模式
  • 内存敏感:使用享元模式
  • 少量对象:直接创建即可

注意事项

⚠️ 享元模式虽然有用,但要注意:

  • 区分内部状态和外部状态
  • 确保对象是线程安全的
相关推荐
寻星探路2 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
曹牧4 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
爬山算法5 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7255 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎5 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄5 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
忆~遂愿5 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
小韩学长yyds6 小时前
Java序列化避坑指南:明确这4种场景,再也不盲目实现Serializable
java·序列化
仟濹6 小时前
【Java基础】多态 | 打卡day2
java·开发语言
Re.不晚6 小时前
JAVA进阶之路——无奖问答挑战2
java·开发语言