设计模式——享元模式

享元模式 (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缓存
  • 游戏开发:游戏中的角色、道具等

使用建议

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

注意事项

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

  • 区分内部状态和外部状态
  • 确保对象是线程安全的
相关推荐
J_liaty1 小时前
深入理解Java反射:原理、应用与最佳实践
java·开发语言·反射
小冷coding1 小时前
【面试】围绕‌服务注册与发现、配置中心、熔断限流、API网关路由‌四大核心组件会面临哪些问题?
java·面试·职场和发展
张彦峰ZYF1 小时前
Java+Python双语言开发AI工具全景分析与选型指南
java·人工智能·python
可儿·四系桜1 小时前
Kafka从入门到精通:分布式消息队列实战指南(Zookeeper 模式)
java·开发语言·zookeeper·kafka
小北方城市网2 小时前
SpringBoot 集成 Redis 实战(缓存优化与分布式锁):打造高可用缓存体系与并发控制
java·spring boot·redis·python·缓存·rabbitmq·java-rabbitmq
步步为营DotNet2 小时前
深度解析.NET 中Nullable<T>:灵活处理可能为空值的类型
java·前端·.net
努力d小白2 小时前
leetcode49.字母异位词分组
java·开发语言
爱笑的rabbit2 小时前
Linux和Windows的word模板导出转PDF下载保姆级教程,含PDF图片处理
java·spring
weixin_462446232 小时前
【实战】Java使用 Jsoup 将浏览器书签 HTML 转换为 JSON(支持多级目录)
java·html·json·书签